forked from openshift/origin
/
impersonation.go
142 lines (121 loc) · 5.05 KB
/
impersonation.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
132
133
134
135
136
137
138
139
140
141
142
package handlers
import (
"fmt"
"net/http"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/httplog"
"k8s.io/kubernetes/pkg/serviceaccount"
authenticationapi "github.com/openshift/origin/pkg/auth/api"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
"github.com/openshift/origin/pkg/authorization/authorizer"
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy"
userapi "github.com/openshift/origin/pkg/user/api"
uservalidation "github.com/openshift/origin/pkg/user/api/validation"
)
type GroupCache interface {
GroupsFor(string) ([]*userapi.Group, error)
}
// ImpersonationFilter checks for impersonation rules against the current user.
func ImpersonationFilter(handler http.Handler, a authorizer.Authorizer, groupCache GroupCache, contextMapper kapi.RequestContextMapper) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
requestedUser := req.Header.Get(authenticationapi.ImpersonateUserHeader)
if len(requestedUser) == 0 {
handler.ServeHTTP(w, req)
return
}
subjects := authorizationapi.BuildSubjects([]string{requestedUser}, req.Header[authenticationapi.ImpersonateGroupHeader],
// validates whether the usernames are regular users or system users
uservalidation.ValidateUserName,
// validates group names are regular groups or system groups
uservalidation.ValidateGroupName)
ctx, exists := contextMapper.Get(req)
if !exists {
Forbidden("context not found", nil, w, req)
return
}
// if groups are not specified, then we need to look them up differently depending on the type of user
// if they are specified, then they are the authority
groupsSpecified := len(req.Header[authenticationapi.ImpersonateGroupHeader]) > 0
// make sure we're allowed to impersonate each subject. While we're iterating through, start building username
// and group information
username := ""
groups := []string{}
for _, subject := range subjects {
actingAsAttributes := &authorizer.DefaultAuthorizationAttributes{
Verb: "impersonate",
}
switch subject.GetObjectKind().GroupVersionKind().GroupKind() {
case userapi.Kind(authorizationapi.GroupKind):
actingAsAttributes.APIGroup = userapi.GroupName
actingAsAttributes.Resource = authorizationapi.GroupResource
actingAsAttributes.ResourceName = subject.Name
groups = append(groups, subject.Name)
case userapi.Kind(authorizationapi.SystemGroupKind):
actingAsAttributes.APIGroup = userapi.GroupName
actingAsAttributes.Resource = authorizationapi.SystemGroupResource
actingAsAttributes.ResourceName = subject.Name
groups = append(groups, subject.Name)
case userapi.Kind(authorizationapi.UserKind):
actingAsAttributes.APIGroup = userapi.GroupName
actingAsAttributes.Resource = authorizationapi.UserResource
actingAsAttributes.ResourceName = subject.Name
username = subject.Name
if !groupsSpecified {
if actualGroups, err := groupCache.GroupsFor(subject.Name); err == nil {
for _, group := range actualGroups {
groups = append(groups, group.Name)
}
}
groups = append(groups, bootstrappolicy.AuthenticatedGroup, bootstrappolicy.AuthenticatedOAuthGroup)
}
case userapi.Kind(authorizationapi.SystemUserKind):
actingAsAttributes.APIGroup = userapi.GroupName
actingAsAttributes.Resource = authorizationapi.SystemUserResource
actingAsAttributes.ResourceName = subject.Name
username = subject.Name
if !groupsSpecified {
if subject.Name == bootstrappolicy.UnauthenticatedUsername {
groups = append(groups, bootstrappolicy.UnauthenticatedGroup)
} else {
groups = append(groups, bootstrappolicy.AuthenticatedGroup)
}
}
case kapi.Kind(authorizationapi.ServiceAccountKind):
actingAsAttributes.APIGroup = kapi.GroupName
actingAsAttributes.Resource = authorizationapi.ServiceAccountResource
actingAsAttributes.ResourceName = subject.Name
username = serviceaccount.MakeUsername(subject.Namespace, subject.Name)
if !groupsSpecified {
groups = append(serviceaccount.MakeGroupNames(subject.Namespace, subject.Name), bootstrappolicy.AuthenticatedGroup)
}
default:
Forbidden(fmt.Sprintf("unknown subject type: %v", subject), actingAsAttributes, w, req)
return
}
authCheckCtx := kapi.WithNamespace(ctx, subject.Namespace)
allowed, reason, err := a.Authorize(authCheckCtx, actingAsAttributes)
if err != nil {
Forbidden(err.Error(), actingAsAttributes, w, req)
return
}
if !allowed {
Forbidden(reason, actingAsAttributes, w, req)
return
}
}
var extra map[string][]string
if requestScopes, ok := req.Header[authenticationapi.ImpersonateUserScopeHeader]; ok {
extra = map[string][]string{authorizationapi.ScopesKey: requestScopes}
}
newUser := &user.DefaultInfo{
Name: username,
Groups: groups,
Extra: extra,
}
contextMapper.Update(req, kapi.WithUser(ctx, newUser))
oldUser, _ := kapi.UserFrom(ctx)
httplog.LogOf(req, w).Addf("%v is acting as %v", oldUser, newUser)
handler.ServeHTTP(w, req)
})
}