Example #1
0
func TestAuthorizer(t *testing.T) {
	tests := []struct {
		roles               []*rbac.Role
		roleBindings        []*rbac.RoleBinding
		clusterRoles        []*rbac.ClusterRole
		clusterRoleBindings []*rbac.ClusterRoleBinding

		shouldPass []authorizer.Attributes
		shouldFail []authorizer.Attributes
	}{
		{
			clusterRoles: []*rbac.ClusterRole{
				newClusterRole("admin", newRule("*", "*", "*", "*")),
			},
			roleBindings: []*rbac.RoleBinding{
				newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
			},
			shouldPass: []authorizer.Attributes{
				&defaultAttributes{"admin", "", "get", "Pods", "", "ns1", ""},
				&defaultAttributes{"admin", "", "watch", "Pods", "", "ns1", ""},
				&defaultAttributes{"admin", "group1", "watch", "Foobar", "", "ns1", ""},
				&defaultAttributes{"joe", "admins", "watch", "Foobar", "", "ns1", ""},
				&defaultAttributes{"joe", "group1,admins", "watch", "Foobar", "", "ns1", ""},
			},
			shouldFail: []authorizer.Attributes{
				&defaultAttributes{"admin", "", "GET", "Pods", "", "ns2", ""},
				&defaultAttributes{"admin", "", "GET", "Nodes", "", "", ""},
				&defaultAttributes{"admin", "admins", "GET", "Pods", "", "ns2", ""},
				&defaultAttributes{"admin", "admins", "GET", "Nodes", "", "", ""},
			},
		},
		{
			// Non-resource-url tests
			clusterRoles: []*rbac.ClusterRole{
				newClusterRole("non-resource-url-getter", newRule("get", "", "", "/apis")),
				newClusterRole("non-resource-url", newRule("*", "", "", "/apis")),
				newClusterRole("non-resource-url-prefix", newRule("get", "", "", "/apis/*")),
			},
			clusterRoleBindings: []*rbac.ClusterRoleBinding{
				newClusterRoleBinding("non-resource-url-getter", "User:foo", "Group:bar"),
				newClusterRoleBinding("non-resource-url", "User:admin", "Group:admin"),
				newClusterRoleBinding("non-resource-url-prefix", "User:prefixed", "Group:prefixed"),
			},
			shouldPass: []authorizer.Attributes{
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "foo"}, Verb: "get", Path: "/apis"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"bar"}}, Verb: "get", Path: "/apis"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "admin"}, Verb: "get", Path: "/apis"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"admin"}}, Verb: "get", Path: "/apis"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "admin"}, Verb: "watch", Path: "/apis"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"admin"}}, Verb: "watch", Path: "/apis"},

				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "prefixed"}, Verb: "get", Path: "/apis/v1"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/apis/v1"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "prefixed"}, Verb: "get", Path: "/apis/v1/foobar"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/apis/v1/foorbar"},
			},
			shouldFail: []authorizer.Attributes{
				// wrong verb
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "foo"}, Verb: "watch", Path: "/apis"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"bar"}}, Verb: "watch", Path: "/apis"},

				// wrong path
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "foo"}, Verb: "get", Path: "/api/v1"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"bar"}}, Verb: "get", Path: "/api/v1"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "admin"}, Verb: "get", Path: "/api/v1"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"admin"}}, Verb: "get", Path: "/api/v1"},

				// not covered by prefix
				authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "prefixed"}, Verb: "get", Path: "/api/v1"},
				authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/api/v1"},
			},
		},
		{
			// test subresource resolution
			clusterRoles: []*rbac.ClusterRole{
				newClusterRole("admin", newRule("*", "*", "pods", "*")),
			},
			roleBindings: []*rbac.RoleBinding{
				newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
			},
			shouldPass: []authorizer.Attributes{
				&defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""},
			},
			shouldFail: []authorizer.Attributes{
				&defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""},
			},
		},
		{
			// test subresource resolution
			clusterRoles: []*rbac.ClusterRole{
				newClusterRole("admin", newRule("*", "*", "pods/status", "*")),
			},
			roleBindings: []*rbac.RoleBinding{
				newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
			},
			shouldPass: []authorizer.Attributes{
				&defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""},
			},
			shouldFail: []authorizer.Attributes{
				&defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""},
			},
		},
	}
	for i, tt := range tests {
		ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
		a := RBACAuthorizer{ruleResolver}
		for _, attr := range tt.shouldPass {
			if authorized, _, _ := a.Authorize(attr); !authorized {
				t.Errorf("case %d: incorrectly restricted %s", i, attr)
			}
		}

		for _, attr := range tt.shouldFail {
			if authorized, _, _ := a.Authorize(attr); authorized {
				t.Errorf("case %d: incorrectly passed %s", i, attr)
			}
		}
	}
}
func TestSubjectLocator(t *testing.T) {
	type actionToSubjects struct {
		action   authorizer.Attributes
		subjects []rbac.Subject
	}

	tests := []struct {
		name                string
		roles               []*rbac.Role
		roleBindings        []*rbac.RoleBinding
		clusterRoles        []*rbac.ClusterRole
		clusterRoleBindings []*rbac.ClusterRoleBinding

		superUser string

		actionsToSubjects []actionToSubjects
	}{
		{
			name: "no super user, star matches star",
			clusterRoles: []*rbac.ClusterRole{
				newClusterRole("admin", newRule("*", "*", "*", "*")),
			},
			clusterRoleBindings: []*rbac.ClusterRoleBinding{
				newClusterRoleBinding("admin", "User:super-admin", "Group:super-admins"),
			},
			roleBindings: []*rbac.RoleBinding{
				newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"),
			},
			actionsToSubjects: []actionToSubjects{
				{
					&defaultAttributes{"", "", "get", "Pods", "", "ns1", ""},
					[]rbac.Subject{
						{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
						{Kind: rbac.UserKind, Name: "super-admin"},
						{Kind: rbac.GroupKind, Name: "super-admins"},
						{Kind: rbac.UserKind, Name: "admin"},
						{Kind: rbac.GroupKind, Name: "admins"},
					},
				},
				{
					// cluster role matches star in namespace
					&defaultAttributes{"", "", "*", "Pods", "", "*", ""},
					[]rbac.Subject{
						{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
						{Kind: rbac.UserKind, Name: "super-admin"},
						{Kind: rbac.GroupKind, Name: "super-admins"},
					},
				},
				{
					// empty ns
					&defaultAttributes{"", "", "*", "Pods", "", "", ""},
					[]rbac.Subject{
						{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
						{Kind: rbac.UserKind, Name: "super-admin"},
						{Kind: rbac.GroupKind, Name: "super-admins"},
					},
				},
			},
		},
		{
			name:      "super user, local roles work",
			superUser: "******",
			clusterRoles: []*rbac.ClusterRole{
				newClusterRole("admin", newRule("*", "*", "*", "*")),
			},
			clusterRoleBindings: []*rbac.ClusterRoleBinding{
				newClusterRoleBinding("admin", "User:super-admin", "Group:super-admins"),
			},
			roles: []*rbac.Role{
				newRole("admin", "ns1", newRule("get", "*", "Pods", "*")),
			},
			roleBindings: []*rbac.RoleBinding{
				newRoleBinding("ns1", "admin", bindToRole, "User:admin", "Group:admins"),
			},
			actionsToSubjects: []actionToSubjects{
				{
					&defaultAttributes{"", "", "get", "Pods", "", "ns1", ""},
					[]rbac.Subject{
						{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
						{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: "foo"},
						{Kind: rbac.UserKind, Name: "super-admin"},
						{Kind: rbac.GroupKind, Name: "super-admins"},
						{Kind: rbac.UserKind, Name: "admin"},
						{Kind: rbac.GroupKind, Name: "admins"},
					},
				},
				{
					// verb matchies correctly
					&defaultAttributes{"", "", "create", "Pods", "", "ns1", ""},
					[]rbac.Subject{
						{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
						{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: "foo"},
						{Kind: rbac.UserKind, Name: "super-admin"},
						{Kind: rbac.GroupKind, Name: "super-admins"},
					},
				},
				{
					// binding only works in correct ns
					&defaultAttributes{"", "", "get", "Pods", "", "ns2", ""},
					[]rbac.Subject{
						{Kind: rbac.GroupKind, Name: user.SystemPrivilegedGroup},
						{Kind: rbac.UserKind, APIVersion: "v1alpha1", Name: "foo"},
						{Kind: rbac.UserKind, Name: "super-admin"},
						{Kind: rbac.GroupKind, Name: "super-admins"},
					},
				},
			},
		},
	}
	for _, tt := range tests {
		ruleResolver, lister := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
		a := SubjectAccessEvaluator{tt.superUser, lister, lister, ruleResolver}
		for i, action := range tt.actionsToSubjects {
			actualSubjects, err := a.AllowedSubjects(action.action)
			if err != nil {
				t.Errorf("case %q %d: error %v", tt.name, i, err)
			}
			if !reflect.DeepEqual(actualSubjects, action.subjects) {
				t.Errorf("case %q %d: expected %v actual %v", tt.name, i, action.subjects, actualSubjects)
			}
		}
	}
}