// WithAuthorizationCheck passes all authorized requests on to handler, and returns a forbidden error otherwise. func WithAuthorization(handler http.Handler, requestContextMapper request.RequestContextMapper, a authorizer.Authorizer) http.Handler { if a == nil { glog.Warningf("Authorization is disabled") return handler } return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { ctx, ok := requestContextMapper.Get(req) if !ok { responsewriters.InternalError(w, req, errors.New("no context found for request")) return } attributes, err := GetAuthorizerAttributes(ctx) if err != nil { responsewriters.InternalError(w, req, err) return } authorized, reason, err := a.Authorize(attributes) if authorized { handler.ServeHTTP(w, req) return } if err != nil { responsewriters.InternalError(w, req, err) return } glog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason) responsewriters.Forbidden(attributes, w, req, reason) }) }
// authorizedForPolicy returns true if info is authorized to perform a "get" on policy. func authorizedForPolicy(info user.Info, policy *extensions.PodSecurityPolicy, authz authorizer.Authorizer) bool { // if no info exists then the API is being hit via the unsecured port. In this case // authorize the request. if info == nil { return true } attr := buildAttributes(info, policy) allowed, _, _ := authz.Authorize(attr) return allowed }
// BindingAuthorized returns true if the user associated with the context is explicitly authorized to bind the specified roleRef func BindingAuthorized(ctx genericapirequest.Context, roleRef rbac.RoleRef, bindingNamespace string, a authorizer.Authorizer) bool { if a == nil { return false } user, ok := genericapirequest.UserFrom(ctx) if !ok { return false } attrs := authorizer.AttributesRecord{ User: user, Verb: "bind", // check against the namespace where the binding is being created (or the empty namespace for clusterrolebindings). // this allows delegation to bind particular clusterroles in rolebindings within particular namespaces, // and to authorize binding a clusterrole across all namespaces in a clusterrolebinding. Namespace: bindingNamespace, ResourceRequest: true, } // This occurs after defaulting and conversion, so values pulled from the roleRef won't change // Invalid APIGroup or Name values will fail validation switch roleRef.Kind { case "ClusterRole": attrs.APIGroup = roleRef.APIGroup attrs.Resource = "clusterroles" attrs.Name = roleRef.Name case "Role": attrs.APIGroup = roleRef.APIGroup attrs.Resource = "roles" attrs.Name = roleRef.Name default: return false } ok, _, err := a.Authorize(attrs) if err != nil { utilruntime.HandleError(fmt.Errorf( "error authorizing user %#v to bind %#v in namespace %s: %v", roleRef, bindingNamespace, user, err, )) } return ok }
// 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 request.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) responsewriters.InternalError(w, req, err) return } if len(impersonationRequests) == 0 { handler.ServeHTTP(w, req) return } ctx, exists := requestContextMapper.Get(req) if !exists { responsewriters.InternalError(w, req, errors.New("no context found for request")) return } requestor, exists := request.UserFrom(ctx) if !exists { responsewriters.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) responsewriters.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) responsewriters.Forbidden(actingAsAttributes, w, req, reason) return } } newUser := &user.DefaultInfo{ Name: username, Groups: groups, Extra: userExtra, } requestContextMapper.Update(req, request.WithUser(ctx, newUser)) oldUser, _ := request.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) }) }