k8s.io/kubernetes@v1.29.3/pkg/registry/authorization/subjectaccessreview/rest_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package subjectaccessreview 18 19 import ( 20 "context" 21 "errors" 22 "reflect" 23 "strings" 24 "testing" 25 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apiserver/pkg/authentication/user" 28 "k8s.io/apiserver/pkg/authorization/authorizer" 29 genericapirequest "k8s.io/apiserver/pkg/endpoints/request" 30 "k8s.io/apiserver/pkg/registry/rest" 31 authorizationapi "k8s.io/kubernetes/pkg/apis/authorization" 32 ) 33 34 type fakeAuthorizer struct { 35 attrs authorizer.Attributes 36 37 decision authorizer.Decision 38 reason string 39 err error 40 } 41 42 func (f *fakeAuthorizer) Authorize(ctx context.Context, attrs authorizer.Attributes) (authorizer.Decision, string, error) { 43 f.attrs = attrs 44 return f.decision, f.reason, f.err 45 } 46 47 func TestCreate(t *testing.T) { 48 testcases := map[string]struct { 49 spec authorizationapi.SubjectAccessReviewSpec 50 decision authorizer.Decision 51 reason string 52 err error 53 54 expectedErr string 55 expectedAttrs authorizer.Attributes 56 expectedStatus authorizationapi.SubjectAccessReviewStatus 57 }{ 58 "empty": { 59 expectedErr: "nonResourceAttributes or resourceAttributes", 60 }, 61 62 "nonresource rejected": { 63 spec: authorizationapi.SubjectAccessReviewSpec{ 64 User: "bob", 65 NonResourceAttributes: &authorizationapi.NonResourceAttributes{Verb: "get", Path: "/mypath"}, 66 }, 67 decision: authorizer.DecisionNoOpinion, 68 reason: "myreason", 69 err: errors.New("myerror"), 70 expectedAttrs: authorizer.AttributesRecord{ 71 User: &user.DefaultInfo{Name: "bob"}, 72 Verb: "get", 73 Path: "/mypath", 74 ResourceRequest: false, 75 }, 76 expectedStatus: authorizationapi.SubjectAccessReviewStatus{ 77 Allowed: false, 78 Reason: "myreason", 79 EvaluationError: "myerror", 80 }, 81 }, 82 83 "nonresource allowed": { 84 spec: authorizationapi.SubjectAccessReviewSpec{ 85 User: "bob", 86 NonResourceAttributes: &authorizationapi.NonResourceAttributes{Verb: "get", Path: "/mypath"}, 87 }, 88 decision: authorizer.DecisionAllow, 89 reason: "allowed", 90 err: nil, 91 expectedAttrs: authorizer.AttributesRecord{ 92 User: &user.DefaultInfo{Name: "bob"}, 93 Verb: "get", 94 Path: "/mypath", 95 ResourceRequest: false, 96 }, 97 expectedStatus: authorizationapi.SubjectAccessReviewStatus{ 98 Allowed: true, 99 Reason: "allowed", 100 EvaluationError: "", 101 }, 102 }, 103 104 "resource rejected": { 105 spec: authorizationapi.SubjectAccessReviewSpec{ 106 User: "bob", 107 ResourceAttributes: &authorizationapi.ResourceAttributes{ 108 Namespace: "myns", 109 Verb: "create", 110 Group: "extensions", 111 Version: "v1beta1", 112 Resource: "deployments", 113 Subresource: "scale", 114 Name: "mydeployment", 115 }, 116 }, 117 decision: authorizer.DecisionNoOpinion, 118 reason: "myreason", 119 err: errors.New("myerror"), 120 expectedAttrs: authorizer.AttributesRecord{ 121 User: &user.DefaultInfo{Name: "bob"}, 122 Namespace: "myns", 123 Verb: "create", 124 APIGroup: "extensions", 125 APIVersion: "v1beta1", 126 Resource: "deployments", 127 Subresource: "scale", 128 Name: "mydeployment", 129 ResourceRequest: true, 130 }, 131 expectedStatus: authorizationapi.SubjectAccessReviewStatus{ 132 Allowed: false, 133 Denied: false, 134 Reason: "myreason", 135 EvaluationError: "myerror", 136 }, 137 }, 138 139 "resource allowed": { 140 spec: authorizationapi.SubjectAccessReviewSpec{ 141 User: "bob", 142 ResourceAttributes: &authorizationapi.ResourceAttributes{ 143 Namespace: "myns", 144 Verb: "create", 145 Group: "extensions", 146 Version: "v1beta1", 147 Resource: "deployments", 148 Subresource: "scale", 149 Name: "mydeployment", 150 }, 151 }, 152 decision: authorizer.DecisionAllow, 153 reason: "allowed", 154 err: nil, 155 expectedAttrs: authorizer.AttributesRecord{ 156 User: &user.DefaultInfo{Name: "bob"}, 157 Namespace: "myns", 158 Verb: "create", 159 APIGroup: "extensions", 160 APIVersion: "v1beta1", 161 Resource: "deployments", 162 Subresource: "scale", 163 Name: "mydeployment", 164 ResourceRequest: true, 165 }, 166 expectedStatus: authorizationapi.SubjectAccessReviewStatus{ 167 Allowed: true, 168 Denied: false, 169 Reason: "allowed", 170 EvaluationError: "", 171 }, 172 }, 173 174 "resource denied": { 175 spec: authorizationapi.SubjectAccessReviewSpec{ 176 User: "bob", 177 ResourceAttributes: &authorizationapi.ResourceAttributes{}, 178 }, 179 decision: authorizer.DecisionDeny, 180 expectedAttrs: authorizer.AttributesRecord{ 181 User: &user.DefaultInfo{Name: "bob"}, 182 ResourceRequest: true, 183 APIVersion: "*", 184 }, 185 expectedStatus: authorizationapi.SubjectAccessReviewStatus{ 186 Allowed: false, 187 Denied: true, 188 }, 189 }, 190 } 191 192 for k, tc := range testcases { 193 auth := &fakeAuthorizer{ 194 decision: tc.decision, 195 reason: tc.reason, 196 err: tc.err, 197 } 198 storage := NewREST(auth) 199 200 result, err := storage.Create(genericapirequest.NewContext(), &authorizationapi.SubjectAccessReview{Spec: tc.spec}, rest.ValidateAllObjectFunc, &metav1.CreateOptions{}) 201 if err != nil { 202 if tc.expectedErr != "" { 203 if !strings.Contains(err.Error(), tc.expectedErr) { 204 t.Errorf("%s: expected %s to contain %q", k, err, tc.expectedErr) 205 } 206 } else { 207 t.Errorf("%s: %v", k, err) 208 } 209 continue 210 } 211 if !reflect.DeepEqual(auth.attrs, tc.expectedAttrs) { 212 t.Errorf("%s: expected\n%#v\ngot\n%#v", k, tc.expectedAttrs, auth.attrs) 213 } 214 status := result.(*authorizationapi.SubjectAccessReview).Status 215 if !reflect.DeepEqual(status, tc.expectedStatus) { 216 t.Errorf("%s: expected\n%#v\ngot\n%#v", k, tc.expectedStatus, status) 217 } 218 } 219 }