// WithImpersonation is a filter that will inspect and check requests that attempt to change the user.Info for their requests func WithImpersonation(handler http.Handler, requestContextMapper api.RequestContextMapper, a authorizer.Authorizer) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { impersonationRequests, err := buildImpersonationRequests(req.Header) if err != nil { glog.V(4).Infof("%v", err) internalError(w, req, err) return } if len(impersonationRequests) == 0 { handler.ServeHTTP(w, req) return } ctx, exists := requestContextMapper.Get(req) if !exists { internalError(w, req, errors.New("no context found for request")) return } requestor, exists := api.UserFrom(ctx) if !exists { internalError(w, req, errors.New("no user found for request")) return } // if groups are not specified, then we need to look them up differently depending on the type of user // if they are specified, then they are the authority groupsSpecified := len(req.Header[authenticationapi.ImpersonateGroupHeader]) > 0 // make sure we're allowed to impersonate each thing we're requesting. While we're iterating through, start building username // and group information username := "" groups := []string{} userExtra := map[string][]string{} for _, impersonationRequest := range impersonationRequests { actingAsAttributes := &authorizer.AttributesRecord{ User: requestor, Verb: "impersonate", APIGroup: impersonationRequest.GetObjectKind().GroupVersionKind().Group, Namespace: impersonationRequest.Namespace, Name: impersonationRequest.Name, ResourceRequest: true, } switch impersonationRequest.GetObjectKind().GroupVersionKind().GroupKind() { case api.Kind("ServiceAccount"): actingAsAttributes.Resource = "serviceaccounts" username = serviceaccount.MakeUsername(impersonationRequest.Namespace, impersonationRequest.Name) if !groupsSpecified { // if groups aren't specified for a service account, we know the groups because its a fixed mapping. Add them groups = serviceaccount.MakeGroupNames(impersonationRequest.Namespace, impersonationRequest.Name) } case api.Kind("User"): actingAsAttributes.Resource = "users" username = impersonationRequest.Name case api.Kind("Group"): actingAsAttributes.Resource = "groups" groups = append(groups, impersonationRequest.Name) case authenticationapi.Kind("UserExtra"): extraKey := impersonationRequest.FieldPath extraValue := impersonationRequest.Name actingAsAttributes.Resource = "userextras" actingAsAttributes.Subresource = extraKey userExtra[extraKey] = append(userExtra[extraKey], extraValue) default: glog.V(4).Infof("unknown impersonation request type: %v", impersonationRequest) forbidden(actingAsAttributes, w, req, fmt.Sprintf("unknown impersonation request type: %v", impersonationRequest)) return } allowed, reason, err := a.Authorize(actingAsAttributes) if err != nil || !allowed { glog.V(4).Infof("Forbidden: %#v, Reason: %s, Error: %v", req.RequestURI, reason, err) forbidden(actingAsAttributes, w, req, reason) return } } newUser := &user.DefaultInfo{ Name: username, Groups: groups, Extra: userExtra, } requestContextMapper.Update(req, api.WithUser(ctx, newUser)) oldUser, _ := api.UserFrom(ctx) httplog.LogOf(req, w).Addf("%v is acting as %v", oldUser, newUser) // clear all the impersonation headers from the request req.Header.Del(authenticationapi.ImpersonateUserHeader) req.Header.Del(authenticationapi.ImpersonateGroupHeader) for headerName := range req.Header { if strings.HasPrefix(headerName, authenticationapi.ImpersonateUserExtraHeaderPrefix) { req.Header.Del(headerName) } } handler.ServeHTTP(w, req) }) }
func (c *MasterConfig) impersonationFilter(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestedUser := req.Header.Get(authenticationapi.ImpersonateUserHeader) if len(requestedUser) == 0 { handler.ServeHTTP(w, req) return } subjects := authorizationapi.BuildSubjects([]string{requestedUser}, req.Header[authenticationapi.ImpersonateGroupHeader], // validates whether the usernames are regular users or system users uservalidation.ValidateUserName, // validates group names are regular groups or system groups uservalidation.ValidateGroupName) ctx, exists := c.RequestContextMapper.Get(req) if !exists { forbidden("context not found", nil, w, req) return } // if groups are not specified, then we need to look them up differently depending on the type of user // if they are specified, then they are the authority groupsSpecified := len(req.Header[authenticationapi.ImpersonateGroupHeader]) > 0 // make sure we're allowed to impersonate each subject. While we're iterating through, start building username // and group information username := "" groups := []string{} for _, subject := range subjects { actingAsAttributes := &authorizer.DefaultAuthorizationAttributes{ Verb: "impersonate", } switch subject.GetObjectKind().GroupVersionKind().GroupKind() { case userapi.Kind(authorizationapi.GroupKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.GroupResource actingAsAttributes.ResourceName = subject.Name groups = append(groups, subject.Name) case userapi.Kind(authorizationapi.SystemGroupKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.SystemGroupResource actingAsAttributes.ResourceName = subject.Name groups = append(groups, subject.Name) case userapi.Kind(authorizationapi.UserKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.UserResource actingAsAttributes.ResourceName = subject.Name username = subject.Name if !groupsSpecified { if actualGroups, err := c.GroupCache.GroupsFor(subject.Name); err == nil { for _, group := range actualGroups { groups = append(groups, group.Name) } } groups = append(groups, bootstrappolicy.AuthenticatedGroup, bootstrappolicy.AuthenticatedOAuthGroup) } case userapi.Kind(authorizationapi.SystemUserKind): actingAsAttributes.APIGroup = userapi.GroupName actingAsAttributes.Resource = authorizationapi.SystemUserResource actingAsAttributes.ResourceName = subject.Name username = subject.Name if !groupsSpecified { if subject.Name == bootstrappolicy.UnauthenticatedUsername { groups = append(groups, bootstrappolicy.UnauthenticatedGroup) } else { groups = append(groups, bootstrappolicy.AuthenticatedGroup) } } case kapi.Kind(authorizationapi.ServiceAccountKind): actingAsAttributes.APIGroup = kapi.GroupName actingAsAttributes.Resource = authorizationapi.ServiceAccountResource actingAsAttributes.ResourceName = subject.Name username = serviceaccount.MakeUsername(subject.Namespace, subject.Name) if !groupsSpecified { groups = append(serviceaccount.MakeGroupNames(subject.Namespace, subject.Name), bootstrappolicy.AuthenticatedGroup) } default: forbidden(fmt.Sprintf("unknown subject type: %v", subject), actingAsAttributes, w, req) return } authCheckCtx := kapi.WithNamespace(ctx, subject.Namespace) allowed, reason, err := c.Authorizer.Authorize(authCheckCtx, actingAsAttributes) if err != nil { forbidden(err.Error(), actingAsAttributes, w, req) return } if !allowed { forbidden(reason, actingAsAttributes, w, req) return } } var extra map[string][]string if requestScopes, ok := req.Header[authenticationapi.ImpersonateUserScopeHeader]; ok { extra = map[string][]string{authorizationapi.ScopesKey: requestScopes} } newUser := &user.DefaultInfo{ Name: username, Groups: groups, Extra: extra, } c.RequestContextMapper.Update(req, kapi.WithUser(ctx, newUser)) oldUser, _ := kapi.UserFrom(ctx) httplog.LogOf(req, w).Addf("%v is acting as %v", oldUser, newUser) handler.ServeHTTP(w, req) }) }
func (c *MasterConfig) impersonationFilter(handler http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { requestedSubject := req.Header.Get(authenticationapi.ImpersonateUserHeader) if len(requestedSubject) == 0 { handler.ServeHTTP(w, req) return } resource, namespace, name, err := parseRequestedSubject(requestedSubject) if err != nil { forbidden(err.Error(), nil, w, req) return } ctx, exists := c.RequestContextMapper.Get(req) if !exists { forbidden("context not found", nil, w, req) return } actingAsAttributes := &authorizer.DefaultAuthorizationAttributes{ Verb: "impersonate", APIGroup: resource.Group, Resource: resource.Resource, ResourceName: name, } authCheckCtx := kapi.WithNamespace(ctx, namespace) allowed, reason, err := c.Authorizer.Authorize(authCheckCtx, actingAsAttributes) if err != nil { forbidden(err.Error(), actingAsAttributes, w, req) return } if !allowed { forbidden(reason, actingAsAttributes, w, req) return } var extra map[string][]string if requestScopes, ok := req.Header[authenticationapi.ImpersonateUserScopeHeader]; ok { extra = map[string][]string{authorizationapi.ScopesKey: requestScopes} } switch resource { case kapi.Resource(authorizationapi.ServiceAccountResource): newUser := &user.DefaultInfo{ Name: serviceaccount.MakeUsername(namespace, name), Groups: serviceaccount.MakeGroupNames(namespace, name), Extra: extra, } newUser.Groups = append(newUser.Groups, bootstrappolicy.AuthenticatedGroup) c.RequestContextMapper.Update(req, kapi.WithUser(ctx, newUser)) case userapi.Resource(authorizationapi.UserResource): newUser := &user.DefaultInfo{ Name: name, Extra: extra, } groups, err := c.GroupCache.GroupsFor(name) if err == nil { for _, group := range groups { newUser.Groups = append(newUser.Groups, group.Name) } } newUser.Groups = append(newUser.Groups, bootstrappolicy.AuthenticatedGroup, bootstrappolicy.AuthenticatedOAuthGroup) c.RequestContextMapper.Update(req, kapi.WithUser(ctx, newUser)) case userapi.Resource(authorizationapi.SystemUserResource): newUser := &user.DefaultInfo{ Name: name, Extra: extra, } if name == bootstrappolicy.UnauthenticatedUsername { newUser.Groups = append(newUser.Groups, bootstrappolicy.UnauthenticatedGroup) } else { newUser.Groups = append(newUser.Groups, bootstrappolicy.AuthenticatedGroup) } c.RequestContextMapper.Update(req, kapi.WithUser(ctx, newUser)) default: forbidden(fmt.Sprintf("%v is an unhandled resource for acting-as", resource), nil, w, req) return } newCtx, _ := c.RequestContextMapper.Get(req) oldUser, _ := kapi.UserFrom(ctx) newUser, _ := kapi.UserFrom(newCtx) httplog.LogOf(req, w).Addf("%v is acting as %v", oldUser, newUser) handler.ServeHTTP(w, req) }) }