1
16
17 package validation
18
19 import (
20 "testing"
21
22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 "k8s.io/apimachinery/pkg/util/validation/field"
24 "k8s.io/kubernetes/pkg/apis/rbac"
25 )
26
27 func TestValidateClusterRoleBinding(t *testing.T) {
28 errs := ValidateClusterRoleBinding(
29 &rbac.ClusterRoleBinding{
30 ObjectMeta: metav1.ObjectMeta{Name: "master"},
31 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
32 Subjects: []rbac.Subject{
33 {Name: "validsaname", APIGroup: "", Namespace: "foo", Kind: rbac.ServiceAccountKind},
34 {Name: "valid@username", APIGroup: rbac.GroupName, Kind: rbac.UserKind},
35 {Name: "valid@groupname", APIGroup: rbac.GroupName, Kind: rbac.GroupKind},
36 },
37 },
38 )
39 if len(errs) != 0 {
40 t.Errorf("expected success: %v", errs)
41 }
42
43 errorCases := map[string]struct {
44 A rbac.ClusterRoleBinding
45 T field.ErrorType
46 F string
47 }{
48 "bad group": {
49 A: rbac.ClusterRoleBinding{
50 ObjectMeta: metav1.ObjectMeta{Name: "default"},
51 RoleRef: rbac.RoleRef{APIGroup: "rbac.GroupName", Kind: "ClusterRole", Name: "valid"},
52 },
53 T: field.ErrorTypeNotSupported,
54 F: "roleRef.apiGroup",
55 },
56 "bad kind": {
57 A: rbac.ClusterRoleBinding{
58 ObjectMeta: metav1.ObjectMeta{Name: "default"},
59 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Type", Name: "valid"},
60 },
61 T: field.ErrorTypeNotSupported,
62 F: "roleRef.kind",
63 },
64 "reference role": {
65 A: rbac.ClusterRoleBinding{
66 ObjectMeta: metav1.ObjectMeta{Name: "default"},
67 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
68 },
69 T: field.ErrorTypeNotSupported,
70 F: "roleRef.kind",
71 },
72 "zero-length name": {
73 A: rbac.ClusterRoleBinding{
74 ObjectMeta: metav1.ObjectMeta{},
75 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
76 },
77 T: field.ErrorTypeRequired,
78 F: "metadata.name",
79 },
80 "bad role": {
81 A: rbac.ClusterRoleBinding{
82 ObjectMeta: metav1.ObjectMeta{Name: "default"},
83 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole"},
84 },
85 T: field.ErrorTypeRequired,
86 F: "roleRef.name",
87 },
88 "bad subject kind": {
89 A: rbac.ClusterRoleBinding{
90 ObjectMeta: metav1.ObjectMeta{Name: "master"},
91 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
92 Subjects: []rbac.Subject{{Name: "subject"}},
93 },
94 T: field.ErrorTypeNotSupported,
95 F: "subjects[0].kind",
96 },
97 "bad subject name": {
98 A: rbac.ClusterRoleBinding{
99 ObjectMeta: metav1.ObjectMeta{Name: "master"},
100 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
101 Subjects: []rbac.Subject{{Namespace: "foo", Name: "subject:bad", Kind: rbac.ServiceAccountKind}},
102 },
103 T: field.ErrorTypeInvalid,
104 F: "subjects[0].name",
105 },
106 "missing SA namespace": {
107 A: rbac.ClusterRoleBinding{
108 ObjectMeta: metav1.ObjectMeta{Name: "master"},
109 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
110 Subjects: []rbac.Subject{{Name: "good", Kind: rbac.ServiceAccountKind}},
111 },
112 T: field.ErrorTypeRequired,
113 F: "subjects[0].namespace",
114 },
115 "missing subject name": {
116 A: rbac.ClusterRoleBinding{
117 ObjectMeta: metav1.ObjectMeta{Name: "master"},
118 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
119 Subjects: []rbac.Subject{{Namespace: "foo", Kind: rbac.ServiceAccountKind}},
120 },
121 T: field.ErrorTypeRequired,
122 F: "subjects[0].name",
123 },
124 }
125 for k, v := range errorCases {
126 errs := ValidateClusterRoleBinding(&v.A)
127 if len(errs) == 0 {
128 t.Errorf("expected failure %s for %v", k, v.A)
129 continue
130 }
131 for i := range errs {
132 if errs[i].Type != v.T {
133 t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
134 }
135 if errs[i].Field != v.F {
136 t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
137 }
138 }
139 }
140 }
141
142 func TestValidateRoleBinding(t *testing.T) {
143 errs := ValidateRoleBinding(
144 &rbac.RoleBinding{
145 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master"},
146 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
147 Subjects: []rbac.Subject{
148 {Name: "validsaname", APIGroup: "", Kind: rbac.ServiceAccountKind},
149 {Name: "valid@username", APIGroup: rbac.GroupName, Kind: rbac.UserKind},
150 {Name: "valid@groupname", APIGroup: rbac.GroupName, Kind: rbac.GroupKind},
151 },
152 },
153 )
154 if len(errs) != 0 {
155 t.Errorf("expected success: %v", errs)
156 }
157
158 errorCases := map[string]struct {
159 A rbac.RoleBinding
160 T field.ErrorType
161 F string
162 }{
163 "bad group": {
164 A: rbac.RoleBinding{
165 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "default"},
166 RoleRef: rbac.RoleRef{APIGroup: "rbac.GroupName", Kind: "ClusterRole", Name: "valid"},
167 },
168 T: field.ErrorTypeNotSupported,
169 F: "roleRef.apiGroup",
170 },
171 "bad kind": {
172 A: rbac.RoleBinding{
173 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "default"},
174 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Type", Name: "valid"},
175 },
176 T: field.ErrorTypeNotSupported,
177 F: "roleRef.kind",
178 },
179 "zero-length namespace": {
180 A: rbac.RoleBinding{
181 ObjectMeta: metav1.ObjectMeta{Name: "default"},
182 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
183 },
184 T: field.ErrorTypeRequired,
185 F: "metadata.namespace",
186 },
187 "zero-length name": {
188 A: rbac.RoleBinding{
189 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault},
190 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
191 },
192 T: field.ErrorTypeRequired,
193 F: "metadata.name",
194 },
195 "bad role": {
196 A: rbac.RoleBinding{
197 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "default"},
198 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role"},
199 },
200 T: field.ErrorTypeRequired,
201 F: "roleRef.name",
202 },
203 "bad subject kind": {
204 A: rbac.RoleBinding{
205 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master"},
206 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
207 Subjects: []rbac.Subject{{Name: "subject"}},
208 },
209 T: field.ErrorTypeNotSupported,
210 F: "subjects[0].kind",
211 },
212 "bad subject name": {
213 A: rbac.RoleBinding{
214 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master"},
215 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
216 Subjects: []rbac.Subject{{Name: "subject:bad", Kind: rbac.ServiceAccountKind}},
217 },
218 T: field.ErrorTypeInvalid,
219 F: "subjects[0].name",
220 },
221 "missing subject name": {
222 A: rbac.RoleBinding{
223 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master"},
224 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
225 Subjects: []rbac.Subject{{Kind: rbac.ServiceAccountKind}},
226 },
227 T: field.ErrorTypeRequired,
228 F: "subjects[0].name",
229 },
230 }
231 for k, v := range errorCases {
232 errs := ValidateRoleBinding(&v.A)
233 if len(errs) == 0 {
234 t.Errorf("expected failure %s for %v", k, v.A)
235 continue
236 }
237 for i := range errs {
238 if errs[i].Type != v.T {
239 t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
240 }
241 if errs[i].Field != v.F {
242 t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
243 }
244 }
245 }
246 }
247
248 func TestValidateRoleBindingUpdate(t *testing.T) {
249 old := &rbac.RoleBinding{
250 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master", ResourceVersion: "1"},
251 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
252 }
253
254 errs := ValidateRoleBindingUpdate(
255 &rbac.RoleBinding{
256 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master", ResourceVersion: "1"},
257 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
258 },
259 old,
260 )
261 if len(errs) != 0 {
262 t.Errorf("expected success: %v", errs)
263 }
264
265 errorCases := map[string]struct {
266 A rbac.RoleBinding
267 T field.ErrorType
268 F string
269 }{
270 "changedRef": {
271 A: rbac.RoleBinding{
272 ObjectMeta: metav1.ObjectMeta{Namespace: metav1.NamespaceDefault, Name: "master", ResourceVersion: "1"},
273 RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "changed"},
274 },
275 T: field.ErrorTypeInvalid,
276 F: "roleRef",
277 },
278 }
279 for k, v := range errorCases {
280 errs := ValidateRoleBindingUpdate(&v.A, old)
281 if len(errs) == 0 {
282 t.Errorf("expected failure %s for %v", k, v.A)
283 continue
284 }
285 for i := range errs {
286 if errs[i].Type != v.T {
287 t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
288 }
289 if errs[i].Field != v.F {
290 t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
291 }
292 }
293 }
294 }
295
296 type ValidateRoleTest struct {
297 role rbac.Role
298 wantErr bool
299 errType field.ErrorType
300 field string
301 }
302
303 func (v ValidateRoleTest) test(t *testing.T) {
304 errs := ValidateRole(&v.role)
305 if len(errs) == 0 {
306 if v.wantErr {
307 t.Fatal("expected validation error")
308 }
309 return
310 }
311 if !v.wantErr {
312 t.Errorf("didn't expect error, got %v", errs)
313 return
314 }
315 for i := range errs {
316 if errs[i].Type != v.errType {
317 t.Errorf("expected errors to have type %s: %v", v.errType, errs[i])
318 }
319 if errs[i].Field != v.field {
320 t.Errorf("expected errors to have field %s: %v", v.field, errs[i])
321 }
322 }
323 }
324
325 type ValidateClusterRoleTest struct {
326 role rbac.ClusterRole
327 wantErr bool
328 errType field.ErrorType
329 field string
330 }
331
332 func (v ValidateClusterRoleTest) test(t *testing.T) {
333 errs := ValidateClusterRole(&v.role, ClusterRoleValidationOptions{false})
334 if len(errs) == 0 {
335 if v.wantErr {
336 t.Fatal("expected validation error")
337 }
338 return
339 }
340 if !v.wantErr {
341 t.Errorf("didn't expect error, got %v", errs)
342 return
343 }
344 for i := range errs {
345 if errs[i].Type != v.errType {
346 t.Errorf("expected errors to have type %s: %v", v.errType, errs[i])
347 }
348 if errs[i].Field != v.field {
349 t.Errorf("expected errors to have field %s: %v", v.field, errs[i])
350 }
351 }
352 }
353
354 func TestValidateRoleZeroLengthNamespace(t *testing.T) {
355 ValidateRoleTest{
356 role: rbac.Role{
357 ObjectMeta: metav1.ObjectMeta{Name: "default"},
358 },
359 wantErr: true,
360 errType: field.ErrorTypeRequired,
361 field: "metadata.namespace",
362 }.test(t)
363 }
364
365 func TestValidateRoleZeroLengthName(t *testing.T) {
366 ValidateRoleTest{
367 role: rbac.Role{
368 ObjectMeta: metav1.ObjectMeta{Namespace: "default"},
369 },
370 wantErr: true,
371 errType: field.ErrorTypeRequired,
372 field: "metadata.name",
373 }.test(t)
374 }
375
376 func TestValidateRoleValidRole(t *testing.T) {
377 ValidateRoleTest{
378 role: rbac.Role{
379 ObjectMeta: metav1.ObjectMeta{
380 Namespace: "default",
381 Name: "default",
382 },
383 },
384 wantErr: false,
385 }.test(t)
386 }
387
388 func TestValidateRoleValidRoleNoNamespace(t *testing.T) {
389 ValidateClusterRoleTest{
390 role: rbac.ClusterRole{
391 ObjectMeta: metav1.ObjectMeta{
392 Name: "default",
393 },
394 },
395 wantErr: false,
396 }.test(t)
397 }
398
399 func TestValidateRoleNonResourceURL(t *testing.T) {
400 ValidateClusterRoleTest{
401 role: rbac.ClusterRole{
402 ObjectMeta: metav1.ObjectMeta{
403 Name: "default",
404 },
405 Rules: []rbac.PolicyRule{{
406 Verbs: []string{"get"},
407 NonResourceURLs: []string{"/*"},
408 }},
409 },
410 wantErr: false,
411 }.test(t)
412 }
413
414 func TestValidateRoleNamespacedNonResourceURL(t *testing.T) {
415 ValidateRoleTest{
416 role: rbac.Role{
417 ObjectMeta: metav1.ObjectMeta{
418 Namespace: "default",
419 Name: "default",
420 },
421 Rules: []rbac.PolicyRule{{
422
423 Verbs: []string{"get"},
424 NonResourceURLs: []string{"/*"},
425 }},
426 },
427 wantErr: true,
428 errType: field.ErrorTypeInvalid,
429 field: "rules[0].nonResourceURLs",
430 }.test(t)
431 }
432
433 func TestValidateRoleNonResourceURLNoVerbs(t *testing.T) {
434 ValidateClusterRoleTest{
435 role: rbac.ClusterRole{
436 ObjectMeta: metav1.ObjectMeta{
437 Name: "default",
438 },
439 Rules: []rbac.PolicyRule{{
440 Verbs: []string{},
441 NonResourceURLs: []string{"/*"},
442 }},
443 },
444 wantErr: true,
445 errType: field.ErrorTypeRequired,
446 field: "rules[0].verbs",
447 }.test(t)
448 }
449
450 func TestValidateRoleMixedNonResourceAndResource(t *testing.T) {
451 ValidateRoleTest{
452 role: rbac.Role{
453 ObjectMeta: metav1.ObjectMeta{
454 Name: "default",
455 Namespace: "default",
456 },
457 Rules: []rbac.PolicyRule{{
458 Verbs: []string{"get"},
459 NonResourceURLs: []string{"/*"},
460 APIGroups: []string{"v1"},
461 Resources: []string{"pods"},
462 }},
463 },
464 wantErr: true,
465 errType: field.ErrorTypeInvalid,
466 field: "rules[0].nonResourceURLs",
467 }.test(t)
468 }
469
470 func TestValidateRoleValidResource(t *testing.T) {
471 ValidateRoleTest{
472 role: rbac.Role{
473 ObjectMeta: metav1.ObjectMeta{
474 Name: "default",
475 Namespace: "default",
476 },
477 Rules: []rbac.PolicyRule{{
478 Verbs: []string{"get"},
479 APIGroups: []string{"v1"},
480 Resources: []string{"pods"},
481 }},
482 },
483 wantErr: false,
484 }.test(t)
485 }
486
487 func TestValidateRoleNoAPIGroup(t *testing.T) {
488 ValidateRoleTest{
489 role: rbac.Role{
490 ObjectMeta: metav1.ObjectMeta{
491 Name: "default",
492 Namespace: "default",
493 },
494 Rules: []rbac.PolicyRule{{
495 Verbs: []string{"get"},
496 Resources: []string{"pods"},
497 }},
498 },
499 wantErr: true,
500 errType: field.ErrorTypeRequired,
501 field: "rules[0].apiGroups",
502 }.test(t)
503 }
504
505 func TestValidateRoleNoResources(t *testing.T) {
506 ValidateRoleTest{
507 role: rbac.Role{
508 ObjectMeta: metav1.ObjectMeta{
509 Name: "default",
510 Namespace: "default",
511 },
512 Rules: []rbac.PolicyRule{{
513 Verbs: []string{"get"},
514 APIGroups: []string{"v1"},
515 }},
516 },
517 wantErr: true,
518 errType: field.ErrorTypeRequired,
519 field: "rules[0].resources",
520 }.test(t)
521 }
522
View as plain text