1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 12:25:22 +02:00

fix(bouncer): add support for JWT revocation BE-11179 (#12165)
Some checks failed
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
ci / build_images (map[arch:arm platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Has been cancelled
ci / build_images (map[arch:s390x platform:linux version:]) (push) Has been cancelled
/ triage (push) Has been cancelled
Lint / Run linters (push) Has been cancelled
Test / test-client (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:linux]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Has been cancelled
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Has been cancelled
Test / test-server (map[arch:arm64 platform:linux]) (push) Has been cancelled
ci / build_manifests (push) Has been cancelled

This commit is contained in:
andres-portainer 2024-08-30 20:24:14 -03:00 committed by GitHub
parent 9133cbf544
commit 6cc95e11ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 176 additions and 12 deletions

View file

@ -103,7 +103,7 @@ func (service *Service) GenerateToken(data *portainer.TokenData) (string, time.T
}
// ParseAndVerifyToken parses a JWT token and verify its validity. It returns an error if token is invalid.
func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData, error) {
func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData, string, time.Time, error) {
scope := parseScope(token)
secret := service.secrets[scope]
parsedToken, err := jwt.ParseWithClaims(token, &claims{}, func(token *jwt.Token) (interface{}, error) {
@ -119,10 +119,10 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData,
user, err := service.dataStore.User().Read(portainer.UserID(cl.UserID))
if err != nil {
return nil, errInvalidJWTToken
return nil, "", time.Time{}, errInvalidJWTToken
}
if user.TokenIssueAt > cl.StandardClaims.IssuedAt {
return nil, errInvalidJWTToken
return nil, "", time.Time{}, errInvalidJWTToken
}
return &portainer.TokenData{
@ -131,10 +131,11 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData,
Role: portainer.UserRole(cl.Role),
Token: token,
ForceChangePassword: cl.ForceChangePassword,
}, nil
}, cl.Id, time.Unix(cl.ExpiresAt, 0), nil
}
}
return nil, errInvalidJWTToken
return nil, "", time.Time{}, errInvalidJWTToken
}
// parse a JWT token, fallback to defaultScope if no scope is present in the JWT

View file

@ -6,8 +6,10 @@ import (
"github.com/golang-jwt/jwt/v4"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/datastore"
i "github.com/portainer/portainer/api/internal/testhelpers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGenerateSignedToken(t *testing.T) {
@ -55,3 +57,56 @@ func TestGenerateSignedToken_InvalidScope(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, "invalid scope: testing", err.Error())
}
func TestGenerationAndParsing(t *testing.T) {
_, store := datastore.MustNewTestStore(t, true, false)
err := store.User().Create(&portainer.User{ID: 1})
require.NoError(t, err)
service, err := NewService("1h", store)
require.NoError(t, err)
expectedToken := &portainer.TokenData{
Username: "User",
ID: 1,
Role: 1,
}
tokenString, _, err := service.GenerateToken(expectedToken)
require.NoError(t, err)
expectedToken.Token = tokenString
token, _, _, err := service.ParseAndVerifyToken(tokenString)
require.NoError(t, err)
require.Equal(t, expectedToken, token)
}
func TestExpiration(t *testing.T) {
_, store := datastore.MustNewTestStore(t, true, false)
err := store.User().Create(&portainer.User{ID: 1})
require.NoError(t, err)
service, err := NewService("1h", store)
require.NoError(t, err)
expectedToken := &portainer.TokenData{
Username: "User",
ID: 1,
Role: 1,
}
service.SetUserSessionDuration(time.Second)
tokenString, _, err := service.GenerateToken(expectedToken)
require.NoError(t, err)
expectedToken.Token = tokenString
time.Sleep(2 * time.Second)
_, _, _, err = service.ParseAndVerifyToken(tokenString)
require.Error(t, err)
}