From 8ad4dd6a36412b2055b7b2454ea6afd663032306 Mon Sep 17 00:00:00 2001 From: Przemek Pokrywka <12400578+dekiel@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:41:10 +0100 Subject: [PATCH] Run expiration check with extended time for all tokens (#12245) * Remove unused flags Print oidc verifier config in log messages * Skip expiry check and run expiration check with 10 minutes expiration time by default for all tokens. Added options to set expiry check and expiration time values. Verify method runs own expiration check if upstream expiry check is skipped. Added expiration check verification. Applying options only if provided. This allows better logging. --- cmd/oidc-token-verifier/main.go | 61 ++---------- pkg/oidc/oidc.go | 122 ++++++++++++++++++------ pkg/oidc/oidc_test.go | 164 +++++++++++++++++++++++++++----- pkg/oidc/oidc_unit_test.go | 37 +++++++ 4 files changed, 280 insertions(+), 104 deletions(-) create mode 100644 pkg/oidc/oidc_unit_test.go diff --git a/cmd/oidc-token-verifier/main.go b/cmd/oidc-token-verifier/main.go index 993ae9bc82bb..9f8c9a80917b 100644 --- a/cmd/oidc-token-verifier/main.go +++ b/cmd/oidc-token-verifier/main.go @@ -1,11 +1,9 @@ package main import ( - "errors" "fmt" "os" - "github.com/coreos/go-oidc/v3/oidc" "github.com/kyma-project/test-infra/pkg/logging" tioidc "github.com/kyma-project/test-infra/pkg/oidc" "github.com/spf13/cobra" @@ -24,9 +22,6 @@ type Logger interface { type options struct { token string clientID string - outputPath string - publicKeyPath string - newPublicKeysVarName string trustedWorkflows []string debug bool oidcTokenExpirationTime int // OIDC token expiration time in minutes @@ -46,7 +41,6 @@ func NewRootCmd() *cobra.Command { It uses OIDC discovery to get the public keys and verify the token whenever the public keys are not cached or expired.`, } rootCmd.PersistentFlags().StringVarP(&opts.token, "token", "t", "", "OIDC token to verify") - rootCmd.PersistentFlags().StringVarP(&opts.newPublicKeysVarName, "new-keys-var", "n", "OIDC_NEW_PUBLIC_KEYS", "Name of the environment variable to set when new public keys are fetched") // This flag should be enabled once we add support for it in the code. // rootCmd.PersistentFlags().StringSliceVarP(&opts.trustedWorkflows, "trusted-workflows", "w", []string{}, "List of trusted workflows") // err := rootCmd.MarkPersistentFlagRequired("trusted-workflows") @@ -54,7 +48,6 @@ func NewRootCmd() *cobra.Command { // panic(err) // } rootCmd.PersistentFlags().StringVarP(&opts.clientID, "client-id", "c", "image-builder", "OIDC token client ID, this is used to verify the audience claim in the token. The value should be the same as the audience claim value in the token.") - rootCmd.PersistentFlags().StringVarP(&opts.publicKeyPath, "public-key-path", "p", "", "Path to the cached public keys directory") rootCmd.PersistentFlags().BoolVarP(&opts.debug, "debug", "d", false, "Enable debug mode") rootCmd.PersistentFlags().IntVarP(&opts.oidcTokenExpirationTime, "oidc-token-expiration-time", "e", 10, "OIDC token expiration time in minutes") return rootCmd @@ -65,7 +58,7 @@ func NewVerifyCmd() *cobra.Command { Use: "verify", Short: "Verify token and expected claims values", RunE: func(_ *cobra.Command, _ []string) error { - if err := opts.extractClaims(); err != nil { + if err := opts.verifyToken(); err != nil { return err } return nil @@ -105,12 +98,11 @@ func isTokenProvided(logger Logger, opts *options) error { // It verifies the token signature and expiration time, verifies if the token is issued by a trusted issuer, // and the claims have expected values. // It uses OIDC discovery to get the identity provider public keys. -func (opts *options) extractClaims() error { +func (opts *options) verifyToken() error { var ( - zapLogger *zap.Logger - err error - tokenExpiredError *oidc.TokenExpiredError - token *tioidc.Token + zapLogger *zap.Logger + err error + token *tioidc.Token ) if opts.debug { zapLogger, err = zap.NewDevelopment() @@ -130,13 +122,10 @@ func (opts *options) extractClaims() error { // Print used options values. logger.Infow("Using the following trusted workflows", "trusted-workflows", opts.trustedWorkflows) logger.Infow("Using the following client ID", "client-id", opts.clientID) - logger.Infow("Using the following public key path", "public-key-path", opts.publicKeyPath) - logger.Infow("Using the following new public keys environment variable", "new-keys-var", opts.newPublicKeysVarName) - logger.Infow("Using the following claims output path", "claims-output-path", opts.outputPath) // Create a new verifier config that will be used to verify the token. // The clientID is used to verify the audience claim in the token. - verifyConfig, err := tioidc.NewVerifierConfig(logger, opts.clientID) + verifyConfig, err := tioidc.NewVerifierConfig(logger, opts.clientID, tioidc.SkipExpiryCheck()) if err != nil { return err } @@ -164,20 +153,14 @@ func (opts *options) extractClaims() error { // Create a new verifier using the provider and the verifier config. // The verifier is used to verify the token signature, expiration time and execute standard OIDC validation. - verifier := provider.NewVerifier(logger, verifyConfig) + verifier, err := provider.NewVerifier(logger, verifyConfig, tioidc.WithExtendedExpiration(opts.oidcTokenExpirationTime)) + if err != nil { + return err + } logger.Infow("New verifier created") // Verify the token token, err = verifier.Verify(ctx, opts.token) - if errors.As(err, &tokenExpiredError) { - err = verifier.VerifyExtendedExpiration(err.(*oidc.TokenExpiredError).Expiry, opts.oidcTokenExpirationTime) - if err != nil { - return err - } - verifyConfig.SkipExpiryCheck = false - verifierWithoutExpiration := provider.NewVerifier(logger, verifyConfig) - token, err = verifierWithoutExpiration.Verify(ctx, opts.token) - } if err != nil { return err } @@ -199,30 +182,6 @@ func (opts *options) extractClaims() error { return nil } -// If the public keys are not cached or expired, it uses OIDC discovery to get the public keys. -// New public keys are written to the file specified by the --public-key-path flag. -// If new public keys are fetched, it sets ado environment variable to true. - -// loadPublicKeysFromLocal loads the public keys from the file specified by the --public-key-path flag. -// example implementation https://gist.github.com/nilsmagnus/199d56ce849b83bdd7df165b25cb2f56 -// func (opts *options) loadPublicKeysFromLocal() error { -// -// } -// - -// savePublicKeysFromRemote fetches the public keys from the OIDC discovery endpoint. -// It writes the public keys to the file specified by the --public-key-path flag. -// It sets the environment variable specified by --new-public-keys-var-name to true to indicate that new public keys are fetched. -// func (opts *options) savePublicKeysFromRemote(issuer string) error { -// -// } - -// setAdoEnvVar sets the Azure DevOps pipeline environment variable to true. -// Environment variable name is specified by --new-public-keys-var-name flag. -// func (opts *options) setAdoEnvVar() error { -// -// } - func main() { if err := rootCmd.Execute(); err != nil { panic(err) diff --git a/pkg/oidc/oidc.go b/pkg/oidc/oidc.go index b105df761bab..409045e1e230 100644 --- a/pkg/oidc/oidc.go +++ b/pkg/oidc/oidc.go @@ -95,6 +95,13 @@ type VerifierConfig struct { oidc.Config } +// String returns the string representation of the VerifierConfig. +// It's used for logging purposes. +func (config *VerifierConfig) String() string { + return fmt.Sprintf("ClientID: %s, SkipClientIDCheck: %t, SkipExpiryCheck: %t, SkipIssuerCheck: %t, InsecureSkipSignatureCheck: %t, SupportedSigningAlgs: %v, Now: %T", + config.ClientID, config.SkipClientIDCheck, config.SkipExpiryCheck, config.SkipIssuerCheck, config.InsecureSkipSignatureCheck, config.SupportedSigningAlgs, config.Now) +} + // TokenProcessor is responsible for processing the token. type TokenProcessor struct { rawToken string @@ -134,6 +141,16 @@ type GithubClaims struct { // VerifierConfigOption is a function that modifies the VerifierConfig. type VerifierConfigOption func(*VerifierConfig) error +// SkipExpiryCheck set verifier config to skip the token expiration check. +// It's used to allow longer token expiration time. +// The Verifier must run its own expiration check for extended expiration time. +func SkipExpiryCheck() VerifierConfigOption { + return func(config *VerifierConfig) error { + config.SkipExpiryCheck = true + return nil + } +} + // Provider is the OIDC provider. // It abstracts the provider implementation. // VerifierProvider provides the OIDC token verifier. @@ -145,16 +162,31 @@ type Provider struct { // Token is the OIDC token. // It abstracts the IDToken implementation. type Token struct { - Token ClaimsReader + Token ClaimsReader + IssuedAt time.Time } // TokenVerifier is the OIDC token verifier. // It abstracts the Verifier implementation. type TokenVerifier struct { - Verifier Verifier - Logger LoggerInterface + Config VerifierConfig + ExpirationTimeMinutes int + Verifier Verifier + Logger LoggerInterface +} + +// TokenVerifierOption is a function that modifies the TokenVerifier. +type TokenVerifierOption func(verifier *TokenVerifier) error + +// WithExtendedExpiration sets the custom expiration time used by the TokenVerifier. +func WithExtendedExpiration(expirationTimeMinutes int) TokenVerifierOption { + return func(verifier *TokenVerifier) error { + verifier.ExpirationTimeMinutes = expirationTimeMinutes + return nil + } } +// maskToken masks the token value. It's used for debug logging purposes. func maskToken(token string) string { if len(token) < 15 { return "********" @@ -205,42 +237,57 @@ func NewVerifierConfig(logger LoggerInterface, clientID string, options ...Verif // Verify verifies the raw OIDC token. // It returns a Token struct which contains the verified token if successful. +// Verify allow checking extended expiration time for the token. +// It runs the token expiration check if the upstream verifier is configured to skip it. func (tokenVerifier *TokenVerifier) Verify(ctx context.Context, rawToken string) (*Token, error) { logger := tokenVerifier.Logger - logger.Debugw("Verifying token") - logger.Debugw("Got raw token value", "rawToken", maskToken(rawToken)) + logger.Debugw("verifying token", "rawToken", maskToken(rawToken)) idToken, err := tokenVerifier.Verifier.Verify(ctx, rawToken) if err != nil { - token := Token{} - return &token, fmt.Errorf("failed to verify token: %w", err) + return nil, fmt.Errorf("failed to verify token: %w", err) } - logger.Debugw("Token verified successfully") + logger.Debugw("upstream verifier checks finished") token := Token{ - Token: idToken, + Token: idToken, + IssuedAt: idToken.IssuedAt, } + logger.Debugw("checking if upstream verifier is configured to skip token expiration check", "SkipExpiryCheck", tokenVerifier.Config.SkipExpiryCheck) + if tokenVerifier.Config.SkipExpiryCheck { + logger.Debugw("upstream verifier configured to skip token expiration check, running our own check", "expirationTimeMinutes", tokenVerifier.ExpirationTimeMinutes, "tokenIssuedAt", token.IssuedAt) + err = token.IsTokenExpired(logger, tokenVerifier.ExpirationTimeMinutes) + logger.Debugw("finished token expiration check") + } + if err != nil { + return nil, fmt.Errorf("failed to verify token: %w", err) + } + logger.Debugw("token verified successfully") return &token, nil } -// VerifyExtendedExpiration checks the OIDC token expiration timestamp against the provided expiration time. -// It allows to accept tokens after the token original expiration time elapsed. -// The other aspects of the token must be verified separately with expiration check disabled. -func (tokenVerifier *TokenVerifier) VerifyExtendedExpiration(expirationTimestamp time.Time, gracePeriodMinutes int) error { - logger := tokenVerifier.Logger - logger.Debugw("Verifying token expiration time", "expirationTimestamp", expirationTimestamp, "gracePeriodMinutes", gracePeriodMinutes) +// IsTokenExpired checks the OIDC token expiration timestamp against the provided expiration time. +// It allows accepting tokens after the token original expiration time elapsed. +// The other aspects of the token must be verified separately with the expiration check disabled. +func (token *Token) IsTokenExpired(logger LoggerInterface, expirationTimeMinutes int) error { + logger.Debugw("verifying token expiration time", "tokenIssuedAt", token.IssuedAt, "expirationTimeMinutes", expirationTimeMinutes) now := time.Now() - // check if expirationTimestamp is in the future - if expirationTimestamp.After(now) { - return fmt.Errorf("token expiration time is in the future: %v", expirationTimestamp) + if token.IssuedAt.After(now) { + return fmt.Errorf("token issued in the future, tokenIssuedAt: %v, now: %v", token.IssuedAt, now) } - elapsed := now.Sub(expirationTimestamp) - gracePeriod := time.Minute - if elapsed <= gracePeriod { + logger.Debugw("token issued in the past") + expirationTime := token.IssuedAt.Add(time.Minute * time.Duration(expirationTimeMinutes)) + logger.Debugw("computed expiration time", "expirationTime", expirationTime) + if expirationTime.After(now) || expirationTime.Equal(now) { + logger.Debugw("token not expired") return nil } - return fmt.Errorf("token expired more than %v ago", gracePeriod) + return fmt.Errorf("token expired, tokenIssuedAt: %v, expired at %v", token.IssuedAt, expirationTime) } // Claims gets the claims from the token and unmarshal them into the provided claims struct. +// TODO: Should we have a tests for this method? +// +// We can test for returned error. +// We can test the claims struct is populated with the expected values. func (token *Token) Claims(claims interface{}) error { return token.Token.Claims(claims) } @@ -284,15 +331,26 @@ func NewProviderFromDiscovery(ctx context.Context, logger LoggerInterface, issue // NewVerifier creates a new TokenVerifier for provider. // It returns a TokenVerifier struct containing the new Verifier if successful. -func (provider *Provider) NewVerifier(logger LoggerInterface, verifierConfig VerifierConfig) TokenVerifier { +func (provider *Provider) NewVerifier(logger LoggerInterface, verifierConfig VerifierConfig, options ...TokenVerifierOption) (TokenVerifier, error) { logger.Debugw("Creating new verifier with config", "config", fmt.Sprintf("%+v", verifierConfig)) verifier := provider.VerifierProvider.Verifier(&verifierConfig.Config) tokenVerifier := TokenVerifier{ + Config: verifierConfig, Verifier: verifier, Logger: logger, } + if len(options) > 0 { + logger.Debugw("Applying TokenVerifierOptions") + for _, option := range options { + err := option(&tokenVerifier) + if err != nil { + return TokenVerifier{}, fmt.Errorf("failed to apply TokenVerifierOption: %w", err) + } + } + logger.Debugw("Applied all TokenVerifierOptions") + } logger.Debugw("Created new verifier") - return tokenVerifier + return tokenVerifier, nil } // NewTokenProcessor creates a new TokenProcessor for trusted issuers. @@ -339,14 +397,16 @@ func NewTokenProcessor( tokenProcessor.issuer = trustedIssuer logger.Debugw("Added trusted issuer to TokenProcessor", "issuer", tokenProcessor.issuer) - logger.Debugw("Applying TokenProcessorOptions") - for _, option := range options { - err := option(&tokenProcessor) - if err != nil { - return TokenProcessor{}, fmt.Errorf("failed to apply TokenProcessorOption: %w", err) + if len(options) > 0 { + logger.Debugw("Applying TokenProcessorOptions") + for _, option := range options { + err := option(&tokenProcessor) + if err != nil { + return TokenProcessor{}, fmt.Errorf("failed to apply TokenProcessorOption: %w", err) + } } + logger.Debugw("Applied all TokenProcessorOptions") } - logger.Debugw("Applied all TokenProcessorOptions") logger.Debugw("Created token processor", "issuer", tokenProcessor.issuer) return tokenProcessor, nil @@ -396,8 +456,8 @@ func (tokenProcessor *TokenProcessor) isTrustedIssuer(issuer string, trustedIssu return Issuer{}, fmt.Errorf("issuer %s is not trusted", issuer) } -// TODO(dekiel): This should return Issuer struct or has a different name. // Issuer returns the issuer of the token. +// TODO(dekiel): This should return Issuer struct or has a different name. func (tokenProcessor *TokenProcessor) Issuer() string { return tokenProcessor.issuer.IssuerURL } diff --git a/pkg/oidc/oidc_test.go b/pkg/oidc/oidc_test.go index 48a91d111635..70f4d967308d 100644 --- a/pkg/oidc/oidc_test.go +++ b/pkg/oidc/oidc_test.go @@ -41,6 +41,16 @@ var _ = Describe("OIDC", func() { clientID = "testClientID" }) + Describe("SkipExpiryCheck", func() { + It("should set SkipExpiryCheck to true", func() { + config := &tioidc.VerifierConfig{} + option := tioidc.SkipExpiryCheck() + err := option(config) + Expect(err).NotTo(HaveOccurred()) + Expect(config.SkipExpiryCheck).To(BeTrue()) + }) + }) + Describe("NewVerifierConfig", func() { var ( verifierConfigOption tioidc.VerifierConfigOption @@ -270,54 +280,163 @@ var _ = Describe("OIDC", func() { Verifier: verifier, Logger: logger, } + verifierConfig, err = tioidc.NewVerifierConfig(logger, clientID) + Expect(err).NotTo(HaveOccurred()) ctx = context.Background() rawToken, err = os.ReadFile("test-fixtures/raw-oidc-token") Expect(err).NotTo(HaveOccurred()) }) + + Describe("WithExtendedExpiration option", func() { + + It("should set expiration time", func() { + expirationTime := 1 + option := tioidc.WithExtendedExpiration(expirationTime) + err := option(&tokenVerifier) + Expect(err).NotTo(HaveOccurred()) + Expect(tokenVerifier.ExpirationTimeMinutes).To(Equal(expirationTime)) + }) + }) + Describe("Verify", func() { - It("should return Token when the token is valid", func() { - verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(&oidc.IDToken{}, nil) + It("should return Token when the token is valid with standard expiration time", func() { + // prepare + issuedAt := time.Now().Add(-4 * time.Minute) + idToken := &oidc.IDToken{IssuedAt: issuedAt} + tokenVerifier.Config.SkipExpiryCheck = false + tokenVerifier.ExpirationTimeMinutes = 10 + verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(idToken, nil) + + // execute token, err = tokenVerifier.Verify(ctx, string(rawToken)) + + // verify + Expect(err).NotTo(HaveOccurred()) + Expect(token).To(Equal(&tioidc.Token{Token: idToken, IssuedAt: issuedAt})) + }) + + It("should return Token when the token is valid with extended expiration time", func() { + // prepare + issuedAt := time.Now().Add(-9 * time.Minute) + idToken := &oidc.IDToken{IssuedAt: issuedAt} + verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(idToken, nil) + tokenVerifier.Config.SkipExpiryCheck = true + tokenVerifier.ExpirationTimeMinutes = 10 + + // execute + token, err = tokenVerifier.Verify(ctx, string(rawToken)) + + // verify Expect(err).NotTo(HaveOccurred()) - Expect(token).To(BeAssignableToTypeOf(&tioidc.Token{})) + Expect(token).To(Equal(&tioidc.Token{Token: idToken, IssuedAt: issuedAt})) }) - It("should return an error when the token is invalid", func() { - verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(&oidc.IDToken{}, errors.New("invalid token")) + It("should return an error when the token is invalid with standard expiration time", func() { + // prepare + verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(nil, errors.New("invalid token")) + tokenVerifier.Config.SkipExpiryCheck = false + tokenVerifier.ExpirationTimeMinutes = 10 + + // execute token, err = tokenVerifier.Verify(ctx, string(rawToken)) + + // verify Expect(err).To(HaveOccurred()) Expect(err).To(MatchError("failed to verify token: invalid token")) - Expect(token).To(Equal(&tioidc.Token{})) + Expect(token).To(BeNil()) + }) + + It("should return an error when the token is invalid with extended expiration time", func() { + // prepare + verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(nil, errors.New("invalid token")) + tokenVerifier.Config.SkipExpiryCheck = true + tokenVerifier.ExpirationTimeMinutes = 10 + + // execute + token, err = tokenVerifier.Verify(ctx, string(rawToken)) + + // verify + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError("failed to verify token: invalid token")) + Expect(token).To(BeNil()) + }) + + It("should return an error when token expired with standard expiration check", func() { + // prepare + // issuedAt := time.Now().Add(-6 * time.Minute) + // idToken := &oidc.IDToken{IssuedAt: issuedAt} + verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(nil, errors.New("token expired")) + tokenVerifier.Config.SkipExpiryCheck = false + tokenVerifier.ExpirationTimeMinutes = 10 + + // execute + token, err = tokenVerifier.Verify(ctx, string(rawToken)) + + // verify + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError("failed to verify token: token expired")) + Expect(token).To(BeNil()) + }) + + It("should return an error when token expired with extended expiration check", func() { + // prepare + issuedAt := time.Now().Add(-11 * time.Minute) + idToken := &oidc.IDToken{IssuedAt: issuedAt} + verifier.On("Verify", mock.AnythingOfType("backgroundCtx"), string(rawToken)).Return(idToken, nil) + tokenVerifier.Config.SkipExpiryCheck = true + tokenVerifier.ExpirationTimeMinutes = 10 + + // execute + token, err = tokenVerifier.Verify(ctx, string(rawToken)) + + // verify + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError(fmt.Errorf("failed to verify token: %w", + fmt.Errorf("token expired, tokenIssuedAt: %v, expired at %v", issuedAt, issuedAt.Add(time.Minute*time.Duration(tokenVerifier.ExpirationTimeMinutes))), + ))) + Expect(token).To(BeNil()) }) }) - Describe("VerifyExtendedExpiration", func() { + }) + + Describe("Token", func() { + + Describe("IsTokenExpired", func() { var ( - expirationTimestamp time.Time - gracePeriodMinutes int + now time.Time + expirationTimeMinutes int ) BeforeEach(func() { - gracePeriodMinutes = 1 + now = time.Now() + expirationTimeMinutes = 1 }) - It("should return no error when the token is within the grace period", func() { - expirationTimestamp = time.Now().Add(-30 * time.Second) - err := tokenVerifier.VerifyExtendedExpiration(expirationTimestamp, gracePeriodMinutes) + It("should return no error when the token is within the expiration time", func() { + token := tioidc.Token{ + IssuedAt: now, + } + err := token.IsTokenExpired(logger, expirationTimeMinutes) Expect(err).NotTo(HaveOccurred()) }) - It("should return an error when the token is expired beyond the grace period", func() { - expirationTimestamp = time.Now().Add(-2 * time.Minute) - err := tokenVerifier.VerifyExtendedExpiration(expirationTimestamp, gracePeriodMinutes) + It("should return an error when the token is expired", func() { + token := tioidc.Token{ + IssuedAt: now.Add(-2 * time.Minute), // 2 minutes ago + } + extendedExpiration := token.IssuedAt.Add(time.Minute * time.Duration(expirationTimeMinutes)) + err := token.IsTokenExpired(logger, expirationTimeMinutes) Expect(err).To(HaveOccurred()) - Expect(err).To(MatchError("token expired more than 1m0s ago")) + Expect(err).To(MatchError(fmt.Errorf("token expired, tokenIssuedAt: %v, expired at %v", token.IssuedAt, extendedExpiration))) }) - It("should return an error when the token expiration timestamp is in the future", func() { - expirationTimestamp = time.Now().Add(1 * time.Minute) - err := tokenVerifier.VerifyExtendedExpiration(expirationTimestamp, gracePeriodMinutes) + It("should return an error when the token issued in the future", func() { + token := tioidc.Token{ + IssuedAt: now.Add(2 * time.Minute), // 2 minutes ago + } + err := token.IsTokenExpired(logger, expirationTimeMinutes) Expect(err).To(HaveOccurred()) - Expect(err).To(MatchError(fmt.Sprintf("token expiration time is in the future: %v", expirationTimestamp))) + Expect(err).To(MatchError(MatchRegexp("token issued in the future, tokenIssuedAt: .+, now: .+"))) }) }) }) @@ -339,7 +458,8 @@ var _ = Describe("OIDC", func() { Describe("NewVerifier", func() { It("should return a new TokenVerifier", func() { oidcProvider.On("Verifier", &verifierConfig.Config).Return(&oidc.IDTokenVerifier{}) - verifier := provider.NewVerifier(logger, verifierConfig) + verifier, err := provider.NewVerifier(logger, verifierConfig) + Expect(err).NotTo(HaveOccurred()) Expect(verifier).NotTo(BeNil()) Expect(verifier).To(BeAssignableToTypeOf(tioidc.TokenVerifier{})) }) diff --git a/pkg/oidc/oidc_unit_test.go b/pkg/oidc/oidc_unit_test.go new file mode 100644 index 000000000000..a4b996cc4fca --- /dev/null +++ b/pkg/oidc/oidc_unit_test.go @@ -0,0 +1,37 @@ +package oidc + +// oidc_unit_test.go contains tests which require access to non-exported functions and variables. + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("OIDC", func() { + Describe("maskToken", func() { + It("should mask the token if length is less than 15", func() { + token := "shorttoken" + maskedToken := maskToken(token) + Expect(maskedToken).To(Equal("********")) + }) + + It("should mask the token if length is exactly 15", func() { + token := "123456789012345" + maskedToken := maskToken(token) + Expect(maskedToken).To(Equal("12********45")) + }) + + It("should mask the token if length is greater than 15", func() { + token := "12345678901234567890" + maskedToken := maskToken(token) + Expect(maskedToken).To(Equal("12********90")) + }) + + It("should mask the token if it's empty", func() { + token := "" + maskedToken := maskToken(token) + Expect(maskedToken).To(Equal("********")) + }) + }) + +})