func TestVerbRestrictionsWork(t *testing.T) { test1 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Valerie"}), attributes: &DefaultAuthorizationAttributes{ Verb: "get", Resource: "buildConfigs", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test1.clusterPolicies = newDefaultClusterPolicies() test1.policies = newAdzePolicies() test1.clusterBindings = newDefaultClusterPolicyBindings() test1.bindings = newAdzeBindings() test1.test(t) test2 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Valerie"}), attributes: &DefaultAuthorizationAttributes{ Verb: "create", Resource: "buildConfigs", }, expectedAllowed: false, expectedReason: `User "Valerie" cannot create buildConfigs in project "adze"`, } test2.clusterPolicies = newDefaultClusterPolicies() test2.policies = newAdzePolicies() test2.clusterBindings = newDefaultClusterPolicyBindings() test2.bindings = newAdzeBindings() test2.test(t) }
func TestResourceRestrictionsWithWeirdWork(t *testing.T) { test1 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Rachel"}), attributes: &DefaultAuthorizationAttributes{ Verb: "get", Resource: "BUILDCONFIGS", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test1.clusterPolicies = newDefaultClusterPolicies() test1.policies = newAdzePolicies() test1.clusterBindings = newDefaultClusterPolicyBindings() test1.bindings = newAdzeBindings() test1.test(t) test2 := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Rachel"}), attributes: &DefaultAuthorizationAttributes{ Verb: "get", Resource: "buildconfigs", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test2.clusterPolicies = newDefaultClusterPolicies() test2.policies = newAdzePolicies() test2.clusterBindings = newDefaultClusterPolicyBindings() test2.bindings = newAdzeBindings() test2.test(t) }
func WithActingAs(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", // ResourceName: requestedSubject, ResourceRequest: true, } 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) }) }
// 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, "Authorization" header is removed from the request and 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 } // authorization header is not required anymore in case of a successful authentication. req.Header.Del("Authorization") 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 TestListProjects(t *testing.T) { namespaceList := kapi.NamespaceList{ Items: []kapi.Namespace{ { ObjectMeta: kapi.ObjectMeta{Name: "foo"}, }, }, } mockClient := testclient.NewSimpleFake(&namespaceList) storage := REST{ client: mockClient.Namespaces(), lister: &mockLister{&namespaceList}, } user := &user.DefaultInfo{ Name: "test-user", UID: "test-uid", Groups: []string{"test-groups"}, } ctx := kapi.WithUser(kapi.NewContext(), user) response, err := storage.List(ctx, labels.Everything(), fields.Everything()) if err != nil { t.Errorf("%#v should be nil.", err) } projects := response.(*api.ProjectList) if len(projects.Items) != 1 { t.Errorf("%#v projects.Items should have len 1.", projects.Items) } responseProject := projects.Items[0] if e, r := responseProject.Name, "foo"; e != r { t.Errorf("%#v != %#v.", e, r) } }
func (r *RBACAuthorizer) Authorize(attr authorizer.Attributes) (bool, string, error) { if r.superUser != "" && attr.GetUser() != nil && attr.GetUser().GetName() == r.superUser { return true, "", nil } ctx := api.WithNamespace(api.WithUser(api.NewContext(), attr.GetUser()), attr.GetNamespace()) // Frame the authorization request as a privilege escalation check. var requestedRule rbac.PolicyRule if attr.IsResourceRequest() { requestedRule = rbac.PolicyRule{ Verbs: []string{attr.GetVerb()}, APIGroups: []string{attr.GetAPIGroup()}, // TODO(ericchiang): add api version here too? Resources: []string{attr.GetResource()}, ResourceNames: []string{attr.GetName()}, } } else { requestedRule = rbac.PolicyRule{ Verbs: []string{attr.GetVerb()}, NonResourceURLs: []string{attr.GetPath()}, } } // TODO(nhlfr): Try to find more lightweight way to check attributes than escalation checks. err := validation.ConfirmNoEscalation(ctx, r.authorizationRuleResolver, []rbac.PolicyRule{requestedRule}) if err != nil { return false, err.Error(), nil } return true, "", nil }
// OriginAuthorizerAttributes adapts Kubernetes authorization attributes to Origin authorization attributes // Note that some info (like resourceName, apiVersion, apiGroup) is not available from the Kubernetes attributes func OriginAuthorizerAttributes(kattrs kauthorizer.Attributes) (kapi.Context, oauthorizer.AuthorizationAttributes) { // Build a context to hold the namespace and user info ctx := kapi.NewContext() ctx = kapi.WithNamespace(ctx, kattrs.GetNamespace()) ctx = kapi.WithUser(ctx, &user.DefaultInfo{ Name: kattrs.GetUserName(), Groups: kattrs.GetGroups(), }) // If we recognize the type, use the embedded type. Do NOT use it directly, because not all things that quack are ducks. if castAdapterAttributes, ok := kattrs.(AdapterAttributes); ok { return ctx, castAdapterAttributes.authorizationAttributes } // Otherwise build what we can oattrs := &oauthorizer.DefaultAuthorizationAttributes{ Verb: kattrs.GetVerb(), APIGroup: kattrs.GetAPIGroup(), APIVersion: kattrs.GetAPIVersion(), Resource: kattrs.GetResource(), ResourceName: kattrs.GetName(), NonResourceURL: kattrs.IsResourceRequest() == false, URL: kattrs.GetPath(), // TODO: add to kube authorizer attributes // RequestAttributes interface{} } if len(kattrs.GetSubresource()) > 0 { oattrs.Resource = kattrs.GetResource() + "/" + kattrs.GetSubresource() } return ctx, oattrs }
func TestAllowedWithMissingBinding(t *testing.T) { test := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Anna"}), attributes: &DefaultAuthorizationAttributes{ Verb: "update", Resource: "roles", }, expectedAllowed: true, expectedReason: "allowed by rule in adze", } test.clusterPolicies = newDefaultClusterPolicies() test.policies = append(test.policies, newAdzePolicies()...) test.clusterBindings = newDefaultClusterPolicyBindings() test.bindings = append(test.bindings, newAdzeBindings()...) test.bindings[0].RoleBindings["missing"] = &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{ Name: "missing", }, RoleRef: kapi.ObjectReference{ Name: "not-a-real-binding", }, Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Anna"}}, } test.test(t) }
// Create registers a given new ResourceAccessReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { rulesReview, ok := obj.(*authorizationapi.SubjectRulesReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a SubjectRulesReview: %#v", obj)) } namespace := kapi.NamespaceValue(ctx) if len(namespace) == 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace)) } userToCheck := &user.DefaultInfo{ Name: rulesReview.Spec.User, Groups: rulesReview.Spec.Groups, Extra: map[string][]string{}, } if len(rulesReview.Spec.Scopes) > 0 { userToCheck.Extra[authorizationapi.ScopesKey] = rulesReview.Spec.Scopes } rules, errors := GetEffectivePolicyRules(kapi.WithUser(ctx, userToCheck), r.ruleResolver, r.clusterPolicyGetter) ret := &authorizationapi.SubjectRulesReview{ Status: authorizationapi.SubjectRulesReviewStatus{ Rules: rules, }, } if len(errors) != 0 { ret.Status.EvaluationError = kutilerrors.NewAggregate(errors).Error() } return ret, nil }
func TestUpdate(t *testing.T) { storage := makeLocalTestStorage() ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) realizedRoleObj, err := storage.Create(ctx, &authorizationapi.Role{ ObjectMeta: kapi.ObjectMeta{Name: "my-role"}, }) if err != nil { t.Fatalf("unexpected error: %v", err) } realizedRole := realizedRoleObj.(*authorizationapi.Role) role := &authorizationapi.Role{ ObjectMeta: kapi.ObjectMeta{Name: "my-role", ResourceVersion: realizedRole.ResourceVersion}, } obj, created, err := storage.Update(ctx, role) if err != nil || created { t.Errorf("Unexpected error %v", err) } switch obj.(type) { case *unversioned.Status: t.Errorf("Unexpected operation error: %v", obj) case *authorizationapi.Role: if !reflect.DeepEqual(role, obj) { t.Errorf("Updated role does not match input role."+ " Expected: %v, Got: %v", role, obj) } default: t.Errorf("Unexpected result type: %v", obj) } }
func (r *RBACAuthorizer) Authorize(attr authorizer.Attributes) error { if r.superUser != "" && attr.GetUserName() == r.superUser { return nil } userInfo := &user.DefaultInfo{ Name: attr.GetUserName(), Groups: attr.GetGroups(), } ctx := api.WithNamespace(api.WithUser(api.NewContext(), userInfo), attr.GetNamespace()) // Frame the authorization request as a privilege escalation check. var requestedRule rbac.PolicyRule if attr.IsResourceRequest() { requestedRule = rbac.PolicyRule{ Verbs: []string{attr.GetVerb()}, APIGroups: []string{attr.GetAPIGroup()}, // TODO(ericchiang): add api version here too? Resources: []string{attr.GetResource()}, ResourceNames: []string{attr.GetName()}, } } else { requestedRule = rbac.PolicyRule{ NonResourceURLs: []string{attr.GetPath()}, } } return validation.ConfirmNoEscalation(ctx, r.authorizationRuleResolver, []rbac.PolicyRule{requestedRule}) }
func TestUpdateImageStreamOK(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Data["/imagestreams/default/bar"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"}, }), ModifiedIndex: 2, }, }, } storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) obj, created, err := storage.Update(ctx, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "1"}}) if !errors.IsConflict(err) { t.Fatalf("unexpected non-error: %v", err) } obj, created, err = storage.Update(ctx, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "bar", ResourceVersion: "2"}}) if err != nil || created { t.Fatalf("Unexpected non-nil error: %#v", err) } stream, ok := obj.(*api.ImageStream) if !ok { t.Errorf("Expected image stream, got %#v", obj) } if stream.Name != "bar" { t.Errorf("Unexpected stream returned: %#v", stream) } }
func TestConflictingUpdate(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: original.ObjectMeta, RoleRef: kapi.ObjectReference{Name: "admin"}, Subjects: []kapi.ObjectReference{{Name: "bob", Kind: "User"}}, } roleBinding.ResourceVersion = roleBinding.ResourceVersion + "1" _, _, err = storage.Update(ctx, roleBinding.Name, rest.DefaultUpdatedObjectInfo(roleBinding, kapi.Scheme)) if err == nil || !kapierrors.IsConflict(err) { t.Errorf("Expected conflict error, got: %#v", err) } }
func TestConflictingUpdate(t *testing.T) { storage := makeLocalTestStorage() ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) realizedRoleObj, err := storage.Create(ctx, &authorizationapi.Role{ ObjectMeta: kapi.ObjectMeta{Name: "my-role"}, Rules: []authorizationapi.PolicyRule{ {Verbs: sets.NewString(authorizationapi.VerbAll)}, }, }) if err != nil { t.Fatalf("unexpected error: %v", err) } realizedRole := realizedRoleObj.(*authorizationapi.Role) role := &authorizationapi.Role{ ObjectMeta: realizedRole.ObjectMeta, Rules: []authorizationapi.PolicyRule{ {Verbs: sets.NewString("list", "update")}, }, } role.ResourceVersion += "1" _, _, err = storage.Update(ctx, role.Name, rest.DefaultUpdatedObjectInfo(role, kapi.Scheme)) if err == nil || !kapierrors.IsConflict(err) { t.Errorf("Expected conflict error, got: %#v", err) } }
func TestCreateImageStreamOK(t *testing.T) { _, helper := newHelper(t) storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) stream := &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}} ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) _, err := storage.Create(ctx, stream) if err != nil { t.Fatalf("Unexpected non-nil error: %#v", err) } actual := &api.ImageStream{} if err := helper.Get("/imagestreams/default/foo", actual, false); err != nil { t.Fatalf("unexpected extraction error: %v", err) } if actual.Name != stream.Name { t.Errorf("unexpected stream: %#v", actual) } if len(actual.UID) == 0 { t.Errorf("expected stream UID to be set: %#v", actual) } if stream.CreationTimestamp.IsZero() { t.Error("Unexpected zero CreationTimestamp") } if stream.Spec.DockerImageRepository != "" { t.Errorf("unexpected stream: %#v", stream) } }
func TestUpdateError(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-roleBinding", ResourceVersion: original.ResourceVersion}, RoleRef: kapi.ObjectReference{Name: "admin"}, } _, _, err = storage.Update(ctx, roleBinding) if err == nil { t.Errorf("Missing expected error") return } if !kapierrors.IsNotFound(err) { t.Errorf("Unexpected error %v", err) } }
func TestDeniedWithError(t *testing.T) { test := &authorizeTest{ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Anna"}), attributes: &DefaultAuthorizationAttributes{ Verb: "update", Resource: "roles", }, expectedAllowed: false, expectedError: "my special error", } test.clusterPolicies = newDefaultClusterPolicies() test.policies = append(test.policies, newAdzePolicies()...) test.clusterBindings = newDefaultClusterPolicyBindings() test.bindings = append(test.bindings, newAdzeBindings()...) test.bindings[0].RoleBindings["missing"] = &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{ Name: "missing", }, RoleRef: kapi.ObjectReference{ Name: "not-a-real-binding", }, Users: util.NewStringSet("Anna"), } test.policyRetrievalError = errors.New("my special error") test.test(t) }
func TestStrategyPrepareMethods(t *testing.T) { _, helper := newHelper(t) storage, _ := NewREST(helper, testDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) stream := validNewStream() strategy := fakeStrategy{imagestream.NewStrategy(testDefaultRegistry, &fakeSubjectAccessReviewRegistry{})} storage.store.CreateStrategy = strategy storage.store.UpdateStrategy = strategy ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) obj, err := storage.Create(ctx, stream) if err != nil { t.Fatalf("Unexpected error: %v", err) } updatedStream := obj.(*api.ImageStream) if updatedStream.Annotations["test"] != "PrepareForCreate" { t.Errorf("Expected PrepareForCreate annotation") } obj, _, err = storage.Update(ctx, updatedStream) if err != nil { t.Errorf("Unexpected error: %v", err) } updatedStream = obj.(*api.ImageStream) if updatedStream.Annotations["test"] != "PrepareForUpdate" { t.Errorf("Expected PrepareForUpdate annotation") } }
// OriginAuthorizerAttributes adapts Kubernetes authorization attributes to Origin authorization attributes // Note that some info (like resourceName, apiVersion, apiGroup) is not available from the Kubernetes attributes func OriginAuthorizerAttributes(kattrs kauthorizer.Attributes) (kapi.Context, oauthorizer.AuthorizationAttributes) { // Build a context to hold the namespace and user info ctx := kapi.NewContext() ctx = kapi.WithNamespace(ctx, kattrs.GetNamespace()) ctx = kapi.WithUser(ctx, &user.DefaultInfo{ Name: kattrs.GetUserName(), Groups: kattrs.GetGroups(), }) // If the passed attributes already satisfy our interface, use it directly if oattrs, ok := kattrs.(oauthorizer.AuthorizationAttributes); ok { return ctx, oattrs } // Otherwise build what we can oattrs := &oauthorizer.DefaultAuthorizationAttributes{ Verb: kattrs.GetVerb(), Resource: kattrs.GetResource(), // TODO: add to kube authorizer attributes // APIVersion string // APIGroup string // ResourceName string // RequestAttributes interface{} // NonResourceURL bool // URL string } return ctx, oattrs }
func TestUpdateCannotChangeRoleRefError(t *testing.T) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) storage := makeTestStorage() obj, err := storage.Create(ctx, &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different"}, RoleRef: kapi.ObjectReference{Name: "admin"}, }) if err != nil { t.Errorf("unexpected error: %v", err) return } original := obj.(*authorizationapi.RoleBinding) roleBinding := &authorizationapi.RoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: "my-different", ResourceVersion: original.ResourceVersion}, RoleRef: kapi.ObjectReference{Name: "cluster-admin"}, } _, _, err = storage.Update(ctx, roleBinding) if err == nil { t.Errorf("Missing expected error") return } expectedErr := "cannot change roleRef" if !strings.Contains(err.Error(), expectedErr) { t.Errorf("Expected %v, got %v", expectedErr, err.Error()) } }
// WithAuthentication 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 WithAuthentication(handler http.Handler, mapper api.RequestContextMapper, auth authenticator.Request, failed http.Handler) http.Handler { if auth == nil { glog.Warningf("Authentication is disabled") return handler } return api.WithRequestContext( 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) }), mapper, ) }
func TestUpdateImageStreamConflictingNamespace(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Data["/imagestreams/legal-name/bar"] = tools.EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(latest.Codec, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "default"}, }), ModifiedIndex: 2, }, }, } storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "legal-name"), &fakeUser{}) obj, created, err := storage.Update(ctx, &api.ImageStream{ ObjectMeta: kapi.ObjectMeta{Name: "bar", Namespace: "some-value", ResourceVersion: "2"}, }) if obj != nil || created { t.Error("Expected a nil obj, but we got a value") } checkExpectedNamespaceError(t, err) }
func create(t *testing.T, storage *REST, obj *api.ImageStream) *api.ImageStream { ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) newObj, err := storage.Create(ctx, obj) if err != nil { t.Fatalf("Unexpected error: %v", err) } return newObj.(*api.ImageStream) }
func TestCreate(t *testing.T) { _, helper := newHelper(t) storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) stream := validNewStream() ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) _, err := storage.Create(ctx, stream) if err != nil { t.Fatalf("unexpected error: %v", err) } }
func TestCreateValidationError(t *testing.T) { storage := makeTestStorage() roleBinding := &authorizationapi.RoleBinding{} ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) _, err := storage.Create(ctx, roleBinding) if err == nil { t.Errorf("Expected validation error") } }
func (r *restrictedEndpointsAdmission) checkAccess(attr kadmission.Attributes) (bool, error) { ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), attr.GetNamespace()), attr.GetUserInfo()) authzAttr := authorizer.DefaultAuthorizationAttributes{ Verb: "create", Resource: authorizationapi.RestrictedEndpointsResource, APIGroup: kapi.GroupName, ResourceName: attr.GetName(), } allow, _, err := r.authorizer.Authorize(ctx, authzAttr) return allow, err }
func (r *subjectAccessTest) runTest(t *testing.T) { storage := NewREST(subjectaccessreview.NewRegistry(subjectaccessreview.NewREST(r.authorizer))) expectedResponse := &authorizationapi.SubjectAccessReviewResponse{ Namespace: r.reviewRequest.Action.Namespace, Allowed: r.authorizer.allowed, Reason: r.authorizer.reason, } expectedAttributes := authorizer.ToDefaultAuthorizationAttributes(r.reviewRequest.Action) ctx := kapi.WithNamespace(kapi.NewContext(), r.reviewRequest.Action.Namespace) if r.requestingUser != nil { ctx = kapi.WithUser(ctx, r.requestingUser) } obj, err := storage.Create(ctx, r.reviewRequest) if err != nil && len(r.authorizer.err) == 0 { t.Fatalf("unexpected error: %v", err) } if len(r.authorizer.err) != 0 { if err == nil { t.Fatalf("unexpected non-error: %v", err) } if e, a := r.authorizer.err, err.Error(); e != a { t.Fatalf("expected %v, got %v", e, a) } return } switch obj.(type) { case *authorizationapi.SubjectAccessReviewResponse: if !reflect.DeepEqual(expectedResponse, obj) { t.Errorf("diff %v", diff.ObjectGoPrintDiff(expectedResponse, obj)) } case nil: if len(r.authorizer.err) == 0 { t.Fatal("unexpected nil object") } default: t.Errorf("Unexpected obj type: %v", obj) } if !reflect.DeepEqual(expectedAttributes, r.authorizer.actualAttributes) { t.Errorf("diff %v", diff.ObjectGoPrintDiff(expectedAttributes, r.authorizer.actualAttributes)) } if !reflect.DeepEqual(r.expectedUserInfo, r.authorizer.actualUserInfo) { t.Errorf("diff %v", diff.ObjectGoPrintDiff(r.expectedUserInfo, r.authorizer.actualUserInfo)) } }
func TestCreateRegistryErrorSaving(t *testing.T) { fakeEtcdClient, helper := newHelper(t) fakeEtcdClient.Err = fmt.Errorf("foo") storage, _ := NewREST(helper, noDefaultRegistry, &fakeSubjectAccessReviewRegistry{}) ctx := kapi.WithUser(kapi.NewDefaultContext(), &fakeUser{}) _, err := storage.Create(ctx, &api.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: "foo"}}) if err != fakeEtcdClient.Err { t.Fatalf("Unexpected non-nil error: %#v", err) } }
func TestDeleteError(t *testing.T) { bindingRegistry := &test.PolicyBindingRegistry{} bindingRegistry.Err = errors.New("Sample Error") storage := NewVirtualStorage(bindingRegistry, rulevalidation.NewDefaultRuleResolver(&test.PolicyRegistry{}, bindingRegistry, &test.ClusterPolicyRegistry{}, &test.ClusterPolicyBindingRegistry{})) ctx := kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "unittest"), &user.DefaultInfo{Name: "system:admin"}) _, err := storage.Delete(ctx, "foo", nil) if err != bindingRegistry.Err { t.Errorf("unexpected error: %v", err) } }
// Create registers a given new ResourceAccessReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { subjectAccessReview, ok := obj.(*authorizationapi.SubjectAccessReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a subjectAccessReview: %#v", obj)) } if err := kutilerrors.NewAggregate(authorizationvalidation.ValidateSubjectAccessReview(subjectAccessReview)); err != nil { return nil, err } // if a namespace is present on the request, then the namespace on the on the SAR is overwritten. // This is to support backwards compatibility. To have gotten here in this state, it means that // the authorizer decided that a user could run an SAR against this namespace if namespace := kapi.NamespaceValue(ctx); len(namespace) > 0 { subjectAccessReview.Action.Namespace = namespace } else if err := r.isAllowed(ctx, subjectAccessReview); err != nil { // this check is mutually exclusive to the condition above. localSAR and localRAR both clear the namespace before delegating their calls // We only need to check if the SAR is allowed **again** if the authorizer didn't already approve the request for a legacy call. return nil, err } var userToCheck user.Info if (len(subjectAccessReview.User) == 0) && (len(subjectAccessReview.Groups) == 0) { // if no user or group was specified, use the info from the context ctxUser, exists := kapi.UserFrom(ctx) if !exists { return nil, kapierrors.NewBadRequest("user missing from context") } userToCheck = ctxUser } else { userToCheck = &user.DefaultInfo{ Name: subjectAccessReview.User, Groups: subjectAccessReview.Groups.List(), } } requestContext := kapi.WithNamespace(kapi.WithUser(ctx, userToCheck), subjectAccessReview.Action.Namespace) attributes := authorizer.ToDefaultAuthorizationAttributes(subjectAccessReview.Action) allowed, reason, err := r.authorizer.Authorize(requestContext, attributes) if err != nil { return nil, err } response := &authorizationapi.SubjectAccessReviewResponse{ Namespace: subjectAccessReview.Action.Namespace, Allowed: allowed, Reason: reason, } return response, nil }