-
Notifications
You must be signed in to change notification settings - Fork 70
/
auth_middleware.go
117 lines (98 loc) · 2.77 KB
/
auth_middleware.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
package handlers
import (
"context"
"errors"
"fmt"
"net/http"
"policy-server/uaa_client"
"strings"
"code.cloudfoundry.org/cf-networking-helpers/middleware"
"code.cloudfoundry.org/lager"
)
type Key string
const TokenDataKey = Key("tokenData")
const MAX_REQ_BODY_SIZE = 10 << 20 // 10 MB
//go:generate counterfeiter -o fakes/http_handler.go --fake-name HTTPHandler . http_handler
type http_handler interface {
http.Handler
}
type UAAClient interface {
CheckToken(token string) (uaa_client.CheckTokenResponse, error)
}
type Authenticator struct {
Client UAAClient
Scopes []string
ErrorResponse errorResponse
ScopeChecking bool
}
func getLogger(req *http.Request) lager.Logger {
if v := req.Context().Value(middleware.Key("logger")); v != nil {
if logger, ok := v.(lager.Logger); ok {
return logger
}
}
return lager.NewLogger("cfnetworking.policy-server")
}
func getTokenData(req *http.Request) uaa_client.CheckTokenResponse {
if v := req.Context().Value(TokenDataKey); v != nil {
if token, ok := v.(uaa_client.CheckTokenResponse); ok {
return token
}
}
return uaa_client.CheckTokenResponse{}
}
func (a *Authenticator) Wrap(handle http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
logger := getLogger(req)
logger = logger.Session("authentication")
authorization := req.Header["Authorization"]
if len(authorization) < 1 {
err := errors.New("no auth header")
a.ErrorResponse.Unauthorized(logger, w, err, "missing authorization header")
return
}
token := authorization[0]
token = strings.TrimPrefix(token, "Bearer ")
token = strings.TrimPrefix(token, "bearer ")
tokenData, err := a.Client.CheckToken(token)
if err != nil {
a.ErrorResponse.Forbidden(logger, w, err, "failed to verify token with uaa")
return
}
if a.ScopeChecking && !isAuthorized(tokenData.Scope, a.Scopes) {
err := errors.New(fmt.Sprintf("provided scopes %s do not include allowed scopes %s", tokenData.Scope, a.Scopes))
a.ErrorResponse.Forbidden(logger, w, err, err.Error())
return
}
req.Body = http.MaxBytesReader(w, req.Body, MAX_REQ_BODY_SIZE)
contextWithTokenData := context.WithValue(req.Context(), TokenDataKey, tokenData)
req = req.WithContext(contextWithTokenData)
handle.ServeHTTP(w, req)
})
}
func isAuthorized(scopes, allowedScopes []string) bool {
for _, scope := range scopes {
for _, allowed := range allowedScopes {
if scope == allowed {
return true
}
}
}
return false
}
func isNetworkAdmin(scopes []string) bool {
for _, scope := range scopes {
if scope == "network.admin" {
return true
}
}
return false
}
func isNetworkWrite(scopes []string) bool {
for _, scope := range scopes {
if scope == "network.write" {
return true
}
}
return false
}