...

Source file src/k8s.io/kubernetes/pkg/apis/rbac/validation/validation_test.go

Documentation: k8s.io/kubernetes/pkg/apis/rbac/validation

     1  /*
     2  Copyright 2016 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 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  				// non-resource URLs are invalid for namespaced rules
   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