From d9429f45b7d897a8b234ad61766bcc44aeadb672 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Mon, 8 Oct 2018 00:05:52 -0700 Subject: [PATCH] Delete oidc --- pkg/kubeapiserver/authenticator/config.go | 59 - pkg/kubeapiserver/options/authentication.go | 78 - .../plugin/pkg/authenticator/token/oidc/BUILD | 51 - .../pkg/authenticator/token/oidc/OWNERS | 7 - .../pkg/authenticator/token/oidc/oidc.go | 703 ------- .../pkg/authenticator/token/oidc/oidc_test.go | 1643 ----------------- .../token/oidc/testdata/ecdsa_1.pem | 7 - .../token/oidc/testdata/ecdsa_2.pem | 7 - .../token/oidc/testdata/ecdsa_3.pem | 7 - .../authenticator/token/oidc/testdata/gen.sh | 29 - .../token/oidc/testdata/rsa_1.pem | 27 - .../token/oidc/testdata/rsa_2.pem | 27 - .../token/oidc/testdata/rsa_3.pem | 27 - 13 files changed, 2672 deletions(-) delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/BUILD delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/OWNERS delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc_test.go delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_1.pem delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_2.pem delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_3.pem delete mode 100755 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/gen.sh delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_1.pem delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_2.pem delete mode 100644 staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_3.pem diff --git a/pkg/kubeapiserver/authenticator/config.go b/pkg/kubeapiserver/authenticator/config.go index 3a4d1b6d29..a9ecdc47e7 100644 --- a/pkg/kubeapiserver/authenticator/config.go +++ b/pkg/kubeapiserver/authenticator/config.go @@ -34,7 +34,6 @@ import ( utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/apiserver/plugin/pkg/authenticator/password/passwordfile" "k8s.io/apiserver/plugin/pkg/authenticator/request/basicauth" - "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" "k8s.io/apiserver/plugin/pkg/authenticator/token/webhook" // Initialize all known client auth plugins. @@ -51,15 +50,6 @@ type Config struct { BasicAuthFile string ClientCAFile string TokenAuthFile string - OIDCIssuerURL string - OIDCClientID string - OIDCCAFile string - OIDCUsernameClaim string - OIDCUsernamePrefix string - OIDCGroupsClaim string - OIDCGroupsPrefix string - OIDCSigningAlgs []string - OIDCRequiredClaims map[string]string ServiceAccountKeyFiles []string ServiceAccountLookup bool ServiceAccountIssuer string @@ -138,30 +128,6 @@ func (config Config) New() (authenticator.Request, error) { } tokenAuthenticators = append(tokenAuthenticators, serviceAccountAuth) } - // NOTE(ericchiang): Keep the OpenID Connect after Service Accounts. - // - // Because both plugins verify JWTs whichever comes first in the union experiences - // cache misses for all requests using the other. While the service account plugin - // simply returns an error, the OpenID Connect plugin may query the provider to - // update the keys, causing performance hits. - if len(config.OIDCIssuerURL) > 0 && len(config.OIDCClientID) > 0 { - oidcAuth, err := newAuthenticatorFromOIDCIssuerURL(oidc.Options{ - IssuerURL: config.OIDCIssuerURL, - ClientID: config.OIDCClientID, - APIAudiences: config.APIAudiences, - CAFile: config.OIDCCAFile, - UsernameClaim: config.OIDCUsernameClaim, - UsernamePrefix: config.OIDCUsernamePrefix, - GroupsClaim: config.OIDCGroupsClaim, - GroupsPrefix: config.OIDCGroupsPrefix, - SupportedSigningAlgs: config.OIDCSigningAlgs, - RequiredClaims: config.OIDCRequiredClaims, - }) - if err != nil { - return nil, err - } - tokenAuthenticators = append(tokenAuthenticators, oidcAuth) - } if len(config.WebhookTokenAuthnConfigFile) > 0 { webhookTokenAuth, err := newWebhookTokenAuthenticator(config.WebhookTokenAuthnConfigFile, config.WebhookTokenAuthnCacheTTL, config.APIAudiences) if err != nil { @@ -226,31 +192,6 @@ func newAuthenticatorFromTokenFile(tokenAuthFile string) (authenticator.Token, e return tokenAuthenticator, nil } -// newAuthenticatorFromOIDCIssuerURL returns an authenticator.Token or an error. -func newAuthenticatorFromOIDCIssuerURL(opts oidc.Options) (authenticator.Token, error) { - const noUsernamePrefix = "-" - - if opts.UsernamePrefix == "" && opts.UsernameClaim != "email" { - // Old behavior. If a usernamePrefix isn't provided, prefix all claims other than "email" - // with the issuerURL. - // - // See https://github.com/kubernetes/kubernetes/issues/31380 - opts.UsernamePrefix = opts.IssuerURL + "#" - } - - if opts.UsernamePrefix == noUsernamePrefix { - // Special value indicating usernames shouldn't be prefixed. - opts.UsernamePrefix = "" - } - - tokenAuthenticator, err := oidc.New(opts) - if err != nil { - return nil, err - } - - return tokenAuthenticator, nil -} - // newLegacyServiceAccountAuthenticator returns an authenticator.Token or an error func newLegacyServiceAccountAuthenticator(keyfiles []string, lookup bool, apiAudiences authenticator.Audiences, serviceAccountGetter serviceaccount.ServiceAccountTokenGetter) (authenticator.Token, error) { allPublicKeys := []interface{}{} diff --git a/pkg/kubeapiserver/options/authentication.go b/pkg/kubeapiserver/options/authentication.go index b1f5c9030c..096305421e 100644 --- a/pkg/kubeapiserver/options/authentication.go +++ b/pkg/kubeapiserver/options/authentication.go @@ -29,7 +29,6 @@ import ( "k8s.io/apiserver/pkg/authentication/authenticator" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" - cliflag "k8s.io/component-base/cli/flag" kubeauthenticator "k8s.io/kubernetes/pkg/kubeapiserver/authenticator" authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes" ) @@ -38,7 +37,6 @@ type BuiltInAuthenticationOptions struct { APIAudiences []string Anonymous *AnonymousAuthenticationOptions ClientCert *genericoptions.ClientCertAuthenticationOptions - OIDC *OIDCAuthenticationOptions PasswordFile *PasswordFileAuthenticationOptions RequestHeader *genericoptions.RequestHeaderAuthenticationOptions ServiceAccounts *ServiceAccountAuthenticationOptions @@ -53,18 +51,6 @@ type AnonymousAuthenticationOptions struct { Allow bool } -type OIDCAuthenticationOptions struct { - CAFile string - ClientID string - IssuerURL string - UsernameClaim string - UsernamePrefix string - GroupsClaim string - GroupsPrefix string - SigningAlgs []string - RequiredClaims map[string]string -} - type PasswordFileAuthenticationOptions struct { BasicAuthFile string } @@ -96,7 +82,6 @@ func (s *BuiltInAuthenticationOptions) WithAll() *BuiltInAuthenticationOptions { return s. WithAnonymous(). WithClientCert(). - WithOIDC(). WithPasswordFile(). WithRequestHeader(). WithServiceAccounts(). @@ -114,11 +99,6 @@ func (s *BuiltInAuthenticationOptions) WithClientCert() *BuiltInAuthenticationOp return s } -func (s *BuiltInAuthenticationOptions) WithOIDC() *BuiltInAuthenticationOptions { - s.OIDC = &OIDCAuthenticationOptions{} - return s -} - func (s *BuiltInAuthenticationOptions) WithPasswordFile() *BuiltInAuthenticationOptions { s.PasswordFile = &PasswordFileAuthenticationOptions{} return s @@ -150,10 +130,6 @@ func (s *BuiltInAuthenticationOptions) WithWebHook() *BuiltInAuthenticationOptio func (s *BuiltInAuthenticationOptions) Validate() []error { allErrors := []error{} - if s.OIDC != nil && (len(s.OIDC.IssuerURL) > 0) != (len(s.OIDC.ClientID) > 0) { - allErrors = append(allErrors, fmt.Errorf("oidc-issuer-url and oidc-client-id should be specified together")) - } - if s.ServiceAccounts != nil && len(s.ServiceAccounts.Issuer) > 0 && strings.Contains(s.ServiceAccounts.Issuer, ":") { if _, err := url.Parse(s.ServiceAccounts.Issuer); err != nil { allErrors = append(allErrors, fmt.Errorf("service-account-issuer contained a ':' but was not a valid URL: %v", err)) @@ -181,48 +157,6 @@ func (s *BuiltInAuthenticationOptions) AddFlags(fs *pflag.FlagSet) { s.ClientCert.AddFlags(fs) } - if s.OIDC != nil { - fs.StringVar(&s.OIDC.IssuerURL, "oidc-issuer-url", s.OIDC.IssuerURL, ""+ - "The URL of the OpenID issuer, only HTTPS scheme will be accepted. "+ - "If set, it will be used to verify the OIDC JSON Web Token (JWT).") - - fs.StringVar(&s.OIDC.ClientID, "oidc-client-id", s.OIDC.ClientID, - "The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.") - - fs.StringVar(&s.OIDC.CAFile, "oidc-ca-file", s.OIDC.CAFile, ""+ - "If set, the OpenID server's certificate will be verified by one of the authorities "+ - "in the oidc-ca-file, otherwise the host's root CA set will be used.") - - fs.StringVar(&s.OIDC.UsernameClaim, "oidc-username-claim", "sub", ""+ - "The OpenID claim to use as the user name. Note that claims other than the default ('sub') "+ - "is not guaranteed to be unique and immutable. This flag is experimental, please see "+ - "the authentication documentation for further details.") - - fs.StringVar(&s.OIDC.UsernamePrefix, "oidc-username-prefix", "", ""+ - "If provided, all usernames will be prefixed with this value. If not provided, "+ - "username claims other than 'email' are prefixed by the issuer URL to avoid "+ - "clashes. To skip any prefixing, provide the value '-'.") - - fs.StringVar(&s.OIDC.GroupsClaim, "oidc-groups-claim", "", ""+ - "If provided, the name of a custom OpenID Connect claim for specifying user groups. "+ - "The claim value is expected to be a string or array of strings. This flag is experimental, "+ - "please see the authentication documentation for further details.") - - fs.StringVar(&s.OIDC.GroupsPrefix, "oidc-groups-prefix", "", ""+ - "If provided, all groups will be prefixed with this value to prevent conflicts with "+ - "other authentication strategies.") - - fs.StringSliceVar(&s.OIDC.SigningAlgs, "oidc-signing-algs", []string{"RS256"}, ""+ - "Comma-separated list of allowed JOSE asymmetric signing algorithms. JWTs with a "+ - "'alg' header value not in this list will be rejected. "+ - "Values are defined by RFC 7518 https://tools.ietf.org/html/rfc7518#section-3.1.") - - fs.Var(cliflag.NewMapStringStringNoSplit(&s.OIDC.RequiredClaims), "oidc-required-claim", ""+ - "A key=value pair that describes a required claim in the ID Token. "+ - "If set, the claim is verified to be present in the ID Token with a matching value. "+ - "Repeat this flag to specify multiple claims.") - } - if s.PasswordFile != nil { fs.StringVar(&s.PasswordFile.BasicAuthFile, "basic-auth-file", s.PasswordFile.BasicAuthFile, ""+ "If set, the file that will be used to admit requests to the secure port of the API server "+ @@ -289,18 +223,6 @@ func (s *BuiltInAuthenticationOptions) ToAuthenticationConfig() kubeauthenticato ret.ClientCAFile = s.ClientCert.ClientCA } - if s.OIDC != nil { - ret.OIDCCAFile = s.OIDC.CAFile - ret.OIDCClientID = s.OIDC.ClientID - ret.OIDCGroupsClaim = s.OIDC.GroupsClaim - ret.OIDCGroupsPrefix = s.OIDC.GroupsPrefix - ret.OIDCIssuerURL = s.OIDC.IssuerURL - ret.OIDCUsernameClaim = s.OIDC.UsernameClaim - ret.OIDCUsernamePrefix = s.OIDC.UsernamePrefix - ret.OIDCSigningAlgs = s.OIDC.SigningAlgs - ret.OIDCRequiredClaims = s.OIDC.RequiredClaims - } - if s.PasswordFile != nil { ret.BasicAuthFile = s.PasswordFile.BasicAuthFile } diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/BUILD b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/BUILD deleted file mode 100644 index df9f34382a..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/BUILD +++ /dev/null @@ -1,51 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -load( - "@io_bazel_rules_go//go:def.bzl", - "go_library", - "go_test", -) - -go_test( - name = "go_default_test", - size = "small", - srcs = ["oidc_test.go"], - data = glob(["testdata/**"]), - embed = [":go_default_library"], - deps = [ - "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", - "//vendor/github.com/coreos/go-oidc:go_default_library", - "//vendor/gopkg.in/square/go-jose.v2:go_default_library", - "//vendor/k8s.io/klog:go_default_library", - ], -) - -go_library( - name = "go_default_library", - srcs = ["oidc.go"], - importmap = "k8s.io/kubernetes/vendor/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc", - importpath = "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc", - deps = [ - "//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/authentication/authenticator:go_default_library", - "//staging/src/k8s.io/apiserver/pkg/authentication/user:go_default_library", - "//staging/src/k8s.io/client-go/util/cert:go_default_library", - "//vendor/github.com/coreos/go-oidc:go_default_library", - "//vendor/k8s.io/klog:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], -) diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/OWNERS b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/OWNERS deleted file mode 100644 index 03fb44ea24..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/OWNERS +++ /dev/null @@ -1,7 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -approvers: -- ericchiang -reviewers: -- ericchiang -- rithujohn191 diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go deleted file mode 100644 index 1888fa91d6..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc.go +++ /dev/null @@ -1,703 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -/* -oidc implements the authenticator.Token interface using the OpenID Connect protocol. - - config := oidc.Options{ - IssuerURL: "https://accounts.google.com", - ClientID: os.Getenv("GOOGLE_CLIENT_ID"), - UsernameClaim: "email", - } - tokenAuthenticator, err := oidc.New(config) -*/ -package oidc - -import ( - "context" - "crypto/tls" - "crypto/x509" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "strings" - "sync" - "sync/atomic" - "time" - - oidc "github.com/coreos/go-oidc" - "k8s.io/klog" - - "k8s.io/apimachinery/pkg/util/net" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - certutil "k8s.io/client-go/util/cert" -) - -var ( - // synchronizeTokenIDVerifierForTest should be set to true to force a - // wait until the token ID verifiers are ready. - synchronizeTokenIDVerifierForTest = false -) - -type Options struct { - // IssuerURL is the URL the provider signs ID Tokens as. This will be the "iss" - // field of all tokens produced by the provider and is used for configuration - // discovery. - // - // The URL is usually the provider's URL without a path, for example - // "https://accounts.google.com" or "https://login.salesforce.com". - // - // The provider must implement configuration discovery. - // See: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig - IssuerURL string - - // ClientID the JWT must be issued for, the "sub" field. This plugin only trusts a single - // client to ensure the plugin can be used with public providers. - // - // The plugin supports the "authorized party" OpenID Connect claim, which allows - // specialized providers to issue tokens to a client for a different client. - // See: https://openid.net/specs/openid-connect-core-1_0.html#IDToken - ClientID string - - // APIAudiences are the audiences that the API server identitifes as. The - // (API audiences unioned with the ClientIDs) should have a non-empty - // intersection with the request's target audience. This preserves the - // behavior of the OIDC authenticator pre-introduction of API audiences. - APIAudiences authenticator.Audiences - - // Path to a PEM encoded root certificate of the provider. - CAFile string - - // UsernameClaim is the JWT field to use as the user's username. - UsernameClaim string - - // UsernamePrefix, if specified, causes claims mapping to username to be prefix with - // the provided value. A value "oidc:" would result in usernames like "oidc:john". - UsernamePrefix string - - // GroupsClaim, if specified, causes the OIDCAuthenticator to try to populate the user's - // groups with an ID Token field. If the GroupsClaim field is present in an ID Token the value - // must be a string or list of strings. - GroupsClaim string - - // GroupsPrefix, if specified, causes claims mapping to group names to be prefixed with the - // value. A value "oidc:" would result in groups like "oidc:engineering" and "oidc:marketing". - GroupsPrefix string - - // SupportedSigningAlgs sets the accepted set of JOSE signing algorithms that - // can be used by the provider to sign tokens. - // - // https://tools.ietf.org/html/rfc7518#section-3.1 - // - // This value defaults to RS256, the value recommended by the OpenID Connect - // spec: - // - // https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation - SupportedSigningAlgs []string - - // RequiredClaims, if specified, causes the OIDCAuthenticator to verify that all the - // required claims key value pairs are present in the ID Token. - RequiredClaims map[string]string - - // now is used for testing. It defaults to time.Now. - now func() time.Time -} - -// initVerifier creates a new ID token verifier for the given configuration and issuer URL. On success, calls setVerifier with the -// resulting verifier. -func initVerifier(ctx context.Context, config *oidc.Config, iss string) (*oidc.IDTokenVerifier, error) { - provider, err := oidc.NewProvider(ctx, iss) - if err != nil { - return nil, fmt.Errorf("init verifier failed: %v", err) - } - return provider.Verifier(config), nil -} - -// asyncIDTokenVerifier is an ID token verifier that allows async initialization -// of the issuer check. Must be passed by reference as it wraps sync.Mutex. -type asyncIDTokenVerifier struct { - m sync.Mutex - - // v is the ID token verifier initialized asynchronously. It remains nil - // up until it is eventually initialized. - // Guarded by m - v *oidc.IDTokenVerifier -} - -// newAsyncIDTokenVerifier creates a new asynchronous token verifier. The -// verifier is available immediately, but may remain uninitialized for some time -// after creation. -func newAsyncIDTokenVerifier(ctx context.Context, c *oidc.Config, iss string) *asyncIDTokenVerifier { - t := &asyncIDTokenVerifier{} - - sync := make(chan struct{}) - // Polls indefinitely in an attempt to initialize the distributed claims - // verifier, or until context canceled. - initFn := func() (done bool, err error) { - klog.V(4).Infof("oidc authenticator: attempting init: iss=%v", iss) - v, err := initVerifier(ctx, c, iss) - if err != nil { - klog.Errorf("oidc authenticator: async token verifier for issuer: %q: %v", iss, err) - return false, nil - } - t.m.Lock() - defer t.m.Unlock() - t.v = v - close(sync) - return true, nil - } - - go func() { - if done, _ := initFn(); !done { - go wait.PollUntil(time.Second*10, initFn, ctx.Done()) - } - }() - - if synchronizeTokenIDVerifierForTest { - <-sync - } - - return t -} - -// verifier returns the underlying ID token verifier, or nil if one is not yet initialized. -func (a *asyncIDTokenVerifier) verifier() *oidc.IDTokenVerifier { - a.m.Lock() - defer a.m.Unlock() - return a.v -} - -type Authenticator struct { - issuerURL string - - usernameClaim string - usernamePrefix string - groupsClaim string - groupsPrefix string - requiredClaims map[string]string - clientIDs authenticator.Audiences - apiAudiences authenticator.Audiences - - // Contains an *oidc.IDTokenVerifier. Do not access directly use the - // idTokenVerifier method. - verifier atomic.Value - - cancel context.CancelFunc - - // resolver is used to resolve distributed claims. - resolver *claimResolver -} - -func (a *Authenticator) setVerifier(v *oidc.IDTokenVerifier) { - a.verifier.Store(v) -} - -func (a *Authenticator) idTokenVerifier() (*oidc.IDTokenVerifier, bool) { - if v := a.verifier.Load(); v != nil { - return v.(*oidc.IDTokenVerifier), true - } - return nil, false -} - -func (a *Authenticator) Close() { - a.cancel() -} - -func New(opts Options) (*Authenticator, error) { - return newAuthenticator(opts, func(ctx context.Context, a *Authenticator, config *oidc.Config) { - // Asynchronously attempt to initialize the authenticator. This enables - // self-hosted providers, providers that run on top of Kubernetes itself. - go wait.PollUntil(time.Second*10, func() (done bool, err error) { - provider, err := oidc.NewProvider(ctx, a.issuerURL) - if err != nil { - klog.Errorf("oidc authenticator: initializing plugin: %v", err) - return false, nil - } - - verifier := provider.Verifier(config) - a.setVerifier(verifier) - return true, nil - }, ctx.Done()) - }) -} - -// whitelist of signing algorithms to ensure users don't mistakenly pass something -// goofy. -var allowedSigningAlgs = map[string]bool{ - oidc.RS256: true, - oidc.RS384: true, - oidc.RS512: true, - oidc.ES256: true, - oidc.ES384: true, - oidc.ES512: true, - oidc.PS256: true, - oidc.PS384: true, - oidc.PS512: true, -} - -func newAuthenticator(opts Options, initVerifier func(ctx context.Context, a *Authenticator, config *oidc.Config)) (*Authenticator, error) { - url, err := url.Parse(opts.IssuerURL) - if err != nil { - return nil, err - } - - if url.Scheme != "https" { - return nil, fmt.Errorf("'oidc-issuer-url' (%q) has invalid scheme (%q), require 'https'", opts.IssuerURL, url.Scheme) - } - - if opts.UsernameClaim == "" { - return nil, errors.New("no username claim provided") - } - - supportedSigningAlgs := opts.SupportedSigningAlgs - if len(supportedSigningAlgs) == 0 { - // RS256 is the default recommended by OpenID Connect and an 'alg' value - // providers are required to implement. - supportedSigningAlgs = []string{oidc.RS256} - } - for _, alg := range supportedSigningAlgs { - if !allowedSigningAlgs[alg] { - return nil, fmt.Errorf("oidc: unsupported signing alg: %q", alg) - } - } - - var roots *x509.CertPool - if opts.CAFile != "" { - roots, err = certutil.NewPool(opts.CAFile) - if err != nil { - return nil, fmt.Errorf("Failed to read the CA file: %v", err) - } - } else { - klog.Info("OIDC: No x509 certificates provided, will use host's root CA set") - } - - // Copied from http.DefaultTransport. - tr := net.SetTransportDefaults(&http.Transport{ - // According to golang's doc, if RootCAs is nil, - // TLS uses the host's root CA set. - TLSClientConfig: &tls.Config{RootCAs: roots}, - }) - - client := &http.Client{Transport: tr, Timeout: 30 * time.Second} - - ctx, cancel := context.WithCancel(context.Background()) - ctx = oidc.ClientContext(ctx, client) - - now := opts.now - if now == nil { - now = time.Now - } - - verifierConfig := &oidc.Config{ - ClientID: opts.ClientID, - SupportedSigningAlgs: supportedSigningAlgs, - Now: now, - } - - var resolver *claimResolver - if opts.GroupsClaim != "" { - resolver = newClaimResolver(opts.GroupsClaim, client, verifierConfig) - } - - authenticator := &Authenticator{ - issuerURL: opts.IssuerURL, - usernameClaim: opts.UsernameClaim, - usernamePrefix: opts.UsernamePrefix, - groupsClaim: opts.GroupsClaim, - groupsPrefix: opts.GroupsPrefix, - requiredClaims: opts.RequiredClaims, - clientIDs: authenticator.Audiences{opts.ClientID}, - apiAudiences: opts.APIAudiences, - cancel: cancel, - resolver: resolver, - } - - initVerifier(ctx, authenticator, verifierConfig) - return authenticator, nil -} - -// untrustedIssuer extracts an untrusted "iss" claim from the given JWT token, -// or returns an error if the token can not be parsed. Since the JWT is not -// verified, the returned issuer should not be trusted. -func untrustedIssuer(token string) (string, error) { - parts := strings.Split(token, ".") - if len(parts) != 3 { - return "", fmt.Errorf("malformed token") - } - payload, err := base64.RawURLEncoding.DecodeString(parts[1]) - if err != nil { - return "", fmt.Errorf("error decoding token: %v", err) - } - claims := struct { - // WARNING: this JWT is not verified. Do not trust these claims. - Issuer string `json:"iss"` - }{} - if err := json.Unmarshal(payload, &claims); err != nil { - return "", fmt.Errorf("while unmarshaling token: %v", err) - } - // Coalesce the legacy GoogleIss with the new one. - // - // http://openid.net/specs/openid-connect-core-1_0.html#GoogleIss - if claims.Issuer == "accounts.google.com" { - return "https://accounts.google.com", nil - } - return claims.Issuer, nil -} - -func hasCorrectIssuer(iss, tokenData string) bool { - uiss, err := untrustedIssuer(tokenData) - if err != nil { - return false - } - if uiss != iss { - return false - } - return true -} - -// endpoint represents an OIDC distributed claims endpoint. -type endpoint struct { - // URL to use to request the distributed claim. This URL is expected to be - // prefixed by one of the known issuer URLs. - URL string `json:"endpoint,omitempty"` - // AccessToken is the bearer token to use for access. If empty, it is - // not used. Access token is optional per the OIDC distributed claims - // specification. - // See: http://openid.net/specs/openid-connect-core-1_0.html#DistributedExample - AccessToken string `json:"access_token,omitempty"` - // JWT is the container for aggregated claims. Not supported at the moment. - // See: http://openid.net/specs/openid-connect-core-1_0.html#AggregatedExample - JWT string `json:"JWT,omitempty"` -} - -// claimResolver expands distributed claims by calling respective claim source -// endpoints. -type claimResolver struct { - // claim is the distributed claim that may be resolved. - claim string - - // client is the to use for resolving distributed claims - client *http.Client - - // config is the OIDC configuration used for resolving distributed claims. - config *oidc.Config - - // verifierPerIssuer contains, for each issuer, the appropriate verifier to use - // for this claim. It is assumed that there will be very few entries in - // this map. - // Guarded by m. - verifierPerIssuer map[string]*asyncIDTokenVerifier - - m sync.Mutex -} - -// newClaimResolver creates a new resolver for distributed claims. -func newClaimResolver(claim string, client *http.Client, config *oidc.Config) *claimResolver { - return &claimResolver{claim: claim, client: client, config: config, verifierPerIssuer: map[string]*asyncIDTokenVerifier{}} -} - -// Verifier returns either the verifier for the specified issuer, or error. -func (r *claimResolver) Verifier(iss string) (*oidc.IDTokenVerifier, error) { - r.m.Lock() - av := r.verifierPerIssuer[iss] - if av == nil { - // This lazy init should normally be very quick. - // TODO: Make this context cancelable. - ctx := oidc.ClientContext(context.Background(), r.client) - av = newAsyncIDTokenVerifier(ctx, r.config, iss) - r.verifierPerIssuer[iss] = av - } - r.m.Unlock() - - v := av.verifier() - if v == nil { - return nil, fmt.Errorf("verifier not initialized for issuer: %q", iss) - } - return v, nil -} - -// expand extracts the distributed claims from claim names and claim sources. -// The extracted claim value is pulled up into the supplied claims. -// -// Distributed claims are of the form as seen below, and are defined in the -// OIDC Connect Core 1.0, section 5.6.2. -// See: https://openid.net/specs/openid-connect-core-1_0.html#AggregatedDistributedClaims -// -// { -// ... (other normal claims)... -// "_claim_names": { -// "groups": "src1" -// }, -// "_claim_sources": { -// "src1": { -// "endpoint": "https://www.example.com", -// "access_token": "f005ba11" -// }, -// }, -// } -func (r *claimResolver) expand(c claims) error { - const ( - // The claim containing a map of endpoint references per claim. - // OIDC Connect Core 1.0, section 5.6.2. - claimNamesKey = "_claim_names" - // The claim containing endpoint specifications. - // OIDC Connect Core 1.0, section 5.6.2. - claimSourcesKey = "_claim_sources" - ) - - _, ok := c[r.claim] - if ok { - // There already is a normal claim, skip resolving. - return nil - } - names, ok := c[claimNamesKey] - if !ok { - // No _claim_names, no keys to look up. - return nil - } - - claimToSource := map[string]string{} - if err := json.Unmarshal([]byte(names), &claimToSource); err != nil { - return fmt.Errorf("oidc: error parsing distributed claim names: %v", err) - } - - rawSources, ok := c[claimSourcesKey] - if !ok { - // Having _claim_names claim, but no _claim_sources is not an expected - // state. - return fmt.Errorf("oidc: no claim sources") - } - - var sources map[string]endpoint - if err := json.Unmarshal([]byte(rawSources), &sources); err != nil { - // The claims sources claim is malformed, this is not an expected state. - return fmt.Errorf("oidc: could not parse claim sources: %v", err) - } - - src, ok := claimToSource[r.claim] - if !ok { - // No distributed claim present. - return nil - } - ep, ok := sources[src] - if !ok { - return fmt.Errorf("id token _claim_names contained a source %s missing in _claims_sources", src) - } - if ep.URL == "" { - // This is maybe an aggregated claim (ep.JWT != ""). - return nil - } - return r.resolve(ep, c) -} - -// resolve requests distributed claims from all endpoints passed in, -// and inserts the lookup results into allClaims. -func (r *claimResolver) resolve(endpoint endpoint, allClaims claims) error { - // TODO: cache resolved claims. - jwt, err := getClaimJWT(r.client, endpoint.URL, endpoint.AccessToken) - if err != nil { - return fmt.Errorf("while getting distributed claim %q: %v", r.claim, err) - } - untrustedIss, err := untrustedIssuer(jwt) - if err != nil { - return fmt.Errorf("getting untrusted issuer from endpoint %v failed for claim %q: %v", endpoint.URL, r.claim, err) - } - v, err := r.Verifier(untrustedIss) - if err != nil { - return fmt.Errorf("verifying untrusted issuer %v failed: %v", untrustedIss, err) - } - t, err := v.Verify(context.Background(), jwt) - if err != nil { - return fmt.Errorf("verify distributed claim token: %v", err) - } - var distClaims claims - if err := t.Claims(&distClaims); err != nil { - return fmt.Errorf("could not parse distributed claims for claim %v: %v", r.claim, err) - } - value, ok := distClaims[r.claim] - if !ok { - return fmt.Errorf("jwt returned by distributed claim endpoint %s did not contain claim: %v", endpoint, r.claim) - } - allClaims[r.claim] = value - return nil -} - -func (a *Authenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) { - if reqAuds, ok := authenticator.AudiencesFrom(ctx); ok { - if len(reqAuds.Intersect(a.clientIDs)) == 0 && len(reqAuds.Intersect(a.apiAudiences)) == 0 { - return nil, false, nil - } - } - if !hasCorrectIssuer(a.issuerURL, token) { - return nil, false, nil - } - - verifier, ok := a.idTokenVerifier() - if !ok { - return nil, false, fmt.Errorf("oidc: authenticator not initialized") - } - - idToken, err := verifier.Verify(ctx, token) - if err != nil { - return nil, false, fmt.Errorf("oidc: verify token: %v", err) - } - - var c claims - if err := idToken.Claims(&c); err != nil { - return nil, false, fmt.Errorf("oidc: parse claims: %v", err) - } - if a.resolver != nil { - if err := a.resolver.expand(c); err != nil { - return nil, false, fmt.Errorf("oidc: could not expand distributed claims: %v", err) - } - } - - var username string - if err := c.unmarshalClaim(a.usernameClaim, &username); err != nil { - return nil, false, fmt.Errorf("oidc: parse username claims %q: %v", a.usernameClaim, err) - } - - if a.usernameClaim == "email" { - // If the email_verified claim is present, ensure the email is valid. - // https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims - if hasEmailVerified := c.hasClaim("email_verified"); hasEmailVerified { - var emailVerified bool - if err := c.unmarshalClaim("email_verified", &emailVerified); err != nil { - return nil, false, fmt.Errorf("oidc: parse 'email_verified' claim: %v", err) - } - - // If the email_verified claim is present we have to verify it is set to `true`. - if !emailVerified { - return nil, false, fmt.Errorf("oidc: email not verified") - } - } - } - - if a.usernamePrefix != "" { - username = a.usernamePrefix + username - } - - info := &user.DefaultInfo{Name: username} - if a.groupsClaim != "" { - if _, ok := c[a.groupsClaim]; ok { - // Some admins want to use string claims like "role" as the group value. - // Allow the group claim to be a single string instead of an array. - // - // See: https://github.com/kubernetes/kubernetes/issues/33290 - var groups stringOrArray - if err := c.unmarshalClaim(a.groupsClaim, &groups); err != nil { - return nil, false, fmt.Errorf("oidc: parse groups claim %q: %v", a.groupsClaim, err) - } - info.Groups = []string(groups) - } - } - - if a.groupsPrefix != "" { - for i, group := range info.Groups { - info.Groups[i] = a.groupsPrefix + group - } - } - - // check to ensure all required claims are present in the ID token and have matching values. - for claim, value := range a.requiredClaims { - if !c.hasClaim(claim) { - return nil, false, fmt.Errorf("oidc: required claim %s not present in ID token", claim) - } - - // NOTE: Only string values are supported as valid required claim values. - var claimValue string - if err := c.unmarshalClaim(claim, &claimValue); err != nil { - return nil, false, fmt.Errorf("oidc: parse claim %s: %v", claim, err) - } - if claimValue != value { - return nil, false, fmt.Errorf("oidc: required claim %s value does not match. Got = %s, want = %s", claim, claimValue, value) - } - } - - return &authenticator.Response{User: info}, true, nil -} - -// getClaimJWT gets a distributed claim JWT from url, using the supplied access -// token as bearer token. If the access token is "", the authorization header -// will not be set. -// TODO: Allow passing in JSON hints to the IDP. -func getClaimJWT(client *http.Client, url, accessToken string) (string, error) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // TODO: Allow passing request body with configurable information. - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return "", fmt.Errorf("while calling %v: %v", url, err) - } - if accessToken != "" { - req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", accessToken)) - } - req = req.WithContext(ctx) - response, err := client.Do(req) - if err != nil { - return "", err - } - // Report non-OK status code as an error. - if response.StatusCode < http.StatusOK || response.StatusCode > http.StatusIMUsed { - return "", fmt.Errorf("error while getting distributed claim JWT: %v", response.Status) - } - defer response.Body.Close() - responseBytes, err := ioutil.ReadAll(response.Body) - if err != nil { - return "", fmt.Errorf("could not decode distributed claim response") - } - return string(responseBytes), nil -} - -type stringOrArray []string - -func (s *stringOrArray) UnmarshalJSON(b []byte) error { - var a []string - if err := json.Unmarshal(b, &a); err == nil { - *s = a - return nil - } - var str string - if err := json.Unmarshal(b, &str); err != nil { - return err - } - *s = []string{str} - return nil -} - -type claims map[string]json.RawMessage - -func (c claims) unmarshalClaim(name string, v interface{}) error { - val, ok := c[name] - if !ok { - return fmt.Errorf("claim not present") - } - return json.Unmarshal([]byte(val), v) -} - -func (c claims) hasClaim(name string) bool { - if _, ok := c[name]; !ok { - return false - } - return true -} diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc_test.go b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc_test.go deleted file mode 100644 index 3f5db497e4..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/oidc_test.go +++ /dev/null @@ -1,1643 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package oidc - -import ( - "bytes" - "context" - "crypto" - "crypto/x509" - "encoding/hex" - "encoding/json" - "encoding/pem" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "os" - "reflect" - "strings" - "testing" - "text/template" - "time" - - oidc "github.com/coreos/go-oidc" - jose "gopkg.in/square/go-jose.v2" - - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/klog" -) - -// utilities for loading JOSE keys. - -func loadRSAKey(t *testing.T, filepath string, alg jose.SignatureAlgorithm) *jose.JSONWebKey { - return loadKey(t, filepath, alg, func(b []byte) (interface{}, error) { - key, err := x509.ParsePKCS1PrivateKey(b) - if err != nil { - return nil, err - } - return key.Public(), nil - }) -} - -func loadRSAPrivKey(t *testing.T, filepath string, alg jose.SignatureAlgorithm) *jose.JSONWebKey { - return loadKey(t, filepath, alg, func(b []byte) (interface{}, error) { - return x509.ParsePKCS1PrivateKey(b) - }) -} - -func loadECDSAKey(t *testing.T, filepath string, alg jose.SignatureAlgorithm) *jose.JSONWebKey { - return loadKey(t, filepath, alg, func(b []byte) (interface{}, error) { - key, err := x509.ParseECPrivateKey(b) - if err != nil { - return nil, err - } - return key.Public(), nil - }) -} - -func loadECDSAPrivKey(t *testing.T, filepath string, alg jose.SignatureAlgorithm) *jose.JSONWebKey { - return loadKey(t, filepath, alg, func(b []byte) (interface{}, error) { - return x509.ParseECPrivateKey(b) - }) -} - -func loadKey(t *testing.T, filepath string, alg jose.SignatureAlgorithm, unmarshal func([]byte) (interface{}, error)) *jose.JSONWebKey { - data, err := ioutil.ReadFile(filepath) - if err != nil { - t.Fatalf("load file: %v", err) - } - block, _ := pem.Decode(data) - if block == nil { - t.Fatalf("file contained no PEM encoded data: %s", filepath) - } - priv, err := unmarshal(block.Bytes) - if err != nil { - t.Fatalf("unmarshal key: %v", err) - } - key := &jose.JSONWebKey{Key: priv, Use: "sig", Algorithm: string(alg)} - thumbprint, err := key.Thumbprint(crypto.SHA256) - if err != nil { - t.Fatalf("computing thumbprint: %v", err) - } - key.KeyID = hex.EncodeToString(thumbprint) - return key -} - -// staticKeySet implements oidc.KeySet. -type staticKeySet struct { - keys []*jose.JSONWebKey -} - -func (s *staticKeySet) VerifySignature(ctx context.Context, jwt string) (payload []byte, err error) { - jws, err := jose.ParseSigned(jwt) - if err != nil { - return nil, err - } - if len(jws.Signatures) == 0 { - return nil, fmt.Errorf("jwt contained no signatures") - } - kid := jws.Signatures[0].Header.KeyID - - for _, key := range s.keys { - if key.KeyID == kid { - return jws.Verify(key) - } - } - - return nil, fmt.Errorf("no keys matches jwk keyid") -} - -var ( - expired, _ = time.Parse(time.RFC3339Nano, "2009-11-10T22:00:00Z") - now, _ = time.Parse(time.RFC3339Nano, "2009-11-10T23:00:00Z") - valid, _ = time.Parse(time.RFC3339Nano, "2009-11-11T00:00:00Z") -) - -type claimsTest struct { - name string - options Options - now time.Time - signingKey *jose.JSONWebKey - pubKeys []*jose.JSONWebKey - claims string - want *user.DefaultInfo - wantSkip bool - wantErr bool - wantInitErr bool - claimToResponseMap map[string]string - openIDConfig string - reqAudiences authenticator.Audiences -} - -// Replace formats the contents of v into the provided template. -func replace(tmpl string, v interface{}) string { - t := template.Must(template.New("test").Parse(tmpl)) - buf := bytes.NewBuffer(nil) - t.Execute(buf, &v) - ret := buf.String() - klog.V(4).Infof("Replaced: %v into: %v", tmpl, ret) - return ret -} - -// newClaimServer returns a new test HTTPS server, which is rigged to return -// OIDC responses to requests that resolve distributed claims. signer is the -// signer used for the served JWT tokens. claimToResponseMap is a map of -// responses that the server will return for each claim it is given. -func newClaimServer(t *testing.T, keys jose.JSONWebKeySet, signer jose.Signer, claimToResponseMap map[string]string, openIDConfig *string) *httptest.Server { - ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - klog.V(5).Infof("request: %+v", *r) - switch r.URL.Path { - case "/.testing/keys": - w.Header().Set("Content-Type", "application/json") - keyBytes, err := json.Marshal(keys) - if err != nil { - t.Fatalf("unexpected error while marshaling keys: %v", err) - } - klog.V(5).Infof("%v: returning: %+v", r.URL, string(keyBytes)) - w.Write(keyBytes) - - case "/.well-known/openid-configuration": - w.Header().Set("Content-Type", "application/json") - klog.V(5).Infof("%v: returning: %+v", r.URL, *openIDConfig) - w.Write([]byte(*openIDConfig)) - // These claims are tested in the unit tests. - case "/groups": - fallthrough - case "/rabbits": - if claimToResponseMap == nil { - t.Errorf("no claims specified in response") - } - claim := r.URL.Path[1:] // "/groups" -> "groups" - expectedAuth := fmt.Sprintf("Bearer %v_token", claim) - auth := r.Header.Get("Authorization") - if auth != expectedAuth { - t.Errorf("bearer token expected: %q, was %q", expectedAuth, auth) - } - jws, err := signer.Sign([]byte(claimToResponseMap[claim])) - if err != nil { - t.Errorf("while signing response token: %v", err) - } - token, err := jws.CompactSerialize() - if err != nil { - t.Errorf("while serializing response token: %v", err) - } - w.Write([]byte(token)) - default: - w.WriteHeader(http.StatusNotFound) - fmt.Fprintf(w, "unexpected URL: %v", r.URL) - } - })) - klog.V(4).Infof("Serving OIDC at: %v", ts.URL) - return ts -} - -// writeTempCert writes out the supplied certificate into a temporary file in -// PEM-encoded format. Returns the name of the temporary file used. The caller -// is responsible for cleaning the file up. -func writeTempCert(t *testing.T, cert []byte) string { - tempFile, err := ioutil.TempFile("", "ca.crt") - if err != nil { - t.Fatalf("could not open temp file: %v", err) - } - block := &pem.Block{ - Type: "CERTIFICATE", - Bytes: cert, - } - if err := pem.Encode(tempFile, block); err != nil { - t.Fatalf("could not write to temp file %v: %v", tempFile.Name(), err) - } - tempFile.Close() - return tempFile.Name() -} - -func toKeySet(keys []*jose.JSONWebKey) jose.JSONWebKeySet { - ret := jose.JSONWebKeySet{} - for _, k := range keys { - ret.Keys = append(ret.Keys, *k) - } - return ret -} - -func (c *claimsTest) run(t *testing.T) { - var ( - signer jose.Signer - err error - ) - if c.signingKey != nil { - // Initialize the signer only in the tests that make use of it. We can - // not defer this initialization because the test server uses it too. - signer, err = jose.NewSigner(jose.SigningKey{ - Algorithm: jose.SignatureAlgorithm(c.signingKey.Algorithm), - Key: c.signingKey, - }, nil) - if err != nil { - t.Fatalf("initialize signer: %v", err) - } - } - // The HTTPS server used for requesting distributed groups claims. - ts := newClaimServer(t, toKeySet(c.pubKeys), signer, c.claimToResponseMap, &c.openIDConfig) - defer ts.Close() - - // Make the certificate of the helper server available to the authenticator - // by writing its root CA certificate into a temporary file. - tempFileName := writeTempCert(t, ts.TLS.Certificates[0].Certificate[0]) - defer os.Remove(tempFileName) - c.options.CAFile = tempFileName - - // Allow claims to refer to the serving URL of the test server. For this, - // substitute all references to {{.URL}} in appropriate places. - v := struct{ URL string }{URL: ts.URL} - c.claims = replace(c.claims, &v) - c.openIDConfig = replace(c.openIDConfig, &v) - c.options.IssuerURL = replace(c.options.IssuerURL, &v) - for claim, response := range c.claimToResponseMap { - c.claimToResponseMap[claim] = replace(response, &v) - } - - // Initialize the authenticator. - a, err := newAuthenticator(c.options, func(ctx context.Context, a *Authenticator, config *oidc.Config) { - // Set the verifier to use the public key set instead of reading from a remote. - a.setVerifier(oidc.NewVerifier( - c.options.IssuerURL, - &staticKeySet{keys: c.pubKeys}, - config, - )) - }) - if err != nil { - if !c.wantInitErr { - t.Fatalf("initialize authenticator: %v", err) - } - return - } - if c.wantInitErr { - t.Fatalf("wanted initialization error") - } - - // Sign and serialize the claims in a JWT. - jws, err := signer.Sign([]byte(c.claims)) - if err != nil { - t.Fatalf("sign claims: %v", err) - } - token, err := jws.CompactSerialize() - if err != nil { - t.Fatalf("serialize token: %v", err) - } - - ctx := context.Background() - if c.reqAudiences != nil { - ctx = authenticator.WithAudiences(ctx, c.reqAudiences) - } - - got, ok, err := a.AuthenticateToken(ctx, token) - - if err != nil { - if !c.wantErr { - t.Fatalf("authenticate token: %v", err) - } - return - } - - if c.wantErr { - t.Fatalf("expected error authenticating token") - } - if !ok { - if !c.wantSkip { - // We don't have any cases where we return (nil, false, nil) - t.Fatalf("no error but token not authenticated") - } - return - } - if c.wantSkip { - t.Fatalf("expected authenticator to skip token") - } - - gotUser := got.User.(*user.DefaultInfo) - if !reflect.DeepEqual(gotUser, c.want) { - t.Fatalf("wanted user=%#v, got=%#v", c.want, gotUser) - } -} - -func TestToken(t *testing.T) { - synchronizeTokenIDVerifierForTest = true - tests := []claimsTest{ - { - name: "token", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "no-username", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "email", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "email", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "email": "jane@example.com", - "email_verified": true, - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane@example.com", - }, - }, - { - name: "email-not-verified", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "email", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "email": "jane@example.com", - "email_verified": false, - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - // If "email_verified" isn't present, assume true - name: "no-email-verified-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "email", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "email": "jane@example.com", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane@example.com", - }, - }, - { - name: "invalid-email-verified-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "email", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - // string value for "email_verified" - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "email": "jane@example.com", - "email_verified": "false", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "groups", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - Groups: []string{"team1", "team2"}, - }, - }, - { - name: "groups-distributed", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - want: &user.DefaultInfo{ - Name: "jane", - Groups: []string{"team1", "team2"}, - }, - }, - { - name: "groups-distributed-malformed-claim-names", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "nonexistent-claim-source" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - wantErr: true, - }, - { - name: "groups-distributed-malformed-names-and-sources", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - wantErr: true, - }, - { - name: "groups-distributed-malformed-distributed-claim", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - // Doesn't contain the "groups" claim as it promises. - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - wantErr: true, - }, - { - name: "groups-distributed-unusual-name", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "rabbits", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "rabbits": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/rabbits", - "access_token": "rabbits_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "rabbits": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "rabbits": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - want: &user.DefaultInfo{ - Name: "jane", - Groups: []string{"team1", "team2"}, - }, - }, - { - name: "groups-distributed-wrong-audience", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - // Note mismatching "aud" - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "your-client", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - // "aud" was "your-client", not "my-client" - wantErr: true, - }, - { - name: "groups-distributed-wrong-audience", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - // Note expired timestamp. - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": ["team1", "team2"], - "exp": %d - }`, expired.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - // The distributed token is expired. - wantErr: true, - }, - { - // Specs are unclear about this behavior. We adopt a behavior where - // normal claim wins over a distributed claim by the same name. - name: "groups-distributed-normal-claim-wins", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "groups": "team1", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": ["team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - want: &user.DefaultInfo{ - Name: "jane", - // "team1" is from the normal "groups" claim. - Groups: []string{"team1"}, - }, - }, - { - // Groups should be able to be a single string, not just a slice. - name: "group-string-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "groups": "team1", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - Groups: []string{"team1"}, - }, - }, - { - // Groups should be able to be a single string, not just a slice. - name: "group-string-claim-distributed", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": "team1", - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - want: &user.DefaultInfo{ - Name: "jane", - Groups: []string{"team1"}, - }, - }, - { - name: "group-string-claim-aggregated-not-supported", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "JWT": "some.jwt.token" - } - }, - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - // if the groups claim isn't provided, this shouldn't error out - name: "no-groups-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "invalid-groups-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "groups": 42, - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "required-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - RequiredClaims: map[string]string{ - "hd": "example.com", - "sub": "test", - }, - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "hd": "example.com", - "sub": "test", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "no-required-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - RequiredClaims: map[string]string{ - "hd": "example.com", - }, - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "invalid-required-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - GroupsClaim: "groups", - RequiredClaims: map[string]string{ - "hd": "example.com", - }, - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "hd": "example.org", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "invalid-signature", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_2.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "expired", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, expired.Unix()), - wantErr: true, - }, - { - name: "invalid-aud", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "not-my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - // ID tokens may contain multiple audiences: - // https://openid.net/specs/openid-connect-core-1_0.html#IDToken - name: "multiple-audiences", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": ["not-my-client", "my-client"], - "azp": "not-my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "invalid-issuer", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - wantSkip: true, - }, - { - name: "username-prefix", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - UsernamePrefix: "oidc:", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "oidc:jane", - }, - }, - { - name: "groups-prefix", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - UsernamePrefix: "oidc:", - GroupsClaim: "groups", - GroupsPrefix: "groups:", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "oidc:jane", - Groups: []string{"groups:team1", "groups:team2"}, - }, - }, - { - name: "groups-prefix-distributed", - options: Options{ - IssuerURL: "{{.URL}}", - ClientID: "my-client", - UsernameClaim: "username", - UsernamePrefix: "oidc:", - GroupsClaim: "groups", - GroupsPrefix: "groups:", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "username": "jane", - "_claim_names": { - "groups": "src1" - }, - "_claim_sources": { - "src1": { - "endpoint": "{{.URL}}/groups", - "access_token": "groups_token" - } - }, - "exp": %d - }`, valid.Unix()), - claimToResponseMap: map[string]string{ - "groups": fmt.Sprintf(`{ - "iss": "{{.URL}}", - "aud": "my-client", - "groups": ["team1", "team2"], - "exp": %d - }`, valid.Unix()), - }, - openIDConfig: `{ - "issuer": "{{.URL}}", - "jwks_uri": "{{.URL}}/.testing/keys" - }`, - want: &user.DefaultInfo{ - Name: "oidc:jane", - Groups: []string{"groups:team1", "groups:team2"}, - }, - }, - { - name: "invalid-signing-alg", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - // Correct key but invalid signature algorithm "PS256" - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.PS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - wantErr: true, - }, - { - name: "ps256", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - SupportedSigningAlgs: []string{"PS256"}, - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.PS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.PS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "es512", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - SupportedSigningAlgs: []string{"ES512"}, - now: func() time.Time { return now }, - }, - signingKey: loadECDSAPrivKey(t, "testdata/ecdsa_2.pem", jose.ES512), - pubKeys: []*jose.JSONWebKey{ - loadECDSAKey(t, "testdata/ecdsa_1.pem", jose.ES512), - loadECDSAKey(t, "testdata/ecdsa_2.pem", jose.ES512), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "not-https", - options: Options{ - IssuerURL: "http://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - wantInitErr: true, - }, - { - name: "no-username-claim", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - now: func() time.Time { return now }, - }, - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - wantInitErr: true, - }, - { - name: "invalid-sig-alg", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - UsernameClaim: "username", - SupportedSigningAlgs: []string{"HS256"}, - now: func() time.Time { return now }, - }, - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - wantInitErr: true, - }, - { - name: "accounts.google.com issuer", - options: Options{ - IssuerURL: "https://accounts.google.com", - ClientID: "my-client", - UsernameClaim: "email", - now: func() time.Time { return now }, - }, - claims: fmt.Sprintf(`{ - "iss": "accounts.google.com", - "email": "thomas.jefferson@gmail.com", - "aud": "my-client", - "exp": %d - }`, valid.Unix()), - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - want: &user.DefaultInfo{ - Name: "thomas.jefferson@gmail.com", - }, - }, - { - name: "good token with api req audience", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - APIAudiences: authenticator.Audiences{"api"}, - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - reqAudiences: authenticator.Audiences{"api"}, - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "good token with multiple api req audience", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - APIAudiences: authenticator.Audiences{"api", "other"}, - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - reqAudiences: authenticator.Audiences{"api"}, - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "good token with client_id req audience", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - APIAudiences: authenticator.Audiences{"api"}, - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - reqAudiences: authenticator.Audiences{"my-client"}, - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "good token with client_id and api req audience", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - APIAudiences: authenticator.Audiences{"api"}, - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - reqAudiences: authenticator.Audiences{"my-client", "api"}, - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "good token with client_id and api req audience", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - APIAudiences: authenticator.Audiences{"api"}, - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - reqAudiences: authenticator.Audiences{"my-client", "api"}, - want: &user.DefaultInfo{ - Name: "jane", - }, - }, - { - name: "good token with client_id and bad req audience", - options: Options{ - IssuerURL: "https://auth.example.com", - ClientID: "my-client", - APIAudiences: authenticator.Audiences{"api"}, - UsernameClaim: "username", - now: func() time.Time { return now }, - }, - signingKey: loadRSAPrivKey(t, "testdata/rsa_1.pem", jose.RS256), - pubKeys: []*jose.JSONWebKey{ - loadRSAKey(t, "testdata/rsa_1.pem", jose.RS256), - }, - claims: fmt.Sprintf(`{ - "iss": "https://auth.example.com", - "aud": "my-client", - "username": "jane", - "exp": %d - }`, valid.Unix()), - reqAudiences: authenticator.Audiences{"other"}, - wantSkip: true, - }, - } - for _, test := range tests { - t.Run(test.name, test.run) - } -} - -func TestUnmarshalClaimError(t *testing.T) { - // Ensure error strings returned by unmarshaling claims don't include the claim. - const token = "96bb299a-02e9-11e8-8673-54ee7553240e" - payload := fmt.Sprintf(`{ - "token": "%s" - }`, token) - - var c claims - if err := json.Unmarshal([]byte(payload), &c); err != nil { - t.Fatal(err) - } - var n int - err := c.unmarshalClaim("token", &n) - if err == nil { - t.Fatal("expected error") - } - - if strings.Contains(err.Error(), token) { - t.Fatalf("unmarshal error included token") - } -} - -func TestUnmarshalClaim(t *testing.T) { - tests := []struct { - name string - claims string - do func(claims) (interface{}, error) - want interface{} - wantErr bool - }{ - { - name: "string claim", - claims: `{"aud":"foo"}`, - do: func(c claims) (interface{}, error) { - var s string - err := c.unmarshalClaim("aud", &s) - return s, err - }, - want: "foo", - }, - { - name: "mismatched types", - claims: `{"aud":"foo"}`, - do: func(c claims) (interface{}, error) { - var n int - err := c.unmarshalClaim("aud", &n) - return n, err - - }, - wantErr: true, - }, - { - name: "bool claim", - claims: `{"email":"foo@coreos.com","email_verified":true}`, - do: func(c claims) (interface{}, error) { - var verified bool - err := c.unmarshalClaim("email_verified", &verified) - return verified, err - }, - want: true, - }, - { - name: "strings claim", - claims: `{"groups":["a","b","c"]}`, - do: func(c claims) (interface{}, error) { - var groups []string - err := c.unmarshalClaim("groups", &groups) - return groups, err - }, - want: []string{"a", "b", "c"}, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - var c claims - if err := json.Unmarshal([]byte(test.claims), &c); err != nil { - t.Fatal(err) - } - - got, err := test.do(c) - if err != nil { - if test.wantErr { - return - } - t.Fatalf("unexpected error: %v", err) - } - if test.wantErr { - t.Fatalf("expected error") - } - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("wanted=%#v, got=%#v", test.want, got) - } - }) - } -} diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_1.pem b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_1.pem deleted file mode 100644 index c56852dca2..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_1.pem +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIAvxtZy9aI/lEt6LVLIhVrWLSwmlMFThU/nZUPr88nA5yKzJMyKbW/ -QA+umam9YtO78WwzriTGC9qwW6+t+liXrcCgBwYFK4EEACOhgYkDgYYABAGzIO9n -tdTx6oVg1O59ljYP4FHY9RNUy+wHeXFnB6fo9asGg9jwLMg/iX0F+whFkllQjNLf -kKp/9ATWQHrzSbzuqwB9UU5zfQ3ulhMwEBpxbM6aSi1HyYtc5pQn7KB6h1VXiuQK -CIj4kVYHClZuKz0om/XAJL4vWVDwJqDBN6m9Yi9ZLQ== ------END EC PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_2.pem b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_2.pem deleted file mode 100644 index 611a4ba3be..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_2.pem +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIBtxiwrrDmi1U+NxClUKIr2cvmL6PPLxjAULjPuORt0AWbqKakphSJ -43VmIbPBBCuLnN2PuVS9N8jLDlR1KUnnFSGgBwYFK4EEACOhgYkDgYYABAEgshGY -Oflwnz2SQOWIkvSPmijMhS4nWmLYedR2H/Dg9c9nuiyQqL3XpqkPnQQwqOgcXjMT -hTec2tiLcRS3Gj02yQEpe/6Do6if4K4cQ9KsNtVHsn0bibsqLtRuvI7xUu9JJAs7 -vSLNUtmxVzFo4s4spnIjLT71uz1Vag/NrKwot7cz4g== ------END EC PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_3.pem b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_3.pem deleted file mode 100644 index 1bd6e0a347..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/ecdsa_3.pem +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIAQTHP4V93rz1w1D+jF1Jvx5QHzkQQIYxbN1LPuvQjEoplQrjZ4Qiu -h9mKK6DBCaDlfSos+wnTOlZH1z1tpa9soPOgBwYFK4EEACOhgYkDgYYABAFn+QOY -a937Lp+WO1S+zJU9ITnzdvjqQtD/TjtJPQsllV8rD0QNXZb/pLFQFZtDEehiZKEu -WA0REGNs+rVMO63YZAAyDMwZTz87ulH23OR6EaoyDp9qEPx7kpxgaJqeIztla2t8 -SLVpv/FPR92E/OmguT6sFI5mP0AhV8UVlLYuHaovnw== ------END EC PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/gen.sh b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/gen.sh deleted file mode 100755 index d7b3df8167..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/gen.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2018 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e - -rm ./*.pem - -for N in $(seq 1 3); do - ssh-keygen -t rsa -b 2048 -f rsa_"$N".pem -N '' -done - -for N in $(seq 1 3); do - ssh-keygen -t ecdsa -b 521 -f ecdsa_"$N".pem -N '' -done - -rm ./*.pub diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_1.pem b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_1.pem deleted file mode 100644 index 2c4a9238c9..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_1.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA0pXWMYjWRjBEds/fKj/u9r2E6SIDx0J+TAg+eyVeR20Ky9jZ -mIXW5zSxE/EKpNQpiBWm1e6G9kmhMuqjr7g455S7E+3rD3OVkdTT6SU5AKBNSFoR -XUd+G/YJEtRzrpEYNtEJHkxUxWuyfCHblHSt+wsrE6t0DccCqC87lKQiGb/QfC8u -P6ZS99SCjKBEFp1fZvyNkYwStFc2OH5fBGPXXb6SNsquvDeKX9NeWjXkmxDkbOg2 -kSkel4s/zw5KwcW3JzERfEcLStrDQ8fRbJ1C3uC088sUk4q4APQmKI/8FTvJe431 -Vne9sOSptphiqCjlR+Knja58rc/vt4TkSPZf2wIDAQABAoIBAQDO3UgjMtOi8Wlf -+YW1IEbjdXrp9XMWu9gLYpHWMPgzXAeeBfCDJv7b8uP8ve2By7TcrMBOKVnE+MF0 -nhCb3nFv9KftxOsDK70DG7nrrpgXaGFisK+cHU3hs8hoCfF1y6yotKGrdLpVkR0t -Wak1ZYU/NlJjqSqBGj0e7/8sXivtc7oME8tBBRBCEa8OqPqaelCInfFF1rX5vmxX -pQjPpZoA+vroSJy8SYE0N5oqtGwOPT+9rVuDOL10eaMbGUcssZl8ofwuvzOYPMW4 -KFSVtvdtKnACq94Qy6XQbK5hZbZXSpzxANKq8SFyG2N1wOlpu/ktdXqkyDs08AZY -c/KkpXspAoGBAPdC73GOZn/hxzkwZ2Dl+S9rgrLT3VbeuhMp6GXSdiT+f9babMuw -HlYw6uULmvL1gD/0GmyWrHopPFJxodBG5SlwYS5wl49slcxeKCjK26vbNfK2eCbu -9uMtED4dN/5NlaXF4hqy/FmSyaFhQT+5hvx8n/zvLsgpuSQ+SCiDAHMfAoGBANoH -FCZeCWzzUFhObYG9wxGJ9FBPQa0htafIYEgTwezlKPsrfXfCTnVg1lLkr6Z4IwYQ -9VufJZNAc5V0X9H/ceyKJYxhQ+E01NEVzVpoK8fOC4yCYSYtbJnqkOUQzZJzkjFT -mNcIa8o4UrBOWzMhMQa0AOZH4VrbtZDCZhid+hfFAoGAAbKh9kOmDIa+WXQtoYqy -tVKlqRivUmNhH7SP9fMGAKcGtbD2QkfJTYo0crIrtDNfWBETBV/be1NBKMfC9q0l -8azl3e3D/KYgOTEEUZNjAsEUk8AQ/yNw6opqrCKDOenKd0LulIRaGztYyxTh39Ak -TyOD7bauuY0fylHrKOwNWr0CgYEAsVZ0o0h1rjKyNUGFfLQWyFtHZ1Mv/lye3tvy -xG2dnMxAaxvSr+hR3NNpQH9WB7dL9ZExoNZvv7f6y6OelLaLuXQcWnR6u+E3AOIU -5+Y3RgtoBV+/GUh1PzQ1qrviGa77SDfQ54an9hGd4F27fHkQ4XzkBmqM+FQg+J/G -X1uPomkCgYBo4ZBEA20Wvf1k2iWOVdfsxZNeOLxwcN5x89dAvm0v6RHg2NMy+XKw -Rj+YRuudFdxfg39J/V/Md9qsvjW+4FthD8GhgPs22dksV+7j6ApWkYTmIKG4rmh3 -RhHOr6uLg9BeShnlvMMaMJKf2eA7SaVtmuS6uBGgEUNaa3qEBq0R+Q== ------END RSA PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_2.pem b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_2.pem deleted file mode 100644 index e89fdb8687..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_2.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAxmLv1fqjacxZu5jyfQzytwjdt9/BBDzPM6G+R92YvsB7o2FH -ISiySbT8pyj7wGUgDvBdc9+GT3thf2pKGl/THaYJCLbh90GXVMTTak8Najqp2Qod -kxIpjSOBgukmd0LUtUVGKJg7YTEqsxAUmn9mfFiUZ6ixHr0U2NAXu7TF4dw7C9bt -ORi9DKDfUhEiV3Vcyrc5d/9VdmWG6fs/kq0B/6AboiSIIGAKSugNi4BgV7rNZYwZ -37UT72CW28TQQuuAtmTgXWMkfeWZiQKD1P8Nl1byORpgivp2A+2pMNlcLuogVhGY -TIZstbeMqoPyLW57GitWDg1tbakwJdCR23gCKQIDAQABAoIBACZmDf//1FNtD01F -TGIx+GS/HZMyhvyX/I8E1ny4gpEhVo0IDil35BJqKqD8SMYzjKH3mk8MS8Xknrl3 -zEIQnB9X/NWn+FLQakcpFba0+GbAVhHBaHoIAOzlm3LIR/67e8peTzcaSBwG1Tn1 -eddxo1ecGZV6zFWjyX4xwPY/BjIyA/b1LewqIK6W/I4u3RwtEzqANV9ddVbFH53e -Y+i2X1HVuLm0LETsX4jB/G/ZDP6Y101gOwPFddm+h1ixZ2jrAkyTbvYL5ukIsU8Z -okIEZsd6nv08YN+LOXOPh0CxvgHI347RDzgfbDmHGqq8gh20+wLP/MV+dOiBBAJT -RfnoFcUCgYEA8SpMW64CNhRkH3Nv5A5ffSOa7NqiN7OdNEswgcgkAbjR5YsTATPg -p9iWqGcEodX1FWjnL2NLMdMvYxh4MwMCACIa8FQ2/RDEwViaVjxcOK64MIvyvnNq -NObx8pMClUBXWF/llxxTR+/CJWRdCABBm56lQPuuX/qEi/xqybHPcAcCgYEA0pb9 -FGmGhDXl3bG3zNNIim+FuqG0xQoIjVPwdvkMI30h/ii6qs3jxwHlw6KBf8AI9wI+ -bWbzhwcYVkS6It0Yj4q/mqOVHi89frrAQygsJkMQkdl8WiWwPeiiIdsHYTUcBv5+ -i6YLs8ycnzMeFAxg8kuxrq6mm3yW6u5CuInsEE8CgYAWXqUMj/x2hbevzyZe0hJ7 -ahURyUnovsljM2JBd44XdsxJbXgK0YQSLZ3z6vJcDJuaK8vd8mjkK0GnAHsNyEak -OoWjKzyahrapdI2EWD75pwNAxYpzrgL4+z8QECDaNUik0uhZ9u+mqY+ppkCW4Gc1 -hyau+2l2T6eB0J0bLloeewKBgQC+fZn8JuBpI6AEg8ew3cYWg37CLZgpTEQkIzO3 -StyyFXT0RL9l1cwerha6ensNphX16e+yYpgTIlXfY1fERZ776RQcu7Adl7nWsvNL -TEFzcuLAK60SlljwB0jxuwDX64SoxviNNewL/iAG2eRxWikvw0y8qHtI1tBlPpTX -/NqufQKBgD1jAPRgu+IN9IDXoqnMiXbSfrVsJ1ndyPCRBq4dfvawcbEDTZfkiid0 -aNrdRoOETfLCynAcG6o6uS3+2sumzXLrMNr8MDF8NEa2Rh8nN3IjZqESV4CNgaV6 -JhAlWFp+AvYv6N1iHK52nNAFiX/cfaMpWTUKqk2Z4VZCr5qhLUVs ------END RSA PRIVATE KEY----- diff --git a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_3.pem b/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_3.pem deleted file mode 100644 index 3c660ed197..0000000000 --- a/staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc/testdata/rsa_3.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpgIBAAKCAQEA1uO3LV0wHadHjQb8U8KGUpzlZTyBHlinL7lF5yKk2hXOyssT -Z0UVF6ofPq/L+ZN5VkTb1FJWMEBiX1BgXlboDdYKAYTl1QaeEQrfrAM4gp2FdWS4 -fMUuagFdVXs8T2J4GGPEE83ybwz/YEM3p83Qojifvx/IjVtuHCMkUpcj92scjsCY -EeSKRjJicVBmJ1RK0ShEorHhnYmokKYsPl41mV5VdmWZOtmPK4jV05cBfg7eC7yI -cwwYhowLkYvd9d9H74otK5tD7KTxFG6JJ0N5zwf6XBRcXBWKstfOOZ5Qgo9z0Tkm -n3Klp9vwun25aaA1MlSSByByiCb7qvS8jhqMkQIDAQABAoIBAQCjN58AU9GiFFai -ZXXuYMgJo6YRON2RoSCLfRv9LTEtfHbvTUPVooEc0lidEoXJcRwuTGr0X/2a9KxD -XRd1UGk9aR98e+bd4QLaSvoM+v1HKEIgInqGOnbAiXzM2qe6XD5/t/dMW5cShjrK -cQOq7wbS0FN1pbx8sb92m7KREL9+wnXuOCHYtublRf7arsMkaZcpSBBaI+raMaZR -dUC+LmalIvR8+dNegducwWsdE8/Vh+xq97ZbNFlyut3JOvfuHmaAOvUsX/4touj2 -dDkJmvzvmpTBG888t+6hv9eKWaacsTAKuPLThRBD53coTEvHK8iic9fOok65y5Bn -nFP/irUpAoGBAPUsPoAPwcNajZX/E4XeG/2eV+IHMxYR9gJwBzpoUfwHr5mR54HK -POia/z7/M2KVV9kMWBlbTumIHSEylEEDCCKNNIe1gHBxQ7uGuaf+vVXpVgjBigUz -7oiCjb5RdjevfiyudX/z0B9IQSI9djCXebifEHKpUxAOmU3oP0SEMULLAoGBAOBh -G+fDouMU7QN93NG0hssu44yc7xQhb7VLB+isrEQASVG2xWkd3iDrdRxwHAHZqxFd -4DRzDTFC7yeR+FEbVVkWQRaeDwFJM1zmRTXsYjBkK49GNzB4QEtHvPouuxMAQ4UD -zJ9a3LEDSs867R7XEbNF8j9NC9z0vk7w9bHTA1aTAoGBAODUUQBY8sQ1zy8lOf8B -/sMmKMti9Mshb2su1sIOFli7p6F5tkZEcnSQZs+bccDO2T92XXfrTsNDigr+egvg -Pt6IhQqKPB1hEM7wLmLLbU9Sag4fhXVd+TmAF4HW7EUGjvtkhOXwbQOy2+ANYswO -rJXMcGXltwE7kgRqnVI0s4PfAoGBALUrM5Dq0bZwyv6qvYVFMiEUdv6uKAwlA0Fq -l7Qy19UANjMYVEUPrK7/7stLahHEYu/e0I0I6HoCBX/5yHoUi9Emut88N/ld1W8J -LpDfkFhqSRGiLCWisqcWAWwwFzS8XcgkzS9N+iui8OBqP9NK7CvIKlUaLJ33r0Gm -JXuzWVqpAoGBAIQ8+YuvFfyhwXuWwQbzxVpWRURH0FRu8KfFIkFFbdyht6leYXuj -uxcrcHWzkEPSLO22BoJX8ECHq4LadAIjkkpr5GCikKCF+r/bq50RnECqvfoJ629J -gA87C8cLU3dXmSYd+vSg6icZyncTmXyyEV0dqoUGJ2M33kE6hYAbc/ic ------END RSA PRIVATE KEY-----