feature: static public keys file support for oidc provider
Co-authored-by: Jan Larwig <jan@larwig.com> Co-authored-by: JJ Łakis <jacek.lakis@checkatrade.com>
This commit is contained in:
		
							parent
							
								
									ae8fb08a89
								
							
						
					
					
						commit
						e28603f7af
					
				|  | @ -16,6 +16,7 @@ | ||||||
| - [#2620](https://github.com/oauth2-proxy/oauth2-proxy/pull/2620) fix: update code_verifier to use recommended method (@vishvananda) | - [#2620](https://github.com/oauth2-proxy/oauth2-proxy/pull/2620) fix: update code_verifier to use recommended method (@vishvananda) | ||||||
| - [#2392](https://github.com/oauth2-proxy/oauth2-proxy/pull/2392) chore: extend test cases for oidc provider and documentation regarding implicit setting of the groups scope when no scope was specified in the config (@jjlakis / @tuunit) | - [#2392](https://github.com/oauth2-proxy/oauth2-proxy/pull/2392) chore: extend test cases for oidc provider and documentation regarding implicit setting of the groups scope when no scope was specified in the config (@jjlakis / @tuunit) | ||||||
| - [#2902](https://github.com/oauth2-proxy/oauth2-proxy/pull/2902) feat(entra): add Workload Identity support for Entra ID (@jjlakis) | - [#2902](https://github.com/oauth2-proxy/oauth2-proxy/pull/2902) feat(entra): add Workload Identity support for Entra ID (@jjlakis) | ||||||
|  | - [#2376](https://github.com/oauth2-proxy/oauth2-proxy/pull/2376) feat: static public keys file support for oidc provider (@axel7083 / @jjlakis) | ||||||
| 
 | 
 | ||||||
| # V7.7.1 | # V7.7.1 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -410,6 +410,7 @@ character. | ||||||
| | `insecureSkipNonce` | _bool_ | InsecureSkipNonce skips verifying the ID Token's nonce claim that must match<br/>the random nonce sent in the initial OAuth flow. Otherwise, the nonce is checked<br/>after the initial OAuth redeem & subsequent token refreshes.<br/>default set to 'true'<br/>Warning: In a future release, this will change to 'false' by default for enhanced security. | | | `insecureSkipNonce` | _bool_ | InsecureSkipNonce skips verifying the ID Token's nonce claim that must match<br/>the random nonce sent in the initial OAuth flow. Otherwise, the nonce is checked<br/>after the initial OAuth redeem & subsequent token refreshes.<br/>default set to 'true'<br/>Warning: In a future release, this will change to 'false' by default for enhanced security. | | ||||||
| | `skipDiscovery` | _bool_ | SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints<br/>default set to 'false' | | | `skipDiscovery` | _bool_ | SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints<br/>default set to 'false' | | ||||||
| | `jwksURL` | _string_ | JwksURL is the OpenID Connect JWKS URL<br/>eg: https://www.googleapis.com/oauth2/v3/certs | | | `jwksURL` | _string_ | JwksURL is the OpenID Connect JWKS URL<br/>eg: https://www.googleapis.com/oauth2/v3/certs | | ||||||
|  | | `publicKeyFiles` | _[]string_ | PublicKeyFiles is a list of paths pointing to public key files in PEM format to use<br/>for verifying JWT tokens | | ||||||
| | `emailClaim` | _string_ | EmailClaim indicates which claim contains the user email,<br/>default set to 'email' | | | `emailClaim` | _string_ | EmailClaim indicates which claim contains the user email,<br/>default set to 'email' | | ||||||
| | `groupsClaim` | _string_ | GroupsClaim indicates which claim contains the user groups<br/>default set to 'groups' | | | `groupsClaim` | _string_ | GroupsClaim indicates which claim contains the user groups<br/>default set to 'groups' | | ||||||
| | `userIDClaim` | _string_ | UserIDClaim indicates which claim contains the user ID<br/>default set to 'email' | | | `userIDClaim` | _string_ | UserIDClaim indicates which claim contains the user ID<br/>default set to 'email' | | ||||||
|  |  | ||||||
|  | @ -96,7 +96,8 @@ Provider specific options can be found on their respective subpages. | ||||||
| | flag: `--oidc-extra-audience`<br/>toml: `oidc_extra_audiences`                                      | string \| list | additional audiences which are allowed to pass verification                                                                                                                                              | `"[]"`                | | | flag: `--oidc-extra-audience`<br/>toml: `oidc_extra_audiences`                                      | string \| list | additional audiences which are allowed to pass verification                                                                                                                                              | `"[]"`                | | ||||||
| | flag: `--oidc-groups-claim`<br/>toml: `oidc_groups_claim`                                           | string         | which OIDC claim contains the user groups                                                                                                                                                                | `"groups"`            | | | flag: `--oidc-groups-claim`<br/>toml: `oidc_groups_claim`                                           | string         | which OIDC claim contains the user groups                                                                                                                                                                | `"groups"`            | | ||||||
| | flag: `--oidc-issuer-url`<br/>toml: `oidc_issuer_url`                                               | string         | the OpenID Connect issuer URL, e.g. `"https://accounts.google.com"`                                                                                                                                      |                       | | | flag: `--oidc-issuer-url`<br/>toml: `oidc_issuer_url`                                               | string         | the OpenID Connect issuer URL, e.g. `"https://accounts.google.com"`                                                                                                                                      |                       | | ||||||
| | flag: `--oidc-jwks-url`<br/>toml: `oidc_jwks_url`                                                   | string         | OIDC JWKS URI for token verification; required if OIDC discovery is disabled                                                                                                                             |                       | | | flag: `--oidc-jwks-url`<br/>toml: `oidc_jwks_url`                                                   | string         | OIDC JWKS URI for token verification; required if OIDC discovery is disabled and public key files are not provided                                                                                       |                       | | ||||||
|  | | flag: `--oidc-public-key-file`<br/>toml: `oidc_public_key_files`                                    | string         | Path to public key file in PEM format to use for verifying JWT tokens (may be given multiple times). Required if OIDC discovery is disabled na JWKS URL isn't provided                                   | string \| list        | | ||||||
| | flag: `--profile-url`<br/>toml: `profile_url`                                                       | string         | Profile access endpoint                                                                                                                                                                                  |                       | | | flag: `--profile-url`<br/>toml: `profile_url`                                                       | string         | Profile access endpoint                                                                                                                                                                                  |                       | | ||||||
| | flag: `--prompt`<br/>toml: `prompt`                                                                 | string         | [OIDC prompt](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest); if present, `approval-prompt` is ignored                                                                               | `""`                  | | | flag: `--prompt`<br/>toml: `prompt`                                                                 | string         | [OIDC prompt](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest); if present, `approval-prompt` is ignored                                                                               | `""`                  | | ||||||
| | flag: `--provider-ca-file`<br/>toml: `provider_ca_files`                                            | string \| list | Paths to CA certificates that should be used when connecting to the provider. If not specified, the default Go trust sources are used instead.                                                           | | | flag: `--provider-ca-file`<br/>toml: `provider_ca_files`                                            | string \| list | Paths to CA certificates that should be used when connecting to the provider. If not specified, the default Go trust sources are used instead.                                                           | | ||||||
|  |  | ||||||
|  | @ -522,6 +522,7 @@ type LegacyProvider struct { | ||||||
| 	OIDCGroupsClaim                    string   `flag:"oidc-groups-claim" cfg:"oidc_groups_claim"` | 	OIDCGroupsClaim                    string   `flag:"oidc-groups-claim" cfg:"oidc_groups_claim"` | ||||||
| 	OIDCAudienceClaims                 []string `flag:"oidc-audience-claim" cfg:"oidc_audience_claims"` | 	OIDCAudienceClaims                 []string `flag:"oidc-audience-claim" cfg:"oidc_audience_claims"` | ||||||
| 	OIDCExtraAudiences                 []string `flag:"oidc-extra-audience" cfg:"oidc_extra_audiences"` | 	OIDCExtraAudiences                 []string `flag:"oidc-extra-audience" cfg:"oidc_extra_audiences"` | ||||||
|  | 	OIDCPublicKeyFiles                 []string `flag:"oidc-public-key-file" cfg:"oidc_public_key_files"` | ||||||
| 	LoginURL                           string   `flag:"login-url" cfg:"login_url"` | 	LoginURL                           string   `flag:"login-url" cfg:"login_url"` | ||||||
| 	RedeemURL                          string   `flag:"redeem-url" cfg:"redeem_url"` | 	RedeemURL                          string   `flag:"redeem-url" cfg:"redeem_url"` | ||||||
| 	ProfileURL                         string   `flag:"profile-url" cfg:"profile_url"` | 	ProfileURL                         string   `flag:"profile-url" cfg:"profile_url"` | ||||||
|  | @ -581,6 +582,7 @@ func legacyProviderFlagSet() *pflag.FlagSet { | ||||||
| 	flagSet.String("oidc-email-claim", OIDCEmailClaim, "which OIDC claim contains the user's email") | 	flagSet.String("oidc-email-claim", OIDCEmailClaim, "which OIDC claim contains the user's email") | ||||||
| 	flagSet.StringSlice("oidc-audience-claim", OIDCAudienceClaims, "which OIDC claims are used as audience to verify against client id") | 	flagSet.StringSlice("oidc-audience-claim", OIDCAudienceClaims, "which OIDC claims are used as audience to verify against client id") | ||||||
| 	flagSet.StringSlice("oidc-extra-audience", []string{}, "additional audiences allowed to pass audience verification") | 	flagSet.StringSlice("oidc-extra-audience", []string{}, "additional audiences allowed to pass audience verification") | ||||||
|  | 	flagSet.StringSlice("oidc-public-key-file", []string{}, "path to public key file in PEM format to use for verifying JWT tokens (may be given multiple times)") | ||||||
| 	flagSet.String("login-url", "", "Authentication endpoint") | 	flagSet.String("login-url", "", "Authentication endpoint") | ||||||
| 	flagSet.String("redeem-url", "", "Token redemption endpoint") | 	flagSet.String("redeem-url", "", "Token redemption endpoint") | ||||||
| 	flagSet.String("profile-url", "", "Profile access endpoint") | 	flagSet.String("profile-url", "", "Profile access endpoint") | ||||||
|  | @ -697,6 +699,7 @@ func (l *LegacyProvider) convert() (Providers, error) { | ||||||
| 		GroupsClaim:                    l.OIDCGroupsClaim, | 		GroupsClaim:                    l.OIDCGroupsClaim, | ||||||
| 		AudienceClaims:                 l.OIDCAudienceClaims, | 		AudienceClaims:                 l.OIDCAudienceClaims, | ||||||
| 		ExtraAudiences:                 l.OIDCExtraAudiences, | 		ExtraAudiences:                 l.OIDCExtraAudiences, | ||||||
|  | 		PublicKeyFiles:                 l.OIDCPublicKeyFiles, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Support for legacy configuration option
 | 	// Support for legacy configuration option
 | ||||||
|  |  | ||||||
|  | @ -242,6 +242,9 @@ type OIDCOptions struct { | ||||||
| 	// JwksURL is the OpenID Connect JWKS URL
 | 	// JwksURL is the OpenID Connect JWKS URL
 | ||||||
| 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | ||||||
| 	JwksURL string `json:"jwksURL,omitempty"` | 	JwksURL string `json:"jwksURL,omitempty"` | ||||||
|  | 	// PublicKeyFiles is a list of paths pointing to public key files in PEM format to use
 | ||||||
|  | 	// for verifying JWT tokens
 | ||||||
|  | 	PublicKeyFiles []string `json:"publicKeyFiles,omitempty"` | ||||||
| 	// EmailClaim indicates which claim contains the user email,
 | 	// EmailClaim indicates which claim contains the user email,
 | ||||||
| 	// default set to 'email'
 | 	// default set to 'email'
 | ||||||
| 	EmailClaim string `json:"emailClaim,omitempty"` | 	EmailClaim string `json:"emailClaim,omitempty"` | ||||||
|  |  | ||||||
|  | @ -2,11 +2,14 @@ package oidc | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/x509" | ||||||
|  | 	"encoding/pem" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"os" | ||||||
| 
 | 
 | ||||||
| 	"github.com/coreos/go-oidc/v3/oidc" | 	"github.com/coreos/go-oidc/v3/oidc" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests" |  | ||||||
| 	k8serrors "k8s.io/apimachinery/pkg/util/errors" | 	k8serrors "k8s.io/apimachinery/pkg/util/errors" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | @ -38,6 +41,10 @@ type ProviderVerifierOptions struct { | ||||||
| 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | 	// eg: https://www.googleapis.com/oauth2/v3/certs
 | ||||||
| 	JWKsURL string | 	JWKsURL string | ||||||
| 
 | 
 | ||||||
|  | 	// PublicKeyFiles is a list of paths pointing to public key files in PEM format to use
 | ||||||
|  | 	// for verifying JWT tokens
 | ||||||
|  | 	PublicKeyFiles []string | ||||||
|  | 
 | ||||||
| 	// SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints
 | 	// SkipDiscovery allows to skip OIDC discovery and use manually supplied Endpoints
 | ||||||
| 	SkipDiscovery bool | 	SkipDiscovery bool | ||||||
| 
 | 
 | ||||||
|  | @ -59,8 +66,12 @@ func (p ProviderVerifierOptions) validate() error { | ||||||
| 		errs = append(errs, errors.New("missing required setting: issuer-url")) | 		errs = append(errs, errors.New("missing required setting: issuer-url")) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if p.SkipDiscovery && p.JWKsURL == "" { | 	if p.SkipDiscovery && p.JWKsURL == "" && len(p.PublicKeyFiles) == 0 { | ||||||
| 		errs = append(errs, errors.New("missing required setting: jwks-url")) | 		errs = append(errs, errors.New("missing required setting: jwks-url or public-key-files")) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if p.JWKsURL != "" && len(p.PublicKeyFiles) > 0 { | ||||||
|  | 		errs = append(errs, errors.New("mutually exclusive settings: jwks-url and public-key-files")) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(errs) > 0 { | 	if len(errs) > 0 { | ||||||
|  | @ -91,12 +102,12 @@ func (p ProviderVerifierOptions) toOIDCConfig() *oidc.Config { | ||||||
| // NewProviderVerifier constructs a ProviderVerifier from the options given.
 | // NewProviderVerifier constructs a ProviderVerifier from the options given.
 | ||||||
| func NewProviderVerifier(ctx context.Context, opts ProviderVerifierOptions) (ProviderVerifier, error) { | func NewProviderVerifier(ctx context.Context, opts ProviderVerifierOptions) (ProviderVerifier, error) { | ||||||
| 	if err := opts.validate(); err != nil { | 	if err := opts.validate(); err != nil { | ||||||
| 		return nil, fmt.Errorf("invalid provider verifier options: %v", err) | 		return nil, fmt.Errorf("invalid provider verifier options: %w", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	verifierBuilder, provider, err := getVerifierBuilder(ctx, opts) | 	verifierBuilder, provider, err := getVerifierBuilder(ctx, opts) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("could not get verifier builder: %v", err) | 		return nil, fmt.Errorf("could not get verifier builder: %w", err) | ||||||
| 	} | 	} | ||||||
| 	verifier := NewVerifier(verifierBuilder(opts.toOIDCConfig()), opts.toVerificationOptions()) | 	verifier := NewVerifier(verifierBuilder(opts.toOIDCConfig()), opts.toVerificationOptions()) | ||||||
| 
 | 
 | ||||||
|  | @ -117,22 +128,78 @@ type verifierBuilder func(*oidc.Config) *oidc.IDTokenVerifier | ||||||
| 
 | 
 | ||||||
| func getVerifierBuilder(ctx context.Context, opts ProviderVerifierOptions) (verifierBuilder, DiscoveryProvider, error) { | func getVerifierBuilder(ctx context.Context, opts ProviderVerifierOptions) (verifierBuilder, DiscoveryProvider, error) { | ||||||
| 	if opts.SkipDiscovery { | 	if opts.SkipDiscovery { | ||||||
|  | 		var keySet oidc.KeySet | ||||||
|  | 		var err error | ||||||
|  | 
 | ||||||
|  | 		if opts.JWKsURL != "" { | ||||||
|  | 			keySet = oidc.NewRemoteKeySet(ctx, opts.JWKsURL) | ||||||
|  | 		} else { | ||||||
|  | 			keySet, err = newKeySetFromStatic(opts.PublicKeyFiles) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return nil, nil, fmt.Errorf("error while parsing public keys: %w", err) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 		// Instead of discovering the JWKs URL, it needs to be specified in the opts already
 | 		// Instead of discovering the JWKs URL, it needs to be specified in the opts already
 | ||||||
| 		return newVerifierBuilder(ctx, opts.IssuerURL, opts.JWKsURL, opts.SupportedSigningAlgs), nil, nil | 		return newVerifierBuilder( | ||||||
|  | 			opts.IssuerURL, | ||||||
|  | 			keySet, | ||||||
|  | 			opts.SupportedSigningAlgs, | ||||||
|  | 		), nil, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	provider, err := NewProvider(ctx, opts.IssuerURL, opts.SkipIssuerVerification) | 	provider, err := NewProvider(ctx, opts.IssuerURL, opts.SkipIssuerVerification) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, nil, fmt.Errorf("error while discovery OIDC configuration: %v", err) | 		return nil, nil, fmt.Errorf("error while discovery OIDC configuration: %w", err) | ||||||
| 	} | 	} | ||||||
| 	verifierBuilder := newVerifierBuilder(ctx, opts.IssuerURL, provider.Endpoints().JWKsURL, provider.SupportedSigningAlgs()) | 
 | ||||||
| 	return verifierBuilder, provider, nil | 	return newVerifierBuilder( | ||||||
|  | 		opts.IssuerURL, | ||||||
|  | 		oidc.NewRemoteKeySet(ctx, provider.Endpoints().JWKsURL), | ||||||
|  | 		provider.SupportedSigningAlgs(), | ||||||
|  | 	), provider, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetPublicKeyFromBytes parses a PEM-encoded public key from a byte array
 | ||||||
|  | // and returns a crypto.PublicKey object.
 | ||||||
|  | func getPublicKeyFromBytes(bytes []byte) (crypto.PublicKey, error) { | ||||||
|  | 	block, _ := pem.Decode(bytes) | ||||||
|  | 	if block == nil { | ||||||
|  | 		return nil, errors.New("failed to parse PEM block containing the public key") | ||||||
|  | 	} | ||||||
|  | 	publicKey, err := x509.ParsePKIXPublicKey(block.Bytes) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("failed to parse public key: %w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	cryptoPublicKey, ok := publicKey.(crypto.PublicKey) | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, errors.New("failed to cast public key to crypto.PublicKey") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return cryptoPublicKey, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // newKeySetFromStatic create a StaticKeySet from a set of files
 | ||||||
|  | func newKeySetFromStatic(keys []string) (*oidc.StaticKeySet, error) { | ||||||
|  | 	keySet := []crypto.PublicKey{} | ||||||
|  | 	for _, keyFile := range keys { | ||||||
|  | 		bytes, err := os.ReadFile(keyFile) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, fmt.Errorf("failed to read file: %w", err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		publicKey, err := getPublicKeyFromBytes(bytes) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, fmt.Errorf("failed to create keys: %w", err) | ||||||
|  | 		} | ||||||
|  | 		keySet = append(keySet, publicKey) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &oidc.StaticKeySet{PublicKeys: keySet}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // newVerifierBuilder returns a function to create a IDToken verifier from an OIDC config.
 | // newVerifierBuilder returns a function to create a IDToken verifier from an OIDC config.
 | ||||||
| func newVerifierBuilder(ctx context.Context, issuerURL, jwksURL string, supportedSigningAlgs []string) verifierBuilder { | func newVerifierBuilder(issuerURL string, keySet oidc.KeySet, supportedSigningAlgs []string) verifierBuilder { | ||||||
| 	ctx = oidc.ClientContext(ctx, requests.DefaultHTTPClient) |  | ||||||
| 	keySet := oidc.NewRemoteKeySet(ctx, jwksURL) |  | ||||||
| 	return func(oidcConfig *oidc.Config) *oidc.IDTokenVerifier { | 	return func(oidcConfig *oidc.Config) *oidc.IDTokenVerifier { | ||||||
| 		if len(supportedSigningAlgs) > 0 { | 		if len(supportedSigningAlgs) > 0 { | ||||||
| 			oidcConfig.SupportedSigningAlgs = supportedSigningAlgs | 			oidcConfig.SupportedSigningAlgs = supportedSigningAlgs | ||||||
|  |  | ||||||
|  | @ -2,6 +2,8 @@ package oidc | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"os" | ||||||
|  | 	"path/filepath" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/golang-jwt/jwt/v5" | 	"github.com/golang-jwt/jwt/v5" | ||||||
|  | @ -10,6 +12,37 @@ import ( | ||||||
| 	. "github.com/onsi/gomega" | 	. "github.com/onsi/gomega" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | var tempDir string | ||||||
|  | var invalidPublicKeyFilePath string | ||||||
|  | var validPublicKeyFilePath string | ||||||
|  | 
 | ||||||
|  | var _ = BeforeSuite(func() { | ||||||
|  | 	var err error | ||||||
|  | 
 | ||||||
|  | 	// Create a temporary directory and public key file
 | ||||||
|  | 	tempDir, err = os.MkdirTemp("/tmp", "provider-verifier-test") | ||||||
|  | 	Expect(err).ToNot(HaveOccurred()) | ||||||
|  | 
 | ||||||
|  | 	invalidPublicKeyFilePath = filepath.Join(tempDir, "invalid.key") | ||||||
|  | 	validPublicKeyFilePath = filepath.Join(tempDir, "valid.key") | ||||||
|  | 
 | ||||||
|  | 	invalidKeyContents := []byte(`-----BEGIN INVALID KEY----- | ||||||
|  | ThisIsNotAValidKey | ||||||
|  | -----END INVALID KEY-----`) | ||||||
|  | 	Expect(os.WriteFile(invalidPublicKeyFilePath, invalidKeyContents, 0644)).To(Succeed()) | ||||||
|  | 
 | ||||||
|  | 	validKeyContents := []byte(`-----BEGIN PUBLIC KEY----- | ||||||
|  | MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALBJK+8qU+aQu2bHxJ8E95AIu2NINztM | ||||||
|  | NmX9R2zI9xlXN8wGQG8kWLYoRLbyiZwY9kdzOBGvYci64wHIjtFswHcCAwEAAQ== | ||||||
|  | -----END PUBLIC KEY-----`) | ||||||
|  | 	Expect(os.WriteFile(validPublicKeyFilePath, validKeyContents, 0644)).To(Succeed()) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | var _ = AfterSuite(func() { | ||||||
|  | 	// Clean up temporary directory
 | ||||||
|  | 	Expect(os.RemoveAll(tempDir)).To(Succeed()) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
| var _ = Describe("ProviderVerifier", func() { | var _ = Describe("ProviderVerifier", func() { | ||||||
| 	var m *mockoidc.MockOIDC | 	var m *mockoidc.MockOIDC | ||||||
| 
 | 
 | ||||||
|  | @ -77,14 +110,42 @@ var _ = Describe("ProviderVerifier", func() { | ||||||
| 				p.SkipDiscovery = true | 				p.SkipDiscovery = true | ||||||
| 				p.JWKsURL = "" | 				p.JWKsURL = "" | ||||||
| 			}, | 			}, | ||||||
| 			expectedError: "invalid provider verifier options: missing required setting: jwks-url", | 			expectedError: "invalid provider verifier options: missing required setting: jwks-url or public-key-files", | ||||||
| 		}), | 		}), | ||||||
| 		Entry("should be succesfful when skipping discovery with the JWKs URL specified", &newProviderVerifierTableInput{ | 		Entry("with skip discovery, the JWKs URL not empty and len(PublicKeyFiles) is greater than 0", &newProviderVerifierTableInput{ | ||||||
|  | 			modifyOpts: func(p *ProviderVerifierOptions) { | ||||||
|  | 				p.SkipDiscovery = true | ||||||
|  | 				p.JWKsURL = "notEmpty" | ||||||
|  | 				p.PublicKeyFiles = []string{"notEmpty"} | ||||||
|  | 			}, | ||||||
|  | 			expectedError: "invalid provider verifier options: mutually exclusive settings: jwks-url and public-key-files", | ||||||
|  | 		}), | ||||||
|  | 		Entry("should be successful when skipping discovery with the JWKs URL specified", &newProviderVerifierTableInput{ | ||||||
| 			modifyOpts: func(p *ProviderVerifierOptions) { | 			modifyOpts: func(p *ProviderVerifierOptions) { | ||||||
| 				p.SkipDiscovery = true | 				p.SkipDiscovery = true | ||||||
| 				p.JWKsURL = m.JWKSEndpoint() | 				p.JWKsURL = m.JWKSEndpoint() | ||||||
| 			}, | 			}, | ||||||
| 		}), | 		}), | ||||||
|  | 		Entry("should pass when the key is valid", &newProviderVerifierTableInput{ | ||||||
|  | 			modifyOpts: func(p *ProviderVerifierOptions) { | ||||||
|  | 				p.SkipDiscovery = true | ||||||
|  | 				p.PublicKeyFiles = []string{validPublicKeyFilePath} | ||||||
|  | 			}, | ||||||
|  | 		}), | ||||||
|  | 		Entry("should fail when the key is invalid", &newProviderVerifierTableInput{ | ||||||
|  | 			modifyOpts: func(p *ProviderVerifierOptions) { | ||||||
|  | 				p.SkipDiscovery = true | ||||||
|  | 				p.PublicKeyFiles = []string{invalidPublicKeyFilePath} | ||||||
|  | 			}, | ||||||
|  | 			expectedError: "could not get verifier builder: error while parsing public keys", | ||||||
|  | 		}), | ||||||
|  | 		Entry("should fail when the key file is not found", &newProviderVerifierTableInput{ | ||||||
|  | 			modifyOpts: func(p *ProviderVerifierOptions) { | ||||||
|  | 				p.SkipDiscovery = true | ||||||
|  | 				p.PublicKeyFiles = []string{"non-existing"} | ||||||
|  | 			}, | ||||||
|  | 			expectedError: "could not get verifier builder: error while parsing public keys: failed to read file", | ||||||
|  | 		}), | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	type verifierTableInput struct { | 	type verifierTableInput struct { | ||||||
|  |  | ||||||
|  | @ -92,6 +92,7 @@ func newProviderDataFromConfig(providerConfig options.Provider) (*ProviderData, | ||||||
| 			ExtraAudiences:         providerConfig.OIDCConfig.ExtraAudiences, | 			ExtraAudiences:         providerConfig.OIDCConfig.ExtraAudiences, | ||||||
| 			IssuerURL:              providerConfig.OIDCConfig.IssuerURL, | 			IssuerURL:              providerConfig.OIDCConfig.IssuerURL, | ||||||
| 			JWKsURL:                providerConfig.OIDCConfig.JwksURL, | 			JWKsURL:                providerConfig.OIDCConfig.JwksURL, | ||||||
|  | 			PublicKeyFiles:         providerConfig.OIDCConfig.PublicKeyFiles, | ||||||
| 			SkipDiscovery:          providerConfig.OIDCConfig.SkipDiscovery, | 			SkipDiscovery:          providerConfig.OIDCConfig.SkipDiscovery, | ||||||
| 			SkipIssuerVerification: providerConfig.OIDCConfig.InsecureSkipIssuerVerification, | 			SkipIssuerVerification: providerConfig.OIDCConfig.InsecureSkipIssuerVerification, | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
|  | @ -86,7 +86,7 @@ func TestSkipOIDCDiscovery(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, err := newProviderDataFromConfig(providerConfig) | 	_, err := newProviderDataFromConfig(providerConfig) | ||||||
| 	g.Expect(err).To(MatchError("error building OIDC ProviderVerifier: invalid provider verifier options: missing required setting: jwks-url")) | 	g.Expect(err).To(MatchError("error building OIDC ProviderVerifier: invalid provider verifier options: missing required setting: jwks-url or public-key-files")) | ||||||
| 
 | 
 | ||||||
| 	providerConfig.LoginURL = msAuthURL | 	providerConfig.LoginURL = msAuthURL | ||||||
| 	providerConfig.RedeemURL = msTokenURL | 	providerConfig.RedeemURL = msTokenURL | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue