internal: route traffic to proxy providers based on cookie domain when multiple domain-level providers exist
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> #2079
This commit is contained in:
parent
525976a81b
commit
14c7d8c4f4
|
@ -187,6 +187,10 @@ func (a *Application) Mode() api.ProxyMode {
|
||||||
return *a.proxyConfig.Mode
|
return *a.proxyConfig.Mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Application) ProxyConfig() api.ProxyOutpostConfig {
|
||||||
|
return a.proxyConfig
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Application) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
func (a *Application) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
a.mux.ServeHTTP(rw, r)
|
a.mux.ServeHTTP(rw, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"goauthentik.io/internal/outpost/proxyv2/application"
|
||||||
"goauthentik.io/internal/outpost/proxyv2/metrics"
|
"goauthentik.io/internal/outpost/proxyv2/metrics"
|
||||||
"goauthentik.io/internal/utils/web"
|
"goauthentik.io/internal/utils/web"
|
||||||
staticWeb "goauthentik.io/web"
|
staticWeb "goauthentik.io/web"
|
||||||
|
@ -43,6 +44,42 @@ func (ps *ProxyServer) HandleStatic(rw http.ResponseWriter, r *http.Request) {
|
||||||
}).Observe(float64(after))
|
}).Observe(float64(after))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ps *ProxyServer) lookupApp(r *http.Request) (*application.Application, string) {
|
||||||
|
host := web.GetHost(r)
|
||||||
|
// Try to find application by directly looking up host first (proxy, forward_auth_single)
|
||||||
|
a, ok := ps.apps[host]
|
||||||
|
if ok {
|
||||||
|
ps.log.WithField("host", host).WithField("app", a).Debug("Found app based direct host match")
|
||||||
|
return a, host
|
||||||
|
}
|
||||||
|
// For forward_auth_domain, we don't have a direct app to domain relationship
|
||||||
|
// Check through all apps, and check how much of their cookie domain matches the host
|
||||||
|
// Return the application that has the longest match
|
||||||
|
var longestMatch *application.Application
|
||||||
|
longestMatchLength := 0
|
||||||
|
for _, app := range ps.apps {
|
||||||
|
// Check if the cookie domain has a leading period for a wildcard
|
||||||
|
// This will decrease the weight of a wildcard domain, but a request to example.com
|
||||||
|
// with the cookie domain set to example.com will still be routed correctly.
|
||||||
|
cd := strings.TrimPrefix(*app.ProxyConfig().CookieDomain, ".")
|
||||||
|
if !strings.HasSuffix(host, cd) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(cd) < longestMatchLength {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
longestMatch = app
|
||||||
|
longestMatchLength = len(cd)
|
||||||
|
}
|
||||||
|
// Check if our longes match is 0, in which case we didn't match, so we
|
||||||
|
// manually return no app
|
||||||
|
if longestMatchLength == 0 {
|
||||||
|
return nil, host
|
||||||
|
}
|
||||||
|
ps.log.WithField("host", host).WithField("app", longestMatch).Debug("Found app based on cookie domain")
|
||||||
|
return longestMatch, host
|
||||||
|
}
|
||||||
|
|
||||||
func (ps *ProxyServer) Handle(rw http.ResponseWriter, r *http.Request) {
|
func (ps *ProxyServer) Handle(rw http.ResponseWriter, r *http.Request) {
|
||||||
if strings.HasPrefix(r.URL.Path, "/akprox/static") {
|
if strings.HasPrefix(r.URL.Path, "/akprox/static") {
|
||||||
ps.HandleStatic(rw, r)
|
ps.HandleStatic(rw, r)
|
||||||
|
@ -52,9 +89,8 @@ func (ps *ProxyServer) Handle(rw http.ResponseWriter, r *http.Request) {
|
||||||
ps.HandlePing(rw, r)
|
ps.HandlePing(rw, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
host := web.GetHost(r)
|
a, host := ps.lookupApp(r)
|
||||||
a, ok := ps.apps[host]
|
if a == nil {
|
||||||
if !ok {
|
|
||||||
// If we only have one handler, host name switching doesn't matter
|
// If we only have one handler, host name switching doesn't matter
|
||||||
if len(ps.apps) == 1 {
|
if len(ps.apps) == 1 {
|
||||||
ps.log.WithField("host", host).Trace("passing to single app mux")
|
ps.log.WithField("host", host).Trace("passing to single app mux")
|
||||||
|
|
|
@ -70,11 +70,12 @@ func NewProxyServer(ac *ak.APIController, portOffset int) *ProxyServer {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *ProxyServer) HandleHost(host string, rw http.ResponseWriter, r *http.Request) bool {
|
func (ps *ProxyServer) HandleHost(rw http.ResponseWriter, r *http.Request) bool {
|
||||||
if app, ok := ps.apps[host]; ok {
|
a, host := ps.lookupApp(r)
|
||||||
if app.Mode() == api.PROXYMODE_PROXY {
|
if a != nil {
|
||||||
|
if a.Mode() == api.PROXYMODE_PROXY {
|
||||||
ps.log.WithField("host", host).Trace("routing to proxy outpost")
|
ps.log.WithField("host", host).Trace("routing to proxy outpost")
|
||||||
app.ServeHTTP(rw, r)
|
a.ServeHTTP(rw, r)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,10 +47,9 @@ func (ws *WebServer) configureProxy() {
|
||||||
ws.proxyErrorHandler(rw, r, fmt.Errorf("authentik core not running yet"))
|
ws.proxyErrorHandler(rw, r, fmt.Errorf("authentik core not running yet"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
host := web.GetHost(r)
|
|
||||||
before := time.Now()
|
before := time.Now()
|
||||||
if ws.ProxyServer != nil {
|
if ws.ProxyServer != nil {
|
||||||
if ws.ProxyServer.HandleHost(host, rw, r) {
|
if ws.ProxyServer.HandleHost(rw, r) {
|
||||||
Requests.With(prometheus.Labels{
|
Requests.With(prometheus.Labels{
|
||||||
"dest": "embedded_outpost",
|
"dest": "embedded_outpost",
|
||||||
}).Observe(float64(time.Since(before)))
|
}).Observe(float64(time.Since(before)))
|
||||||
|
@ -60,7 +59,7 @@ func (ws *WebServer) configureProxy() {
|
||||||
Requests.With(prometheus.Labels{
|
Requests.With(prometheus.Labels{
|
||||||
"dest": "py",
|
"dest": "py",
|
||||||
}).Observe(float64(time.Since(before)))
|
}).Observe(float64(time.Since(before)))
|
||||||
ws.log.WithField("host", host).Trace("routing to application server")
|
ws.log.WithField("host", web.GetHost(r)).Trace("routing to application server")
|
||||||
rp.ServeHTTP(rw, r)
|
rp.ServeHTTP(rw, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue