forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
attributes.go
131 lines (106 loc) · 4 KB
/
attributes.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
119
120
121
122
123
124
125
126
127
128
129
130
131
package authorizer
import (
"fmt"
"path"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
)
type DefaultAuthorizationAttributes struct {
Verb string
APIVersion string
Resource string
ResourceName string
RequestAttributes interface{}
NonResourceURL bool
URL string
}
func (a DefaultAuthorizationAttributes) RuleMatches(rule authorizationapi.PolicyRule) (bool, error) {
if a.IsNonResourceURL() {
if a.nonResourceMatches(rule) {
if a.verbMatches(rule.Verbs) {
return true, nil
}
}
return false, nil
}
if a.verbMatches(rule.Verbs) {
allowedResourceTypes := authorizationapi.ExpandResources(rule.Resources)
if a.resourceMatches(allowedResourceTypes) {
if a.nameMatches(rule.ResourceNames) {
// this rule matches the request, so we should check the additional restrictions to be sure that it's allowed
if rule.AttributeRestrictions.Object != nil {
switch rule.AttributeRestrictions.Object.(type) {
case (*authorizationapi.IsPersonalSubjectAccessReview):
return IsPersonalAccessReview(a)
default:
return false, fmt.Errorf("unable to interpret: %#v", rule.AttributeRestrictions.Object)
}
}
return true, nil
}
}
}
return false, nil
}
func (a DefaultAuthorizationAttributes) verbMatches(verbs util.StringSet) bool {
return verbs.Has(authorizationapi.VerbAll) || verbs.Has(strings.ToLower(a.GetVerb()))
}
func (a DefaultAuthorizationAttributes) resourceMatches(allowedResourceTypes util.StringSet) bool {
return allowedResourceTypes.Has(authorizationapi.ResourceAll) || allowedResourceTypes.Has(strings.ToLower(a.GetResource()))
}
// 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.
// 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
// 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
// handle it like you'd expect: white list is respected for gets while not preventing the list you explicitly asked for.
func (a DefaultAuthorizationAttributes) nameMatches(allowedResourceNames util.StringSet) bool {
if len(allowedResourceNames) == 0 {
return true
}
return allowedResourceNames.Has(a.GetResourceName())
}
func (a DefaultAuthorizationAttributes) GetVerb() string {
return a.Verb
}
// 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
func (a DefaultAuthorizationAttributes) nonResourceMatches(rule authorizationapi.PolicyRule) bool {
for allowedNonResourcePath := range rule.NonResourceURLs {
// if the allowed resource path ends in a wildcard, check to see if the URL starts with it
if strings.HasSuffix(allowedNonResourcePath, "*") {
if strings.HasPrefix(a.GetURL(), allowedNonResourcePath[0:len(allowedNonResourcePath)-1]) {
return true
}
}
// if we have an exact match, return true
if a.GetURL() == allowedNonResourcePath {
return true
}
}
return false
}
// splitPath returns the segments for a URL path.
func splitPath(thePath string) []string {
thePath = strings.Trim(path.Clean(thePath), "/")
if thePath == "" {
return []string{}
}
return strings.Split(thePath, "/")
}
func (a DefaultAuthorizationAttributes) GetAPIVersion() string {
return a.APIVersion
}
func (a DefaultAuthorizationAttributes) GetResource() string {
return a.Resource
}
func (a DefaultAuthorizationAttributes) GetResourceName() string {
return a.ResourceName
}
func (a DefaultAuthorizationAttributes) GetRequestAttributes() interface{} {
return a.RequestAttributes
}
func (a DefaultAuthorizationAttributes) IsNonResourceURL() bool {
return a.NonResourceURL
}
func (a DefaultAuthorizationAttributes) GetURL() string {
return a.URL
}