From 3f80ac1a1fec3dc3a1d627fde183134d3512554a Mon Sep 17 00:00:00 2001 From: Athanasios Markou Date: Wed, 4 Jan 2023 18:35:56 +0200 Subject: [PATCH] authenticators: Introduce authenticators package Add a new authenticators package which includes the implementations of all the authentication methods that oidc-authservice currently supports. Isolate the dependency to the "k8s.io/apiserver/pkg/authentication/authenticator" package, inside the new authenticators package. GitHub-PR: #105 Signed-off-by: Athanasios Markou --- Dockerfile | 1 + authenticator.go | 9 --- authenticators/authenticator.go | 13 ++++ .../idtoken.go | 30 ++++---- authenticator_jwt.go => authenticators/jwt.go | 48 ++++++------- .../jwt_test.go | 14 ++-- .../kubernetes.go | 20 +++--- .../opaque.go | 34 ++++----- .../opaque_test.go | 8 +-- .../session.go | 30 ++++---- main.go | 69 ++++++++++--------- server.go | 14 ++-- 12 files changed, 148 insertions(+), 142 deletions(-) delete mode 100644 authenticator.go create mode 100644 authenticators/authenticator.go rename authenticator_idtoken.go => authenticators/idtoken.go (66%) rename authenticator_jwt.go => authenticators/jwt.go (76%) rename authenticator_jwt_test.go => authenticators/jwt_test.go (95%) rename authenticator_kubernetes.go => authenticators/kubernetes.go (78%) rename authenticator_opaque.go => authenticators/opaque.go (74%) rename authenticator_opaque_test.go => authenticators/opaque_test.go (91%) rename authenticator_session.go => authenticators/session.go (84%) diff --git a/Dockerfile b/Dockerfile index d50f6707..570a6773 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ COPY *.go ./ COPY common common COPY oidc oidc COPY sessions sessions +COPY authenticators authenticators RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o /go/bin/oidc-authservice diff --git a/authenticator.go b/authenticator.go deleted file mode 100644 index 7058f189..00000000 --- a/authenticator.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "net/http" -) - -type Cacheable interface { - getCacheKey(r *http.Request) string -} \ No newline at end of file diff --git a/authenticators/authenticator.go b/authenticators/authenticator.go new file mode 100644 index 00000000..1ca472f0 --- /dev/null +++ b/authenticators/authenticator.go @@ -0,0 +1,13 @@ +package authenticators + +import ( + "net/http" + + "k8s.io/apiserver/pkg/authentication/authenticator" +) + +type AuthenticatorRequest authenticator.Request + +type Cacheable interface { + GetCacheKey(r *http.Request) string +} \ No newline at end of file diff --git a/authenticator_idtoken.go b/authenticators/idtoken.go similarity index 66% rename from authenticator_idtoken.go rename to authenticators/idtoken.go index 1fe8e78d..1e6a8bc3 100644 --- a/authenticator_idtoken.go +++ b/authenticators/idtoken.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "net/http" @@ -9,29 +9,29 @@ import ( "k8s.io/apiserver/pkg/authentication/user" ) -type idTokenAuthenticator struct { - header string // header name where id token is stored - caBundle []byte - provider oidc.IdProvider - clientID string // need client id to verify the id token - userIDClaim string // retrieve the userid if the claim exists - groupsClaim string +type IDTokenAuthenticator struct { + Header string // header name where id token is stored + CaBundle []byte + Provider oidc.IdProvider + ClientID string // need client id to verify the id token + UserIDClaim string // retrieve the userid if the claim exists + GroupsClaim string } -func (s *idTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { +func (s *IDTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { logger := common.LoggerForRequest(r, "idtoken authenticator") // get id-token from header - bearer := common.GetBearerToken(r.Header.Get(s.header)) + bearer := common.GetBearerToken(r.Header.Get(s.Header)) if len(bearer) == 0 { logger.Info("No bearer token found") return nil, false, nil } - ctx := common.SetTLSContext(r.Context(), s.caBundle) + ctx := common.SetTLSContext(r.Context(), s.CaBundle) // Verifying received ID token - verifier := s.provider.Verifier(oidc.NewOidcConfig(s.clientID)) + verifier := s.Provider.Verifier(oidc.NewOidcConfig(s.ClientID)) token, err := verifier.Verify(ctx, bearer) if err != nil { logger.Errorf("id-token verification failed: %v", err) @@ -44,14 +44,14 @@ func (s *idTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authentica return nil, false, nil } - if claims[s.userIDClaim] == nil { + if claims[s.UserIDClaim] == nil { // No USERID_CLAIM, pass this authenticator logger.Error("USERID_CLAIM doesn't exist in the id token") return nil, false, nil } groups := []string{} - groupsClaim := claims[s.groupsClaim] + groupsClaim := claims[s.GroupsClaim] if groupsClaim != nil { groups = common.InterfaceSliceToStringSlice(groupsClaim.([]interface{})) } @@ -61,7 +61,7 @@ func (s *idTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authentica resp := &authenticator.Response{ User: &user.DefaultInfo{ - Name: claims[s.userIDClaim].(string), + Name: claims[s.UserIDClaim].(string), Groups: groups, Extra: extra, }, diff --git a/authenticator_jwt.go b/authenticators/jwt.go similarity index 76% rename from authenticator_jwt.go rename to authenticators/jwt.go index f98b6f65..dde68c8b 100644 --- a/authenticator_jwt.go +++ b/authenticators/jwt.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "net/http" @@ -16,14 +16,14 @@ const ( audienceNotfound = "oidc: expected audience" ) -type jwtTokenAuthenticator struct { - header string // header name where JWT access token is stored - caBundle []byte - provider oidc.IdProvider - audiences []string // need client id to verify the id token - issuer string // need this for the local check - userIDClaim string // retrieve the userid if the claim exists - groupsClaim string +type JWTTokenAuthenticator struct { + Header string // header name where JWT access token is stored + CaBundle []byte + Provider oidc.IdProvider + Audiences []string // need client id to verify the id token + Issuer string // need this for the local check + UserIDClaim string // retrieve the userid if the claim exists + GroupsClaim string } type jwtLocalChecks struct { @@ -31,21 +31,21 @@ type jwtLocalChecks struct { Audiences common.Audience `json:"aud"` } -func (s *jwtTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { +func (s *JWTTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { logger := common.LoggerForRequest(r, "JWT access token authenticator") // Get JWT access token from header - bearer := common.GetBearerToken(r.Header.Get(s.header)) + bearer := common.GetBearerToken(r.Header.Get(s.Header)) if len(bearer) == 0 { logger.Info("No bearer token found") return nil, false, nil } - ctx := common.SetTLSContext(r.Context(), s.caBundle) + ctx := common.SetTLSContext(r.Context(), s.CaBundle) // Verifying received JWT token - for _, aud := range s.audiences { - verifier := s.provider.Verifier(oidc.NewOidcConfig(aud)) + for _, aud := range s.Audiences { + verifier := s.Provider.Verifier(oidc.NewOidcConfig(aud)) token, err := verifier.Verify(ctx, bearer) if err != nil { @@ -99,8 +99,8 @@ func (s *jwtTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authentic } -// Perform local checks for the issuer and the audiences -func (s *jwtTokenAuthenticator) performLocalChecks(bearer string) (error){ +// Perform local checks for the issuer and the audiences +func (s *JWTTokenAuthenticator) performLocalChecks(bearer string) (error){ // Verify that the retrieved Bearer token is a parsable JWT token payload, localErr := common.ParseJWT(bearer) @@ -118,33 +118,33 @@ func (s *jwtTokenAuthenticator) performLocalChecks(bearer string) (error){ } // Check issuer - if tokenLocalChecks.Issuer != s.issuer { // Check next authenticator + if tokenLocalChecks.Issuer != s.Issuer { // Check next authenticator localErr = fmt.Errorf("The retrieved \"iss\" did not match the expected one.") return localErr } // Check audiences - if !common.Contains(s.audiences, tokenLocalChecks.Audiences){ // Check next authenticator + if !common.Contains(s.Audiences, tokenLocalChecks.Audiences){ // Check next authenticator localErr = fmt.Errorf("The retrieved \"aud\" did not match with any of the" + " expected audiences.") return localErr } - // Local checks succeeded. + // Local checks succeeded. return nil } // Retrieve the USERID_CLAIM and the GROUPS_CLAIM from the JWT access token -func (s *jwtTokenAuthenticator) retrieveUserIDGroupsClaims(claims map[string]interface{}) (string, []string, error){ - - if claims[s.userIDClaim] == nil { +func (s *JWTTokenAuthenticator) retrieveUserIDGroupsClaims(claims map[string]interface{}) (string, []string, error){ + + if claims[s.UserIDClaim] == nil { claimErr := fmt.Errorf("USERID_CLAIM not found in the JWT token") return "", []string{}, claimErr } groups := []string{} - groupsClaim := claims[s.groupsClaim] + groupsClaim := claims[s.GroupsClaim] if groupsClaim == nil { claimErr := fmt.Errorf("GROUPS_CLAIM not found in the JWT token") return "", []string{}, claimErr @@ -152,5 +152,5 @@ func (s *jwtTokenAuthenticator) retrieveUserIDGroupsClaims(claims map[string]int groups = common.InterfaceSliceToStringSlice(groupsClaim.([]interface{})) - return claims[s.userIDClaim].(string), groups, nil + return claims[s.UserIDClaim].(string), groups, nil } \ No newline at end of file diff --git a/authenticator_jwt_test.go b/authenticators/jwt_test.go similarity index 95% rename from authenticator_jwt_test.go rename to authenticators/jwt_test.go index 0eb36989..9f400163 100644 --- a/authenticator_jwt_test.go +++ b/authenticators/jwt_test.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "testing" @@ -7,13 +7,13 @@ import ( func TestPerformLocalChecks(t *testing.T) { - s := &jwtTokenAuthenticator { - audiences: []string{ + s := &JWTTokenAuthenticator { + Audiences: []string{ "myaudience1", "myaudience2", "00af7fe8-a019-4859-94af-3d0f4009fed5", }, - issuer: "https://auth.pingone.eu/e6b1425e-6090-4d29-a961-e760860d932a/as", + Issuer: "https://auth.pingone.eu/e6b1425e-6090-4d29-a961-e760860d932a/as", } tests := []struct { @@ -61,9 +61,9 @@ func TestPerformLocalChecks(t *testing.T) { func TestRetrieveUserIDGroupsClaims(t *testing.T) { - s := &jwtTokenAuthenticator { - userIDClaim: "preferred_username", - groupsClaim: "groups", + s := &JWTTokenAuthenticator { + UserIDClaim: "preferred_username", + GroupsClaim: "groups", } tests := []struct { diff --git a/authenticator_kubernetes.go b/authenticators/kubernetes.go similarity index 78% rename from authenticator_kubernetes.go rename to authenticators/kubernetes.go index 1fbb5b85..48c3fc7c 100644 --- a/authenticator_kubernetes.go +++ b/authenticators/kubernetes.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "net/http" @@ -17,12 +17,12 @@ const ( bearerTokenExpiredMsg = "Token has expired" ) -type kubernetesAuthenticator struct { - audiences []string - authenticator authenticator.Request +type KubernetesAuthenticator struct { + Audiences []string + Authenticator authenticator.Request } -func newKubernetesAuthenticator(c *rest.Config, aud []string) (authenticator.Request, error) { +func NewKubernetesAuthenticator(c *rest.Config, aud []string) (authenticator.Request, error) { config := authenticatorfactory.DelegatingAuthenticatorConfig{ Anonymous: false, TokenAccessReviewClient: kubernetes.NewForConfigOrDie(c).AuthenticationV1(), @@ -30,12 +30,12 @@ func newKubernetesAuthenticator(c *rest.Config, aud []string) (authenticator.Req APIAudiences: aud, } k8sAuthenticator, _, err := config.New() - return &kubernetesAuthenticator{audiences: aud, authenticator: k8sAuthenticator}, err + return &KubernetesAuthenticator{Audiences: aud, Authenticator: k8sAuthenticator}, err } -func (k8sauth *kubernetesAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { - resp, found, err := k8sauth.authenticator.AuthenticateRequest( - r.WithContext(authenticator.WithAudiences(r.Context(), k8sauth.audiences)), +func (k8sauth *KubernetesAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { + resp, found, err := k8sauth.Authenticator.AuthenticateRequest( + r.WithContext(authenticator.WithAudiences(r.Context(), k8sauth.Audiences)), ) // If the request contains an expired token, we stop trying and return 403 @@ -63,7 +63,7 @@ func (k8sauth *kubernetesAuthenticator) AuthenticateRequest(r *http.Request) (*a // The Kubernetes Authenticator implements the Cacheable // interface with the getCacheKey(). -func (k8sauth *kubernetesAuthenticator) getCacheKey(r *http.Request) (string) { +func (k8sauth *KubernetesAuthenticator) GetCacheKey(r *http.Request) (string) { return common.GetBearerToken(r.Header.Get("Authorization")) } diff --git a/authenticator_opaque.go b/authenticators/opaque.go similarity index 74% rename from authenticator_opaque.go rename to authenticators/opaque.go index 85f94ecb..8eb810fa 100644 --- a/authenticator_opaque.go +++ b/authenticators/opaque.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "net/http" @@ -11,20 +11,20 @@ import ( "k8s.io/apiserver/pkg/authentication/user" ) -type opaqueTokenAuthenticator struct { - header string // header name where opaque access token is stored - caBundle []byte - provider oidc.IdProvider - oauth2Config *oauth2.Config - userIDClaim string // retrieve the userid claim - groupsClaim string // retrieve the groups claim +type OpaqueTokenAuthenticator struct { + Header string // header name where opaque access token is stored + CaBundle []byte + Provider oidc.IdProvider + Oauth2Config *oauth2.Config + UserIDClaim string // retrieve the userid claim + GroupsClaim string // retrieve the groups claim } -func (s *opaqueTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { +func (s *OpaqueTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { logger := common.LoggerForRequest(r, "opaque access token authenticator") // get id-token from header - bearer := common.GetBearerToken(r.Header.Get(s.header)) + bearer := common.GetBearerToken(r.Header.Get(s.Header)) if len(bearer) == 0 { logger.Info("No bearer token found") return nil, false, nil @@ -35,9 +35,9 @@ func (s *opaqueTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authen TokenType: "Bearer", } - ctx := common.SetTLSContext(r.Context(), s.caBundle) + ctx := common.SetTLSContext(r.Context(), s.CaBundle) - userInfo, err := oidc.GetUserInfo(ctx, s.provider, s.oauth2Config.TokenSource(ctx, opaque)) + userInfo, err := oidc.GetUserInfo(ctx, s.Provider, s.Oauth2Config.TokenSource(ctx, opaque)) if err != nil { var reqErr *common.RequestError if !errors.As(err, &reqErr) { @@ -73,15 +73,15 @@ func (s *opaqueTokenAuthenticator) AuthenticateRequest(r *http.Request) (*authen } // Retrieve the USERID_CLAIM and the GROUPS_CLAIM from the /userinfo response -func (s *opaqueTokenAuthenticator) retrieveUserIDGroupsClaims(claims map[string]interface{}) (string, []string, error){ +func (s *OpaqueTokenAuthenticator) retrieveUserIDGroupsClaims(claims map[string]interface{}) (string, []string, error){ - if claims[s.userIDClaim] == nil { + if claims[s.UserIDClaim] == nil { claimErr := errors.New("USERID_CLAIM not found in the response of the userinfo endpoint") return "", []string{}, claimErr } groups := []string{} - groupsClaim := claims[s.groupsClaim] + groupsClaim := claims[s.GroupsClaim] if groupsClaim == nil { claimErr := errors.New("GROUPS_CLAIM not found in the response of the userinfo endpoint") return "", []string{}, claimErr @@ -89,12 +89,12 @@ func (s *opaqueTokenAuthenticator) retrieveUserIDGroupsClaims(claims map[string] groups = common.InterfaceSliceToStringSlice(groupsClaim.([]interface{})) - return claims[s.userIDClaim].(string), groups, nil + return claims[s.UserIDClaim].(string), groups, nil } // The Opaque Access Token Authenticator implements the Cacheable // interface with the getCacheKey(). -func (s *opaqueTokenAuthenticator) getCacheKey(r *http.Request) (string) { +func (s *OpaqueTokenAuthenticator) GetCacheKey(r *http.Request) (string) { return common.GetBearerToken(r.Header.Get("Authorization")) } \ No newline at end of file diff --git a/authenticator_opaque_test.go b/authenticators/opaque_test.go similarity index 91% rename from authenticator_opaque_test.go rename to authenticators/opaque_test.go index 8e7173eb..13c1db6b 100644 --- a/authenticator_opaque_test.go +++ b/authenticators/opaque_test.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "testing" @@ -6,9 +6,9 @@ import ( func TestRetrieveUserIDGroupsUserInfo(t *testing.T) { - s := &opaqueTokenAuthenticator { - userIDClaim: "preferred_username", - groupsClaim: "groups", + s := &OpaqueTokenAuthenticator { + UserIDClaim: "preferred_username", + GroupsClaim: "groups", } tests := []struct { diff --git a/authenticator_session.go b/authenticators/session.go similarity index 84% rename from authenticator_session.go rename to authenticators/session.go index cfc8bf81..58c4afbd 100644 --- a/authenticator_session.go +++ b/authenticators/session.go @@ -1,4 +1,4 @@ -package main +package authenticators import ( "net/http" @@ -13,33 +13,33 @@ import ( "k8s.io/apiserver/pkg/authentication/user" ) -type sessionAuthenticator struct { +type SessionAuthenticator struct { // store is the session store. - store sessions.Store + Store sessions.Store // cookie is the name of the cookie that holds the session value. - cookie string + Cookie string // header is the header to check as an alternative to finding the session // value. - header string + Header string // strictSessionValidation mode checks the validity of the access token // connected with the session on every request. - strictSessionValidation bool + StrictSessionValidation bool // caBundle specifies CAs to trust when talking with the OIDC Provider. // Relevant only when strictSessionValidation is enabled. - caBundle []byte + CaBundle []byte // oauth2Config is the config to use when talking with the OIDC Provider. // Relevant only when strictSessionValidation is enabled. - oauth2Config *oauth2.Config + Oauth2Config *oauth2.Config // provider is the OIDC Provider. // Relevant only when strictSessionValidation is enabled. - provider oidc.IdProvider + Provider oidc.IdProvider } -func (sa *sessionAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { +func (sa *SessionAuthenticator) AuthenticateRequest(r *http.Request) (*authenticator.Response, bool, error) { logger := common.LoggerForRequest(r, "session authenticator") // Get session from header or cookie - session, authMethod, err := sessions.SessionFromRequest(r, sa.store, sa.cookie, sa.header) + session, authMethod, err := sessions.SessionFromRequest(r, sa.Store, sa.Cookie, sa.Header) // Check if user session is valid if err != nil { @@ -51,11 +51,11 @@ func (sa *sessionAuthenticator) AuthenticateRequest(r *http.Request) (*authentic } // User is logged in - if sa.strictSessionValidation { - ctx := common.SetTLSContext(r.Context(), sa.caBundle) + if sa.StrictSessionValidation { + ctx := common.SetTLSContext(r.Context(), sa.CaBundle) token := session.Values[sessions.UserSessionOAuth2Tokens].(oauth2.Token) // TokenSource takes care of automatically renewing the access token. - _, err := oidc.GetUserInfo(ctx, sa.provider, sa.oauth2Config.TokenSource(ctx, &token)) + _, err := oidc.GetUserInfo(ctx, sa.Provider, sa.Oauth2Config.TokenSource(ctx, &token)) if err != nil { var reqErr *common.RequestError if !errors.As(err, &reqErr) { @@ -71,7 +71,7 @@ func (sa *sessionAuthenticator) AuthenticateRequest(r *http.Request) (*authentic // means that the cookie will remain at the user's browser but it // will be replaced after the user logs in again. err = sessions.RevokeOIDCSession(ctx, httptest.NewRecorder(), session, - sa.provider, sa.oauth2Config, sa.caBundle) + sa.Provider, sa.Oauth2Config, sa.CaBundle) if err != nil { logger.Errorf("Failed to revoke tokens: %v", err) } diff --git a/main.go b/main.go index 28b2ed87..9a8b4671 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "path" "time" + "github.com/arrikto/oidc-authservice/authenticators" "github.com/arrikto/oidc-authservice/common" "github.com/arrikto/oidc-authservice/oidc" "github.com/arrikto/oidc-authservice/sessions" @@ -19,7 +20,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/tevino/abool" "golang.org/x/oauth2" - "k8s.io/apiserver/pkg/authentication/authenticator" clientconfig "sigs.k8s.io/controller-runtime/pkg/client/config" ) @@ -104,7 +104,7 @@ func main() { defer oidcStateStore.Close() // Get Kubernetes authenticator - var k8sAuthenticator authenticator.Request + var k8sAuthenticator authenticators.AuthenticatorRequest restConfig, err := clientconfig.GetConfig() if err != nil && c.KubernetesAuthnEnabled { log.Fatalf("Error getting K8s config: %v", err) @@ -113,7 +113,8 @@ func main() { log.Debugf("Error getting K8s config: %v. " + "Kubernetes authenticator is disabled, skipping ...", err) } else { - k8sAuthenticator, err = newKubernetesAuthenticator(restConfig, c.Audiences) + k8sAuthenticator, err = authenticators.NewKubernetesAuthenticator( + restConfig, c.Audiences) if err != nil && c.KubernetesAuthnEnabled { log.Fatalf("Error creating K8s authenticator: %v", err) } else if err != nil { @@ -133,42 +134,42 @@ func main() { } // Setup authenticators. - sessionAuthenticator := &sessionAuthenticator{ - store: store, - cookie: sessions.UserSessionCookie, - header: c.AuthHeader, - strictSessionValidation: c.StrictSessionValidation, - caBundle: caBundle, - provider: provider, - oauth2Config: oauth2Config, + sessionAuthenticator := &authenticators.SessionAuthenticator{ + Store: store, + Cookie: sessions.UserSessionCookie, + Header: c.AuthHeader, + StrictSessionValidation: c.StrictSessionValidation, + CaBundle: caBundle, + Provider: provider, + Oauth2Config: oauth2Config, } - idTokenAuthenticator := &idTokenAuthenticator{ - header: c.IDTokenHeader, - caBundle: caBundle, - provider: provider, - clientID: c.ClientID, - userIDClaim: c.UserIDClaim, - groupsClaim: c.GroupsClaim, + idTokenAuthenticator := &authenticators.IDTokenAuthenticator{ + Header: c.IDTokenHeader, + CaBundle: caBundle, + Provider: provider, + ClientID: c.ClientID, + UserIDClaim: c.UserIDClaim, + GroupsClaim: c.GroupsClaim, } - jwtTokenAuthenticator := &jwtTokenAuthenticator{ - header: c.IDTokenHeader, - caBundle: caBundle, - provider: provider, - audiences: c.Audiences, - issuer: c.ProviderURL.String(), - userIDClaim: c.UserIDClaim, - groupsClaim: c.GroupsClaim, + jwtTokenAuthenticator := &authenticators.JWTTokenAuthenticator{ + Header: c.IDTokenHeader, + CaBundle: caBundle, + Provider: provider, + Audiences: c.Audiences, + Issuer: c.ProviderURL.String(), + UserIDClaim: c.UserIDClaim, + GroupsClaim: c.GroupsClaim, } - opaqueTokenAuthenticator := &opaqueTokenAuthenticator{ - header: c.IDTokenHeader, - caBundle: caBundle, - provider: provider, - oauth2Config: oauth2Config, - userIDClaim: c.UserIDClaim, - groupsClaim: c.GroupsClaim, + opaqueTokenAuthenticator := &authenticators.OpaqueTokenAuthenticator{ + Header: c.IDTokenHeader, + CaBundle: caBundle, + Provider: provider, + Oauth2Config: oauth2Config, + UserIDClaim: c.UserIDClaim, + GroupsClaim: c.GroupsClaim, } // Set the bearerUserInfoCache cache to store @@ -223,7 +224,7 @@ func main() { AccessTokenAuthn: c.AccessTokenAuthn, authHeader: c.AuthHeader, caBundle: caBundle, - authenticators: []authenticator.Request{ + authenticators: []authenticators.AuthenticatorRequest{ k8sAuthenticator, opaqueTokenAuthenticator, jwtTokenAuthenticator, diff --git a/server.go b/server.go index 37afa607..9466b527 100644 --- a/server.go +++ b/server.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/arrikto/oidc-authservice/authenticators" "github.com/arrikto/oidc-authservice/common" "github.com/arrikto/oidc-authservice/oidc" "github.com/arrikto/oidc-authservice/sessions" @@ -16,7 +17,6 @@ import ( "github.com/pkg/errors" "github.com/tevino/abool" "golang.org/x/oauth2" - "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/user" ) @@ -41,7 +41,7 @@ type server struct { store sessions.ClosableStore oidcStateStore sessions.ClosableStore bearerUserInfoCache *cache.Cache - authenticators []authenticator.Request + authenticators []authenticators.AuthenticatorRequest authorizers []Authorizer afterLoginRedirectURL string homepageURL string @@ -273,20 +273,20 @@ func (s *server) authorized(w http.ResponseWriter, r *http.Request, userInfo use // * the UserInfo // * the cacheKey // if there is an entry in the cache for the examined user. -// Otherwise, it returns nil and an empty string respectively. -func (s *server) getCachedUser(auth authenticator.Request, r *http.Request) (user.Info, string) { +// Otherwise, it returns an empty string for the cacheKey and nil respectively. +func (s *server) getCachedUser(auth authenticators.AuthenticatorRequest, r *http.Request) (user.Info, string) { logger := common.LoggerForRequest(r, logModuleInfo) // If the cache is enabled, check if the current authenticator implements the Cacheable interface. - cacheable := reflect.TypeOf((*Cacheable)(nil)).Elem() + cacheable := reflect.TypeOf((*authenticators.Cacheable)(nil)).Elem() isCacheable := reflect.TypeOf(auth).Implements(cacheable) if isCacheable { // Store the key that we are going to use for caching UserDetails. // We store it before the authentication, because the authenticators may mutate the request object. logger.Debugf("Retrieving the cache key...") - cacheableAuthenticator := reflect.ValueOf(auth).Interface().(Cacheable) - cacheKey := cacheableAuthenticator.getCacheKey(r) + cacheableAuthenticator := reflect.ValueOf(auth).Interface().(authenticators.Cacheable) + cacheKey := cacheableAuthenticator.GetCacheKey(r) if cacheKey != "" { cachedUserInfo, found := s.bearerUserInfoCache.Get(cacheKey)