forked from openshift/origin
/
authorizer.go
72 lines (57 loc) · 2.55 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
package scope
import (
"fmt"
kapi "k8s.io/kubernetes/pkg/api"
kerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/sets"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
defaultauthorizer "github.com/openshift/origin/pkg/authorization/authorizer"
"github.com/openshift/origin/pkg/client"
)
type scopeAuthorizer struct {
delegate defaultauthorizer.Authorizer
clusterPolicyGetter client.ClusterPolicyLister
forbiddenMessageMaker defaultauthorizer.ForbiddenMessageMaker
}
func NewAuthorizer(delegate defaultauthorizer.Authorizer, clusterPolicyGetter client.ClusterPolicyLister, forbiddenMessageMaker defaultauthorizer.ForbiddenMessageMaker) defaultauthorizer.Authorizer {
return &scopeAuthorizer{delegate: delegate, clusterPolicyGetter: clusterPolicyGetter, forbiddenMessageMaker: forbiddenMessageMaker}
}
func (a *scopeAuthorizer) Authorize(ctx kapi.Context, passedAttributes defaultauthorizer.Action) (bool, string, error) {
user, exists := kapi.UserFrom(ctx)
if !exists {
return false, "", fmt.Errorf("user missing from context")
}
scopes := user.GetExtra()[authorizationapi.ScopesKey]
if len(scopes) == 0 {
return a.delegate.Authorize(ctx, passedAttributes)
}
nonFatalErrors := []error{}
namespace, _ := kapi.NamespaceFrom(ctx)
// scopeResolutionErrors aren't fatal. If any of the scopes we find allow this, then the overall scope limits allow it
rules, err := ScopesToRules(scopes, namespace, a.clusterPolicyGetter)
if err != nil {
nonFatalErrors = append(nonFatalErrors, err)
}
attributes := defaultauthorizer.CoerceToDefaultAuthorizationAttributes(passedAttributes)
for _, rule := range rules {
// check rule against attributes
matches, err := attributes.RuleMatches(rule)
if err != nil {
nonFatalErrors = append(nonFatalErrors, err)
continue
}
if matches {
return a.delegate.Authorize(ctx, passedAttributes)
}
}
denyReason, err := a.forbiddenMessageMaker.MakeMessage(defaultauthorizer.MessageContext{User: user, Namespace: namespace, Attributes: attributes})
if err != nil {
denyReason = err.Error()
}
return false, fmt.Sprintf("scopes %v prevent this action; %v", scopes, denyReason), kerrors.NewAggregate(nonFatalErrors)
}
// TODO remove this. We don't logically need it, but it requires splitting our interface
// GetAllowedSubjects returns the subjects it knows can perform the action.
func (a *scopeAuthorizer) GetAllowedSubjects(ctx kapi.Context, attributes defaultauthorizer.Action) (sets.String, sets.String, error) {
return a.delegate.GetAllowedSubjects(ctx, attributes)
}