providers/proxy: rework endpoints logic (#4993)
* providers/proxy: rework endpoints logic again...this time with tests and better logic Signed-off-by: Jens Langhammer <jens@goauthentik.io> * fix tests Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
b69c26d485
commit
ef028af7d1
|
@ -2,7 +2,6 @@ package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"goauthentik.io/api/v3"
|
"goauthentik.io/api/v3"
|
||||||
|
@ -31,40 +30,55 @@ func updateURL(rawUrl string, scheme string, host string) string {
|
||||||
func GetOIDCEndpoint(p api.ProxyOutpostConfig, authentikHost string, embedded bool) OIDCEndpoint {
|
func GetOIDCEndpoint(p api.ProxyOutpostConfig, authentikHost string, embedded bool) OIDCEndpoint {
|
||||||
authUrl := p.OidcConfiguration.AuthorizationEndpoint
|
authUrl := p.OidcConfiguration.AuthorizationEndpoint
|
||||||
endUrl := p.OidcConfiguration.EndSessionEndpoint
|
endUrl := p.OidcConfiguration.EndSessionEndpoint
|
||||||
tokenUrl := p.OidcConfiguration.TokenEndpoint
|
|
||||||
jwksUrl := p.OidcConfiguration.JwksUri
|
|
||||||
issuer := p.OidcConfiguration.Issuer
|
issuer := p.OidcConfiguration.Issuer
|
||||||
if config.Get().AuthentikHostBrowser != "" {
|
|
||||||
authUrl = strings.ReplaceAll(authUrl, authentikHost, config.Get().AuthentikHostBrowser)
|
|
||||||
endUrl = strings.ReplaceAll(endUrl, authentikHost, config.Get().AuthentikHostBrowser)
|
|
||||||
jwksUrl = strings.ReplaceAll(jwksUrl, authentikHost, config.Get().AuthentikHostBrowser)
|
|
||||||
issuer = strings.ReplaceAll(issuer, authentikHost, config.Get().AuthentikHostBrowser)
|
|
||||||
}
|
|
||||||
ep := OIDCEndpoint{
|
ep := OIDCEndpoint{
|
||||||
Endpoint: oauth2.Endpoint{
|
Endpoint: oauth2.Endpoint{
|
||||||
AuthURL: authUrl,
|
AuthURL: authUrl,
|
||||||
TokenURL: tokenUrl,
|
TokenURL: p.OidcConfiguration.TokenEndpoint,
|
||||||
AuthStyle: oauth2.AuthStyleInParams,
|
AuthStyle: oauth2.AuthStyleInParams,
|
||||||
},
|
},
|
||||||
EndSessionEndpoint: endUrl,
|
EndSessionEndpoint: endUrl,
|
||||||
JwksUri: jwksUrl,
|
JwksUri: p.OidcConfiguration.JwksUri,
|
||||||
TokenIntrospection: p.OidcConfiguration.IntrospectionEndpoint,
|
TokenIntrospection: p.OidcConfiguration.IntrospectionEndpoint,
|
||||||
Issuer: issuer,
|
Issuer: issuer,
|
||||||
}
|
}
|
||||||
if !embedded {
|
// For the embedded outpost, we use the configure `authentik_host` for the browser URLs
|
||||||
|
// and localhost (which is what we've got from the API) for backchannel URLs
|
||||||
|
//
|
||||||
|
// For other outposts, when `AUTHENTIK_HOST_BROWSER` is set, we use that for the browser URLs
|
||||||
|
// and use what we got from the API for backchannel
|
||||||
|
hostBrowser := config.Get().AuthentikHostBrowser
|
||||||
|
if !embedded && hostBrowser == "" {
|
||||||
return ep
|
return ep
|
||||||
}
|
}
|
||||||
if authentikHost == "" {
|
var newHost *url.URL
|
||||||
log.Warning("Outpost has localhost/blank API Connection but no authentik_host is configured.")
|
if embedded {
|
||||||
return ep
|
if authentikHost == "" {
|
||||||
|
log.Warning("Outpost has localhost/blank API Connection but no authentik_host is configured.")
|
||||||
|
return ep
|
||||||
|
}
|
||||||
|
aku, err := url.Parse(authentikHost)
|
||||||
|
if err != nil {
|
||||||
|
return ep
|
||||||
|
}
|
||||||
|
newHost = aku
|
||||||
|
} else if hostBrowser != "" {
|
||||||
|
aku, err := url.Parse(hostBrowser)
|
||||||
|
if err != nil {
|
||||||
|
return ep
|
||||||
|
}
|
||||||
|
newHost = aku
|
||||||
}
|
}
|
||||||
aku, err := url.Parse(authentikHost)
|
// Update all browser-accessed URLs to use the new host and scheme
|
||||||
if err != nil {
|
ep.AuthURL = updateURL(authUrl, newHost.Scheme, newHost.Host)
|
||||||
return ep
|
ep.EndSessionEndpoint = updateURL(endUrl, newHost.Scheme, newHost.Host)
|
||||||
|
// Update issuer to use the same host and scheme, which would normally break as we don't
|
||||||
|
// change the token URL here, but the token HTTP transport overwrites the Host header
|
||||||
|
//
|
||||||
|
// This is only used in embedded outposts as there we can guarantee that the request
|
||||||
|
// is routed correctly
|
||||||
|
if embedded {
|
||||||
|
ep.Issuer = updateURL(ep.Issuer, newHost.Scheme, newHost.Host)
|
||||||
}
|
}
|
||||||
ep.AuthURL = updateURL(authUrl, aku.Scheme, aku.Host)
|
|
||||||
ep.EndSessionEndpoint = updateURL(endUrl, aku.Scheme, aku.Host)
|
|
||||||
ep.JwksUri = updateURL(jwksUrl, aku.Scheme, aku.Host)
|
|
||||||
ep.Issuer = updateURL(ep.Issuer, aku.Scheme, aku.Host)
|
|
||||||
return ep
|
return ep
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package application
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"goauthentik.io/api/v3"
|
||||||
|
"goauthentik.io/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEndpointDefault(t *testing.T) {
|
||||||
|
pc := api.ProxyOutpostConfig{
|
||||||
|
OidcConfiguration: api.ProxyOutpostConfigOidcConfiguration{
|
||||||
|
AuthorizationEndpoint: "https://test.goauthentik.io/application/o/authorize/",
|
||||||
|
EndSessionEndpoint: "https://test.goauthentik.io/application/o/test-app/end-session/",
|
||||||
|
IntrospectionEndpoint: "https://test.goauthentik.io/application/o/introspect/",
|
||||||
|
Issuer: "https://test.goauthentik.io/application/o/test-app/",
|
||||||
|
JwksUri: "https://test.goauthentik.io/application/o/test-app/jwks/",
|
||||||
|
TokenEndpoint: "https://test.goauthentik.io/application/o/token/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := GetOIDCEndpoint(pc, "https://authentik-host.test.goauthentik.io", false)
|
||||||
|
// Standard outpost, non embedded
|
||||||
|
// All URLs should use the host that they get from the config
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/authorize/", ep.AuthURL)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/token/", ep.TokenURL)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/test-app/", ep.Issuer)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/test-app/jwks/", ep.JwksUri)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/test-app/end-session/", ep.EndSessionEndpoint)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/introspect/", ep.TokenIntrospection)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEndpointAuthentikHostBrowser(t *testing.T) {
|
||||||
|
c := config.Get()
|
||||||
|
c.AuthentikHostBrowser = "https://browser.test.goauthentik.io"
|
||||||
|
defer func() {
|
||||||
|
c.AuthentikHostBrowser = ""
|
||||||
|
}()
|
||||||
|
pc := api.ProxyOutpostConfig{
|
||||||
|
OidcConfiguration: api.ProxyOutpostConfigOidcConfiguration{
|
||||||
|
AuthorizationEndpoint: "https://test.goauthentik.io/application/o/authorize/",
|
||||||
|
EndSessionEndpoint: "https://test.goauthentik.io/application/o/test-app/end-session/",
|
||||||
|
IntrospectionEndpoint: "https://test.goauthentik.io/application/o/introspect/",
|
||||||
|
Issuer: "https://test.goauthentik.io/application/o/test-app/",
|
||||||
|
JwksUri: "https://test.goauthentik.io/application/o/test-app/jwks/",
|
||||||
|
TokenEndpoint: "https://test.goauthentik.io/application/o/token/",
|
||||||
|
UserinfoEndpoint: "https://test.goauthentik.io/application/o/userinfo/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := GetOIDCEndpoint(pc, "https://authentik-host.test.goauthentik.io", false)
|
||||||
|
// Standard outpost, with AUTHENTIK_HOST_BROWSER set
|
||||||
|
// Only the authorize/end session URLs should be changed
|
||||||
|
assert.Equal(t, "https://browser.test.goauthentik.io/application/o/authorize/", ep.AuthURL)
|
||||||
|
assert.Equal(t, "https://browser.test.goauthentik.io/application/o/test-app/end-session/", ep.EndSessionEndpoint)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/token/", ep.TokenURL)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/test-app/", ep.Issuer)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/test-app/jwks/", ep.JwksUri)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/introspect/", ep.TokenIntrospection)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEndpointEmbedded(t *testing.T) {
|
||||||
|
pc := api.ProxyOutpostConfig{
|
||||||
|
OidcConfiguration: api.ProxyOutpostConfigOidcConfiguration{
|
||||||
|
AuthorizationEndpoint: "https://test.goauthentik.io/application/o/authorize/",
|
||||||
|
EndSessionEndpoint: "https://test.goauthentik.io/application/o/test-app/end-session/",
|
||||||
|
IntrospectionEndpoint: "https://test.goauthentik.io/application/o/introspect/",
|
||||||
|
Issuer: "https://test.goauthentik.io/application/o/test-app/",
|
||||||
|
JwksUri: "https://test.goauthentik.io/application/o/test-app/jwks/",
|
||||||
|
TokenEndpoint: "https://test.goauthentik.io/application/o/token/",
|
||||||
|
UserinfoEndpoint: "https://test.goauthentik.io/application/o/userinfo/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := GetOIDCEndpoint(pc, "https://authentik-host.test.goauthentik.io", true)
|
||||||
|
// Embedded outpost
|
||||||
|
// Browser URLs should use the config of "authentik_host", everything else can use what's
|
||||||
|
// received from the API endpoint
|
||||||
|
// Token URL is an exception since it's sent via a special HTTP transport that overrides the
|
||||||
|
// HTTP Host header, to make sure it's the same value as the issuer
|
||||||
|
assert.Equal(t, "https://authentik-host.test.goauthentik.io/application/o/authorize/", ep.AuthURL)
|
||||||
|
assert.Equal(t, "https://authentik-host.test.goauthentik.io/application/o/test-app/", ep.Issuer)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/token/", ep.TokenURL)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/test-app/jwks/", ep.JwksUri)
|
||||||
|
assert.Equal(t, "https://authentik-host.test.goauthentik.io/application/o/test-app/end-session/", ep.EndSessionEndpoint)
|
||||||
|
assert.Equal(t, "https://test.goauthentik.io/application/o/introspect/", ep.TokenIntrospection)
|
||||||
|
}
|
Reference in New Issue