mirror of
https://github.com/pomerium/pomerium.git
synced 2025-04-29 18:36:30 +02:00
Add a new 'depends_on' route configuration option taking a list of additional hosts to redirect through on login. Update the authorize service and proxy service to support a chain of /.pomerium/callback redirects. Add an integration test for this feature.
98 lines
3.1 KiB
Go
98 lines
3.1 KiB
Go
package authenticateflow_test
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/http/cookiejar"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/pomerium/pomerium/config"
|
|
"github.com/pomerium/pomerium/internal/testenv"
|
|
"github.com/pomerium/pomerium/internal/testenv/scenarios"
|
|
"github.com/pomerium/pomerium/internal/testenv/snippets"
|
|
"github.com/pomerium/pomerium/internal/testenv/upstreams"
|
|
"github.com/pomerium/pomerium/internal/testenv/values"
|
|
)
|
|
|
|
func newHTTPUpstream(
|
|
env testenv.Environment, subdomain string,
|
|
) (upstreams.HTTPUpstream, testenv.Route) {
|
|
up := upstreams.HTTP(nil)
|
|
up.Handle("/", func(w http.ResponseWriter, _ *http.Request) { fmt.Fprintln(w, "hello world") })
|
|
route := up.Route().
|
|
From(env.SubdomainURL(subdomain)).
|
|
To(values.Bind(up.Addr(), func(addr string) string {
|
|
// override the target protocol to use http://
|
|
return fmt.Sprintf("http://%s", addr)
|
|
})).
|
|
Policy(func(p *config.Policy) { p.AllowAnyAuthenticatedUser = true })
|
|
env.AddUpstream(up)
|
|
return up, route
|
|
}
|
|
|
|
func TestMultiDomainLogin(t *testing.T) {
|
|
env := testenv.New(t)
|
|
|
|
env.Add(scenarios.NewIDP([]*scenarios.User{{Email: "test@example.com"}}))
|
|
|
|
// Create three routes to be linked via multi-domain login...
|
|
upstreamA, routeA := newHTTPUpstream(env, "a")
|
|
upstreamB, routeB := newHTTPUpstream(env, "b")
|
|
upstreamC, routeC := newHTTPUpstream(env, "c")
|
|
// ...and one route that will not be involved.
|
|
upstreamD, routeD := newHTTPUpstream(env, "d")
|
|
|
|
// Configure route A to redirect through routes B and C on login.
|
|
routeA.Policy(func(p *config.Policy) {
|
|
p.DependsOn = []string{
|
|
strings.TrimPrefix(routeB.URL().Value(), "https://"),
|
|
strings.TrimPrefix(routeC.URL().Value(), "https://"),
|
|
}
|
|
})
|
|
|
|
env.Start()
|
|
snippets.WaitStartupComplete(env)
|
|
|
|
// By default the testenv code will use a separate http.Client for each
|
|
// separate route. Instead we specifically want to test the cross-route
|
|
// behavior for a single client.
|
|
cj, err := cookiejar.New(nil)
|
|
require.NoError(t, err)
|
|
sharedClient := http.Client{Jar: cj}
|
|
withSharedClient := upstreams.ClientHook(
|
|
func(_ *http.Client) *http.Client { return &sharedClient })
|
|
|
|
assertResponseOK := func(resp *http.Response, err error) {
|
|
t.Helper()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
|
io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
}
|
|
assertRedirect := func(resp *http.Response, err error) {
|
|
t.Helper()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusFound, resp.StatusCode)
|
|
io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
}
|
|
|
|
// Log in to the first route.
|
|
assertResponseOK(upstreamA.Get(routeA, withSharedClient, upstreams.AuthenticateAs("test@example.com")))
|
|
|
|
// The client should also be authenticated for routes B and C without any
|
|
// additional login redirects.
|
|
sharedClient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {
|
|
return http.ErrUseLastResponse
|
|
}
|
|
assertResponseOK(upstreamB.Get(routeB, withSharedClient))
|
|
assertResponseOK(upstreamC.Get(routeC, withSharedClient))
|
|
|
|
// The client should not be authenticated for route D.
|
|
assertRedirect(upstreamD.Get(routeD, withSharedClient))
|
|
}
|