providers/proxy: send token request internally, with overwritten host header (#4675)

* send token request internally, with overwritten host header

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-02-13 16:34:47 +01:00 committed by GitHub
parent 925477b3a2
commit ec42b597ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 55 additions and 20 deletions

View File

@ -43,6 +43,7 @@ def clean_expired_models(self: MonitoredTask):
amount = 0 amount = 0
for session in AuthenticatedSession.objects.all(): for session in AuthenticatedSession.objects.all():
cache_key = f"{KEY_PREFIX}{session.session_key}" cache_key = f"{KEY_PREFIX}{session.session_key}"
value = None
try: try:
value = cache.get(cache_key) value = cache.get(cache_key)
# pylint: disable=broad-except # pylint: disable=broad-except

View File

@ -5,6 +5,7 @@ from django.test import TestCase
from authentik.core.models import User from authentik.core.models import User
from authentik.policies.dummy.models import DummyPolicy from authentik.policies.dummy.models import DummyPolicy
from authentik.policies.engine import PolicyEngine from authentik.policies.engine import PolicyEngine
from authentik.policies.exceptions import PolicyEngineException
from authentik.policies.expression.models import ExpressionPolicy from authentik.policies.expression.models import ExpressionPolicy
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel, PolicyEngineMode from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel, PolicyEngineMode
from authentik.policies.tests.test_process import clear_policy_cache from authentik.policies.tests.test_process import clear_policy_cache
@ -93,7 +94,7 @@ class TestPolicyEngine(TestCase):
"""Test invalid policy type""" """Test invalid policy type"""
pbm = PolicyBindingModel.objects.create() pbm = PolicyBindingModel.objects.create()
PolicyBinding.objects.create(target=pbm, policy=self.policy_wrong_type, order=0) PolicyBinding.objects.create(target=pbm, policy=self.policy_wrong_type, order=0)
with self.assertRaises(TypeError): with self.assertRaises(PolicyEngineException):
engine = PolicyEngine(pbm, self.user) engine = PolicyEngine(pbm, self.user)
engine.build() engine.build()

View File

@ -43,9 +43,10 @@ type Application struct {
outpostName string outpostName string
sessionName string sessionName string
sessions sessions.Store sessions sessions.Store
proxyConfig api.ProxyOutpostConfig proxyConfig api.ProxyOutpostConfig
httpClient *http.Client httpClient *http.Client
publicHostHTTPClient *http.Client
log *log.Entry log *log.Entry
mux *mux.Router mux *mux.Router
@ -110,25 +111,27 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server) (*A
} }
mux := mux.NewRouter() mux := mux.NewRouter()
// Save cookie name, based on hashed client ID
h := sha256.New() h := sha256.New()
bs := string(h.Sum([]byte(*p.ClientId))) bs := string(h.Sum([]byte(*p.ClientId)))
sessionName := fmt.Sprintf("authentik_proxy_%s", bs[:8]) sessionName := fmt.Sprintf("authentik_proxy_%s", bs[:8])
a := &Application{ a := &Application{
Host: externalHost.Host, Host: externalHost.Host,
log: muxLogger, log: muxLogger,
outpostName: server.API().Outpost.Name, outpostName: server.API().Outpost.Name,
sessionName: sessionName, sessionName: sessionName,
endpoint: endpoint, endpoint: endpoint,
oauthConfig: oauth2Config, oauthConfig: oauth2Config,
tokenVerifier: verifier, tokenVerifier: verifier,
proxyConfig: p, proxyConfig: p,
httpClient: c, httpClient: c,
mux: mux, publicHostHTTPClient: web.NewHostInterceptor(c, server.API().Outpost.Config["authentik_host"].(string)),
errorTemplates: templates.GetTemplates(), mux: mux,
ak: server.API(), errorTemplates: templates.GetTemplates(),
authHeaderCache: ttlcache.New(ttlcache.WithDisableTouchOnHit[string, Claims]()), ak: server.API(),
srv: server, authHeaderCache: ttlcache.New(ttlcache.WithDisableTouchOnHit[string, Claims]()),
srv: server,
} }
go a.authHeaderCache.Start() go a.authHeaderCache.Start()
a.sessions = a.getStore(p, externalHost) a.sessions = a.getStore(p, externalHost)

View File

@ -64,7 +64,6 @@ func GetOIDCEndpoint(p api.ProxyOutpostConfig, authentikHost string, embedded bo
ep.AuthURL = updateURL(authUrl, aku.Scheme, aku.Host) ep.AuthURL = updateURL(authUrl, aku.Scheme, aku.Host)
ep.EndSessionEndpoint = updateURL(endUrl, aku.Scheme, aku.Host) ep.EndSessionEndpoint = updateURL(endUrl, aku.Scheme, aku.Host)
ep.JwksUri = updateURL(jwksUrl, aku.Scheme, aku.Host) ep.JwksUri = updateURL(jwksUrl, aku.Scheme, aku.Host)
ep.TokenURL = updateURL(tokenUrl, aku.Scheme, aku.Host)
ep.Issuer = updateURL(ep.Issuer, aku.Scheme, aku.Host) ep.Issuer = updateURL(ep.Issuer, aku.Scheme, aku.Host)
return ep return ep
} }

View File

@ -24,7 +24,7 @@ func (a *Application) redeemCallback(savedState string, u *url.URL, c context.Co
return nil, fmt.Errorf("blank code") return nil, fmt.Errorf("blank code")
} }
ctx := context.WithValue(c, oauth2.HTTPClient, a.httpClient) ctx := context.WithValue(c, oauth2.HTTPClient, a.publicHostHTTPClient)
// Verify state and errors. // Verify state and errors.
oauth2Token, err := a.oauthConfig.Exchange(ctx, code) oauth2Token, err := a.oauthConfig.Exchange(ctx, code)
if err != nil { if err != nil {

View File

@ -0,0 +1,31 @@
package web
import (
"net/http"
"net/url"
log "github.com/sirupsen/logrus"
)
type hostInterceptor struct {
inner http.RoundTripper
host string
}
func (t hostInterceptor) RoundTrip(r *http.Request) (*http.Response, error) {
r.Host = t.host
return t.inner.RoundTrip(r)
}
func NewHostInterceptor(inner *http.Client, host string) *http.Client {
aku, err := url.Parse(host)
if err != nil {
log.WithField("host", host).WithError(err).Warn("failed to parse host")
}
return &http.Client{
Transport: hostInterceptor{
inner: inner.Transport,
host: aku.Host,
},
}
}