mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 02:33:34 +00:00
vendor files
This commit is contained in:
56
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/BUILD
generated
vendored
Normal file
56
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/BUILD
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"policy_compact_test.go",
|
||||
"policy_comparator_test.go",
|
||||
"rule_test.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/registry/rbac/validation",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"policy_compact.go",
|
||||
"policy_comparator.go",
|
||||
"rule.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/pkg/registry/rbac/validation",
|
||||
deps = [
|
||||
"//pkg/apis/rbac:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/authentication/user:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/endpoints/request:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
89
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact.go
generated
vendored
Normal file
89
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact.go
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
type simpleResource struct {
|
||||
Group string
|
||||
Resource string
|
||||
ResourceNameExist bool
|
||||
ResourceName string
|
||||
}
|
||||
|
||||
// CompactRules combines rules that contain a single APIGroup/Resource, differ only by verb, and contain no other attributes.
|
||||
// this is a fast check, and works well with the decomposed "missing rules" list from a Covers check.
|
||||
func CompactRules(rules []rbac.PolicyRule) ([]rbac.PolicyRule, error) {
|
||||
compacted := make([]rbac.PolicyRule, 0, len(rules))
|
||||
|
||||
simpleRules := map[simpleResource]*rbac.PolicyRule{}
|
||||
for _, rule := range rules {
|
||||
if resource, isSimple := isSimpleResourceRule(&rule); isSimple {
|
||||
if existingRule, ok := simpleRules[resource]; ok {
|
||||
// Add the new verbs to the existing simple resource rule
|
||||
if existingRule.Verbs == nil {
|
||||
existingRule.Verbs = []string{}
|
||||
}
|
||||
existingRule.Verbs = append(existingRule.Verbs, rule.Verbs...)
|
||||
} else {
|
||||
// Copy the rule to accumulate matching simple resource rules into
|
||||
simpleRules[resource] = rule.DeepCopy()
|
||||
}
|
||||
} else {
|
||||
compacted = append(compacted, rule)
|
||||
}
|
||||
}
|
||||
|
||||
// Once we've consolidated the simple resource rules, add them to the compacted list
|
||||
for _, simpleRule := range simpleRules {
|
||||
compacted = append(compacted, *simpleRule)
|
||||
}
|
||||
|
||||
return compacted, nil
|
||||
}
|
||||
|
||||
// isSimpleResourceRule returns true if the given rule contains verbs, a single resource, a single API group, at most one Resource Name, and no other values
|
||||
func isSimpleResourceRule(rule *rbac.PolicyRule) (simpleResource, bool) {
|
||||
resource := simpleResource{}
|
||||
|
||||
// If we have "complex" rule attributes, return early without allocations or expensive comparisons
|
||||
if len(rule.ResourceNames) > 1 || len(rule.NonResourceURLs) > 0 {
|
||||
return resource, false
|
||||
}
|
||||
// If we have multiple api groups or resources, return early
|
||||
if len(rule.APIGroups) != 1 || len(rule.Resources) != 1 {
|
||||
return resource, false
|
||||
}
|
||||
|
||||
// Test if this rule only contains APIGroups/Resources/Verbs/ResourceNames
|
||||
simpleRule := &rbac.PolicyRule{APIGroups: rule.APIGroups, Resources: rule.Resources, Verbs: rule.Verbs, ResourceNames: rule.ResourceNames}
|
||||
if !reflect.DeepEqual(simpleRule, rule) {
|
||||
return resource, false
|
||||
}
|
||||
|
||||
if len(rule.ResourceNames) == 0 {
|
||||
resource = simpleResource{Group: rule.APIGroups[0], Resource: rule.Resources[0], ResourceNameExist: false}
|
||||
} else {
|
||||
resource = simpleResource{Group: rule.APIGroups[0], Resource: rule.Resources[0], ResourceNameExist: true, ResourceName: rule.ResourceNames[0]}
|
||||
}
|
||||
|
||||
return resource, true
|
||||
}
|
226
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact_test.go
generated
vendored
Normal file
226
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact_test.go
generated
vendored
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
func TestCompactRules(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Rules []rbac.PolicyRule
|
||||
Expected []rbac.PolicyRule
|
||||
}{
|
||||
"empty": {
|
||||
Rules: []rbac.PolicyRule{},
|
||||
Expected: []rbac.PolicyRule{},
|
||||
},
|
||||
"simple": {
|
||||
Rules: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
{Verbs: []string{"update", "patch"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
|
||||
{Verbs: []string{"create"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}},
|
||||
{Verbs: []string{"delete"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}},
|
||||
{Verbs: []string{"patch"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{""}},
|
||||
{Verbs: []string{"get"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}},
|
||||
|
||||
{Verbs: []string{"educate"}, APIGroups: []string{""}, Resources: []string{"dolphins"}},
|
||||
|
||||
// nil verbs are preserved in non-merge cases.
|
||||
// these are the pirates who don't do anything.
|
||||
{Verbs: nil, APIGroups: []string{""}, Resources: []string{"pirates"}},
|
||||
|
||||
// Test merging into a nil Verbs string set
|
||||
{Verbs: nil, APIGroups: []string{""}, Resources: []string{"pods"}},
|
||||
{Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"pods"}},
|
||||
},
|
||||
Expected: []rbac.PolicyRule{
|
||||
{Verbs: []string{"create", "delete"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}},
|
||||
{Verbs: []string{"patch"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{""}},
|
||||
{Verbs: []string{"get", "list"}, APIGroups: []string{"extensions"}, Resources: []string{"daemonsets"}, ResourceNames: []string{"foo"}},
|
||||
{Verbs: []string{"get", "list", "update", "patch"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
{Verbs: []string{"educate"}, APIGroups: []string{""}, Resources: []string{"dolphins"}},
|
||||
{Verbs: nil, APIGroups: []string{""}, Resources: []string{"pirates"}},
|
||||
{Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"pods"}},
|
||||
},
|
||||
},
|
||||
"complex multi-group": {
|
||||
Rules: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
||||
},
|
||||
Expected: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{"", "builds.openshift.io"}, Resources: []string{"builds"}},
|
||||
},
|
||||
},
|
||||
|
||||
"complex multi-resource": {
|
||||
Rules: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
||||
},
|
||||
Expected: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
||||
},
|
||||
},
|
||||
|
||||
"complex named-resource": {
|
||||
Rules: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild2"}},
|
||||
},
|
||||
Expected: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild"}},
|
||||
{Verbs: []string{"list"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"mybuild2"}},
|
||||
},
|
||||
},
|
||||
|
||||
"complex non-resource": {
|
||||
Rules: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}},
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/foo"}},
|
||||
},
|
||||
Expected: []rbac.PolicyRule{
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}},
|
||||
{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/foo"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
rules := tc.Rules
|
||||
originalRules := make([]rbac.PolicyRule, len(tc.Rules))
|
||||
for i := range tc.Rules {
|
||||
originalRules[i] = *tc.Rules[i].DeepCopy()
|
||||
}
|
||||
compacted, err := CompactRules(tc.Rules)
|
||||
if err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(rules, originalRules) {
|
||||
t.Errorf("%s: CompactRules mutated rules. Expected\n%#v\ngot\n%#v", k, originalRules, rules)
|
||||
continue
|
||||
}
|
||||
if covers, missing := Covers(compacted, rules); !covers {
|
||||
t.Errorf("%s: compacted rules did not cover original rules. missing: %#v", k, missing)
|
||||
continue
|
||||
}
|
||||
if covers, missing := Covers(rules, compacted); !covers {
|
||||
t.Errorf("%s: original rules did not cover compacted rules. missing: %#v", k, missing)
|
||||
continue
|
||||
}
|
||||
|
||||
sort.Stable(rbac.SortableRuleSlice(compacted))
|
||||
sort.Stable(rbac.SortableRuleSlice(tc.Expected))
|
||||
if !reflect.DeepEqual(compacted, tc.Expected) {
|
||||
t.Errorf("%s: Expected\n%#v\ngot\n%#v", k, tc.Expected, compacted)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSimpleResourceRule(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
Rule rbac.PolicyRule
|
||||
Simple bool
|
||||
Resource simpleResource
|
||||
}{
|
||||
"simple, no verbs": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
Simple: true,
|
||||
Resource: simpleResource{Group: "", Resource: "builds"},
|
||||
},
|
||||
"simple, one verb": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
Simple: true,
|
||||
Resource: simpleResource{Group: "", Resource: "builds"},
|
||||
},
|
||||
"simple, one empty resource name": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{""}},
|
||||
Simple: true,
|
||||
Resource: simpleResource{Group: "", Resource: "builds", ResourceNameExist: true, ResourceName: ""},
|
||||
},
|
||||
"simple, one resource name": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"foo"}},
|
||||
Simple: true,
|
||||
Resource: simpleResource{Group: "", Resource: "builds", ResourceNameExist: true, ResourceName: "foo"},
|
||||
},
|
||||
"simple, multi verb": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get", "list"}, APIGroups: []string{""}, Resources: []string{"builds"}},
|
||||
Simple: true,
|
||||
Resource: simpleResource{Group: "", Resource: "builds"},
|
||||
},
|
||||
|
||||
"complex, empty": {
|
||||
Rule: rbac.PolicyRule{},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
"complex, no group": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{}, Resources: []string{"builds"}},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
"complex, multi group": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{"a", "b"}, Resources: []string{"builds"}},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
"complex, no resource": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{}},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
"complex, multi resource": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds", "images"}},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
"complex, resource names": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, ResourceNames: []string{"foo", "bar"}},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
"complex, non-resource urls": {
|
||||
Rule: rbac.PolicyRule{Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"builds"}, NonResourceURLs: []string{"/"}},
|
||||
Simple: false,
|
||||
Resource: simpleResource{},
|
||||
},
|
||||
}
|
||||
|
||||
for k, tc := range testcases {
|
||||
resource, simple := isSimpleResourceRule(&tc.Rule)
|
||||
if simple != tc.Simple {
|
||||
t.Errorf("%s: expected simple=%v, got simple=%v", k, tc.Simple, simple)
|
||||
continue
|
||||
}
|
||||
if resource != tc.Resource {
|
||||
t.Errorf("%s: expected resource=%v, got resource=%v", k, tc.Resource, resource)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
173
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_comparator.go
generated
vendored
Normal file
173
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_comparator.go
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
// Covers determines whether or not the ownerRules cover the servantRules in terms of allowed actions.
|
||||
// It returns whether or not the ownerRules cover and a list of the rules that the ownerRules do not cover.
|
||||
func Covers(ownerRules, servantRules []rbac.PolicyRule) (bool, []rbac.PolicyRule) {
|
||||
// 1. Break every servantRule into individual rule tuples: group, verb, resource, resourceName
|
||||
// 2. Compare the mini-rules against each owner rule. Because the breakdown is down to the most atomic level, we're guaranteed that each mini-servant rule will be either fully covered or not covered by a single owner rule
|
||||
// 3. Any left over mini-rules means that we are not covered and we have a nice list of them.
|
||||
// TODO: it might be nice to collapse the list down into something more human readable
|
||||
|
||||
subrules := []rbac.PolicyRule{}
|
||||
for _, servantRule := range servantRules {
|
||||
subrules = append(subrules, BreakdownRule(servantRule)...)
|
||||
}
|
||||
|
||||
uncoveredRules := []rbac.PolicyRule{}
|
||||
for _, subrule := range subrules {
|
||||
covered := false
|
||||
for _, ownerRule := range ownerRules {
|
||||
if ruleCovers(ownerRule, subrule) {
|
||||
covered = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !covered {
|
||||
uncoveredRules = append(uncoveredRules, subrule)
|
||||
}
|
||||
}
|
||||
|
||||
return (len(uncoveredRules) == 0), uncoveredRules
|
||||
}
|
||||
|
||||
// BreadownRule takes a rule and builds an equivalent list of rules that each have at most one verb, one
|
||||
// resource, and one resource name
|
||||
func BreakdownRule(rule rbac.PolicyRule) []rbac.PolicyRule {
|
||||
subrules := []rbac.PolicyRule{}
|
||||
for _, group := range rule.APIGroups {
|
||||
for _, resource := range rule.Resources {
|
||||
for _, verb := range rule.Verbs {
|
||||
if len(rule.ResourceNames) > 0 {
|
||||
for _, resourceName := range rule.ResourceNames {
|
||||
subrules = append(subrules, rbac.PolicyRule{APIGroups: []string{group}, Resources: []string{resource}, Verbs: []string{verb}, ResourceNames: []string{resourceName}})
|
||||
}
|
||||
|
||||
} else {
|
||||
subrules = append(subrules, rbac.PolicyRule{APIGroups: []string{group}, Resources: []string{resource}, Verbs: []string{verb}})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Non-resource URLs are unique because they only combine with verbs.
|
||||
for _, nonResourceURL := range rule.NonResourceURLs {
|
||||
for _, verb := range rule.Verbs {
|
||||
subrules = append(subrules, rbac.PolicyRule{NonResourceURLs: []string{nonResourceURL}, Verbs: []string{verb}})
|
||||
}
|
||||
}
|
||||
|
||||
return subrules
|
||||
}
|
||||
|
||||
func has(set []string, ele string) bool {
|
||||
for _, s := range set {
|
||||
if s == ele {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasAll(set, contains []string) bool {
|
||||
owning := make(map[string]struct{}, len(set))
|
||||
for _, ele := range set {
|
||||
owning[ele] = struct{}{}
|
||||
}
|
||||
for _, ele := range contains {
|
||||
if _, ok := owning[ele]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func resourceCoversAll(setResources, coversResources []string) bool {
|
||||
// if we have a star or an exact match on all resources, then we match
|
||||
if has(setResources, rbac.ResourceAll) || hasAll(setResources, coversResources) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, path := range coversResources {
|
||||
// if we have an exact match, then we match.
|
||||
if has(setResources, path) {
|
||||
continue
|
||||
}
|
||||
// if we're not a subresource, then we definitely don't match. fail.
|
||||
if !strings.Contains(path, "/") {
|
||||
return false
|
||||
}
|
||||
tokens := strings.SplitN(path, "/", 2)
|
||||
resourceToCheck := "*/" + tokens[1]
|
||||
if !has(setResources, resourceToCheck) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func nonResourceURLsCoversAll(set, covers []string) bool {
|
||||
for _, path := range covers {
|
||||
covered := false
|
||||
for _, owner := range set {
|
||||
if nonResourceURLCovers(owner, path) {
|
||||
covered = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !covered {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func nonResourceURLCovers(ownerPath, subPath string) bool {
|
||||
if ownerPath == subPath {
|
||||
return true
|
||||
}
|
||||
return strings.HasSuffix(ownerPath, "*") && strings.HasPrefix(subPath, strings.TrimRight(ownerPath, "*"))
|
||||
}
|
||||
|
||||
// ruleCovers determines whether the ownerRule (which may have multiple verbs, resources, and resourceNames) covers
|
||||
// the subrule (which may only contain at most one verb, resource, and resourceName)
|
||||
func ruleCovers(ownerRule, subRule rbac.PolicyRule) bool {
|
||||
verbMatches := has(ownerRule.Verbs, rbac.VerbAll) || hasAll(ownerRule.Verbs, subRule.Verbs)
|
||||
groupMatches := has(ownerRule.APIGroups, rbac.APIGroupAll) || hasAll(ownerRule.APIGroups, subRule.APIGroups)
|
||||
resourceMatches := resourceCoversAll(ownerRule.Resources, subRule.Resources)
|
||||
nonResourceURLMatches := nonResourceURLsCoversAll(ownerRule.NonResourceURLs, subRule.NonResourceURLs)
|
||||
|
||||
resourceNameMatches := false
|
||||
|
||||
if len(subRule.ResourceNames) == 0 {
|
||||
resourceNameMatches = (len(ownerRule.ResourceNames) == 0)
|
||||
} else {
|
||||
resourceNameMatches = (len(ownerRule.ResourceNames) == 0) || hasAll(ownerRule.ResourceNames, subRule.ResourceNames)
|
||||
}
|
||||
|
||||
return verbMatches && groupMatches && resourceMatches && resourceNameMatches && nonResourceURLMatches
|
||||
}
|
446
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_comparator_test.go
generated
vendored
Normal file
446
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_comparator_test.go
generated
vendored
Normal file
@ -0,0 +1,446 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
type escalationTest struct {
|
||||
ownerRules []rbac.PolicyRule
|
||||
servantRules []rbac.PolicyRule
|
||||
|
||||
expectedCovered bool
|
||||
expectedUncoveredRules []rbac.PolicyRule
|
||||
}
|
||||
|
||||
func TestCoversExactMatch(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversSubresourceWildcard(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*/scale"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"foo/scale"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversMultipleRulesCoveringSingleRule(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
|
||||
}
|
||||
|
||||
func TestCoversMultipleAPIGroupsCoveringSingleRule(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
|
||||
{APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
|
||||
{APIGroups: []string{"group1"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
|
||||
{APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
|
||||
{APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
|
||||
{APIGroups: []string{"group2"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"group1", "group2"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
|
||||
}
|
||||
|
||||
func TestCoversSingleAPIGroupsCoveringMultiple(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"group1", "group2"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
|
||||
{APIGroups: []string{"group1"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
|
||||
{APIGroups: []string{"group1"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
|
||||
{APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"deployments"}},
|
||||
{APIGroups: []string{"group2"}, Verbs: []string{"delete"}, Resources: []string{"builds"}},
|
||||
{APIGroups: []string{"group2"}, Verbs: []string{"update"}, Resources: []string{"builds", "deployments"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
|
||||
}
|
||||
|
||||
func TestCoversMultipleRulesMissingSingleVerbResourceCombination(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments"}},
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"delete"}, Resources: []string{"pods"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"delete", "update"}, Resources: []string{"builds", "deployments", "pods"}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"update"}, Resources: []string{"pods"}},
|
||||
},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversAPIGroupStarCoveringMultiple(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"group1", "group2"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversEnumerationNotCoveringAPIGroupStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"dummy-group"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversAPIGroupStarCoveringStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"*"}, Verbs: []string{"get"}, Resources: []string{"roles"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversVerbStarCoveringMultiple(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"watch", "list"}, Resources: []string{"roles"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversEnumerationNotCoveringVerbStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get", "list", "watch", "create", "update", "delete", "exec"}, Resources: []string{"roles"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
|
||||
},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversVerbStarCoveringStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"*"}, Resources: []string{"roles"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversResourceStarCoveringMultiple(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"resourcegroup:deployments"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversEnumerationNotCoveringResourceStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"roles", "resourcegroup:deployments"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
|
||||
},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversResourceStarCoveringStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"*"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversResourceNameEmptyCoveringMultiple(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{"foo", "bar"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversEnumerationNotCoveringResourceNameEmpty(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{"foo", "bar"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}, ResourceNames: []string{}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"pods"}},
|
||||
},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversNonResourceURLs(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis"}, Verbs: []string{"*"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis"}, Verbs: []string{"*"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversNonResourceURLsStar(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"*"}, Verbs: []string{"*"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis", "/apis/v1", "/"}, Verbs: []string{"*"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversNonResourceURLsStarAfterPrefixDoesntCover(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis/*"}, Verbs: []string{"*"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis", "/apis/v1"}, Verbs: []string{"get"}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis"}, Verbs: []string{"get"}},
|
||||
},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversNonResourceURLsStarAfterPrefix(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis/*"}, Verbs: []string{"*"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{NonResourceURLs: []string{"/apis/v1/foo", "/apis/v1"}, Verbs: []string{"get"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversNonResourceURLsWithOtherFields(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}, NonResourceURLs: []string{"/apis"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}, NonResourceURLs: []string{"/apis"}},
|
||||
},
|
||||
|
||||
expectedCovered: true,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func TestCoversNonResourceURLsWithOtherFieldsFailure(t *testing.T) {
|
||||
escalationTest{
|
||||
ownerRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}},
|
||||
},
|
||||
servantRules: []rbac.PolicyRule{
|
||||
{APIGroups: []string{"v1"}, Verbs: []string{"get"}, Resources: []string{"builds"}, NonResourceURLs: []string{"/apis"}},
|
||||
},
|
||||
|
||||
expectedCovered: false,
|
||||
expectedUncoveredRules: []rbac.PolicyRule{{NonResourceURLs: []string{"/apis"}, Verbs: []string{"get"}}},
|
||||
}.test(t)
|
||||
}
|
||||
|
||||
func (test escalationTest) test(t *testing.T) {
|
||||
actualCovered, actualUncoveredRules := Covers(test.ownerRules, test.servantRules)
|
||||
|
||||
if actualCovered != test.expectedCovered {
|
||||
t.Errorf("expected %v, but got %v", test.expectedCovered, actualCovered)
|
||||
}
|
||||
|
||||
if !rulesMatch(test.expectedUncoveredRules, actualUncoveredRules) {
|
||||
t.Errorf("expected %v, but got %v", test.expectedUncoveredRules, actualUncoveredRules)
|
||||
}
|
||||
}
|
||||
|
||||
func rulesMatch(expectedRules, actualRules []rbac.PolicyRule) bool {
|
||||
if len(expectedRules) != len(actualRules) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, expectedRule := range expectedRules {
|
||||
found := false
|
||||
for _, actualRule := range actualRules {
|
||||
if reflect.DeepEqual(expectedRule, actualRule) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestNonResourceURLCovers(t *testing.T) {
|
||||
tests := []struct {
|
||||
owner string
|
||||
requested string
|
||||
want bool
|
||||
}{
|
||||
{"*", "", true},
|
||||
{"*", "/", true},
|
||||
{"*", "/api", true},
|
||||
{"/*", "", false},
|
||||
{"/*", "/", true},
|
||||
{"/*", "/foo", true},
|
||||
{"/api", "/api", true},
|
||||
{"/apis", "/api", false},
|
||||
{"/api/v1", "/api", false},
|
||||
{"/api/v1", "/api/v1", true},
|
||||
{"/api/*", "/api/v1", true},
|
||||
{"/api/*", "/api", false},
|
||||
{"/api/*/*", "/api/v1", false},
|
||||
{"/*/v1/*", "/api/v1", false},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
got := nonResourceURLCovers(tc.owner, tc.requested)
|
||||
if got != tc.want {
|
||||
t.Errorf("nonResourceURLCovers(%q, %q): want=(%t), got=(%t)", tc.owner, tc.requested, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
288
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule.go
generated
vendored
Normal file
288
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule.go
generated
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/serviceaccount"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
type AuthorizationRuleResolver interface {
|
||||
// GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namepsace
|
||||
// of the role binding, the empty string if a cluster role binding.
|
||||
GetRoleReferenceRules(roleRef rbac.RoleRef, namespace string) ([]rbac.PolicyRule, error)
|
||||
|
||||
// RulesFor returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of
|
||||
// PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations
|
||||
// can be made on the basis of those rules that are found.
|
||||
RulesFor(user user.Info, namespace string) ([]rbac.PolicyRule, error)
|
||||
|
||||
// VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace, and each error encountered resolving those rules.
|
||||
// If visitor() returns false, visiting is short-circuited.
|
||||
VisitRulesFor(user user.Info, namespace string, visitor func(rule *rbac.PolicyRule, err error) bool)
|
||||
}
|
||||
|
||||
// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role.
|
||||
func ConfirmNoEscalation(ctx genericapirequest.Context, ruleResolver AuthorizationRuleResolver, rules []rbac.PolicyRule) error {
|
||||
ruleResolutionErrors := []error{}
|
||||
|
||||
user, ok := genericapirequest.UserFrom(ctx)
|
||||
if !ok {
|
||||
return fmt.Errorf("no user on context")
|
||||
}
|
||||
namespace, _ := genericapirequest.NamespaceFrom(ctx)
|
||||
|
||||
ownerRules, err := ruleResolver.RulesFor(user, namespace)
|
||||
if err != nil {
|
||||
// As per AuthorizationRuleResolver contract, this may return a non fatal error with an incomplete list of policies. Log the error and continue.
|
||||
glog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err)
|
||||
ruleResolutionErrors = append(ruleResolutionErrors, err)
|
||||
}
|
||||
|
||||
ownerRightsCover, missingRights := Covers(ownerRules, rules)
|
||||
if !ownerRightsCover {
|
||||
return apierrors.NewUnauthorized(fmt.Sprintf("attempt to grant extra privileges: %v user=%v ownerrules=%v ruleResolutionErrors=%v", missingRights, user, ownerRules, ruleResolutionErrors))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DefaultRuleResolver struct {
|
||||
roleGetter RoleGetter
|
||||
roleBindingLister RoleBindingLister
|
||||
clusterRoleGetter ClusterRoleGetter
|
||||
clusterRoleBindingLister ClusterRoleBindingLister
|
||||
}
|
||||
|
||||
func NewDefaultRuleResolver(roleGetter RoleGetter, roleBindingLister RoleBindingLister, clusterRoleGetter ClusterRoleGetter, clusterRoleBindingLister ClusterRoleBindingLister) *DefaultRuleResolver {
|
||||
return &DefaultRuleResolver{roleGetter, roleBindingLister, clusterRoleGetter, clusterRoleBindingLister}
|
||||
}
|
||||
|
||||
type RoleGetter interface {
|
||||
GetRole(namespace, name string) (*rbac.Role, error)
|
||||
}
|
||||
|
||||
type RoleBindingLister interface {
|
||||
ListRoleBindings(namespace string) ([]*rbac.RoleBinding, error)
|
||||
}
|
||||
|
||||
type ClusterRoleGetter interface {
|
||||
GetClusterRole(name string) (*rbac.ClusterRole, error)
|
||||
}
|
||||
|
||||
type ClusterRoleBindingLister interface {
|
||||
ListClusterRoleBindings() ([]*rbac.ClusterRoleBinding, error)
|
||||
}
|
||||
|
||||
func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbac.PolicyRule, error) {
|
||||
visitor := &ruleAccumulator{}
|
||||
r.VisitRulesFor(user, namespace, visitor.visit)
|
||||
return visitor.rules, utilerrors.NewAggregate(visitor.errors)
|
||||
}
|
||||
|
||||
type ruleAccumulator struct {
|
||||
rules []rbac.PolicyRule
|
||||
errors []error
|
||||
}
|
||||
|
||||
func (r *ruleAccumulator) visit(rule *rbac.PolicyRule, err error) bool {
|
||||
if rule != nil {
|
||||
r.rules = append(r.rules, *rule)
|
||||
}
|
||||
if err != nil {
|
||||
r.errors = append(r.errors, err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(rule *rbac.PolicyRule, err error) bool) {
|
||||
if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
|
||||
if !visitor(nil, err) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
for _, clusterRoleBinding := range clusterRoleBindings {
|
||||
if !appliesTo(user, clusterRoleBinding.Subjects, "") {
|
||||
continue
|
||||
}
|
||||
rules, err := r.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
|
||||
if err != nil {
|
||||
if !visitor(nil, err) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
for i := range rules {
|
||||
if !visitor(&rules[i], nil) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(namespace) > 0 {
|
||||
if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
|
||||
if !visitor(nil, err) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
for _, roleBinding := range roleBindings {
|
||||
if !appliesTo(user, roleBinding.Subjects, namespace) {
|
||||
continue
|
||||
}
|
||||
rules, err := r.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
|
||||
if err != nil {
|
||||
if !visitor(nil, err) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
for i := range rules {
|
||||
if !visitor(&rules[i], nil) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.
|
||||
func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbac.RoleRef, bindingNamespace string) ([]rbac.PolicyRule, error) {
|
||||
switch kind := rbac.RoleRefGroupKind(roleRef); kind {
|
||||
case rbac.Kind("Role"):
|
||||
role, err := r.roleGetter.GetRole(bindingNamespace, roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role.Rules, nil
|
||||
|
||||
case rbac.Kind("ClusterRole"):
|
||||
clusterRole, err := r.clusterRoleGetter.GetClusterRole(roleRef.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return clusterRole.Rules, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported role reference kind: %q", kind)
|
||||
}
|
||||
}
|
||||
func appliesTo(user user.Info, bindingSubjects []rbac.Subject, namespace string) bool {
|
||||
for _, bindingSubject := range bindingSubjects {
|
||||
if appliesToUser(user, bindingSubject, namespace) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func appliesToUser(user user.Info, subject rbac.Subject, namespace string) bool {
|
||||
switch subject.Kind {
|
||||
case rbac.UserKind:
|
||||
return user.GetName() == subject.Name
|
||||
|
||||
case rbac.GroupKind:
|
||||
return has(user.GetGroups(), subject.Name)
|
||||
|
||||
case rbac.ServiceAccountKind:
|
||||
// default the namespace to namespace we're working in if its available. This allows rolebindings that reference
|
||||
// SAs in th local namespace to avoid having to qualify them.
|
||||
saNamespace := namespace
|
||||
if len(subject.Namespace) > 0 {
|
||||
saNamespace = subject.Namespace
|
||||
}
|
||||
if len(saNamespace) == 0 {
|
||||
return false
|
||||
}
|
||||
return serviceaccount.MakeUsername(saNamespace, subject.Name) == user.GetName()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// NewTestRuleResolver returns a rule resolver from lists of role objects.
|
||||
func NewTestRuleResolver(roles []*rbac.Role, roleBindings []*rbac.RoleBinding, clusterRoles []*rbac.ClusterRole, clusterRoleBindings []*rbac.ClusterRoleBinding) (AuthorizationRuleResolver, *StaticRoles) {
|
||||
r := StaticRoles{
|
||||
roles: roles,
|
||||
roleBindings: roleBindings,
|
||||
clusterRoles: clusterRoles,
|
||||
clusterRoleBindings: clusterRoleBindings,
|
||||
}
|
||||
return newMockRuleResolver(&r), &r
|
||||
}
|
||||
|
||||
func newMockRuleResolver(r *StaticRoles) AuthorizationRuleResolver {
|
||||
return NewDefaultRuleResolver(r, r, r, r)
|
||||
}
|
||||
|
||||
// StaticRoles is a rule resolver that resolves from lists of role objects.
|
||||
type StaticRoles struct {
|
||||
roles []*rbac.Role
|
||||
roleBindings []*rbac.RoleBinding
|
||||
clusterRoles []*rbac.ClusterRole
|
||||
clusterRoleBindings []*rbac.ClusterRoleBinding
|
||||
}
|
||||
|
||||
func (r *StaticRoles) GetRole(namespace, name string) (*rbac.Role, error) {
|
||||
if len(namespace) == 0 {
|
||||
return nil, errors.New("must provide namespace when getting role")
|
||||
}
|
||||
for _, role := range r.roles {
|
||||
if role.Namespace == namespace && role.Name == name {
|
||||
return role, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("role not found")
|
||||
}
|
||||
|
||||
func (r *StaticRoles) GetClusterRole(name string) (*rbac.ClusterRole, error) {
|
||||
for _, clusterRole := range r.clusterRoles {
|
||||
if clusterRole.Name == name {
|
||||
return clusterRole, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("role not found")
|
||||
}
|
||||
|
||||
func (r *StaticRoles) ListRoleBindings(namespace string) ([]*rbac.RoleBinding, error) {
|
||||
if len(namespace) == 0 {
|
||||
return nil, errors.New("must provide namespace when listing role bindings")
|
||||
}
|
||||
|
||||
roleBindingList := []*rbac.RoleBinding{}
|
||||
for _, roleBinding := range r.roleBindings {
|
||||
if roleBinding.Namespace != namespace {
|
||||
continue
|
||||
}
|
||||
// TODO(ericchiang): need to implement label selectors?
|
||||
roleBindingList = append(roleBindingList, roleBinding)
|
||||
}
|
||||
return roleBindingList, nil
|
||||
}
|
||||
|
||||
func (r *StaticRoles) ListClusterRoleBindings() ([]*rbac.ClusterRoleBinding, error) {
|
||||
return r.clusterRoleBindings, nil
|
||||
}
|
266
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule_test.go
generated
vendored
Normal file
266
vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule_test.go
generated
vendored
Normal file
@ -0,0 +1,266 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
)
|
||||
|
||||
// compute a hash of a policy rule so we can sort in a deterministic order
|
||||
func hashOf(p rbac.PolicyRule) string {
|
||||
hash := fnv.New32()
|
||||
writeStrings := func(slis ...[]string) {
|
||||
for _, sli := range slis {
|
||||
for _, s := range sli {
|
||||
io.WriteString(hash, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
writeStrings(p.Verbs, p.APIGroups, p.Resources, p.ResourceNames, p.NonResourceURLs)
|
||||
return string(hash.Sum(nil))
|
||||
}
|
||||
|
||||
// byHash sorts a set of policy rules by a hash of its fields
|
||||
type byHash []rbac.PolicyRule
|
||||
|
||||
func (b byHash) Len() int { return len(b) }
|
||||
func (b byHash) Less(i, j int) bool { return hashOf(b[i]) < hashOf(b[j]) }
|
||||
func (b byHash) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||
|
||||
func TestDefaultRuleResolver(t *testing.T) {
|
||||
ruleReadPods := rbac.PolicyRule{
|
||||
Verbs: []string{"GET", "WATCH"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"pods"},
|
||||
}
|
||||
ruleReadServices := rbac.PolicyRule{
|
||||
Verbs: []string{"GET", "WATCH"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"services"},
|
||||
}
|
||||
ruleWriteNodes := rbac.PolicyRule{
|
||||
Verbs: []string{"PUT", "CREATE", "UPDATE"},
|
||||
APIGroups: []string{"v1"},
|
||||
Resources: []string{"nodes"},
|
||||
}
|
||||
ruleAdmin := rbac.PolicyRule{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"*"},
|
||||
}
|
||||
|
||||
staticRoles1 := StaticRoles{
|
||||
roles: []*rbac.Role{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "namespace1", Name: "readthings"},
|
||||
Rules: []rbac.PolicyRule{ruleReadPods, ruleReadServices},
|
||||
},
|
||||
},
|
||||
clusterRoles: []*rbac.ClusterRole{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "cluster-admin"},
|
||||
Rules: []rbac.PolicyRule{ruleAdmin},
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "write-nodes"},
|
||||
Rules: []rbac.PolicyRule{ruleWriteNodes},
|
||||
},
|
||||
},
|
||||
roleBindings: []*rbac.RoleBinding{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{Namespace: "namespace1"},
|
||||
Subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "foobar"},
|
||||
{Kind: rbac.GroupKind, Name: "group1"},
|
||||
},
|
||||
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "readthings"},
|
||||
},
|
||||
},
|
||||
clusterRoleBindings: []*rbac.ClusterRoleBinding{
|
||||
{
|
||||
Subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "admin"},
|
||||
{Kind: rbac.GroupKind, Name: "admin"},
|
||||
},
|
||||
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "cluster-admin"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
StaticRoles
|
||||
|
||||
// For a given context, what are the rules that apply?
|
||||
user user.Info
|
||||
namespace string
|
||||
effectiveRules []rbac.PolicyRule
|
||||
}{
|
||||
{
|
||||
StaticRoles: staticRoles1,
|
||||
user: &user.DefaultInfo{Name: "foobar"},
|
||||
namespace: "namespace1",
|
||||
effectiveRules: []rbac.PolicyRule{ruleReadPods, ruleReadServices},
|
||||
},
|
||||
{
|
||||
StaticRoles: staticRoles1,
|
||||
user: &user.DefaultInfo{Name: "foobar"},
|
||||
namespace: "namespace2",
|
||||
effectiveRules: nil,
|
||||
},
|
||||
{
|
||||
StaticRoles: staticRoles1,
|
||||
// Same as above but without a namespace. Only cluster rules should apply.
|
||||
user: &user.DefaultInfo{Name: "foobar", Groups: []string{"admin"}},
|
||||
effectiveRules: []rbac.PolicyRule{ruleAdmin},
|
||||
},
|
||||
{
|
||||
StaticRoles: staticRoles1,
|
||||
user: &user.DefaultInfo{},
|
||||
effectiveRules: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
ruleResolver := newMockRuleResolver(&tc.StaticRoles)
|
||||
rules, err := ruleResolver.RulesFor(tc.user, tc.namespace)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: GetEffectivePolicyRules(context)=%v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Sort for deep equals
|
||||
sort.Sort(byHash(rules))
|
||||
sort.Sort(byHash(tc.effectiveRules))
|
||||
|
||||
if !reflect.DeepEqual(rules, tc.effectiveRules) {
|
||||
ruleDiff := diff.ObjectDiff(rules, tc.effectiveRules)
|
||||
t.Errorf("case %d: %s", i, ruleDiff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppliesTo(t *testing.T) {
|
||||
tests := []struct {
|
||||
subjects []rbac.Subject
|
||||
user user.Info
|
||||
namespace string
|
||||
appliesTo bool
|
||||
testCase string
|
||||
}{
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "foobar"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "foobar"},
|
||||
appliesTo: true,
|
||||
testCase: "single subject that matches username",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "barfoo"},
|
||||
{Kind: rbac.UserKind, Name: "foobar"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "foobar"},
|
||||
appliesTo: true,
|
||||
testCase: "multiple subjects, one that matches username",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "barfoo"},
|
||||
{Kind: rbac.UserKind, Name: "foobar"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "zimzam"},
|
||||
appliesTo: false,
|
||||
testCase: "multiple subjects, none that match username",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "barfoo"},
|
||||
{Kind: rbac.GroupKind, Name: "foobar"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "zimzam", Groups: []string{"foobar"}},
|
||||
appliesTo: true,
|
||||
testCase: "multiple subjects, one that match group",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "barfoo"},
|
||||
{Kind: rbac.GroupKind, Name: "foobar"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "zimzam", Groups: []string{"foobar"}},
|
||||
namespace: "namespace1",
|
||||
appliesTo: true,
|
||||
testCase: "multiple subjects, one that match group, should ignore namespace",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "barfoo"},
|
||||
{Kind: rbac.GroupKind, Name: "foobar"},
|
||||
{Kind: rbac.ServiceAccountKind, Namespace: "kube-system", Name: "default"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "system:serviceaccount:kube-system:default"},
|
||||
namespace: "default",
|
||||
appliesTo: true,
|
||||
testCase: "multiple subjects with a service account that matches",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.UserKind, Name: "*"},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "foobar"},
|
||||
namespace: "default",
|
||||
appliesTo: false,
|
||||
testCase: "* user subject name doesn't match all users",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.GroupKind, Name: user.AllAuthenticated},
|
||||
{Kind: rbac.GroupKind, Name: user.AllUnauthenticated},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "foobar", Groups: []string{user.AllAuthenticated}},
|
||||
namespace: "default",
|
||||
appliesTo: true,
|
||||
testCase: "binding to all authenticated and unauthenticated subjects matches authenticated user",
|
||||
},
|
||||
{
|
||||
subjects: []rbac.Subject{
|
||||
{Kind: rbac.GroupKind, Name: user.AllAuthenticated},
|
||||
{Kind: rbac.GroupKind, Name: user.AllUnauthenticated},
|
||||
},
|
||||
user: &user.DefaultInfo{Name: "system:anonymous", Groups: []string{user.AllUnauthenticated}},
|
||||
namespace: "default",
|
||||
appliesTo: true,
|
||||
testCase: "binding to all authenticated and unauthenticated subjects matches anonymous user",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
got := appliesTo(tc.user, tc.subjects, tc.namespace)
|
||||
if got != tc.appliesTo {
|
||||
t.Errorf("case %q want appliesTo=%t, got appliesTo=%t", tc.testCase, tc.appliesTo, got)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user