Skip to content

Commit ef6c956

Browse files
committed
switch to using interface for authorization matches
1 parent 891ef8b commit ef6c956

File tree

5 files changed

+28
-54
lines changed

5 files changed

+28
-54
lines changed

pkg/authorization/authorizer/attributes.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type DefaultAuthorizationAttributes struct {
2121

2222
// ToDefaultAuthorizationAttributes coerces Action to DefaultAuthorizationAttributes. Namespace is not included
2323
// because the authorizer takes that information on the context
24-
func ToDefaultAuthorizationAttributes(in authorizationapi.Action) DefaultAuthorizationAttributes {
24+
func ToDefaultAuthorizationAttributes(in authorizationapi.Action) Action {
2525
return DefaultAuthorizationAttributes{
2626
Verb: in.Verb,
2727
APIGroup: in.Group,
@@ -33,10 +33,10 @@ func ToDefaultAuthorizationAttributes(in authorizationapi.Action) DefaultAuthori
3333
}
3434
}
3535

36-
func (a DefaultAuthorizationAttributes) RuleMatches(rule authorizationapi.PolicyRule) (bool, error) {
36+
func RuleMatches(a Action, rule authorizationapi.PolicyRule) (bool, error) {
3737
if a.IsNonResourceURL() {
38-
if a.nonResourceMatches(rule) {
39-
if a.verbMatches(rule.Verbs) {
38+
if nonResourceMatches(a, rule) {
39+
if verbMatches(a, rule.Verbs) {
4040
return true, nil
4141
}
4242
}
@@ -50,12 +50,12 @@ func (a DefaultAuthorizationAttributes) RuleMatches(rule authorizationapi.Policy
5050
return false, nil
5151
}
5252

53-
if a.verbMatches(rule.Verbs) {
54-
if a.apiGroupMatches(rule.APIGroups) {
53+
if verbMatches(a, rule.Verbs) {
54+
if apiGroupMatches(a, rule.APIGroups) {
5555

5656
allowedResourceTypes := authorizationapi.NormalizeResources(rule.Resources)
57-
if a.resourceMatches(allowedResourceTypes) {
58-
if a.nameMatches(rule.ResourceNames) {
57+
if resourceMatches(a, allowedResourceTypes) {
58+
if nameMatches(a, rule.ResourceNames) {
5959
return true, nil
6060
}
6161
}
@@ -65,7 +65,7 @@ func (a DefaultAuthorizationAttributes) RuleMatches(rule authorizationapi.Policy
6565
return false, nil
6666
}
6767

68-
func (a DefaultAuthorizationAttributes) apiGroupMatches(allowedGroups []string) bool {
68+
func apiGroupMatches(a Action, allowedGroups []string) bool {
6969
// allowedGroups is expected to be small, so I don't feel bad about this.
7070
for _, allowedGroup := range allowedGroups {
7171
if allowedGroup == authorizationapi.APIGroupAll {
@@ -80,32 +80,28 @@ func (a DefaultAuthorizationAttributes) apiGroupMatches(allowedGroups []string)
8080
return false
8181
}
8282

83-
func (a DefaultAuthorizationAttributes) verbMatches(verbs sets.String) bool {
83+
func verbMatches(a Action, verbs sets.String) bool {
8484
return verbs.Has(authorizationapi.VerbAll) || verbs.Has(strings.ToLower(a.GetVerb()))
8585
}
8686

87-
func (a DefaultAuthorizationAttributes) resourceMatches(allowedResourceTypes sets.String) bool {
87+
func resourceMatches(a Action, allowedResourceTypes sets.String) bool {
8888
return allowedResourceTypes.Has(authorizationapi.ResourceAll) || allowedResourceTypes.Has(strings.ToLower(a.GetResource()))
8989
}
9090

9191
// nameMatches checks to see if the resourceName of the action is in a the specified whitelist. An empty whitelist indicates that any name is allowed.
9292
// An empty string in the whitelist should only match the action's resourceName if the resourceName itself is empty string. This behavior allows for the
9393
// combination of a whitelist for gets in the same rule as a list that won't have a resourceName. I don't recommend writing such a rule, but we do
9494
// handle it like you'd expect: white list is respected for gets while not preventing the list you explicitly asked for.
95-
func (a DefaultAuthorizationAttributes) nameMatches(allowedResourceNames sets.String) bool {
95+
func nameMatches(a Action, allowedResourceNames sets.String) bool {
9696
if len(allowedResourceNames) == 0 {
9797
return true
9898
}
9999

100100
return allowedResourceNames.Has(a.GetResourceName())
101101
}
102102

103-
func (a DefaultAuthorizationAttributes) GetVerb() string {
104-
return a.Verb
105-
}
106-
107103
// nonResourceMatches take the remainer of a URL and attempts to match it against a series of explicitly allowed steps that can end in a wildcard
108-
func (a DefaultAuthorizationAttributes) nonResourceMatches(rule authorizationapi.PolicyRule) bool {
104+
func nonResourceMatches(a Action, rule authorizationapi.PolicyRule) bool {
109105
for allowedNonResourcePath := range rule.NonResourceURLs {
110106
// if the allowed resource path ends in a wildcard, check to see if the URL starts with it
111107
if strings.HasSuffix(allowedNonResourcePath, "*") {
@@ -135,6 +131,10 @@ func splitPath(thePath string) []string {
135131
// DefaultAuthorizationAttributes satisfies the Action interface
136132
var _ Action = DefaultAuthorizationAttributes{}
137133

134+
func (a DefaultAuthorizationAttributes) GetVerb() string {
135+
return a.Verb
136+
}
137+
138138
func (a DefaultAuthorizationAttributes) GetAPIVersion() string {
139139
return a.APIVersion
140140
}

pkg/authorization/authorizer/authorizer.go

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ func NewAuthorizer(ruleResolver rulevalidation.AuthorizationRuleResolver, forbid
2020
return &openshiftAuthorizer{ruleResolver, forbiddenMessageMaker}
2121
}
2222

23-
func (a *openshiftAuthorizer) Authorize(ctx kapi.Context, passedAttributes Action) (bool, string, error) {
24-
attributes := CoerceToDefaultAuthorizationAttributes(passedAttributes)
25-
23+
func (a *openshiftAuthorizer) Authorize(ctx kapi.Context, attributes Action) (bool, string, error) {
2624
user, ok := kapi.UserFrom(ctx)
2725
if !ok {
2826
return false, "", errors.New("no user available on context")
@@ -54,9 +52,7 @@ func (a *openshiftAuthorizer) GetAllowedSubjects(ctx kapi.Context, attributes Ac
5452
return a.getAllowedSubjectsFromNamespaceBindings(namespace, attributes)
5553
}
5654

57-
func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(namespace string, passedAttributes Action) (sets.String, sets.String, error) {
58-
attributes := CoerceToDefaultAuthorizationAttributes(passedAttributes)
59-
55+
func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(namespace string, attributes Action) (sets.String, sets.String, error) {
6056
var errs []error
6157

6258
roleBindings, err := a.ruleResolver.GetRoleBindings(namespace)
@@ -77,7 +73,7 @@ func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(namespace
7773
}
7874

7975
for _, rule := range role.Rules() {
80-
matches, err := attributes.RuleMatches(rule)
76+
matches, err := RuleMatches(attributes, rule)
8177
if err != nil {
8278
errs = append(errs, err)
8379
continue
@@ -96,14 +92,12 @@ func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(namespace
9692
// authorizeWithNamespaceRules returns isAllowed, reason, and error. If an error is returned, isAllowed and reason are still valid. This seems strange
9793
// 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
9894
// 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.
99-
func (a *openshiftAuthorizer) authorizeWithNamespaceRules(user user.Info, namespace string, passedAttributes Action) (bool, string, error) {
100-
attributes := CoerceToDefaultAuthorizationAttributes(passedAttributes)
101-
95+
func (a *openshiftAuthorizer) authorizeWithNamespaceRules(user user.Info, namespace string, attributes Action) (bool, string, error) {
10296
allRules, ruleRetrievalError := a.ruleResolver.RulesFor(user, namespace)
10397

10498
var errs []error
10599
for _, rule := range allRules {
106-
matches, err := attributes.RuleMatches(rule)
100+
matches, err := RuleMatches(attributes, rule)
107101
if err != nil {
108102
errs = append(errs, err)
109103
continue
@@ -126,24 +120,6 @@ func (a *openshiftAuthorizer) authorizeWithNamespaceRules(user user.Info, namesp
126120
return false, "", kerrors.NewAggregate(errs)
127121
}
128122

129-
// TODO this may or may not be the behavior we want for managing rules. As a for instance, a verb might be specified
130-
// that our attributes builder will never satisfy. For now, I think gets us close. Maybe a warning message of some kind?
131-
func CoerceToDefaultAuthorizationAttributes(passedAttributes Action) *DefaultAuthorizationAttributes {
132-
attributes, ok := passedAttributes.(*DefaultAuthorizationAttributes)
133-
if !ok {
134-
attributes = &DefaultAuthorizationAttributes{
135-
APIGroup: passedAttributes.GetAPIGroup(),
136-
Verb: passedAttributes.GetVerb(),
137-
Resource: passedAttributes.GetResource(),
138-
ResourceName: passedAttributes.GetResourceName(),
139-
NonResourceURL: passedAttributes.IsNonResourceURL(),
140-
URL: passedAttributes.GetURL(),
141-
}
142-
}
143-
144-
return attributes
145-
}
146-
147123
func doesApplyToUser(ruleUsers, ruleGroups sets.String, user user.Info) bool {
148124
if ruleUsers.Has(user.GetName()) {
149125
return true

pkg/authorization/authorizer/non_resource_match_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func (test *nonResourceMatchTest) run(t *testing.T) {
6767

6868
rule := authorizationapi.PolicyRule{NonResourceURLs: sets.NewString(test.matcher)}
6969

70-
result := attributes.nonResourceMatches(rule)
70+
result := nonResourceMatches(attributes, rule)
7171

7272
if result != test.expectedResult {
7373
t.Errorf("Expected %v, got %v", test.expectedResult, result)

pkg/authorization/authorizer/scope/authorizer.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ func NewAuthorizer(delegate defaultauthorizer.Authorizer, clusterPolicyGetter cl
2323
return &scopeAuthorizer{delegate: delegate, clusterPolicyGetter: clusterPolicyGetter, forbiddenMessageMaker: forbiddenMessageMaker}
2424
}
2525

26-
func (a *scopeAuthorizer) Authorize(ctx kapi.Context, passedAttributes defaultauthorizer.Action) (bool, string, error) {
26+
func (a *scopeAuthorizer) Authorize(ctx kapi.Context, attributes defaultauthorizer.Action) (bool, string, error) {
2727
user, exists := kapi.UserFrom(ctx)
2828
if !exists {
2929
return false, "", fmt.Errorf("user missing from context")
3030
}
3131

3232
scopes := user.GetExtra()[authorizationapi.ScopesKey]
3333
if len(scopes) == 0 {
34-
return a.delegate.Authorize(ctx, passedAttributes)
34+
return a.delegate.Authorize(ctx, attributes)
3535
}
3636

3737
nonFatalErrors := []error{}
@@ -43,17 +43,15 @@ func (a *scopeAuthorizer) Authorize(ctx kapi.Context, passedAttributes defaultau
4343
nonFatalErrors = append(nonFatalErrors, err)
4444
}
4545

46-
attributes := defaultauthorizer.CoerceToDefaultAuthorizationAttributes(passedAttributes)
47-
4846
for _, rule := range rules {
4947
// check rule against attributes
50-
matches, err := attributes.RuleMatches(rule)
48+
matches, err := defaultauthorizer.RuleMatches(attributes, rule)
5149
if err != nil {
5250
nonFatalErrors = append(nonFatalErrors, err)
5351
continue
5452
}
5553
if matches {
56-
return a.delegate.Authorize(ctx, passedAttributes)
54+
return a.delegate.Authorize(ctx, attributes)
5755
}
5856
}
5957

pkg/authorization/authorizer/scope/converter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ func (e clusterRoleEvaluator) ResolveGettableNamespaces(scope string, clusterPol
357357

358358
errors := []error{}
359359
for _, rule := range rules {
360-
matches, err := attributes.RuleMatches(rule)
360+
matches, err := authorizer.RuleMatches(attributes, rule)
361361
if err != nil {
362362
errors = append(errors, err)
363363
continue

0 commit comments

Comments
 (0)