This repository has been archived by the owner on Jul 18, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
authorizer.go
118 lines (101 loc) · 4.05 KB
/
authorizer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package authorizer
import (
"errors"
kerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apiserver/pkg/authorization/authorizer"
"github.com/openshift/origin/pkg/authorization/rulevalidation"
)
type openshiftAuthorizer struct {
ruleResolver rulevalidation.AuthorizationRuleResolver
forbiddenMessageMaker ForbiddenMessageMaker
}
func NewAuthorizer(ruleResolver rulevalidation.AuthorizationRuleResolver, forbiddenMessageMaker ForbiddenMessageMaker) (authorizer.Authorizer, SubjectLocator) {
ret := &openshiftAuthorizer{ruleResolver, forbiddenMessageMaker}
return ret, ret
}
func (a *openshiftAuthorizer) Authorize(attributes authorizer.Attributes) (bool, string, error) {
if attributes.GetUser() == nil {
return false, "", errors.New("no user available on context")
}
allowed, reason, err := a.authorizeWithNamespaceRules(attributes)
if allowed {
return true, reason, nil
}
// errors are allowed to occur
if err != nil {
return false, "", err
}
denyReason, err := a.forbiddenMessageMaker.MakeMessage(attributes)
if err != nil {
denyReason = err.Error()
}
return false, denyReason, nil
}
// GetAllowedSubjects returns the subjects it knows can perform the action.
// If we got an error, then the list of subjects may not be complete, but it does not contain any incorrect names.
// This is done because policy rules are purely additive and policy determinations
// can be made on the basis of those rules that are found.
func (a *openshiftAuthorizer) GetAllowedSubjects(attributes authorizer.Attributes) (sets.String, sets.String, error) {
return a.getAllowedSubjectsFromNamespaceBindings(attributes)
}
func (a *openshiftAuthorizer) getAllowedSubjectsFromNamespaceBindings(attributes authorizer.Attributes) (sets.String, sets.String, error) {
var errs []error
roleBindings, err := a.ruleResolver.GetRoleBindings(attributes.GetNamespace())
if err != nil {
errs = append(errs, err)
}
users := sets.String{}
groups := sets.String{}
for _, roleBinding := range roleBindings {
role, err := a.ruleResolver.GetRole(roleBinding)
if err != nil {
// If we got an error, then the list of subjects may not be complete, but it does not contain any incorrect names.
// This is done because policy rules are purely additive and policy determinations
// can be made on the basis of those rules that are found.
errs = append(errs, err)
continue
}
for _, rule := range role.Rules() {
matches, err := RuleMatches(attributes, rule)
if err != nil {
errs = append(errs, err)
continue
}
if matches {
users.Insert(roleBinding.Users().List()...)
groups.Insert(roleBinding.Groups().List()...)
}
}
}
return users, groups, kerrors.NewAggregate(errs)
}
// authorizeWithNamespaceRules returns isAllowed, reason, and error. If an error is returned, isAllowed and reason are still valid. This seems strange
// 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
// 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.
func (a *openshiftAuthorizer) authorizeWithNamespaceRules(attributes authorizer.Attributes) (bool, string, error) {
allRules, ruleRetrievalError := a.ruleResolver.RulesFor(attributes.GetUser(), attributes.GetNamespace())
var errs []error
for _, rule := range allRules {
matches, err := RuleMatches(attributes, rule)
if err != nil {
errs = append(errs, err)
continue
}
if matches {
if len(attributes.GetNamespace()) == 0 {
return true, "allowed by cluster rule", nil
}
// not 100% accurate, because the rule may have been provided by a cluster rule. we no longer have
// this distinction upstream in practice.
return true, "allowed by rule in " + attributes.GetNamespace(), nil
}
}
if len(errs) == 0 {
return false, "", ruleRetrievalError
}
if ruleRetrievalError != nil {
errs = append(errs, ruleRetrievalError)
}
return false, "", kerrors.NewAggregate(errs)
}