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) } } } }