Commit 7a4d81ea authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #31271 from deads2k/self-sar

Automatic merge from submit-queue add selfsubjectaccessreview API Exposes the REST API for self subject access reviews. This allows a user to see whether or not they can perform a particular action. @kubernetes/sig-auth
parents 63495d78 2f642ebc
......@@ -9,6 +9,51 @@
},
"apis": [
{
"path": "/apis/authorization.k8s.io/v1beta1/selfsubjectaccessreviews",
"description": "API at /apis/authorization.k8s.io/v1beta1",
"operations": [
{
"type": "v1beta1.SelfSubjectAccessReview",
"method": "POST",
"summary": "create a SelfSubjectAccessReview",
"nickname": "createSelfSubjectAccessReview",
"parameters": [
{
"type": "string",
"paramType": "query",
"name": "pretty",
"description": "If 'true', then the output is pretty printed.",
"required": false,
"allowMultiple": false
},
{
"type": "v1beta1.SelfSubjectAccessReview",
"paramType": "body",
"name": "body",
"description": "",
"required": true,
"allowMultiple": false
}
],
"responseMessages": [
{
"code": 200,
"message": "OK",
"responseModel": "v1beta1.SelfSubjectAccessReview"
}
],
"produces": [
"application/json",
"application/yaml",
"application/vnd.kubernetes.protobuf"
],
"consumes": [
"*/*"
]
}
]
},
{
"path": "/apis/authorization.k8s.io/v1beta1/subjectaccessreviews",
"description": "API at /apis/authorization.k8s.io/v1beta1",
"operations": [
......@@ -78,9 +123,9 @@
}
],
"models": {
"v1beta1.SubjectAccessReview": {
"id": "v1beta1.SubjectAccessReview",
"description": "SubjectAccessReview checks whether or not a user or group can perform an action.",
"v1beta1.SelfSubjectAccessReview": {
"id": "v1beta1.SelfSubjectAccessReview",
"description": "SelfSubjectAccessReview checks whether or the current user can perform an action. Not filling in a spec.namespace means \"in all namespaces\". Self is a special case, because users should always be able to check whether they can perform an action",
"required": [
"spec"
],
......@@ -97,8 +142,8 @@
"$ref": "v1.ObjectMeta"
},
"spec": {
"$ref": "v1beta1.SubjectAccessReviewSpec",
"description": "Spec holds information about the request being evaluated"
"$ref": "v1beta1.SelfSubjectAccessReviewSpec",
"description": "Spec holds information about the request being evaluated. user and groups must be empty"
},
"status": {
"$ref": "v1beta1.SubjectAccessReviewStatus",
......@@ -214,9 +259,9 @@
}
}
},
"v1beta1.SubjectAccessReviewSpec": {
"id": "v1beta1.SubjectAccessReviewSpec",
"description": "SubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes and NonResourceAuthorizationAttributes must be set",
"v1beta1.SelfSubjectAccessReviewSpec": {
"id": "v1beta1.SelfSubjectAccessReviewSpec",
"description": "SelfSubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes and NonResourceAuthorizationAttributes must be set",
"properties": {
"resourceAttributes": {
"$ref": "v1beta1.ResourceAttributes",
......@@ -225,21 +270,6 @@
"nonResourceAttributes": {
"$ref": "v1beta1.NonResourceAttributes",
"description": "NonResourceAttributes describes information for a non-resource access request"
},
"user": {
"type": "string",
"description": "User is the user you're testing for. If you specify \"User\" but not \"Group\", then is it interpreted as \"What if User were not a member of any groups"
},
"group": {
"type": "array",
"items": {
"type": "string"
},
"description": "Groups is the groups you're testing for."
},
"extra": {
"type": "object",
"description": "Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer it needs a reflection here."
}
}
},
......@@ -312,6 +342,63 @@
}
}
},
"v1beta1.SubjectAccessReview": {
"id": "v1beta1.SubjectAccessReview",
"description": "SubjectAccessReview checks whether or not a user or group can perform an action.",
"required": [
"spec"
],
"properties": {
"kind": {
"type": "string",
"description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds"
},
"apiVersion": {
"type": "string",
"description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#resources"
},
"metadata": {
"$ref": "v1.ObjectMeta"
},
"spec": {
"$ref": "v1beta1.SubjectAccessReviewSpec",
"description": "Spec holds information about the request being evaluated"
},
"status": {
"$ref": "v1beta1.SubjectAccessReviewStatus",
"description": "Status is filled in by the server and indicates whether the request is allowed or not"
}
}
},
"v1beta1.SubjectAccessReviewSpec": {
"id": "v1beta1.SubjectAccessReviewSpec",
"description": "SubjectAccessReviewSpec is a description of the access request. Exactly one of ResourceAuthorizationAttributes and NonResourceAuthorizationAttributes must be set",
"properties": {
"resourceAttributes": {
"$ref": "v1beta1.ResourceAttributes",
"description": "ResourceAuthorizationAttributes describes information for a resource access request"
},
"nonResourceAttributes": {
"$ref": "v1beta1.NonResourceAttributes",
"description": "NonResourceAttributes describes information for a non-resource access request"
},
"user": {
"type": "string",
"description": "User is the user you're testing for. If you specify \"User\" but not \"Group\", then is it interpreted as \"What if User were not a member of any groups"
},
"group": {
"type": "array",
"items": {
"type": "string"
},
"description": "Groups is the groups you're testing for."
},
"extra": {
"type": "object",
"description": "Extra corresponds to the user.Info.GetExtra() method from the authenticator. Since that is input to the authorizer it needs a reflection here."
}
}
},
"unversioned.APIResourceList": {
"id": "unversioned.APIResourceList",
"description": "APIResourceList is a list of APIResource, it is used to expose the name of the resources supported in a specific group and version, and if the resource is namespaced.",
......
......@@ -38,6 +38,10 @@ type SubjectAccessReview struct {
Status SubjectAccessReviewStatus
}
// +genclient=true
// +nonNamespaced=true
// +noMethods=true
// SelfSubjectAccessReview checks whether or the current user can perform an action. Not filling in a
// spec.namespace means "in all namespaces". Self is a special case, because users should always be able
// to check whether they can perform an action
......
......@@ -39,6 +39,10 @@ type SubjectAccessReview struct {
Status SubjectAccessReviewStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
// +genclient=true
// +nonNamespaced=true
// +noMethods=true
// SelfSubjectAccessReview checks whether or the current user can perform an action. Not filling in a
// spec.namespace means "in all namespaces". Self is a special case, because users should always be able
// to check whether they can perform an action
......
......@@ -24,6 +24,7 @@ import (
type AuthorizationInterface interface {
GetRESTClient() *restclient.RESTClient
SelfSubjectAccessReviewsGetter
SubjectAccessReviewsGetter
}
......@@ -32,6 +33,10 @@ type AuthorizationClient struct {
*restclient.RESTClient
}
func (c *AuthorizationClient) SelfSubjectAccessReviews() SelfSubjectAccessReviewInterface {
return newSelfSubjectAccessReviews(c)
}
func (c *AuthorizationClient) SubjectAccessReviews() SubjectAccessReviewInterface {
return newSubjectAccessReviews(c)
}
......
......@@ -26,6 +26,10 @@ type FakeAuthorization struct {
*core.Fake
}
func (c *FakeAuthorization) SelfSubjectAccessReviews() unversioned.SelfSubjectAccessReviewInterface {
return &FakeSelfSubjectAccessReviews{c}
}
func (c *FakeAuthorization) SubjectAccessReviews() unversioned.SubjectAccessReviewInterface {
return &FakeSubjectAccessReviews{c}
}
......
......@@ -26,3 +26,8 @@ func (c *FakeSubjectAccessReviews) Create(sar *authorizationapi.SubjectAccessRev
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("subjectaccessreviews"), sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.SubjectAccessReview), err
}
func (c *FakeSelfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{})
return obj.(*authorizationapi.SelfSubjectAccessReview), 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 fake
// FakeSelfSubjectAccessReviews implements SelfSubjectAccessReviewInterface
type FakeSelfSubjectAccessReviews struct {
Fake *FakeAuthorization
}
/*
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
// SelfSubjectAccessReviewsGetter has a method to return a SelfSubjectAccessReviewInterface.
// A group's client should implement this interface.
type SelfSubjectAccessReviewsGetter interface {
SelfSubjectAccessReviews() SelfSubjectAccessReviewInterface
}
// SelfSubjectAccessReviewInterface has methods to work with SelfSubjectAccessReview resources.
type SelfSubjectAccessReviewInterface interface {
SelfSubjectAccessReviewExpansion
}
// selfSubjectAccessReviews implements SelfSubjectAccessReviewInterface
type selfSubjectAccessReviews struct {
client *AuthorizationClient
}
// newSelfSubjectAccessReviews returns a SelfSubjectAccessReviews
func newSelfSubjectAccessReviews(c *AuthorizationClient) *selfSubjectAccessReviews {
return &selfSubjectAccessReviews{
client: c,
}
}
/*
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 SelfSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error)
}
func (c *selfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
result = &authorizationapi.SelfSubjectAccessReview{}
err = c.client.Post().
Resource("selfsubjectaccessreviews").
Body(sar).
Do().
Into(result)
return
}
......@@ -20,7 +20,6 @@ import (
authorizationapi "k8s.io/kubernetes/pkg/apis/authorization"
)
// The PodExpansion interface allows manually adding extra methods to the PodInterface.
type SubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SubjectAccessReview) (result *authorizationapi.SubjectAccessReview, err error)
}
......
......@@ -25,6 +25,7 @@ import (
type AuthorizationInterface interface {
GetRESTClient() *restclient.RESTClient
SelfSubjectAccessReviewsGetter
SubjectAccessReviewsGetter
}
......@@ -33,6 +34,10 @@ type AuthorizationClient struct {
*restclient.RESTClient
}
func (c *AuthorizationClient) SelfSubjectAccessReviews() SelfSubjectAccessReviewInterface {
return newSelfSubjectAccessReviews(c)
}
func (c *AuthorizationClient) SubjectAccessReviews() SubjectAccessReviewInterface {
return newSubjectAccessReviews(c)
}
......
......@@ -26,6 +26,10 @@ type FakeAuthorization struct {
*core.Fake
}
func (c *FakeAuthorization) SelfSubjectAccessReviews() v1beta1.SelfSubjectAccessReviewInterface {
return &FakeSelfSubjectAccessReviews{c}
}
func (c *FakeAuthorization) SubjectAccessReviews() v1beta1.SubjectAccessReviewInterface {
return &FakeSubjectAccessReviews{c}
}
......
/*
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
// FakeSelfSubjectAccessReviews implements SelfSubjectAccessReviewInterface
type FakeSelfSubjectAccessReviews struct {
Fake *FakeAuthorization
}
......@@ -26,3 +26,8 @@ func (c *FakeSubjectAccessReviews) Create(sar *authorizationapi.SubjectAccessRev
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("subjectaccessreviews"), sar), &authorizationapi.SubjectAccessReview{})
return obj.(*authorizationapi.SubjectAccessReview), err
}
func (c *FakeSelfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
obj, err := c.Fake.Invokes(core.NewRootCreateAction(authorizationapi.SchemeGroupVersion.WithResource("selfsubjectaccessreviews"), sar), &authorizationapi.SelfSubjectAccessReview{})
return obj.(*authorizationapi.SelfSubjectAccessReview), 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
// SelfSubjectAccessReviewsGetter has a method to return a SelfSubjectAccessReviewInterface.
// A group's client should implement this interface.
type SelfSubjectAccessReviewsGetter interface {
SelfSubjectAccessReviews() SelfSubjectAccessReviewInterface
}
// SelfSubjectAccessReviewInterface has methods to work with SelfSubjectAccessReview resources.
type SelfSubjectAccessReviewInterface interface {
SelfSubjectAccessReviewExpansion
}
// selfSubjectAccessReviews implements SelfSubjectAccessReviewInterface
type selfSubjectAccessReviews struct {
client *AuthorizationClient
}
// newSelfSubjectAccessReviews returns a SelfSubjectAccessReviews
func newSelfSubjectAccessReviews(c *AuthorizationClient) *selfSubjectAccessReviews {
return &selfSubjectAccessReviews{
client: c,
}
}
/*
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 SelfSubjectAccessReviewExpansion interface {
Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error)
}
func (c *selfSubjectAccessReviews) Create(sar *authorizationapi.SelfSubjectAccessReview) (result *authorizationapi.SelfSubjectAccessReview, err error) {
result = &authorizationapi.SelfSubjectAccessReview{}
err = c.client.Post().
Resource("selfsubjectaccessreviews").
Body(sar).
Do().
Into(result)
return
}
......@@ -525,12 +525,13 @@ 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: "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"}: {},
}
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/selfsubjectaccessreview"
"k8s.io/kubernetes/pkg/registry/authorization/subjectaccessreview"
)
......@@ -53,6 +54,9 @@ func (p AuthorizationRESTStorageProvider) v1beta1Storage(apiResourceConfigSource
if apiResourceConfigSource.ResourceEnabled(version.WithResource("subjectaccessreviews")) {
storage["subjectaccessreviews"] = subjectaccessreview.NewREST(p.Authorizer)
}
if apiResourceConfigSource.ResourceEnabled(version.WithResource("selfsubjectaccessreviews")) {
storage["selfsubjectaccessreviews"] = selfsubjectaccessreview.NewREST(p.Authorizer)
}
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 selfsubjectaccessreview
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
apierrors "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.SelfSubjectAccessReview{}
}
func (r *REST) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
selfSAR, ok := obj.(*authorizationapi.SelfSubjectAccessReview)
if !ok {
return nil, apierrors.NewBadRequest(fmt.Sprintf("not a SelfSubjectAccessReview: %#v", obj))
}
if errs := authorizationvalidation.ValidateSelfSubjectAccessReview(selfSAR); len(errs) > 0 {
return nil, apierrors.NewInvalid(authorizationapi.Kind(selfSAR.Kind), "", errs)
}
userToCheck, exists := api.UserFrom(ctx)
if !exists {
return nil, apierrors.NewBadRequest("no user present on request")
}
var authorizationAttributes authorizer.AttributesRecord
if selfSAR.Spec.ResourceAttributes != nil {
authorizationAttributes = authorizationutil.ResourceAttributesFrom(userToCheck, *selfSAR.Spec.ResourceAttributes)
} else {
authorizationAttributes = authorizationutil.NonResourceAttributesFrom(userToCheck, *selfSAR.Spec.NonResourceAttributes)
}
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
selfSAR.Status = authorizationapi.SubjectAccessReviewStatus{
Allowed: allowed,
Reason: reason,
}
if evaluationErr != nil {
selfSAR.Status.EvaluationError = evaluationErr.Error()
}
return selfSAR, nil
}
......@@ -57,7 +57,6 @@ func alwaysAlice(req *http.Request) (user.Info, bool, error) {
}
func TestSubjectAccessReview(t *testing.T) {
// Set up a master
var m *master.Master
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
m.Handler.ServeHTTP(w, req)
......@@ -153,7 +152,96 @@ func TestSubjectAccessReview(t *testing.T) {
t.Errorf("%s: expected %v, got %v", test.name, test.expectedStatus, response.Status)
continue
}
}
}
func TestSelfSubjectAccessReview(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()
username := "alice"
masterConfig := framework.NewIntegrationTestMasterConfig()
masterConfig.Authenticator = authenticator.RequestFunc(func(req *http.Request) (user.Info, bool, error) {
return &user.DefaultInfo{Name: username}, true, nil
})
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
username string
sar *authorizationapi.SelfSubjectAccessReview
expectedError string
expectedStatus authorizationapi.SubjectAccessReviewStatus
}{
{
name: "simple allow",
username: "alice",
sar: &authorizationapi.SelfSubjectAccessReview{
Spec: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
Verb: "list",
Group: api.GroupName,
Version: "v1",
Resource: "pods",
},
},
},
expectedStatus: authorizationapi.SubjectAccessReviewStatus{
Allowed: true,
Reason: "you're not dave",
},
},
{
name: "simple deny",
username: "dave",
sar: &authorizationapi.SelfSubjectAccessReview{
Spec: authorizationapi.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationapi.ResourceAttributes{
Verb: "list",
Group: api.GroupName,
Version: "v1",
Resource: "pods",
},
},
},
expectedStatus: authorizationapi.SubjectAccessReviewStatus{
Allowed: false,
Reason: "no",
EvaluationError: "I'm sorry, Dave",
},
},
}
for _, test := range tests {
username = test.username
response, err := clientset.Authorization().SelfSubjectAccessReviews().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