/
cf_user.go
87 lines (73 loc) · 2.1 KB
/
cf_user.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
package middleware
import (
"context"
"fmt"
"net/http"
"time"
"code.cloudfoundry.org/korifi/api/authorization"
"k8s.io/apimachinery/pkg/util/cache"
)
const (
cacheTTL = 120 * time.Second
)
type cfUser struct {
nsPermissionChecker NamespacePermissionChecker
identityProvider IdentityProvider
cfRootNamespace string
cfUserCache *cache.Expiring
}
//counterfeiter:generate -o fake -fake-name NamespacePermissionChecker . NamespacePermissionChecker
type NamespacePermissionChecker interface {
AuthorizedIn(context.Context, authorization.Identity, string) (bool, error)
}
func CFUser(
nsPermissionChecker NamespacePermissionChecker,
identityProvider IdentityProvider,
cfRootNamespace string,
cfUserCache *cache.Expiring,
) func(http.Handler) http.Handler {
return (&cfUser{
nsPermissionChecker: nsPermissionChecker,
identityProvider: identityProvider,
cfRootNamespace: cfRootNamespace,
cfUserCache: cfUserCache,
}).middleware
}
func (m *cfUser) middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authInfo, ok := authorization.InfoFromContext(r.Context())
if !ok {
next.ServeHTTP(w, r)
return
}
identity, err := m.identityProvider.GetIdentity(r.Context(), authInfo)
if err != nil {
next.ServeHTTP(w, r)
return
}
isCFUser, err := m.isCFUser(r.Context(), identity)
if err != nil {
next.ServeHTTP(w, r)
return
}
if !isCFUser {
w.Header().Add("X-Cf-Warnings", fmt.Sprintf("Warning: subject '%s/%s' has no CF roles assigned. This is not supported and may cause unexpected behaviour.", identity.Kind, identity.Name))
}
next.ServeHTTP(w, r)
})
}
func (m *cfUser) isCFUser(ctx context.Context, identity authorization.Identity) (bool, error) {
_, isCFUser := m.cfUserCache.Get(identity.Hash())
if isCFUser {
return true, nil
}
authorized, err := m.nsPermissionChecker.AuthorizedIn(ctx, identity, m.cfRootNamespace)
if err != nil {
return false, err
}
if authorized {
m.cfUserCache.Set(identity.Hash(), struct{}{}, cacheTTL)
return true, nil
}
return false, nil
}