add localSAR
This commit is contained in:
parent
ac8aae584d
commit
8fac64b43f
@ -56,6 +56,9 @@ type SelfSubjectAccessReview struct {
|
||||
Status SubjectAccessReviewStatus
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
// +noMethods=true
|
||||
|
||||
// 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
|
||||
// checking.
|
||||
|
@ -57,6 +57,9 @@ type SelfSubjectAccessReview struct {
|
||||
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.
|
||||
// Having a namespace scoped resource makes it much easier to grant namespace scoped policy that includes permissions
|
||||
// checking.
|
||||
|
@ -67,8 +67,19 @@ func ValidateSelfSubjectAccessReview(sar *authorizationapi.SelfSubjectAccessRevi
|
||||
|
||||
func ValidateLocalSubjectAccessReview(sar *authorizationapi.LocalSubjectAccessReview) field.ErrorList {
|
||||
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
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||
)
|
||||
@ -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
|
||||
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{})
|
||||
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
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
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
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
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
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
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
|
||||
}
|
||||
|
||||
var ignoredResources = map[unversioned.GroupVersionResource]struct{}{
|
||||
unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {},
|
||||
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: "selfsubjectaccessreviews"}: {},
|
||||
unversioned.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicationcontrollers"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "bindings"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "componentstatuses"}: {},
|
||||
unversioned.GroupVersionResource{Group: "", Version: "v1", Resource: "events"}: {},
|
||||
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: "selfsubjectaccessreviews"}: {},
|
||||
unversioned.GroupVersionResource{Group: "authorization.k8s.io", Version: "v1beta1", Resource: "localsubjectaccessreviews"}: {},
|
||||
}
|
||||
|
||||
func NewGarbageCollector(metaOnlyClientPool dynamic.ClientPool, clientPool dynamic.ClientPool, resources []unversioned.GroupVersionResource) (*GarbageCollector, error) {
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
authorizationv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"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/subjectaccessreview"
|
||||
)
|
||||
@ -57,6 +58,9 @@ func (p AuthorizationRESTStorageProvider) v1beta1Storage(apiResourceConfigSource
|
||||
if apiResourceConfigSource.ResourceEnabled(version.WithResource("selfsubjectaccessreviews")) {
|
||||
storage["selfsubjectaccessreviews"] = selfsubjectaccessreview.NewREST(p.Authorizer)
|
||||
}
|
||||
if apiResourceConfigSource.ResourceEnabled(version.WithResource("localsubjectaccessreviews")) {
|
||||
storage["localsubjectaccessreviews"] = localsubjectaccessreview.NewREST(p.Authorizer)
|
||||
}
|
||||
|
||||
return storage
|
||||
}
|
||||
|
71
pkg/registry/authorization/localsubjectaccessreview/rest.go
Normal file
71
pkg/registry/authorization/localsubjectaccessreview/rest.go
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
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 (
|
||||
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
|
||||
authorizationvalidation "k8s.io/kubernetes/pkg/apis/authorization/validation"
|
||||
"k8s.io/kubernetes/pkg/auth/authorizer"
|
||||
"k8s.io/kubernetes/pkg/auth/user"
|
||||
authorizationutil "k8s.io/kubernetes/pkg/registry/authorization/util"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
@ -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)
|
||||
}
|
||||
|
||||
userToCheck := &user.DefaultInfo{
|
||||
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)
|
||||
}
|
||||
|
||||
authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(subjectAccessReview.Spec)
|
||||
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
||||
|
||||
subjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
|
||||
@ -75,15 +62,3 @@ func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, err
|
||||
|
||||
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
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user