k8s.io/apiserver@v0.31.1/pkg/authorization/union/union_test.go (about) 1 /* 2 Copyright 2014 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 union 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "reflect" 24 "testing" 25 26 "k8s.io/apiserver/pkg/authentication/user" 27 "k8s.io/apiserver/pkg/authorization/authorizer" 28 ) 29 30 type mockAuthzHandler struct { 31 decision authorizer.Decision 32 err error 33 } 34 35 func (mock *mockAuthzHandler) Authorize(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { 36 return mock.decision, "", mock.err 37 } 38 39 func TestAuthorizationSecondPasses(t *testing.T) { 40 handler1 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion} 41 handler2 := &mockAuthzHandler{decision: authorizer.DecisionAllow} 42 authzHandler := New(handler1, handler2) 43 44 authorized, _, _ := authzHandler.Authorize(context.Background(), nil) 45 if authorized != authorizer.DecisionAllow { 46 t.Errorf("Unexpected authorization failure") 47 } 48 } 49 50 func TestAuthorizationFirstPasses(t *testing.T) { 51 handler1 := &mockAuthzHandler{decision: authorizer.DecisionAllow} 52 handler2 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion} 53 authzHandler := New(handler1, handler2) 54 55 authorized, _, _ := authzHandler.Authorize(context.Background(), nil) 56 if authorized != authorizer.DecisionAllow { 57 t.Errorf("Unexpected authorization failure") 58 } 59 } 60 61 func TestAuthorizationNonePasses(t *testing.T) { 62 handler1 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion} 63 handler2 := &mockAuthzHandler{decision: authorizer.DecisionNoOpinion} 64 authzHandler := New(handler1, handler2) 65 66 authorized, _, _ := authzHandler.Authorize(context.Background(), nil) 67 if authorized == authorizer.DecisionAllow { 68 t.Errorf("Expected failed authorization") 69 } 70 } 71 72 func TestAuthorizationError(t *testing.T) { 73 handler1 := &mockAuthzHandler{err: fmt.Errorf("foo")} 74 handler2 := &mockAuthzHandler{err: fmt.Errorf("foo")} 75 authzHandler := New(handler1, handler2) 76 77 _, _, err := authzHandler.Authorize(context.Background(), nil) 78 if err == nil { 79 t.Errorf("Expected error: %v", err) 80 } 81 } 82 83 type mockAuthzRuleHandler struct { 84 resourceRules []authorizer.ResourceRuleInfo 85 nonResourceRules []authorizer.NonResourceRuleInfo 86 err error 87 } 88 89 func (mock *mockAuthzRuleHandler) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) { 90 if mock.err != nil { 91 return []authorizer.ResourceRuleInfo{}, []authorizer.NonResourceRuleInfo{}, false, mock.err 92 } 93 return mock.resourceRules, mock.nonResourceRules, false, nil 94 } 95 96 func TestAuthorizationResourceRules(t *testing.T) { 97 handler1 := &mockAuthzRuleHandler{ 98 resourceRules: []authorizer.ResourceRuleInfo{ 99 &authorizer.DefaultResourceRuleInfo{ 100 Verbs: []string{"*"}, 101 APIGroups: []string{"*"}, 102 Resources: []string{"bindings"}, 103 }, 104 &authorizer.DefaultResourceRuleInfo{ 105 Verbs: []string{"get", "list", "watch"}, 106 APIGroups: []string{"*"}, 107 Resources: []string{"*"}, 108 }, 109 }, 110 } 111 handler2 := &mockAuthzRuleHandler{ 112 resourceRules: []authorizer.ResourceRuleInfo{ 113 &authorizer.DefaultResourceRuleInfo{ 114 Verbs: []string{"*"}, 115 APIGroups: []string{"*"}, 116 Resources: []string{"events"}, 117 }, 118 &authorizer.DefaultResourceRuleInfo{ 119 Verbs: []string{"get"}, 120 APIGroups: []string{"*"}, 121 Resources: []string{"*"}, 122 ResourceNames: []string{"foo"}, 123 }, 124 }, 125 } 126 127 expected := []authorizer.DefaultResourceRuleInfo{ 128 { 129 Verbs: []string{"*"}, 130 APIGroups: []string{"*"}, 131 Resources: []string{"bindings"}, 132 }, 133 { 134 Verbs: []string{"get", "list", "watch"}, 135 APIGroups: []string{"*"}, 136 Resources: []string{"*"}, 137 }, 138 { 139 Verbs: []string{"*"}, 140 APIGroups: []string{"*"}, 141 Resources: []string{"events"}, 142 }, 143 { 144 Verbs: []string{"get"}, 145 APIGroups: []string{"*"}, 146 Resources: []string{"*"}, 147 ResourceNames: []string{"foo"}, 148 }, 149 } 150 151 authzRulesHandler := NewRuleResolvers(handler1, handler2) 152 153 rules, _, _, _ := authzRulesHandler.RulesFor(nil, "") 154 actual := getResourceRules(rules) 155 if !reflect.DeepEqual(expected, actual) { 156 t.Errorf("Expected: \n%#v\n but actual: \n%#v\n", expected, actual) 157 } 158 } 159 160 func TestAuthorizationNonResourceRules(t *testing.T) { 161 handler1 := &mockAuthzRuleHandler{ 162 nonResourceRules: []authorizer.NonResourceRuleInfo{ 163 &authorizer.DefaultNonResourceRuleInfo{ 164 Verbs: []string{"get"}, 165 NonResourceURLs: []string{"/api"}, 166 }, 167 }, 168 } 169 170 handler2 := &mockAuthzRuleHandler{ 171 nonResourceRules: []authorizer.NonResourceRuleInfo{ 172 &authorizer.DefaultNonResourceRuleInfo{ 173 Verbs: []string{"get"}, 174 NonResourceURLs: []string{"/api/*"}, 175 }, 176 }, 177 } 178 179 expected := []authorizer.DefaultNonResourceRuleInfo{ 180 { 181 Verbs: []string{"get"}, 182 NonResourceURLs: []string{"/api"}, 183 }, 184 { 185 Verbs: []string{"get"}, 186 NonResourceURLs: []string{"/api/*"}, 187 }, 188 } 189 190 authzRulesHandler := NewRuleResolvers(handler1, handler2) 191 192 _, rules, _, _ := authzRulesHandler.RulesFor(nil, "") 193 actual := getNonResourceRules(rules) 194 if !reflect.DeepEqual(expected, actual) { 195 t.Errorf("Expected: \n%#v\n but actual: \n%#v\n", expected, actual) 196 } 197 } 198 199 func getResourceRules(infos []authorizer.ResourceRuleInfo) []authorizer.DefaultResourceRuleInfo { 200 rules := make([]authorizer.DefaultResourceRuleInfo, len(infos)) 201 for i, info := range infos { 202 rules[i] = authorizer.DefaultResourceRuleInfo{ 203 Verbs: info.GetVerbs(), 204 APIGroups: info.GetAPIGroups(), 205 Resources: info.GetResources(), 206 ResourceNames: info.GetResourceNames(), 207 } 208 } 209 return rules 210 } 211 212 func getNonResourceRules(infos []authorizer.NonResourceRuleInfo) []authorizer.DefaultNonResourceRuleInfo { 213 rules := make([]authorizer.DefaultNonResourceRuleInfo, len(infos)) 214 for i, info := range infos { 215 rules[i] = authorizer.DefaultNonResourceRuleInfo{ 216 Verbs: info.GetVerbs(), 217 NonResourceURLs: info.GetNonResourceURLs(), 218 } 219 } 220 return rules 221 } 222 223 func TestAuthorizationUnequivocalDeny(t *testing.T) { 224 cs := []struct { 225 authorizers []authorizer.Authorizer 226 decision authorizer.Decision 227 }{ 228 { 229 authorizers: []authorizer.Authorizer{}, 230 decision: authorizer.DecisionNoOpinion, 231 }, 232 { 233 authorizers: []authorizer.Authorizer{ 234 &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}, 235 &mockAuthzHandler{decision: authorizer.DecisionAllow}, 236 &mockAuthzHandler{decision: authorizer.DecisionDeny}, 237 }, 238 decision: authorizer.DecisionAllow, 239 }, 240 { 241 authorizers: []authorizer.Authorizer{ 242 &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}, 243 &mockAuthzHandler{decision: authorizer.DecisionDeny}, 244 &mockAuthzHandler{decision: authorizer.DecisionAllow}, 245 }, 246 decision: authorizer.DecisionDeny, 247 }, 248 { 249 authorizers: []authorizer.Authorizer{ 250 &mockAuthzHandler{decision: authorizer.DecisionNoOpinion}, 251 &mockAuthzHandler{decision: authorizer.DecisionDeny, err: errors.New("webhook failed closed")}, 252 &mockAuthzHandler{decision: authorizer.DecisionAllow}, 253 }, 254 decision: authorizer.DecisionDeny, 255 }, 256 } 257 for i, c := range cs { 258 t.Run(fmt.Sprintf("case %v", i), func(t *testing.T) { 259 authzHandler := New(c.authorizers...) 260 261 decision, _, _ := authzHandler.Authorize(context.Background(), nil) 262 if decision != c.decision { 263 t.Errorf("Unexpected authorization failure: %v, expected: %v", decision, c.decision) 264 } 265 }) 266 } 267 }