Expose the Supervisor OIDC authorization endpoint to the public
This commit is contained in:
parent
a36f7c6c07
commit
33ce79f89d
@ -181,9 +181,10 @@ func run(serverInstallationNamespace string, cfg *supervisor.Config) error {
|
|||||||
|
|
||||||
dynamicJWKSProvider := jwks.NewDynamicJWKSProvider()
|
dynamicJWKSProvider := jwks.NewDynamicJWKSProvider()
|
||||||
dynamicTLSCertProvider := provider.NewDynamicTLSCertProvider()
|
dynamicTLSCertProvider := provider.NewDynamicTLSCertProvider()
|
||||||
|
dynamicUpstreamIDPProvider := provider.NewDynamicUpstreamIDPProvider()
|
||||||
|
|
||||||
// OIDC endpoints will be served by the oidProvidersManager, and any non-OIDC paths will fallback to the healthMux.
|
// OIDC endpoints will be served by the oidProvidersManager, and any non-OIDC paths will fallback to the healthMux.
|
||||||
oidProvidersManager := manager.NewManager(healthMux, dynamicJWKSProvider)
|
oidProvidersManager := manager.NewManager(healthMux, dynamicJWKSProvider, dynamicUpstreamIDPProvider)
|
||||||
|
|
||||||
startControllers(
|
startControllers(
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -44,23 +44,27 @@ func NewHandler(
|
|||||||
|
|
||||||
authorizeRequester, err := oauthHelper.NewAuthorizeRequest(r.Context(), r)
|
authorizeRequester, err := oauthHelper.NewAuthorizeRequest(r.Context(), r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
klog.InfoS("authorize request error", "err", err, "details", fosite.ErrorToRFC6749Error(err).ToValues())
|
||||||
oauthHelper.WriteAuthorizeError(w, authorizeRequester, err)
|
oauthHelper.WriteAuthorizeError(w, authorizeRequester, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
upstreamIDP, err := chooseUpstreamIDP(idpListGetter)
|
upstreamIDP, err := chooseUpstreamIDP(idpListGetter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
klog.InfoS("authorize request upstream selection error", "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, &openid.DefaultSession{})
|
_, err = oauthHelper.NewAuthorizeResponse(r.Context(), authorizeRequester, &openid.DefaultSession{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
klog.InfoS("authorize response error", "err", err, "details", fosite.ErrorToRFC6749Error(err).ToValues())
|
||||||
oauthHelper.WriteAuthorizeError(w, authorizeRequester, err)
|
oauthHelper.WriteAuthorizeError(w, authorizeRequester, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
stateValue, nonceValue, pkceValue, err := generateParams(generateState, generateNonce, generatePKCE)
|
stateValue, nonceValue, pkceValue, err := generateParams(generateState, generateNonce, generatePKCE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
klog.InfoS("authorize generate error", "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +29,7 @@ func PinnipedCLIOIDCClient() *fosite.DefaultOpenIDConnectClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that Fosite requires the HMAC secret to be 32 bytes.
|
func FositeOauth2Helper(oauthStore interface{}, hmacSecretOfLengthAtLeast32 []byte) fosite.OAuth2Provider {
|
||||||
func FositeOauth2Helper(oauthStore interface{}, hmacSecretOfLength32 []byte) fosite.OAuth2Provider {
|
|
||||||
oauthConfig := &compose.Config{
|
oauthConfig := &compose.Config{
|
||||||
EnforcePKCEForPublicClients: true,
|
EnforcePKCEForPublicClients: true,
|
||||||
}
|
}
|
||||||
@ -39,7 +38,8 @@ func FositeOauth2Helper(oauthStore interface{}, hmacSecretOfLength32 []byte) fos
|
|||||||
oauthConfig,
|
oauthConfig,
|
||||||
oauthStore,
|
oauthStore,
|
||||||
&compose.CommonStrategy{
|
&compose.CommonStrategy{
|
||||||
CoreStrategy: compose.NewOAuth2HMACStrategy(oauthConfig, hmacSecretOfLength32, nil),
|
// Note that Fosite requires the HMAC secret to be at least 32 bytes.
|
||||||
|
CoreStrategy: compose.NewOAuth2HMACStrategy(oauthConfig, hmacSecretOfLengthAtLeast32, nil),
|
||||||
},
|
},
|
||||||
nil, // hasher, defaults to using BCrypt when nil. Used for hashing client secrets.
|
nil, // hasher, defaults to using BCrypt when nil. Used for hashing client secrets.
|
||||||
compose.OAuth2AuthorizeExplicitFactory,
|
compose.OAuth2AuthorizeExplicitFactory,
|
||||||
|
@ -8,12 +8,18 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ory/fosite"
|
||||||
|
"github.com/ory/fosite/storage"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"go.pinniped.dev/internal/oidc"
|
"go.pinniped.dev/internal/oidc"
|
||||||
|
"go.pinniped.dev/internal/oidc/auth"
|
||||||
"go.pinniped.dev/internal/oidc/discovery"
|
"go.pinniped.dev/internal/oidc/discovery"
|
||||||
"go.pinniped.dev/internal/oidc/jwks"
|
"go.pinniped.dev/internal/oidc/jwks"
|
||||||
"go.pinniped.dev/internal/oidc/provider"
|
"go.pinniped.dev/internal/oidc/provider"
|
||||||
|
"go.pinniped.dev/internal/oidcclient/nonce"
|
||||||
|
"go.pinniped.dev/internal/oidcclient/pkce"
|
||||||
|
"go.pinniped.dev/internal/oidcclient/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Manager can manage multiple active OIDC providers. It acts as a request router for them.
|
// Manager can manage multiple active OIDC providers. It acts as a request router for them.
|
||||||
@ -25,16 +31,19 @@ type Manager struct {
|
|||||||
providerHandlers map[string]http.Handler // map of all routes for all providers
|
providerHandlers map[string]http.Handler // map of all routes for all providers
|
||||||
nextHandler http.Handler // the next handler in a chain, called when this manager didn't know how to handle a request
|
nextHandler http.Handler // the next handler in a chain, called when this manager didn't know how to handle a request
|
||||||
dynamicJWKSProvider jwks.DynamicJWKSProvider // in-memory cache of per-issuer JWKS data
|
dynamicJWKSProvider jwks.DynamicJWKSProvider // in-memory cache of per-issuer JWKS data
|
||||||
|
idpListGetter auth.IDPListGetter // in-memory cache of upstream IDPs
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager returns an empty Manager.
|
// NewManager returns an empty Manager.
|
||||||
// nextHandler will be invoked for any requests that could not be handled by this manager's providers.
|
// nextHandler will be invoked for any requests that could not be handled by this manager's providers.
|
||||||
// dynamicJWKSProvider will be used as an in-memory cache for per-issuer JWKS data.
|
// dynamicJWKSProvider will be used as an in-memory cache for per-issuer JWKS data.
|
||||||
func NewManager(nextHandler http.Handler, dynamicJWKSProvider jwks.DynamicJWKSProvider) *Manager {
|
// idpListGetter will be used as an in-memory cache of currently configured upstream IDPs.
|
||||||
|
func NewManager(nextHandler http.Handler, dynamicJWKSProvider jwks.DynamicJWKSProvider, idpListGetter auth.IDPListGetter) *Manager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
providerHandlers: make(map[string]http.Handler),
|
providerHandlers: make(map[string]http.Handler),
|
||||||
nextHandler: nextHandler,
|
nextHandler: nextHandler,
|
||||||
dynamicJWKSProvider: dynamicJWKSProvider,
|
dynamicJWKSProvider: dynamicJWKSProvider,
|
||||||
|
idpListGetter: idpListGetter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +69,17 @@ func (m *Manager) SetProviders(oidcProviders ...*provider.OIDCProvider) {
|
|||||||
jwksURL := strings.ToLower(incomingProvider.IssuerHost()) + "/" + incomingProvider.IssuerPath() + oidc.JWKSEndpointPath
|
jwksURL := strings.ToLower(incomingProvider.IssuerHost()) + "/" + incomingProvider.IssuerPath() + oidc.JWKSEndpointPath
|
||||||
m.providerHandlers[jwksURL] = jwks.NewHandler(incomingProvider.Issuer(), m.dynamicJWKSProvider)
|
m.providerHandlers[jwksURL] = jwks.NewHandler(incomingProvider.Issuer(), m.dynamicJWKSProvider)
|
||||||
|
|
||||||
|
// Each OIDC provider gets its own storage.
|
||||||
|
oauthStore := &storage.MemoryStore{
|
||||||
|
Clients: map[string]fosite.Client{oidc.PinnipedCLIOIDCClient().ID: oidc.PinnipedCLIOIDCClient()},
|
||||||
|
AuthorizeCodes: map[string]storage.StoreAuthorizeCode{},
|
||||||
|
PKCES: map[string]fosite.Requester{},
|
||||||
|
}
|
||||||
|
oauthHelper := oidc.FositeOauth2Helper(oauthStore, []byte("some secret - must have at least 32 bytes")) // TODO replace this secret
|
||||||
|
|
||||||
|
authURL := strings.ToLower(incomingProvider.IssuerHost()) + "/" + incomingProvider.IssuerPath() + oidc.AuthorizationEndpointPath
|
||||||
|
m.providerHandlers[authURL] = auth.NewHandler(incomingProvider.Issuer(), m.idpListGetter, oauthHelper, state.Generate, pkce.Generate, nonce.Generate)
|
||||||
|
|
||||||
klog.InfoS("oidc provider manager added or updated issuer", "issuer", incomingProvider.Issuer())
|
klog.InfoS("oidc provider manager added or updated issuer", "issuer", incomingProvider.Issuer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -32,12 +33,15 @@ func TestManager(t *testing.T) {
|
|||||||
dynamicJWKSProvider jwks.DynamicJWKSProvider
|
dynamicJWKSProvider jwks.DynamicJWKSProvider
|
||||||
)
|
)
|
||||||
|
|
||||||
issuer1 := "https://example.com/some/path"
|
const (
|
||||||
issuer1DifferentCaseHostname := "https://eXamPle.coM/some/path"
|
issuer1 = "https://example.com/some/path"
|
||||||
issuer1KeyID := "issuer1-key"
|
issuer1DifferentCaseHostname = "https://eXamPle.coM/some/path"
|
||||||
issuer2 := "https://example.com/some/path/more/deeply/nested/path" // note that this is a sub-path of the other issuer url
|
issuer1KeyID = "issuer1-key"
|
||||||
issuer2DifferentCaseHostname := "https://exAmPlE.Com/some/path/more/deeply/nested/path"
|
issuer2 = "https://example.com/some/path/more/deeply/nested/path" // note that this is a sub-path of the other issuer url
|
||||||
issuer2KeyID := "issuer2-key"
|
issuer2DifferentCaseHostname = "https://exAmPlE.Com/some/path/more/deeply/nested/path"
|
||||||
|
issuer2KeyID = "issuer2-key"
|
||||||
|
upstreamIDPAuthorizationURL = "https://test-upstream.com/auth"
|
||||||
|
)
|
||||||
|
|
||||||
newGetRequest := func(url string) *http.Request {
|
newGetRequest := func(url string) *http.Request {
|
||||||
return httptest.NewRequest(http.MethodGet, url, nil)
|
return httptest.NewRequest(http.MethodGet, url, nil)
|
||||||
@ -50,17 +54,33 @@ func TestManager(t *testing.T) {
|
|||||||
|
|
||||||
r.False(fallbackHandlerWasCalled)
|
r.False(fallbackHandlerWasCalled)
|
||||||
|
|
||||||
|
// Minimal check to ensure that the right discovery endpoint was called
|
||||||
r.Equal(http.StatusOK, recorder.Code)
|
r.Equal(http.StatusOK, recorder.Code)
|
||||||
responseBody, err := ioutil.ReadAll(recorder.Body)
|
responseBody, err := ioutil.ReadAll(recorder.Body)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
parsedDiscoveryResult := discovery.Metadata{}
|
parsedDiscoveryResult := discovery.Metadata{}
|
||||||
err = json.Unmarshal(responseBody, &parsedDiscoveryResult)
|
err = json.Unmarshal(responseBody, &parsedDiscoveryResult)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
// Minimal check to ensure that the right discovery endpoint was called
|
|
||||||
r.Equal(expectedIssuerInResponse, parsedDiscoveryResult.Issuer)
|
r.Equal(expectedIssuerInResponse, parsedDiscoveryResult.Issuer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requireAuthorizationRequestToBeHandled := func(requestIssuer, requestURLSuffix, expectedRedirectLocationPrefix string) {
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
subject.ServeHTTP(recorder, newGetRequest(requestIssuer+oidc.AuthorizationEndpointPath+requestURLSuffix))
|
||||||
|
|
||||||
|
r.False(fallbackHandlerWasCalled)
|
||||||
|
|
||||||
|
// Minimal check to ensure that the right endpoint was called
|
||||||
|
r.Equal(http.StatusFound, recorder.Code)
|
||||||
|
actualLocation := recorder.Header().Get("Location")
|
||||||
|
r.True(
|
||||||
|
strings.HasPrefix(actualLocation, expectedRedirectLocationPrefix),
|
||||||
|
"actual location %s did not start with expected prefix %s",
|
||||||
|
actualLocation, expectedRedirectLocationPrefix,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
requireJWKSRequestToBeHandled := func(requestIssuer, requestURLSuffix, expectedJWKKeyID string) {
|
requireJWKSRequestToBeHandled := func(requestIssuer, requestURLSuffix, expectedJWKKeyID string) {
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
@ -68,14 +88,13 @@ func TestManager(t *testing.T) {
|
|||||||
|
|
||||||
r.False(fallbackHandlerWasCalled)
|
r.False(fallbackHandlerWasCalled)
|
||||||
|
|
||||||
|
// Minimal check to ensure that the right JWKS endpoint was called
|
||||||
r.Equal(http.StatusOK, recorder.Code)
|
r.Equal(http.StatusOK, recorder.Code)
|
||||||
responseBody, err := ioutil.ReadAll(recorder.Body)
|
responseBody, err := ioutil.ReadAll(recorder.Body)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
parsedJWKSResult := jose.JSONWebKeySet{}
|
parsedJWKSResult := jose.JSONWebKeySet{}
|
||||||
err = json.Unmarshal(responseBody, &parsedJWKSResult)
|
err = json.Unmarshal(responseBody, &parsedJWKSResult)
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
|
|
||||||
// Minimal check to ensure that the right JWKS endpoint was called
|
|
||||||
r.Equal(expectedJWKKeyID, parsedJWKSResult.Keys[0].KeyID)
|
r.Equal(expectedJWKKeyID, parsedJWKSResult.Keys[0].KeyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +104,20 @@ func TestManager(t *testing.T) {
|
|||||||
fallbackHandlerWasCalled = true
|
fallbackHandlerWasCalled = true
|
||||||
}
|
}
|
||||||
dynamicJWKSProvider = jwks.NewDynamicJWKSProvider()
|
dynamicJWKSProvider = jwks.NewDynamicJWKSProvider()
|
||||||
subject = NewManager(nextHandler, dynamicJWKSProvider)
|
|
||||||
|
parsedUpstreamIDPAuthorizationURL, err := url.Parse(upstreamIDPAuthorizationURL)
|
||||||
|
r.NoError(err)
|
||||||
|
idpListGetter := provider.NewDynamicUpstreamIDPProvider()
|
||||||
|
idpListGetter.SetIDPList([]provider.UpstreamOIDCIdentityProvider{
|
||||||
|
{
|
||||||
|
Name: "test-idp",
|
||||||
|
ClientID: "test-client-id",
|
||||||
|
AuthorizationURL: *parsedUpstreamIDPAuthorizationURL,
|
||||||
|
Scopes: []string{"test-scope"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
subject = NewManager(nextHandler, dynamicJWKSProvider, idpListGetter)
|
||||||
})
|
})
|
||||||
|
|
||||||
when("given no providers via SetProviders()", func() {
|
when("given no providers via SetProviders()", func() {
|
||||||
@ -113,40 +145,7 @@ func TestManager(t *testing.T) {
|
|||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
when("given some valid providers via SetProviders()", func() {
|
requireRoutesMatchingRequestsToAppropriateProvider := func() {
|
||||||
it.Before(func() {
|
|
||||||
p1, err := provider.NewOIDCProvider(issuer1)
|
|
||||||
r.NoError(err)
|
|
||||||
p2, err := provider.NewOIDCProvider(issuer2)
|
|
||||||
r.NoError(err)
|
|
||||||
subject.SetProviders(p1, p2)
|
|
||||||
|
|
||||||
dynamicJWKSProvider.SetIssuerToJWKSMap(map[string]*jose.JSONWebKeySet{
|
|
||||||
issuer1: {Keys: []jose.JSONWebKey{newTestJWK(issuer1KeyID)}},
|
|
||||||
issuer2: {Keys: []jose.JSONWebKey{newTestJWK(issuer2KeyID)}},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("sends all non-matching host requests to the nextHandler", func() {
|
|
||||||
r.False(fallbackHandlerWasCalled)
|
|
||||||
url := strings.ReplaceAll(issuer1+oidc.WellKnownEndpointPath, "example.com", "wrong-host.com")
|
|
||||||
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest(url))
|
|
||||||
r.True(fallbackHandlerWasCalled)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("sends all non-matching path requests to the nextHandler", func() {
|
|
||||||
r.False(fallbackHandlerWasCalled)
|
|
||||||
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest("https://example.com/path-does-not-match-any-provider"))
|
|
||||||
r.True(fallbackHandlerWasCalled)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("sends requests which match the issuer prefix but do not match any of that provider's known paths to the nextHandler", func() {
|
|
||||||
r.False(fallbackHandlerWasCalled)
|
|
||||||
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest(issuer1+"/unhandled-sub-path"))
|
|
||||||
r.True(fallbackHandlerWasCalled)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("routes matching requests to the appropriate provider", func() {
|
|
||||||
requireDiscoveryRequestToBeHandled(issuer1, "", issuer1)
|
requireDiscoveryRequestToBeHandled(issuer1, "", issuer1)
|
||||||
requireDiscoveryRequestToBeHandled(issuer2, "", issuer2)
|
requireDiscoveryRequestToBeHandled(issuer2, "", issuer2)
|
||||||
requireDiscoveryRequestToBeHandled(issuer2, "?some=query", issuer2)
|
requireDiscoveryRequestToBeHandled(issuer2, "?some=query", issuer2)
|
||||||
@ -164,6 +163,62 @@ func TestManager(t *testing.T) {
|
|||||||
requireJWKSRequestToBeHandled(issuer1DifferentCaseHostname, "", issuer1KeyID)
|
requireJWKSRequestToBeHandled(issuer1DifferentCaseHostname, "", issuer1KeyID)
|
||||||
requireJWKSRequestToBeHandled(issuer2DifferentCaseHostname, "", issuer2KeyID)
|
requireJWKSRequestToBeHandled(issuer2DifferentCaseHostname, "", issuer2KeyID)
|
||||||
requireJWKSRequestToBeHandled(issuer2DifferentCaseHostname, "?some=query", issuer2KeyID)
|
requireJWKSRequestToBeHandled(issuer2DifferentCaseHostname, "?some=query", issuer2KeyID)
|
||||||
|
|
||||||
|
authRedirectURI := "http://127.0.0.1/callback"
|
||||||
|
authRequestParams := "?" + url.Values{
|
||||||
|
"response_type": []string{"code"},
|
||||||
|
"scope": []string{"openid profile email"},
|
||||||
|
"client_id": []string{"pinniped-cli"},
|
||||||
|
"state": []string{"some-state-value"},
|
||||||
|
"nonce": []string{"some-nonce-value"},
|
||||||
|
"code_challenge": []string{"some-challenge"},
|
||||||
|
"code_challenge_method": []string{"S256"},
|
||||||
|
"redirect_uri": []string{authRedirectURI},
|
||||||
|
}.Encode()
|
||||||
|
|
||||||
|
requireAuthorizationRequestToBeHandled(issuer1, authRequestParams, upstreamIDPAuthorizationURL)
|
||||||
|
requireAuthorizationRequestToBeHandled(issuer2, authRequestParams, upstreamIDPAuthorizationURL)
|
||||||
|
|
||||||
|
// Hostnames are case-insensitive, so test that we can handle that.
|
||||||
|
requireAuthorizationRequestToBeHandled(issuer1DifferentCaseHostname, authRequestParams, upstreamIDPAuthorizationURL)
|
||||||
|
requireAuthorizationRequestToBeHandled(issuer2DifferentCaseHostname, authRequestParams, upstreamIDPAuthorizationURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
when("given some valid providers via SetProviders()", func() {
|
||||||
|
it.Before(func() {
|
||||||
|
p1, err := provider.NewOIDCProvider(issuer1)
|
||||||
|
r.NoError(err)
|
||||||
|
p2, err := provider.NewOIDCProvider(issuer2)
|
||||||
|
r.NoError(err)
|
||||||
|
subject.SetProviders(p1, p2)
|
||||||
|
|
||||||
|
dynamicJWKSProvider.SetIssuerToJWKSMap(map[string]*jose.JSONWebKeySet{
|
||||||
|
issuer1: {Keys: []jose.JSONWebKey{newTestJWK(issuer1KeyID)}},
|
||||||
|
issuer2: {Keys: []jose.JSONWebKey{newTestJWK(issuer2KeyID)}},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sends all non-matching host requests to the nextHandler", func() {
|
||||||
|
r.False(fallbackHandlerWasCalled)
|
||||||
|
wrongHostURL := strings.ReplaceAll(issuer1+oidc.WellKnownEndpointPath, "example.com", "wrong-host.com")
|
||||||
|
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest(wrongHostURL))
|
||||||
|
r.True(fallbackHandlerWasCalled)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sends all non-matching path requests to the nextHandler", func() {
|
||||||
|
r.False(fallbackHandlerWasCalled)
|
||||||
|
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest("https://example.com/path-does-not-match-any-provider"))
|
||||||
|
r.True(fallbackHandlerWasCalled)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sends requests which match the issuer prefix but do not match any of that provider's known paths to the nextHandler", func() {
|
||||||
|
r.False(fallbackHandlerWasCalled)
|
||||||
|
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest(issuer1+"/unhandled-sub-path"))
|
||||||
|
r.True(fallbackHandlerWasCalled)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("routes matching requests to the appropriate provider", func() {
|
||||||
|
requireRoutesMatchingRequestsToAppropriateProvider()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -182,23 +237,7 @@ func TestManager(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("still routes matching requests to the appropriate provider", func() {
|
it("still routes matching requests to the appropriate provider", func() {
|
||||||
requireDiscoveryRequestToBeHandled(issuer1, "", issuer1)
|
requireRoutesMatchingRequestsToAppropriateProvider()
|
||||||
requireDiscoveryRequestToBeHandled(issuer2, "", issuer2)
|
|
||||||
requireDiscoveryRequestToBeHandled(issuer2, "?some=query", issuer2)
|
|
||||||
|
|
||||||
// Hostnames are case-insensitive, so test that we can handle that.
|
|
||||||
requireDiscoveryRequestToBeHandled(issuer1DifferentCaseHostname, "", issuer1)
|
|
||||||
requireDiscoveryRequestToBeHandled(issuer2DifferentCaseHostname, "", issuer2)
|
|
||||||
requireDiscoveryRequestToBeHandled(issuer2DifferentCaseHostname, "?some=query", issuer2)
|
|
||||||
|
|
||||||
requireJWKSRequestToBeHandled(issuer1, "", issuer1KeyID)
|
|
||||||
requireJWKSRequestToBeHandled(issuer2, "", issuer2KeyID)
|
|
||||||
requireJWKSRequestToBeHandled(issuer2, "?some=query", issuer2KeyID)
|
|
||||||
|
|
||||||
// Hostnames are case-insensitive, so test that we can handle that.
|
|
||||||
requireJWKSRequestToBeHandled(issuer1DifferentCaseHostname, "", issuer1KeyID)
|
|
||||||
requireJWKSRequestToBeHandled(issuer2DifferentCaseHostname, "", issuer2KeyID)
|
|
||||||
requireJWKSRequestToBeHandled(issuer2DifferentCaseHostname, "?some=query", issuer2KeyID)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user