diff --git a/api/swagger-spec/authorization.k8s.io_v1beta1.json b/api/swagger-spec/authorization.k8s.io_v1beta1.json index 4116f3e0937..eb539d24548 100644 --- a/api/swagger-spec/authorization.k8s.io_v1beta1.json +++ b/api/swagger-spec/authorization.k8s.io_v1beta1.json @@ -8,6 +8,51 @@ "description": "" }, "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", @@ -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.", diff --git a/pkg/apis/authorization/types.go b/pkg/apis/authorization/types.go index 33ad58c3539..37f271f8b4f 100644 --- a/pkg/apis/authorization/types.go +++ b/pkg/apis/authorization/types.go @@ -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 diff --git a/pkg/apis/authorization/v1beta1/types.go b/pkg/apis/authorization/v1beta1/types.go index 558a1e5750b..2cdc69dc57e 100644 --- a/pkg/apis/authorization/v1beta1/types.go +++ b/pkg/apis/authorization/v1beta1/types.go @@ -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 diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/authorization_client.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/authorization_client.go index 5b63753ea6d..cb7faf3ac01 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/authorization_client.go +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/authorization_client.go @@ -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) } diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_authorization_client.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_authorization_client.go index 2151c25baed..b125d121683 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_authorization_client.go +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_authorization_client.go @@ -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} } diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_generated_expansion.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_generated_expansion.go index 54eed3652d4..461a4698bcd 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_generated_expansion.go +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_generated_expansion.go @@ -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 +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_selfsubjectaccessreview.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_selfsubjectaccessreview.go new file mode 100644 index 00000000000..b107c1b2c45 --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/fake/fake_selfsubjectaccessreview.go @@ -0,0 +1,22 @@ +/* +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 +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/selfsubjectaccessreview.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/selfsubjectaccessreview.go new file mode 100644 index 00000000000..258b9ff9517 --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/selfsubjectaccessreview.go @@ -0,0 +1,40 @@ +/* +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, + } +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/selfsubjectaccessreview_expansion.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/selfsubjectaccessreview_expansion.go new file mode 100644 index 00000000000..0cde6e83b41 --- /dev/null +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/selfsubjectaccessreview_expansion.go @@ -0,0 +1,35 @@ +/* +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 +} diff --git a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/subjectaccessreview_expansion.go b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/subjectaccessreview_expansion.go index 16a170ece21..ce6e91eb449 100644 --- a/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/subjectaccessreview_expansion.go +++ b/pkg/client/clientset_generated/internalclientset/typed/authorization/unversioned/subjectaccessreview_expansion.go @@ -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) } diff --git a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/authorization_client.go b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/authorization_client.go index 3e1c216dab8..43c4ddbbf13 100644 --- a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/authorization_client.go +++ b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/authorization_client.go @@ -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) } diff --git a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_authorization_client.go b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_authorization_client.go index 0933cfe4d83..719b41a083d 100644 --- a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_authorization_client.go +++ b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_authorization_client.go @@ -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} } diff --git a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go new file mode 100644 index 00000000000..b107c1b2c45 --- /dev/null +++ b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_selfsubjectaccessreview.go @@ -0,0 +1,22 @@ +/* +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 +} diff --git a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_subjectaccessreview_expansion.go b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_subjectaccessreview_expansion.go index 88df166ef58..2356220f986 100644 --- a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_subjectaccessreview_expansion.go +++ b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/fake/fake_subjectaccessreview_expansion.go @@ -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 +} diff --git a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/selfsubjectaccessreview.go b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/selfsubjectaccessreview.go new file mode 100644 index 00000000000..7e0fd5fc260 --- /dev/null +++ b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/selfsubjectaccessreview.go @@ -0,0 +1,40 @@ +/* +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, + } +} diff --git a/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/selfsubjectaccessreview_expansion.go b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/selfsubjectaccessreview_expansion.go new file mode 100644 index 00000000000..a64678243ec --- /dev/null +++ b/pkg/client/clientset_generated/release_1_4/typed/authorization/v1beta1/selfsubjectaccessreview_expansion.go @@ -0,0 +1,35 @@ +/* +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 +} diff --git a/pkg/controller/garbagecollector/garbagecollector.go b/pkg/controller/garbagecollector/garbagecollector.go index 566306e5763..d4a17f042f4 100644 --- a/pkg/controller/garbagecollector/garbagecollector.go +++ b/pkg/controller/garbagecollector/garbagecollector.go @@ -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) { diff --git a/pkg/master/storage_authorization.go b/pkg/master/storage_authorization.go index 0ddb4f7a50c..fb09eb075ba 100644 --- a/pkg/master/storage_authorization.go +++ b/pkg/master/storage_authorization.go @@ -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 } diff --git a/pkg/registry/authorization/selfsubjectaccessreview/rest.go b/pkg/registry/authorization/selfsubjectaccessreview/rest.go new file mode 100644 index 00000000000..bdb9bbbf070 --- /dev/null +++ b/pkg/registry/authorization/selfsubjectaccessreview/rest.go @@ -0,0 +1,74 @@ +/* +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 +} diff --git a/test/integration/auth/accessreview_test.go b/test/integration/auth/accessreview_test.go index 6b76e0fc9d9..52a516a4cb9 100644 --- a/test/integration/auth/accessreview_test.go +++ b/test/integration/auth/accessreview_test.go @@ -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 + } + } }