// NewRequestAuthenticator creates an http handler that tries to authenticate the given request as a user, and then // stores any such user found onto the provided context for the request. If authentication fails or returns an error // the failed handler is used. On success, handler is invoked to serve the request. func NewRequestAuthenticator(mapper api.RequestContextMapper, auth authenticator.Request, failed http.Handler, handler http.Handler) (http.Handler, error) { return api.NewRequestContextFilter( mapper, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { user, ok, err := auth.AuthenticateRequest(req) if err != nil || !ok { if err != nil { glog.Errorf("Unable to authenticate the request due to an error: %v", err) } failed.ServeHTTP(w, req) return } if ctx, ok := mapper.Get(req); ok { mapper.Update(req, api.WithUser(ctx, user)) } authenticatedUserCounter.WithLabelValues(compressUsername(user.GetName())).Inc() handler.ServeHTTP(w, req) }), ) }
func WithImpersonation(handler http.Handler, requestContextMapper api.RequestContextMapper, a authorizer.Authorizer) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestedSubject := req.Header.Get("Impersonate-User") if len(requestedSubject) == 0 { handler.ServeHTTP(w, req) return } ctx, exists := requestContextMapper.Get(req) if !exists { forbidden(w, req) return } requestor, exists := api.UserFrom(ctx) if !exists { forbidden(w, req) return } actingAsAttributes := &authorizer.AttributesRecord{ User: requestor, Verb: "impersonate", APIGroup: api.GroupName, Resource: "users", Name: requestedSubject, ResourceRequest: true, } if namespace, name, err := serviceaccount.SplitUsername(requestedSubject); err == nil { actingAsAttributes.Resource = "serviceaccounts" actingAsAttributes.Namespace = namespace actingAsAttributes.Name = name } err := a.Authorize(actingAsAttributes) if err != nil { forbidden(w, req) return } switch { case strings.HasPrefix(requestedSubject, serviceaccount.ServiceAccountUsernamePrefix): namespace, name, err := serviceaccount.SplitUsername(requestedSubject) if err != nil { forbidden(w, req) return } requestContextMapper.Update(req, api.WithUser(ctx, serviceaccount.UserInfo(namespace, name, ""))) default: newUser := &user.DefaultInfo{ Name: requestedSubject, } requestContextMapper.Update(req, api.WithUser(ctx, newUser)) } newCtx, _ := requestContextMapper.Get(req) oldUser, _ := api.UserFrom(ctx) newUser, _ := api.UserFrom(newCtx) httplog.LogOf(req, w).Addf("%v is acting as %v", oldUser, newUser) handler.ServeHTTP(w, req) }) }