This repository has been archived by the owner on Aug 24, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
cf_auth_proxy.go
137 lines (116 loc) · 3.54 KB
/
cf_auth_proxy.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
package cfauthproxy
import (
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"time"
"code.cloudfoundry.org/log-cache/internal/auth"
sharedtls "code.cloudfoundry.org/log-cache/internal/tls"
)
type CFAuthProxy struct {
blockOnStart bool
ln net.Listener
gatewayURL *url.URL
addr string
certPath string
keyPath string
proxyCACertPool *x509.CertPool
authMiddleware func(http.Handler) http.Handler
accessMiddleware func(http.Handler) *auth.AccessHandler
}
func NewCFAuthProxy(gatewayAddr, addr, certPath, keyPath string, proxyCACertPool *x509.CertPool, opts ...CFAuthProxyOption) *CFAuthProxy {
gatewayURL, err := url.Parse(gatewayAddr)
if err != nil {
panic(fmt.Sprintf("Couldn't parse gateway address: %s", err))
}
p := &CFAuthProxy{
gatewayURL: gatewayURL,
addr: addr,
certPath: certPath,
keyPath: keyPath,
proxyCACertPool: proxyCACertPool,
authMiddleware: func(h http.Handler) http.Handler {
return h
},
accessMiddleware: auth.NewNullAccessMiddleware(),
}
for _, o := range opts {
o(p)
}
return p
}
// CFAuthProxyOption configures a CFAuthProxy
type CFAuthProxyOption func(*CFAuthProxy)
// WithCFAuthProxyBlock returns a CFAuthProxyOption that determines if Start
// launches a go-routine or not. It defaults to launching a go-routine. If
// this is set, start will block on serving the HTTP endpoint.
func WithCFAuthProxyBlock() CFAuthProxyOption {
return func(p *CFAuthProxy) {
p.blockOnStart = true
}
}
// WithAuthMiddleware returns a CFAuthProxyOption that sets the CFAuthProxy's
// authentication and authorization middleware.
func WithAuthMiddleware(authMiddleware func(http.Handler) http.Handler) CFAuthProxyOption {
return func(p *CFAuthProxy) {
p.authMiddleware = authMiddleware
}
}
func WithAccessMiddleware(accessMiddleware func(http.Handler) *auth.AccessHandler) CFAuthProxyOption {
return func(p *CFAuthProxy) {
p.accessMiddleware = accessMiddleware
}
}
// Start starts the HTTP listener and serves the HTTP server. If the
// CFAuthProxy was initialized with the WithCFAuthProxyBlock option this
// method will block.
func (p *CFAuthProxy) Start() {
ln, err := net.Listen("tcp", p.addr)
if err != nil {
log.Fatalf("failed to start listener: %s", err)
}
p.ln = ln
server := http.Server{
Handler: p.accessMiddleware(p.authMiddleware(p.reverseProxy())),
TLSConfig: sharedtls.NewBaseTLSConfig(),
}
if p.blockOnStart {
log.Fatal(server.ServeTLS(ln, p.certPath, p.keyPath))
}
go func() {
log.Fatal(server.ServeTLS(ln, p.certPath, p.keyPath))
}()
}
// Addr returns the listener address. This must be called after calling Start.
func (p *CFAuthProxy) Addr() string {
return p.ln.Addr().String()
}
func (p *CFAuthProxy) reverseProxy() *httputil.ReverseProxy {
proxy := httputil.NewSingleHostReverseProxy(p.gatewayURL)
proxy.Transport = NewTransportWithRootCA(p.proxyCACertPool)
return proxy
}
func NewTransportWithRootCA(rootCACertPool *x509.CertPool) *http.Transport {
// Aside from the Root CA for the gateway, these values are defaults
// from Golang's http.DefaultTransport
return &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
RootCAs: rootCACertPool,
},
}
}