Commit 8fac64b4 authored by deads2k's avatar deads2k

add localSAR

parent ac8aae58
...@@ -56,6 +56,9 @@ type SelfSubjectAccessReview struct { ...@@ -56,6 +56,9 @@ type SelfSubjectAccessReview struct {
Status SubjectAccessReviewStatus Status SubjectAccessReviewStatus
} }
// +genclient=true
// +noMethods=true
// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. // LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace.
// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions // Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions
// checking. // checking.
......
...@@ -57,6 +57,9 @@ type SelfSubjectAccessReview struct { ...@@ -57,6 +57,9 @@ type SelfSubjectAccessReview struct {
Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
} }
// +genclient=true
// +noMethods=true
// LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. // LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace.
// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions // Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions
// checking. // checking.
......
...@@ -67,8 +67,19 @@ func ValidateSelfSubjectAccessReview(sar *authorizationapi.SelfSubjectAccessRevi ...@@ -67,8 +67,19 @@ func ValidateSelfSubjectAccessReview(sar *authorizationapi.SelfSubjectAccessRevi
func ValidateLocalSubjectAccessReview(sar *authorizationapi.LocalSubjectAccessReview) field.ErrorList { func ValidateLocalSubjectAccessReview(sar *authorizationapi.LocalSubjectAccessReview) field.ErrorList {
allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec")) allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec"))
if !api.Semantic.DeepEqual(api.ObjectMeta{}, sar.ObjectMeta) {
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata"), sar.ObjectMeta, `must be empty`)) objectMetaShallowCopy := sar.ObjectMeta
objectMetaShallowCopy.Namespace = ""
if !api.Semantic.DeepEqual(api.ObjectMeta{}, objectMetaShallowCopy) {
allErrs = append(allErrs, field.Invalid(field.NewPath("metadata"), sar.ObjectMeta, `must be empty except for namespace`))
} }
if sar.Spec.ResourceAttributes != nil && sar.Spec.ResourceAttributes.Namespace != sar.Namespace {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec.resourceAttributes.namespace"), sar.Spec.ResourceAttributes.Namespace, `must match metadata.namespace`))
}
if sar.Spec.NonResourceAttributes != nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec.nonResourceAttributes"), sar.Spec.NonResourceAttributes, `disallowed on this kind of request`))
}
return allErrs return allErrs
} }
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/api"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
"k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/validation/field"
) )
...@@ -133,3 +134,68 @@ func TestValidateSelfSAR(t *testing.T) { ...@@ -133,3 +134,68 @@ func TestValidateSelfSAR(t *testing.T) {
} }
} }
} }
func TestValidateLocalSAR(t *testing.T) {
successCases := []authorizationapi.LocalSubjectAccessReview{
{
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
},
}
for _, successCase := range successCases {
if errs := ValidateLocalSubjectAccessReview(&successCase); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := []struct {
name string
obj *authorizationapi.LocalSubjectAccessReview
msg string
}{
{
name: "name",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Name: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
},
msg: "must be empty except for namespace",
},
{
name: "namespace conflict",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Namespace: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{},
User: "user",
},
},
msg: "must match metadata.namespace",
},
{
name: "nonresource",
obj: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Namespace: "a"},
Spec: authorizationapi.SubjectAccessReviewSpec{
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
User: "user",
},
},
msg: "disallowed on this kind of request",
},
}
for _, c := range errorCases {
errs := ValidateLocalSubjectAccessReview(c.obj)
if len(errs) == 0 {
t.Errorf("%s: expected failure for %q", c.name, c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
}
}
}
...@@ -31,3 +31,8 @@ func (c *FakeSelfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectA ...@@ -31,3 +31,8 @@ func (c *FakeSelfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectA
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{}) obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{})
return obj.(*authorizationapi.SelfSubjectAccessReview), err return obj.(*authorizationapi.SelfSubjectAccessReview), err
} }
func (c *FakeLocalSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewCreateAction(authorizationapi.SchemeGroupVersion.WithResource("localsubjectaccessreviews"), c.ns, sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.LocalSubjectAccessReview), err
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package unversioned
import (
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
)
type LocalSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error)
}
func (c *localSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
result = &authorizationapi.LocalSubjectAccessReview{}
err = c.client.Post().
Namespace(c.ns).
Resource("localsubjectaccessreviews").
Body(sar).
Do().
Into(result)
return
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
"k8s.io/kubernetes/pkg/client/testing/core"
)
func (c *FakeLocalSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewCreateAction(authorizationapi.SchemeGroupVersion.WithResource("localsubjectaccessreviews"), c.ns, sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.LocalSubjectAccessReview), err
}
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1beta1
import (
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
)
type LocalSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error)
}
func (c *localSubjectAccessReviews) Create(sar *authorizationapi.LocalSubjectAccessReview) (result *authorizationapi.LocalSubjectAccessReview, err error) {
result = &authorizationapi.LocalSubjectAccessReview{}
err = c.client.Post().
Namespace(c.ns).
Resource("localsubjectaccessreviews").
Body(sar).
Do().
Into(result)
return
}
...@@ -525,13 +525,14 @@ func (gc *GarbageCollector) monitorFor(resource unversioned.GroupVersionResource ...@@ -525,13 +525,14 @@ func (gc *GarbageCollector) monitorFor(resource unversioned.GroupVersionResource
} }
var ignoredResources = map[unversioned.GroupVersionResource]struct{}{ var ignoredResources = map[unversioned.GroupVersionResource]struct{}{
unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {}, unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {},
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {}, unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {},
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {}, unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {},
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {}, unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {},
unversioned.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"}: {}, unversioned.GroupVersionResource{Group: "authentication.k8s.io", Version: "v1beta1", Resource: "tokenreviews"}: {},
unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"}: {}, unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "subjectaccessreviews"}: {},
unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "selfsubjectaccessreviews"}: {}, unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "selfsubjectaccessreviews"}: {},
unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"}: {},
} }
func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) { func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) {
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
authorizationv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1" authorizationv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/registry/authorization/localsubjectaccessreview"
"k8s.io/kubernetes/pkg/registry/authorization/selfsubjectaccessreview" "k8s.io/kubernetes/pkg/registry/authorization/selfsubjectaccessreview"
"k8s.io/kubernetes/pkg/registry/authorization/subjectaccessreview" "k8s.io/kubernetes/pkg/registry/authorization/subjectaccessreview"
) )
...@@ -57,6 +58,9 @@ func (p AuthorizationRESTStorageProvider) v1beta1Storage(apiResourceConfigSource ...@@ -57,6 +58,9 @@ func (p AuthorizationRESTStorageProvider) v1beta1Storage(apiResourceConfigSource
if apiResourceConfigSource.ResourceEnabled(version.WithResource("selfsubjectaccessreviews")) { if apiResourceConfigSource.ResourceEnabled(version.WithResource("selfsubjectaccessreviews")) {
storage["selfsubjectaccessreviews"] = selfsubjectaccessreview.NewREST(p.Authorizer) storage["selfsubjectaccessreviews"] = selfsubjectaccessreview.NewREST(p.Authorizer)
} }
if apiResourceConfigSource.ResourceEnabled(version.WithResource("localsubjectaccessreviews")) {
storage["localsubjectaccessreviews"] = localsubjectaccessreview.NewREST(p.Authorizer)
}
return storage return storage
} }
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package localsubjectaccessreview
import (
"fmt"
kapi "k8s.io/kubernetes/pkg/api"
kapierrors "k8s.io/kubernetes/pkg/api/errors"
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
"k8s.io/kubernetes/pkg/auth/authorizer"
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
"k8s.io/kubernetes/pkg/runtime"
)
type REST struct {
authorizer authorizer.Authorizer
}
func NewREST(authorizer authorizer.Authorizer) *REST {
return &REST{authorizer}
}
func (r *REST) New() runtime.Object {
return &authorizationapi.LocalSubjectAccessReview{}
}
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
localSubjectAccessReview, ok := obj.(*authorizationapi.LocalSubjectAccessReview)
if !ok {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a LocaLocalSubjectAccessReview: %#v", obj))
}
if errs := authorizationvalidation.ValidateLocalSubjectAccessReview(localSubjectAccessReview); len(errs) > 0 {
return nil, kapierrors.NewInvalid(authorizationapi.Kind(localSubjectAccessReview.Kind), "", errs)
}
namespace := kapi.NamespaceValue(ctx)
if len(namespace) == 0 {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("namespace is required on this type: %v", namespace))
}
if namespace != localSubjectAccessReview.Namespace {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("spec.resourceAttributes.namespace must match namespace: %v", namespace))
}
authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(localSubjectAccessReview.Spec)
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
localSubjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
Allowed: allowed,
Reason: reason,
}
if evaluationErr != nil {
localSubjectAccessReview.Status.EvaluationError = evaluationErr.Error()
}
return localSubjectAccessReview, nil
}
...@@ -24,7 +24,6 @@ import ( ...@@ -24,7 +24,6 @@ import (
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation" authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
"k8s.io/kubernetes/pkg/auth/authorizer" "k8s.io/kubernetes/pkg/auth/authorizer"
"k8s.io/kubernetes/pkg/auth/user"
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util" authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
) )
...@@ -50,19 +49,7 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err ...@@ -50,19 +49,7 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
return nil, kapierrors.NewInvalid(authorizationapi.Kind(subjectAccessReview.Kind), "", errs) return nil, kapierrors.NewInvalid(authorizationapi.Kind(subjectAccessReview.Kind), "", errs)
} }
userToCheck := &user.DefaultInfo{ authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(subjectAccessReview.Spec)
Name: subjectAccessReview.Spec.User,
Groups: subjectAccessReview.Spec.Groups,
Extra: convertToUserInfoExtra(subjectAccessReview.Spec.Extra),
}
var authorizationAttributes authorizer.AttributesRecord
if subjectAccessReview.Spec.ResourceAttributes != nil {
authorizationAttributes = authorizationutil.ResourceAttributesFrom(userToCheck, *subjectAccessReview.Spec.ResourceAttributes)
} else {
authorizationAttributes = authorizationutil.NonResourceAttributesFrom(userToCheck, *subjectAccessReview.Spec.NonResourceAttributes)
}
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes) allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
subjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{ subjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
...@@ -75,15 +62,3 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err ...@@ -75,15 +62,3 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
return subjectAccessReview, nil return subjectAccessReview, nil
} }
func convertToUserInfoExtra(extra map[string]authorizationapi.ExtraValue) map[string][]string {
if extra == nil {
return nil
}
ret := map[string][]string{}
for k, v := range extra {
ret[k] = []string(v)
}
return ret
}
...@@ -42,3 +42,33 @@ func NonResourceAttributesFrom(user user.Info, in authorizationapi.NonResourceAt ...@@ -42,3 +42,33 @@ func NonResourceAttributesFrom(user user.Info, in authorizationapi.NonResourceAt
Path: in.Path, Path: in.Path,
} }
} }
func convertToUserInfoExtra(extra map[string]authorizationapi.ExtraValue) map[string][]string {
if extra == nil {
return nil
}
ret := map[string][]string{}
for k, v := range extra {
ret[k] = []string(v)
}
return ret
}
// AuthorizationAttributesFrom takes a spec and returns the proper authz attributes to check it.
func AuthorizationAttributesFrom(spec authorizationapi.SubjectAccessReviewSpec) authorizer.AttributesRecord {
userToCheck := &user.DefaultInfo{
Name: spec.User,
Groups: spec.Groups,
Extra: convertToUserInfoExtra(spec.Extra),
}
var authorizationAttributes authorizer.AttributesRecord
if spec.ResourceAttributes != nil {
authorizationAttributes = ResourceAttributesFrom(userToCheck, *spec.ResourceAttributes)
} else {
authorizationAttributes = NonResourceAttributesFrom(userToCheck, *spec.NonResourceAttributes)
}
return authorizationAttributes
}
...@@ -245,3 +245,130 @@ func TestSelfSubjectAccessReview(t *testing.T) { ...@@ -245,3 +245,130 @@ func TestSelfSubjectAccessReview(t *testing.T) {
} }
} }
} }
func TestLocalSubjectAccessReview(t *testing.T) {
var m *master.Master
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
m.Handler.ServeHTTP(w, req)
}))
defer s.Close()
masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.Authenticator = authenticator.RequestFunc(alwaysAlice)
masterConfig.Authorizer = sarAuthorizer{}
masterConfig.AdmissionControl = admit.NewAlwaysAdmit()
m, err := master.New(masterConfig)
if err != nil {
t.Fatalf("error in bringing up the master: %v", err)
}
clientset := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}})
tests := []struct {
name string
namespace string
sar *authorizationapi.LocalSubjectAccessReview
expectedError string
expectedStatus authorizationapi.SubjectAccessReviewStatus
}{
{
name: "simple allow",
namespace: "foo",
sar: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Namespace: "foo"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
Verb: "list",
Group: api.GroupName,
Version: "v1",
Resource: "pods",
Namespace: "foo",
},
User: "alice",
},
},
expectedStatus: authorizationapi.SubjectAccessReviewStatus{
Allowed: true,
Reason: "you're not dave",
},
},
{
name: "simple deny",
namespace: "foo",
sar: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Namespace: "foo"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
Verb: "list",
Group: api.GroupName,
Version: "v1",
Resource: "pods",
Namespace: "foo",
},
User: "dave",
},
},
expectedStatus: authorizationapi.SubjectAccessReviewStatus{
Allowed: false,
Reason: "no",
EvaluationError: "I'm sorry, Dave",
},
},
{
name: "conflicting namespace",
namespace: "foo",
sar: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Namespace: "foo"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
Verb: "list",
Group: api.GroupName,
Version: "v1",
Resource: "pods",
Namespace: "bar",
},
User: "dave",
},
},
expectedError: "must match metadata.namespace",
},
{
name: "missing namespace",
namespace: "foo",
sar: &authorizationapi.LocalSubjectAccessReview{
ObjectMeta: api.ObjectMeta{Namespace: "foo"},
Spec: authorizationapi.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
Verb: "list",
Group: api.GroupName,
Version: "v1",
Resource: "pods",
},
User: "dave",
},
},
expectedError: "must match metadata.namespace",
},
}
for _, test := range tests {
response, err := clientset.Authorization().LocalSubjectAccessReviews(test.namespace).Create(test.sar)
switch {
case err == nil && len(test.expectedError) == 0:
case err != nil && strings.Contains(err.Error(), test.expectedError):
continue
case err != nil && len(test.expectedError) != 0:
t.Errorf("%s: unexpected error: %v", test.name, err)
continue
default:
t.Errorf("%s: expected %v, got %v", test.name, test.expectedError, err)
continue
}
if response.Status != test.expectedStatus {
t.Errorf("%s: expected %v, got %v", test.name, test.expectedStatus, response.Status)
continue
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment