func (v *TagVerifier) Verify(old, stream *api.ImageStream, user user.Info) field.ErrorList { var errors field.ErrorList oldTags := map[string]api.TagReference{} if old != nil && old.Spec.Tags != nil { oldTags = old.Spec.Tags } for tag, tagRef := range stream.Spec.Tags { if tagRef.From == nil { continue } if len(tagRef.From.Namespace) == 0 { continue } if stream.Namespace == tagRef.From.Namespace { continue } if oldRef, ok := oldTags[tag]; ok && !tagRefChanged(oldRef, tagRef, stream.Namespace) { continue } streamName, _, err := parseFromReference(stream, tagRef.From) fromPath := field.NewPath("spec", "tags").Key(tag).Child("from") if err != nil { errors = append(errors, field.Invalid(fromPath.Child("name"), tagRef.From.Name, "must be of the form <tag>, <repo>:<tag>, <id>, or <repo>@<id>")) continue } // Make sure this user can pull the specified image before allowing them to tag it into another imagestream subjectAccessReview := authorizationapi.AddUserToSAR(user, &authorizationapi.SubjectAccessReview{ Action: authorizationapi.Action{ Verb: "get", Group: api.GroupName, Resource: "imagestreams/layers", ResourceName: streamName, }, }) ctx := kapi.WithNamespace(kapi.NewContext(), tagRef.From.Namespace) glog.V(4).Infof("Performing SubjectAccessReview for user=%s, groups=%v to %s/%s", user.GetName(), user.GetGroups(), tagRef.From.Namespace, streamName) resp, err := v.subjectAccessReviewClient.CreateSubjectAccessReview(ctx, subjectAccessReview) if err != nil || resp == nil || (resp != nil && !resp.Allowed) { errors = append(errors, field.Forbidden(fromPath, fmt.Sprintf("%s/%s", tagRef.From.Namespace, streamName))) continue } } return errors }
func (r *RemoteAuthorizer) Authorize(ctx kapi.Context, a authorizer.AuthorizationAttributes) (bool, string, error) { var ( result *authzapi.SubjectAccessReviewResponse err error ) // Extract namespace from context namespace, _ := kapi.NamespaceFrom(ctx) // Extract user from context user := "" groups := sets.NewString() userInfo, ok := kapi.UserFrom(ctx) if ok { user = userInfo.GetName() groups.Insert(userInfo.GetGroups()...) } // Make sure we don't run a subject access review on our own permissions if len(user) == 0 && len(groups) == 0 { user = bootstrappolicy.UnauthenticatedUsername groups = sets.NewString(bootstrappolicy.UnauthenticatedGroup) } if len(namespace) > 0 { result, err = r.client.LocalSubjectAccessReviews(namespace).Create( authzapi.AddUserToLSAR(userInfo, &authzapi.LocalSubjectAccessReview{Action: getAction(namespace, a)})) } else { result, err = r.client.SubjectAccessReviews().Create( authzapi.AddUserToSAR(userInfo, &authzapi.SubjectAccessReview{Action: getAction(namespace, a)})) } if err != nil { glog.Errorf("error running subject access review: %v", err) return false, "", kerrs.NewInternalError(err) } glog.V(2).Infof("allowed=%v, reason=%s", result.Allowed, result.Reason) return result.Allowed, result.Reason, nil }
func (r *REST) List(ctx kapi.Context, options *kapi.ListOptions) (runtime.Object, error) { userInfo, exists := kapi.UserFrom(ctx) if !exists { return nil, errors.New("a user must be provided") } // the caller might not have permission to run a subject access review (he has it by default, but it could have been removed). // So we'll escalate for the subject access review to determine rights accessReview := authorizationapi.AddUserToSAR(userInfo, &authorizationapi.SubjectAccessReview{ Action: authorizationapi.Action{ Verb: "create", Group: projectapi.GroupName, Resource: "projectrequests", }, }) accessReviewResponse, err := r.openshiftClient.SubjectAccessReviews().Create(accessReview) if err != nil { return nil, err } if accessReviewResponse.Allowed { return &unversioned.Status{Status: unversioned.StatusSuccess}, nil } forbiddenError := kapierror.NewForbidden(projectapi.Resource("projectrequest"), "", errors.New("you may not request a new project via this API.")) if len(r.message) > 0 { forbiddenError.ErrStatus.Message = r.message forbiddenError.ErrStatus.Details = &unversioned.StatusDetails{ Kind: "ProjectRequest", Causes: []unversioned.StatusCause{ {Message: r.message}, }, } } else { forbiddenError.ErrStatus.Message = "You may not request a new project via this API." } return nil, forbiddenError }