diff --git a/internal/idp/providers/jwt/session.go b/internal/idp/providers/jwt/session.go index 58ee9ab86..09cea2b5a 100644 --- a/internal/idp/providers/jwt/session.go +++ b/internal/idp/providers/jwt/session.go @@ -92,17 +92,14 @@ func (s *Session) validateToken(ctx context.Context, token string) (*oidc.IDToke return nil, fmt.Errorf("%w: invalid signature: %v", ErrInvalidToken, err) } - if !claims.GetExpiration().IsZero() { - if err = oidc.CheckExpiration(claims, offset); err != nil { - return nil, fmt.Errorf("%w: expired: %v", ErrInvalidToken, err) - } + if err = oidc.CheckExpiration(claims, offset); err != nil { + return nil, fmt.Errorf("%w: expired: %v", ErrInvalidToken, err) } - if !claims.GetIssuedAt().IsZero() { - if err = oidc.CheckIssuedAt(claims, maxAge, offset); err != nil { - return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err) - } + if err = oidc.CheckIssuedAt(claims, maxAge, offset); err != nil { + return nil, fmt.Errorf("%w: %v", ErrInvalidToken, err) } + return claims, nil } diff --git a/internal/idp/providers/jwt/session_test.go b/internal/idp/providers/jwt/session_test.go index de761f153..a6bcee0fa 100644 --- a/internal/idp/providers/jwt/session_test.go +++ b/internal/idp/providers/jwt/session_test.go @@ -104,6 +104,109 @@ func TestSession_FetchUser(t *testing.T) { }, }, }, + { + name: "invalid token (expired)", + fields: fields{ + issuer: "https://jwt.com", + jwtEndpoint: "https://auth.com/jwt", + keysEndpoint: "https://jwt.com/keys", + headerName: "jwt-header", + encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm { + return crypto.CreateMockEncryptionAlg(gomock.NewController(t)) + }, + httpMock: func(issuer string) { + gock.New(issuer). + Get("/keys"). + Reply(200). + JSON(keys(t)) + }, + authURL: "https://auth.com/jwt?authRequestID=testState", + tokens: &oidc.Tokens[*oidc.IDTokenClaims]{ + Token: &oauth2.Token{}, + IDToken: idToken(t, "https://jwt.com", time.Now().Add(-time.Minute), 0), + IDTokenClaims: &oidc.IDTokenClaims{ + TokenClaims: oidc.TokenClaims{ + Subject: "sub", + }, + UserInfoProfile: oidc.UserInfoProfile{ + Picture: "picture", + Name: "firstname lastname", + GivenName: "firstname", + FamilyName: "lastname", + Nickname: "nickname", + PreferredUsername: "username", + Profile: "profile", + Locale: oidc.NewLocale(language.English), + }, + UserInfoEmail: oidc.UserInfoEmail{ + Email: "email", + EmailVerified: oidc.Bool(true), + }, + UserInfoPhone: oidc.UserInfoPhone{ + PhoneNumber: "phone", + PhoneNumberVerified: true, + }, + }, + }, + }, + want: want{ + err: func(err error) bool { + return errors.Is(err, ErrInvalidToken) + }, + }, + }, + { + name: "invalid token (issuedAt in the future)", + fields: fields{ + issuer: "https://jwt.com", + jwtEndpoint: "https://auth.com/jwt", + keysEndpoint: "https://jwt.com/keys", + headerName: "jwt-header", + encryptionAlg: func(t *testing.T) crypto.EncryptionAlgorithm { + return crypto.CreateMockEncryptionAlg(gomock.NewController(t)) + }, + httpMock: func(issuer string) { + gock.New(issuer). + Get("/keys"). + Reply(200). + JSON(keys(t)) + }, + authURL: "https://auth.com/jwt?authRequestID=testState", + tokens: &oidc.Tokens[*oidc.IDTokenClaims]{ + Token: &oauth2.Token{}, + // skew is used to determine the iat (among other claims). Using a negative value will actually add it to the iat claim. + IDToken: idToken(t, "https://jwt.com", time.Now().Add(time.Hour), -time.Minute), + IDTokenClaims: &oidc.IDTokenClaims{ + TokenClaims: oidc.TokenClaims{ + Subject: "sub", + }, + UserInfoProfile: oidc.UserInfoProfile{ + Picture: "picture", + Name: "firstname lastname", + GivenName: "firstname", + FamilyName: "lastname", + Nickname: "nickname", + PreferredUsername: "username", + Profile: "profile", + Locale: oidc.NewLocale(language.English), + }, + UserInfoEmail: oidc.UserInfoEmail{ + Email: "email", + EmailVerified: oidc.Bool(true), + }, + UserInfoPhone: oidc.UserInfoPhone{ + PhoneNumber: "phone", + PhoneNumberVerified: true, + }, + }, + }, + }, + want: want{ + err: func(err error) bool { + return errors.Is(err, ErrInvalidToken) + }, + }, + }, { name: "successful fetch", fields: fields{ @@ -123,7 +226,7 @@ func TestSession_FetchUser(t *testing.T) { authURL: "https://auth.com/jwt?authRequestID=testState", tokens: &oidc.Tokens[*oidc.IDTokenClaims]{ Token: &oauth2.Token{}, - IDToken: idToken(t, "https://jwt.com"), + IDToken: idToken(t, "https://jwt.com", time.Now().Add(time.Hour), 0), IDTokenClaims: &oidc.IDTokenClaims{ TokenClaims: oidc.TokenClaims{ Subject: "sub", @@ -212,18 +315,18 @@ func TestSession_FetchUser(t *testing.T) { } } -func idToken(t *testing.T, issuer string) string { +func idToken(t *testing.T, issuer string, expiration time.Time, skew time.Duration) string { claims := oidc.NewIDTokenClaims( issuer, "sub", []string{"clientID"}, - time.Now().Add(1*time.Hour), - time.Now().Add(-1*time.Minute), + expiration, + time.Now().Add(-1*time.Hour), "", "", nil, "clientID", - 0, + skew, ) claims.UserInfoProfile = oidc.UserInfoProfile{ GivenName: "firstname",