Switch to pointer to policy rule, visit and short circuit during authorization

This commit is contained in:
Jordan Liggitt
2017-04-13 10:33:28 -04:00
parent 2c6fbc95c4
commit 67360883bc
7 changed files with 176 additions and 32 deletions

View File

@@ -39,6 +39,10 @@ type AuthorizationRuleResolver interface {
// 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.
@@ -93,12 +97,31 @@ type ClusterRoleBindingLister interface {
}
func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbac.PolicyRule, error) {
policyRules := []rbac.PolicyRule{}
errorlist := []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 {
errorlist = append(errorlist, err)
if !visitor(nil, err) {
return
}
} else {
for _, clusterRoleBinding := range clusterRoleBindings {
if !appliesTo(user, clusterRoleBinding.Subjects, "") {
@@ -106,17 +129,24 @@ func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbac
}
rules, err := r.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
if err != nil {
errorlist = append(errorlist, err)
if !visitor(nil, err) {
return
}
continue
}
policyRules = append(policyRules, rules...)
for i := range rules {
if !visitor(&rules[i], nil) {
return
}
}
}
}
if len(namespace) > 0 {
if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
errorlist = append(errorlist, err)
if !visitor(nil, err) {
return
}
} else {
for _, roleBinding := range roleBindings {
if !appliesTo(user, roleBinding.Subjects, namespace) {
@@ -124,15 +154,19 @@ func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbac
}
rules, err := r.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
if err != nil {
errorlist = append(errorlist, err)
if !visitor(nil, err) {
return
}
continue
}
policyRules = append(policyRules, rules...)
for i := range rules {
if !visitor(&rules[i], nil) {
return
}
}
}
}
}
return policyRules, utilerrors.NewAggregate(errorlist)
}
// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.

View File

@@ -128,7 +128,7 @@ func TestDefaultRuleResolver(t *testing.T) {
StaticRoles: staticRoles1,
user: &user.DefaultInfo{Name: "foobar"},
namespace: "namespace2",
effectiveRules: []rbac.PolicyRule{},
effectiveRules: nil,
},
{
StaticRoles: staticRoles1,
@@ -139,7 +139,7 @@ func TestDefaultRuleResolver(t *testing.T) {
{
StaticRoles: staticRoles1,
user: &user.DefaultInfo{},
effectiveRules: []rbac.PolicyRule{},
effectiveRules: nil,
},
}