fix(jwt): fix handling of non-expiring JWT tokens BE-11242 (#12220)

pull/12223/head
andres-portainer 2 months ago committed by GitHub
parent dbe7cd16d4
commit 5fd4f52e35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -381,7 +381,9 @@ func (bouncer *RequestBouncer) RevokeJWT(token string) {
func (bouncer *RequestBouncer) cleanUpExpiredJWTPass() { func (bouncer *RequestBouncer) cleanUpExpiredJWTPass() {
bouncer.revokedJWT.Range(func(key, value any) bool { bouncer.revokedJWT.Range(func(key, value any) bool {
if time.Now().After(value.(time.Time)) { if t := value.(time.Time); t.IsZero() {
return true
} else if time.Now().After(t) {
bouncer.revokedJWT.Delete(key) bouncer.revokedJWT.Delete(key)
} }

@ -473,6 +473,17 @@ func TestJWTRevocation(t *testing.T) {
token, _, err := jwtService.GenerateToken(&portainer.TokenData{ID: 1}) token, _, err := jwtService.GenerateToken(&portainer.TokenData{ID: 1})
require.NoError(t, err) require.NoError(t, err)
settings, err := store.Settings().Settings()
require.NoError(t, err)
settings.KubeconfigExpiry = "0"
err = store.Settings().UpdateSettings(settings)
require.NoError(t, err)
kubeToken, err := jwtService.GenerateTokenForKubeconfig(&portainer.TokenData{ID: 1})
require.NoError(t, err)
apiKeyService := apikey.NewAPIKeyService(nil, nil) apiKeyService := apikey.NewAPIKeyService(nil, nil)
bouncer := NewRequestBouncer(store, jwtService, apiKeyService) bouncer := NewRequestBouncer(store, jwtService, apiKeyService)
@ -491,6 +502,7 @@ func TestJWTRevocation(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
bouncer.RevokeJWT(token) bouncer.RevokeJWT(token)
bouncer.RevokeJWT(kubeToken)
revokeLen := func() (l int) { revokeLen := func() (l int) {
bouncer.revokedJWT.Range(func(key, value any) bool { bouncer.revokedJWT.Range(func(key, value any) bool {
@ -501,7 +513,7 @@ func TestJWTRevocation(t *testing.T) {
return l return l
} }
require.Equal(t, 1, revokeLen()) require.Equal(t, 2, revokeLen())
_, err = bouncer.JWTAuthLookup(r) _, err = bouncer.JWTAuthLookup(r)
require.Error(t, err) require.Error(t, err)
@ -513,5 +525,5 @@ func TestJWTRevocation(t *testing.T) {
bouncer.cleanUpExpiredJWTPass() bouncer.cleanUpExpiredJWTPass()
require.Equal(t, 0, revokeLen()) require.Equal(t, 1, revokeLen())
} }

@ -137,6 +137,10 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData,
return nil, "", time.Time{}, errInvalidJWTToken return nil, "", time.Time{}, errInvalidJWTToken
} }
if cl.ExpiresAt == nil {
cl.ExpiresAt = &jwt.NumericDate{}
}
return &portainer.TokenData{ return &portainer.TokenData{
ID: portainer.UserID(cl.UserID), ID: portainer.UserID(cl.UserID),
Username: cl.Username, Username: cl.Username,

@ -3,14 +3,20 @@ package jwt
import ( import (
"testing" "testing"
"github.com/golang-jwt/jwt/v4"
portainer "github.com/portainer/portainer/api" portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/dataservices"
i "github.com/portainer/portainer/api/internal/testhelpers" "github.com/portainer/portainer/api/datastore"
"github.com/golang-jwt/jwt/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestService_GenerateTokenForKubeconfig(t *testing.T) { func TestService_GenerateTokenForKubeconfig(t *testing.T) {
_, store := datastore.MustNewTestStore(t, true, false)
err := store.User().Create(&portainer.User{ID: 1})
assert.NoError(t, err)
type fields struct { type fields struct {
userSessionTimeout string userSessionTimeout string
dataStore dataservices.DataStore dataStore dataservices.DataStore
@ -20,13 +26,17 @@ func TestService_GenerateTokenForKubeconfig(t *testing.T) {
data *portainer.TokenData data *portainer.TokenData
} }
mySettings := &portainer.Settings{ settings, err := store.Settings().Settings()
KubeconfigExpiry: "0", assert.NoError(t, err)
}
settings.KubeconfigExpiry = "0"
err = store.Settings().UpdateSettings(settings)
assert.NoError(t, err)
myFields := fields{ myFields := fields{
userSessionTimeout: "24h", userSessionTimeout: "24h",
dataStore: i.NewDatastore(i.WithSettingsService(mySettings)), dataStore: store,
} }
myTokenData := &portainer.TokenData{ myTokenData := &portainer.TokenData{
@ -66,6 +76,9 @@ func TestService_GenerateTokenForKubeconfig(t *testing.T) {
return return
} }
_, _, _, err = service.ParseAndVerifyToken(got)
assert.NoError(t, err)
parsedToken, err := jwt.ParseWithClaims(got, &claims{}, func(token *jwt.Token) (any, error) { parsedToken, err := jwt.ParseWithClaims(got, &claims{}, func(token *jwt.Token) (any, error) {
return service.secrets[kubeConfigScope], nil return service.secrets[kubeConfigScope], nil
}) })

Loading…
Cancel
Save