// 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)
	})
}
Exemple #2
0
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)
	})
}
Exemple #3
0
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)
	})
}