forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rest.go
105 lines (88 loc) · 3.97 KB
/
rest.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
package subjectaccessreview
import (
"errors"
"fmt"
kapi "k8s.io/kubernetes/pkg/api"
kapierrors "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/runtime"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
authorizationvalidation "github.com/openshift/origin/pkg/authorization/api/validation"
"github.com/openshift/origin/pkg/authorization/authorizer"
)
// REST implements the RESTStorage interface in terms of an Registry.
type REST struct {
authorizer authorizer.Authorizer
}
// NewREST creates a new REST for policies.
func NewREST(authorizer authorizer.Authorizer) *REST {
return &REST{authorizer}
}
// New creates a new ResourceAccessReview object
func (r *REST) New() runtime.Object {
return &authorizationapi.SubjectAccessReview{}
}
// Create registers a given new ResourceAccessReview instance to r.registry.
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
subjectAccessReview, ok := obj.(*authorizationapi.SubjectAccessReview)
if !ok {
return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a subjectAccessReview: %#v", obj))
}
if errs := authorizationvalidation.ValidateSubjectAccessReview(subjectAccessReview); len(errs) > 0 {
return nil, kapierrors.NewInvalid(authorizationapi.Kind(subjectAccessReview.Kind), "", errs)
}
// if a namespace is present on the request, then the namespace on the on the SAR is overwritten.
// This is to support backwards compatibility. To have gotten here in this state, it means that
// the authorizer decided that a user could run an SAR against this namespace
if namespace := kapi.NamespaceValue(ctx); len(namespace) > 0 {
subjectAccessReview.Action.Namespace = namespace
} else if err := r.isAllowed(ctx, subjectAccessReview); err != nil {
// this check is mutually exclusive to the condition above. localSAR and localRAR both clear the namespace before delegating their calls
// We only need to check if the SAR is allowed **again** if the authorizer didn't already approve the request for a legacy call.
return nil, err
}
var userToCheck user.Info
if (len(subjectAccessReview.User) == 0) && (len(subjectAccessReview.Groups) == 0) {
// if no user or group was specified, use the info from the context
ctxUser, exists := kapi.UserFrom(ctx)
if !exists {
return nil, kapierrors.NewBadRequest("user missing from context")
}
userToCheck = ctxUser
} else {
userToCheck = &user.DefaultInfo{
Name: subjectAccessReview.User,
Groups: subjectAccessReview.Groups.List(),
}
}
requestContext := kapi.WithNamespace(kapi.WithUser(ctx, userToCheck), subjectAccessReview.Action.Namespace)
attributes := authorizer.ToDefaultAuthorizationAttributes(subjectAccessReview.Action)
allowed, reason, err := r.authorizer.Authorize(requestContext, attributes)
if err != nil {
return nil, err
}
response := &authorizationapi.SubjectAccessReviewResponse{
Namespace: subjectAccessReview.Action.Namespace,
Allowed: allowed,
Reason: reason,
}
return response, nil
}
// isAllowed checks to see if the current user has rights to issue a LocalSubjectAccessReview on the namespace they're attempting to access
func (r *REST) isAllowed(ctx kapi.Context, sar *authorizationapi.SubjectAccessReview) error {
localSARAttributes := authorizer.DefaultAuthorizationAttributes{
Verb: "create",
Resource: "localsubjectaccessreviews",
RequestAttributes: sar,
}
allowed, reason, err := r.authorizer.Authorize(kapi.WithNamespace(ctx, sar.Action.Namespace), localSARAttributes)
if err != nil {
return kapierrors.NewForbidden(authorizationapi.Resource(localSARAttributes.GetResource()), localSARAttributes.GetResourceName(), err)
}
if !allowed {
forbiddenError, _ := kapierrors.NewForbidden(authorizationapi.Resource(localSARAttributes.GetResource()), localSARAttributes.GetResourceName(), errors.New("") /*discarded*/).(*kapierrors.StatusError)
forbiddenError.ErrStatus.Message = reason
return forbiddenError
}
return nil
}