Mostly consistent with upstream - did not remove the reason field
| ... | ... |
@@ -1,6 +1,8 @@ |
| 1 | 1 |
package authorizer |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "errors" |
|
| 5 |
+ |
|
| 4 | 6 |
kapi "k8s.io/kubernetes/pkg/api" |
| 5 | 7 |
"k8s.io/kubernetes/pkg/auth/user" |
| 6 | 8 |
kerrors "k8s.io/kubernetes/pkg/util/errors" |
| ... | ... |
@@ -21,36 +23,20 @@ func NewAuthorizer(ruleResolver rulevalidation.AuthorizationRuleResolver, forbid |
| 21 | 21 |
func (a *openshiftAuthorizer) Authorize(ctx kapi.Context, passedAttributes Action) (bool, string, error) {
|
| 22 | 22 |
attributes := CoerceToDefaultAuthorizationAttributes(passedAttributes) |
| 23 | 23 |
|
| 24 |
- // keep track of errors in case we are unable to authorize the action. |
|
| 25 |
- // It is entirely possible to get an error and be able to continue determine authorization status in spite of it. |
|
| 26 |
- // This is most common when a bound role is missing, but enough roles are still present and bound to authorize the request. |
|
| 27 |
- errs := []error{}
|
|
| 28 |
- |
|
| 29 |
- masterContext := kapi.WithNamespace(ctx, kapi.NamespaceNone) |
|
| 30 |
- globalAllowed, globalReason, err := a.authorizeWithNamespaceRules(masterContext, attributes) |
|
| 31 |
- if globalAllowed {
|
|
| 32 |
- return true, globalReason, nil |
|
| 33 |
- } |
|
| 34 |
- if err != nil {
|
|
| 35 |
- errs = append(errs, err) |
|
| 24 |
+ user, ok := kapi.UserFrom(ctx) |
|
| 25 |
+ if !ok {
|
|
| 26 |
+ return false, "", errors.New("no user available on context")
|
|
| 36 | 27 |
} |
| 37 |
- |
|
| 38 | 28 |
namespace, _ := kapi.NamespaceFrom(ctx) |
| 39 |
- if len(namespace) != 0 {
|
|
| 40 |
- namespaceAllowed, namespaceReason, err := a.authorizeWithNamespaceRules(ctx, attributes) |
|
| 41 |
- if namespaceAllowed {
|
|
| 42 |
- return true, namespaceReason, nil |
|
| 43 |
- } |
|
| 44 |
- if err != nil {
|
|
| 45 |
- errs = append(errs, err) |
|
| 46 |
- } |
|
| 29 |
+ allowed, reason, err := a.authorizeWithNamespaceRules(user, namespace, attributes) |
|
| 30 |
+ if allowed {
|
|
| 31 |
+ return true, reason, nil |
|
| 47 | 32 |
} |
| 48 |
- |
|
| 49 |
- if len(errs) > 0 {
|
|
| 50 |
- return false, "", kerrors.NewAggregate(errs) |
|
| 33 |
+ // errors are allowed to occur |
|
| 34 |
+ if err != nil {
|
|
| 35 |
+ return false, "", err |
|
| 51 | 36 |
} |
| 52 | 37 |
|
| 53 |
- user, _ := kapi.UserFrom(ctx) |
|
| 54 | 38 |
denyReason, err := a.forbiddenMessageMaker.MakeMessage(MessageContext{user, namespace, attributes})
|
| 55 | 39 |
if err != nil {
|
| 56 | 40 |
denyReason = err.Error() |
| ... | ... |
@@ -64,37 +50,18 @@ func (a *openshiftAuthorizer) Authorize(ctx kapi.Context, passedAttributes Actio |
| 64 | 64 |
// This is done because policy rules are purely additive and policy determinations |
| 65 | 65 |
// can be made on the basis of those rules that are found. |
| 66 | 66 |
func (a *openshiftAuthorizer) GetAllowedSubjects(ctx kapi.Context, attributes Action) (sets.String, sets.String, error) {
|
| 67 |
- errs := []error{}
|
|
| 68 |
- |
|
| 69 |
- masterContext := kapi.WithNamespace(ctx, kapi.NamespaceNone) |
|
| 70 |
- globalUsers, globalGroups, err := a.getAllowedSubjectsFromNamespaceBindings(masterContext, attributes) |
|
| 71 |
- if err != nil {
|
|
| 72 |
- errs = append(errs, err) |
|
| 73 |
- } |
|
| 74 |
- localUsers, localGroups, err := a.getAllowedSubjectsFromNamespaceBindings(ctx, attributes) |
|
| 75 |
- if err != nil {
|
|
| 76 |
- errs = append(errs, err) |
|
| 77 |
- } |
|
| 78 |
- |
|
| 79 |
- users := sets.String{}
|
|
| 80 |
- users.Insert(globalUsers.List()...) |
|
| 81 |
- users.Insert(localUsers.List()...) |
|
| 82 |
- |
|
| 83 |
- groups := sets.String{}
|
|
| 84 |
- groups.Insert(globalGroups.List()...) |
|
| 85 |
- groups.Insert(localGroups.List()...) |
|
| 86 |
- |
|
| 87 |
- return users, groups, kerrors.NewAggregate(errs) |
|
| 67 |
+ namespace, _ := kapi.NamespaceFrom(ctx) |
|
| 68 |
+ return a.getAllowedSubjectsFromNamespaceBindings(namespace, attributes) |
|
| 88 | 69 |
} |
| 89 | 70 |
|
| 90 |
-func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(ctx kapi.Context, passedAttributes Action) (sets.String, sets.String, error) {
|
|
| 71 |
+func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(namespace string, passedAttributes Action) (sets.String, sets.String, error) {
|
|
| 91 | 72 |
attributes := CoerceToDefaultAuthorizationAttributes(passedAttributes) |
| 92 | 73 |
|
| 93 |
- errs := []error{}
|
|
| 74 |
+ var errs []error |
|
| 94 | 75 |
|
| 95 |
- roleBindings, err := a.ruleResolver.GetRoleBindings(ctx) |
|
| 76 |
+ roleBindings, err := a.ruleResolver.GetRoleBindings(namespace) |
|
| 96 | 77 |
if err != nil {
|
| 97 |
- return nil, nil, err |
|
| 78 |
+ errs = append(errs, err) |
|
| 98 | 79 |
} |
| 99 | 80 |
|
| 100 | 81 |
users := sets.String{}
|
| ... | ... |
@@ -129,26 +96,34 @@ func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(ctx kapi.C |
| 129 | 129 |
// authorizeWithNamespaceRules returns isAllowed, reason, and error. If an error is returned, isAllowed and reason are still valid. This seems strange |
| 130 | 130 |
// but errors are not always fatal to the authorization process. It is entirely possible to get an error and be able to continue determine authorization |
| 131 | 131 |
// status in spite of it. This is most common when a bound role is missing, but enough roles are still present and bound to authorize the request. |
| 132 |
-func (a *openshiftAuthorizer) authorizeWithNamespaceRules(ctx kapi.Context, passedAttributes Action) (bool, string, error) {
|
|
| 132 |
+func (a *openshiftAuthorizer) authorizeWithNamespaceRules(user user.Info, namespace string, passedAttributes Action) (bool, string, error) {
|
|
| 133 | 133 |
attributes := CoerceToDefaultAuthorizationAttributes(passedAttributes) |
| 134 | 134 |
|
| 135 |
- allRules, ruleRetrievalError := a.ruleResolver.GetEffectivePolicyRules(ctx) |
|
| 135 |
+ allRules, ruleRetrievalError := a.ruleResolver.RulesFor(user, namespace) |
|
| 136 | 136 |
|
| 137 |
+ var errs []error |
|
| 137 | 138 |
for _, rule := range allRules {
|
| 138 | 139 |
matches, err := attributes.RuleMatches(rule) |
| 139 | 140 |
if err != nil {
|
| 140 |
- return false, "", err |
|
| 141 |
+ errs = append(errs, err) |
|
| 142 |
+ continue |
|
| 141 | 143 |
} |
| 142 | 144 |
if matches {
|
| 143 |
- namespace := kapi.NamespaceValue(ctx) |
|
| 144 | 145 |
if len(namespace) == 0 {
|
| 145 | 146 |
return true, "allowed by cluster rule", nil |
| 146 | 147 |
} |
| 148 |
+ // not 100% accurate, because the rule may have been provided by a cluster rule. we no longer have |
|
| 149 |
+ // this distinction upstream in practice. |
|
| 147 | 150 |
return true, "allowed by rule in " + namespace, nil |
| 148 | 151 |
} |
| 149 | 152 |
} |
| 150 |
- |
|
| 151 |
- return false, "", ruleRetrievalError |
|
| 153 |
+ if len(errs) == 0 {
|
|
| 154 |
+ return false, "", ruleRetrievalError |
|
| 155 |
+ } |
|
| 156 |
+ if ruleRetrievalError != nil {
|
|
| 157 |
+ errs = append(errs, ruleRetrievalError) |
|
| 158 |
+ } |
|
| 159 |
+ return false, "", kerrors.NewAggregate(errs) |
|
| 152 | 160 |
} |
| 153 | 161 |
|
| 154 | 162 |
// TODO this may or may not be the behavior we want for managing rules. As a for instance, a verb might be specified |
| ... | ... |
@@ -414,7 +414,7 @@ func TestGlobalPolicyOutranksLocalPolicy(t *testing.T) {
|
| 414 | 414 |
Resource: "roles", |
| 415 | 415 |
}, |
| 416 | 416 |
expectedAllowed: true, |
| 417 |
- expectedReason: "allowed by cluster rule", |
|
| 417 |
+ expectedReason: "allowed by rule in adze", |
|
| 418 | 418 |
} |
| 419 | 419 |
test.clusterPolicies = newDefaultClusterPolicies() |
| 420 | 420 |
test.policies = append(test.policies, newAdzePolicies()...) |
| ... | ... |
@@ -23,7 +23,7 @@ func TestClusterAdminUseGroup(t *testing.T) {
|
| 23 | 23 |
Resource: "jobs", |
| 24 | 24 |
}, |
| 25 | 25 |
expectedAllowed: true, |
| 26 |
- expectedReason: "allowed by cluster rule", |
|
| 26 |
+ expectedReason: "allowed by rule in mallet", |
|
| 27 | 27 |
} |
| 28 | 28 |
test.clusterPolicies = newDefaultClusterPolicies() |
| 29 | 29 |
test.clusterBindings = newDefaultClusterPolicyBindings() |
| ... | ... |
@@ -40,7 +40,7 @@ func TestClusterReaderUseGroup(t *testing.T) {
|
| 40 | 40 |
Resource: "jobs", |
| 41 | 41 |
}, |
| 42 | 42 |
expectedAllowed: true, |
| 43 |
- expectedReason: "allowed by cluster rule", |
|
| 43 |
+ expectedReason: "allowed by rule in mallet", |
|
| 44 | 44 |
} |
| 45 | 45 |
test.clusterPolicies = newDefaultClusterPolicies() |
| 46 | 46 |
test.clusterBindings = newDefaultClusterPolicyBindings() |
| ... | ... |
@@ -74,26 +74,15 @@ func GetEffectivePolicyRules(ctx kapi.Context, ruleResolver rulevalidation.Autho |
| 74 | 74 |
return nil, []error{kapierrors.NewBadRequest(fmt.Sprintf("user missing from context"))}
|
| 75 | 75 |
} |
| 76 | 76 |
|
| 77 |
- errors := []error{}
|
|
| 78 |
- rules := []authorizationapi.PolicyRule{}
|
|
| 79 |
- |
|
| 80 |
- namespaceRules, err := ruleResolver.GetEffectivePolicyRules(ctx) |
|
| 77 |
+ var errors []error |
|
| 78 |
+ var rules []authorizationapi.PolicyRule |
|
| 79 |
+ namespaceRules, err := ruleResolver.RulesFor(user, namespace) |
|
| 81 | 80 |
if err != nil {
|
| 82 | 81 |
errors = append(errors, err) |
| 83 | 82 |
} |
| 84 | 83 |
for _, rule := range namespaceRules {
|
| 85 | 84 |
rules = append(rules, rulevalidation.BreakdownRule(rule)...) |
| 86 | 85 |
} |
| 87 |
- if len(namespace) != 0 {
|
|
| 88 |
- masterContext := kapi.WithNamespace(ctx, kapi.NamespaceNone) |
|
| 89 |
- clusterRules, err := ruleResolver.GetEffectivePolicyRules(masterContext) |
|
| 90 |
- if err != nil {
|
|
| 91 |
- errors = append(errors, err) |
|
| 92 |
- } |
|
| 93 |
- for _, rule := range clusterRules {
|
|
| 94 |
- rules = append(rules, rulevalidation.BreakdownRule(rule)...) |
|
| 95 |
- } |
|
| 96 |
- } |
|
| 97 | 86 |
|
| 98 | 87 |
if scopes := user.GetExtra()[authorizationapi.ScopesKey]; len(scopes) > 0 {
|
| 99 | 88 |
rules, err = filterRulesByScopes(rules, scopes, namespace, clusterPolicyGetter) |
| ... | ... |
@@ -1,8 +1,6 @@ |
| 1 | 1 |
package rulevalidation |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "errors" |
|
| 5 |
- |
|
| 6 | 4 |
kapi "k8s.io/kubernetes/pkg/api" |
| 7 | 5 |
kapierror "k8s.io/kubernetes/pkg/api/errors" |
| 8 | 6 |
"k8s.io/kubernetes/pkg/auth/user" |
| ... | ... |
@@ -27,48 +25,57 @@ func NewDefaultRuleResolver(policyGetter client.PoliciesListerNamespacer, bindin |
| 27 | 27 |
} |
| 28 | 28 |
|
| 29 | 29 |
type AuthorizationRuleResolver interface {
|
| 30 |
- GetRoleBindings(ctx kapi.Context) ([]authorizationinterfaces.RoleBinding, error) |
|
| 30 |
+ GetRoleBindings(namespace string) ([]authorizationinterfaces.RoleBinding, error) |
|
| 31 | 31 |
GetRole(roleBinding authorizationinterfaces.RoleBinding) (authorizationinterfaces.Role, error) |
| 32 |
- // GetEffectivePolicyRules 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 |
|
| 32 |
+ // 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 |
|
| 33 | 33 |
// PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations |
| 34 | 34 |
// can be made on the basis of those rules that are found. |
| 35 |
- GetEffectivePolicyRules(ctx kapi.Context) ([]authorizationapi.PolicyRule, error) |
|
| 35 |
+ RulesFor(info user.Info, namespace string) ([]authorizationapi.PolicyRule, error) |
|
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
-func (a *DefaultRuleResolver) GetRoleBindings(ctx kapi.Context) ([]authorizationinterfaces.RoleBinding, error) {
|
|
| 39 |
- namespace := kapi.NamespaceValue(ctx) |
|
| 38 |
+func (a *DefaultRuleResolver) GetRoleBindings(namespace string) ([]authorizationinterfaces.RoleBinding, error) {
|
|
| 39 |
+ clusterBindings, clusterErr := a.clusterBindingLister.List(kapi.ListOptions{})
|
|
| 40 | 40 |
|
| 41 |
- if len(namespace) == 0 {
|
|
| 42 |
- policyBindingList, err := a.clusterBindingLister.List(kapi.ListOptions{})
|
|
| 43 |
- if err != nil {
|
|
| 44 |
- return nil, err |
|
| 45 |
- } |
|
| 41 |
+ var namespaceBindings *authorizationapi.PolicyBindingList |
|
| 42 |
+ var namespaceErr error |
|
| 43 |
+ if a.bindingLister != nil && len(namespace) > 0 {
|
|
| 44 |
+ namespaceBindings, namespaceErr = a.bindingLister.PolicyBindings(namespace).List(kapi.ListOptions{})
|
|
| 45 |
+ } |
|
| 46 | 46 |
|
| 47 |
- ret := make([]authorizationinterfaces.RoleBinding, 0, len(policyBindingList.Items)) |
|
| 48 |
- for _, policyBinding := range policyBindingList.Items {
|
|
| 47 |
+ // return all loaded bindings |
|
| 48 |
+ expect := 0 |
|
| 49 |
+ if clusterBindings != nil {
|
|
| 50 |
+ expect += len(clusterBindings.Items) |
|
| 51 |
+ } |
|
| 52 |
+ if namespaceBindings != nil {
|
|
| 53 |
+ expect += len(namespaceBindings.Items) |
|
| 54 |
+ } |
|
| 55 |
+ bindings := make([]authorizationinterfaces.RoleBinding, 0, expect) |
|
| 56 |
+ if clusterBindings != nil {
|
|
| 57 |
+ for _, policyBinding := range clusterBindings.Items {
|
|
| 49 | 58 |
for _, value := range policyBinding.RoleBindings {
|
| 50 |
- ret = append(ret, authorizationinterfaces.NewClusterRoleBindingAdapter(value)) |
|
| 59 |
+ bindings = append(bindings, authorizationinterfaces.NewClusterRoleBindingAdapter(value)) |
|
| 51 | 60 |
} |
| 52 | 61 |
} |
| 53 |
- return ret, nil |
|
| 54 | 62 |
} |
| 55 |
- |
|
| 56 |
- if a.bindingLister == nil {
|
|
| 57 |
- return nil, nil |
|
| 63 |
+ if namespaceBindings != nil {
|
|
| 64 |
+ for _, policyBinding := range namespaceBindings.Items {
|
|
| 65 |
+ for _, value := range policyBinding.RoleBindings {
|
|
| 66 |
+ bindings = append(bindings, authorizationinterfaces.NewLocalRoleBindingAdapter(value)) |
|
| 67 |
+ } |
|
| 68 |
+ } |
|
| 58 | 69 |
} |
| 59 | 70 |
|
| 60 |
- policyBindingList, err := a.bindingLister.PolicyBindings(namespace).List(kapi.ListOptions{})
|
|
| 61 |
- if err != nil {
|
|
| 62 |
- return nil, err |
|
| 71 |
+ // return all errors |
|
| 72 |
+ var errs []error |
|
| 73 |
+ if clusterErr != nil {
|
|
| 74 |
+ errs = append(errs, clusterErr) |
|
| 63 | 75 |
} |
| 64 |
- |
|
| 65 |
- ret := make([]authorizationinterfaces.RoleBinding, 0, len(policyBindingList.Items)) |
|
| 66 |
- for _, policyBinding := range policyBindingList.Items {
|
|
| 67 |
- for _, value := range policyBinding.RoleBindings {
|
|
| 68 |
- ret = append(ret, authorizationinterfaces.NewLocalRoleBindingAdapter(value)) |
|
| 69 |
- } |
|
| 76 |
+ if namespaceErr != nil {
|
|
| 77 |
+ errs = append(errs, namespaceErr) |
|
| 70 | 78 |
} |
| 71 |
- return ret, nil |
|
| 79 |
+ |
|
| 80 |
+ return bindings, kerrors.NewAggregate(errs) |
|
| 72 | 81 |
} |
| 73 | 82 |
|
| 74 | 83 |
func (a *DefaultRuleResolver) GetRole(roleBinding authorizationinterfaces.RoleBinding) (authorizationinterfaces.Role, error) {
|
| ... | ... |
@@ -113,20 +120,17 @@ func (a *DefaultRuleResolver) GetRole(roleBinding authorizationinterfaces.RoleBi |
| 113 | 113 |
|
| 114 | 114 |
} |
| 115 | 115 |
|
| 116 |
-// GetEffectivePolicyRules 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 |
|
| 116 |
+// 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 |
|
| 117 | 117 |
// PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations |
| 118 | 118 |
// can be made on the basis of those rules that are found. |
| 119 |
-func (a *DefaultRuleResolver) GetEffectivePolicyRules(ctx kapi.Context) ([]authorizationapi.PolicyRule, error) {
|
|
| 120 |
- roleBindings, err := a.GetRoleBindings(ctx) |
|
| 119 |
+func (a *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]authorizationapi.PolicyRule, error) {
|
|
| 120 |
+ var errs []error |
|
| 121 |
+ |
|
| 122 |
+ roleBindings, err := a.GetRoleBindings(namespace) |
|
| 121 | 123 |
if err != nil {
|
| 122 |
- return nil, err |
|
| 123 |
- } |
|
| 124 |
- user, exists := kapi.UserFrom(ctx) |
|
| 125 |
- if !exists {
|
|
| 126 |
- return nil, errors.New("user missing from context")
|
|
| 124 |
+ errs = append(errs, err) |
|
| 127 | 125 |
} |
| 128 | 126 |
|
| 129 |
- errs := []error{}
|
|
| 130 | 127 |
rules := make([]authorizationapi.PolicyRule, 0, len(roleBindings)) |
| 131 | 128 |
for _, roleBinding := range roleBindings {
|
| 132 | 129 |
if !roleBinding.AppliesToUser(user) {
|
| ... | ... |
@@ -146,6 +150,7 @@ func (a *DefaultRuleResolver) GetEffectivePolicyRules(ctx kapi.Context) ([]autho |
| 146 | 146 |
|
| 147 | 147 |
return rules, kerrors.NewAggregate(errs) |
| 148 | 148 |
} |
| 149 |
+ |
|
| 149 | 150 |
func appliesToUser(ruleUsers, ruleGroups sets.String, user user.Info) bool {
|
| 150 | 151 |
if ruleUsers.Has(user.GetName()) {
|
| 151 | 152 |
return true |
| ... | ... |
@@ -11,53 +11,46 @@ import ( |
| 11 | 11 |
kapierrors "k8s.io/kubernetes/pkg/api/errors" |
| 12 | 12 |
"k8s.io/kubernetes/pkg/api/unversioned" |
| 13 | 13 |
|
| 14 |
- authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
|
| 15 | 14 |
authorizationinterfaces "github.com/openshift/origin/pkg/authorization/interfaces" |
| 16 | 15 |
) |
| 17 | 16 |
|
| 18 | 17 |
func ConfirmNoEscalation(ctx kapi.Context, resource unversioned.GroupResource, name string, ruleResolver AuthorizationRuleResolver, role authorizationinterfaces.Role) error {
|
| 19 |
- ruleResolutionErrors := []error{}
|
|
| 18 |
+ var ruleResolutionErrors []error |
|
| 20 | 19 |
|
| 21 |
- ownerLocalRules, err := ruleResolver.GetEffectivePolicyRules(ctx) |
|
| 22 |
- if err != nil {
|
|
| 23 |
- // do not fail in this case. Rules are purely additive, so we can continue with a coverage check based on the rules we have |
|
| 24 |
- user, _ := kapi.UserFrom(ctx) |
|
| 25 |
- glog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err)
|
|
| 26 |
- ruleResolutionErrors = append(ruleResolutionErrors, err) |
|
| 20 |
+ user, ok := kapi.UserFrom(ctx) |
|
| 21 |
+ if !ok {
|
|
| 22 |
+ return kapierrors.NewForbidden(resource, name, fmt.Errorf("no user provided in context"))
|
|
| 27 | 23 |
} |
| 28 |
- masterContext := kapi.WithNamespace(ctx, "") |
|
| 29 |
- ownerGlobalRules, err := ruleResolver.GetEffectivePolicyRules(masterContext) |
|
| 24 |
+ namespace, _ := kapi.NamespaceFrom(ctx) |
|
| 25 |
+ |
|
| 26 |
+ ownerRules, err := ruleResolver.RulesFor(user, namespace) |
|
| 30 | 27 |
if err != nil {
|
| 31 | 28 |
// do not fail in this case. Rules are purely additive, so we can continue with a coverage check based on the rules we have |
| 32 |
- user, _ := kapi.UserFrom(ctx) |
|
| 33 |
- glog.V(1).Infof("non-fatal error getting global rules for %v: %v", user, err)
|
|
| 29 |
+ glog.V(1).Infof("non-fatal error getting rules for %v: %v", user, err)
|
|
| 34 | 30 |
ruleResolutionErrors = append(ruleResolutionErrors, err) |
| 35 | 31 |
} |
| 36 | 32 |
|
| 37 |
- ownerRules := make([]authorizationapi.PolicyRule, 0, len(ownerGlobalRules)+len(ownerLocalRules)) |
|
| 38 |
- ownerRules = append(ownerRules, ownerLocalRules...) |
|
| 39 |
- ownerRules = append(ownerRules, ownerGlobalRules...) |
|
| 40 |
- |
|
| 41 | 33 |
ownerRightsCover, missingRights := Covers(ownerRules, role.Rules()) |
| 42 |
- if !ownerRightsCover {
|
|
| 43 |
- if compactedMissingRights, err := CompactRules(missingRights); err == nil {
|
|
| 44 |
- missingRights = compactedMissingRights |
|
| 45 |
- } |
|
| 46 |
- |
|
| 47 |
- missingRightsStrings := make([]string, 0, len(missingRights)) |
|
| 48 |
- for _, missingRight := range missingRights {
|
|
| 49 |
- missingRightsStrings = append(missingRightsStrings, missingRight.CompactString()) |
|
| 50 |
- } |
|
| 51 |
- sort.Strings(missingRightsStrings) |
|
| 52 |
- user, _ := kapi.UserFrom(ctx) |
|
| 53 |
- var internalErr error |
|
| 54 |
- if len(ruleResolutionErrors) > 0 {
|
|
| 55 |
- internalErr = fmt.Errorf("user %q cannot grant extra privileges:\n%v\nrule resolution errors: %v)", user.GetName(), strings.Join(missingRightsStrings, "\n"), ruleResolutionErrors)
|
|
| 56 |
- } else {
|
|
| 57 |
- internalErr = fmt.Errorf("user %q cannot grant extra privileges:\n%v", user.GetName(), strings.Join(missingRightsStrings, "\n"))
|
|
| 58 |
- } |
|
| 59 |
- return kapierrors.NewForbidden(resource, name, internalErr) |
|
| 34 |
+ if ownerRightsCover {
|
|
| 35 |
+ return nil |
|
| 60 | 36 |
} |
| 61 | 37 |
|
| 62 |
- return nil |
|
| 38 |
+ // determine what resources the user is missing |
|
| 39 |
+ if compactedMissingRights, err := CompactRules(missingRights); err == nil {
|
|
| 40 |
+ missingRights = compactedMissingRights |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ missingRightsStrings := make([]string, 0, len(missingRights)) |
|
| 44 |
+ for _, missingRight := range missingRights {
|
|
| 45 |
+ missingRightsStrings = append(missingRightsStrings, missingRight.CompactString()) |
|
| 46 |
+ } |
|
| 47 |
+ sort.Strings(missingRightsStrings) |
|
| 48 |
+ |
|
| 49 |
+ var internalErr error |
|
| 50 |
+ if len(ruleResolutionErrors) > 0 {
|
|
| 51 |
+ internalErr = fmt.Errorf("user %q cannot grant extra privileges:\n%v\nrule resolution errors: %v)", user.GetName(), strings.Join(missingRightsStrings, "\n"), ruleResolutionErrors)
|
|
| 52 |
+ } else {
|
|
| 53 |
+ internalErr = fmt.Errorf("user %q cannot grant extra privileges:\n%v", user.GetName(), strings.Join(missingRightsStrings, "\n"))
|
|
| 54 |
+ } |
|
| 55 |
+ return kapierrors.NewForbidden(resource, name, internalErr) |
|
| 63 | 56 |
} |
| ... | ... |
@@ -730,7 +730,7 @@ func TestAuthorizationSubjectAccessReviewAPIGroup(t *testing.T) {
|
| 730 | 730 |
}, |
| 731 | 731 |
response: authorizationapi.SubjectAccessReviewResponse{
|
| 732 | 732 |
Allowed: true, |
| 733 |
- Reason: "allowed by cluster rule", |
|
| 733 |
+ Reason: "allowed by rule in any-project", |
|
| 734 | 734 |
Namespace: "any-project", |
| 735 | 735 |
}, |
| 736 | 736 |
}.run(t) |
| ... | ... |
@@ -742,7 +742,7 @@ func TestAuthorizationSubjectAccessReviewAPIGroup(t *testing.T) {
|
| 742 | 742 |
}, |
| 743 | 743 |
response: authorizationapi.SubjectAccessReviewResponse{
|
| 744 | 744 |
Allowed: true, |
| 745 |
- Reason: "allowed by cluster rule", |
|
| 745 |
+ Reason: "allowed by rule in any-project", |
|
| 746 | 746 |
Namespace: "any-project", |
| 747 | 747 |
}, |
| 748 | 748 |
}.run(t) |
| ... | ... |
@@ -754,7 +754,7 @@ func TestAuthorizationSubjectAccessReviewAPIGroup(t *testing.T) {
|
| 754 | 754 |
}, |
| 755 | 755 |
response: authorizationapi.SubjectAccessReviewResponse{
|
| 756 | 756 |
Allowed: true, |
| 757 |
- Reason: "allowed by cluster rule", |
|
| 757 |
+ Reason: "allowed by rule in any-project", |
|
| 758 | 758 |
Namespace: "any-project", |
| 759 | 759 |
}, |
| 760 | 760 |
}.run(t) |
| ... | ... |
@@ -766,7 +766,7 @@ func TestAuthorizationSubjectAccessReviewAPIGroup(t *testing.T) {
|
| 766 | 766 |
}, |
| 767 | 767 |
response: authorizationapi.SubjectAccessReviewResponse{
|
| 768 | 768 |
Allowed: true, |
| 769 |
- Reason: "allowed by cluster rule", |
|
| 769 |
+ Reason: "allowed by rule in any-project", |
|
| 770 | 770 |
Namespace: "any-project", |
| 771 | 771 |
}, |
| 772 | 772 |
}.run(t) |