From 5ca02ca26ef45e3c6a0bd05c9475159cd04f3b4f Mon Sep 17 00:00:00 2001 From: Dominic Roy Date: Thu, 13 Aug 2026 06:40:50 -0400 Subject: [PATCH] outposts/proxy: include query string in post-authentication redirect (#25043) providers/proxy: include query string in post-authentication redirect Closes: #24966 --- internal/outpost/proxyv2/application/oauth.go | 3 ++ .../outpost/proxyv2/application/utils_test.go | 17 ++++++++++ src/outpost/proxy/application/handlers/mod.rs | 34 ++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/internal/outpost/proxyv2/application/oauth.go b/internal/outpost/proxyv2/application/oauth.go index d6486db1dc..ee59db06b0 100644 --- a/internal/outpost/proxyv2/application/oauth.go +++ b/internal/outpost/proxyv2/application/oauth.go @@ -77,6 +77,9 @@ func (a *Application) redirectToStart(rw http.ResponseWriter, r *http.Request) { } redirectUrl := urlJoin(a.proxyConfig.ExternalHost, r.URL.EscapedPath()) + if r.URL.RawQuery != "" { + redirectUrl += "?" + r.URL.RawQuery + } if a.Mode() == api.PROXYMODE_FORWARD_DOMAIN { dom := strings.TrimPrefix(*a.proxyConfig.CookieDomain, ".") diff --git a/internal/outpost/proxyv2/application/utils_test.go b/internal/outpost/proxyv2/application/utils_test.go index 9800549005..c84b371767 100644 --- a/internal/outpost/proxyv2/application/utils_test.go +++ b/internal/outpost/proxyv2/application/utils_test.go @@ -27,6 +27,23 @@ func TestRedirectToStart_Proxy(t *testing.T) { assert.Equal(t, "https://test.goauthentik.io/foo/bar/baz", s.Values[constants.SessionRedirect]) } +func TestRedirectToStart_Proxy_Query(t *testing.T) { + a := newTestApplication() + a.proxyConfig.Mode = api.PROXYMODE_PROXY.Ptr() + a.proxyConfig.ExternalHost = "https://test.goauthentik.io" + req, _ := http.NewRequest("GET", "/foo/bar/baz?foo=bar&baz=qux", nil) + + rr := httptest.NewRecorder() + a.redirectToStart(rr, req) + + assert.Equal(t, http.StatusFound, rr.Code) + loc, _ := rr.Result().Location() + assert.Equal(t, "https://test.goauthentik.io/outpost.goauthentik.io/start?rd=https%3A%2F%2Ftest.goauthentik.io%2Ffoo%2Fbar%2Fbaz%3Ffoo%3Dbar%26baz%3Dqux", loc.String()) + + s, _ := a.sessions.Get(req, a.SessionName()) + assert.Equal(t, "https://test.goauthentik.io/foo/bar/baz?foo=bar&baz=qux", s.Values[constants.SessionRedirect]) +} + func TestRedirectToStart_Proxy_EncodedSlash(t *testing.T) { a := newTestApplication() a.proxyConfig.Mode = api.PROXYMODE_PROXY.Ptr() diff --git a/src/outpost/proxy/application/handlers/mod.rs b/src/outpost/proxy/application/handlers/mod.rs index 05202370fd..7da3915bf6 100644 --- a/src/outpost/proxy/application/handlers/mod.rs +++ b/src/outpost/proxy/application/handlers/mod.rs @@ -129,6 +129,13 @@ pub(super) fn auth_start( .into_response()) } +/// The originally-requested URL — path and query — resolved against the +/// configured external host. +fn requested_url(external_host: &str, uri: &Uri) -> String { + let path_and_query = uri.path_and_query().map_or("/", |target| target.as_str()); + oauth::url_join(external_host, path_and_query) +} + /// Redirect an unauthenticated request to the auth-start endpoint, carrying the /// originally-requested URL in the `rd` parameter. #[instrument(skip_all)] @@ -149,7 +156,7 @@ pub(super) fn redirect_to_start( )); } - let mut redirect = oauth::url_join(&app.provider.external_host, uri.path()); + let mut redirect = requested_url(&app.provider.external_host, uri); if app.provider.mode == Some(ProxyMode::ForwardDomain) { let valid = app .provider @@ -351,3 +358,28 @@ pub(super) async fn handle_sign_out( ) .into_response()) } + +#[cfg(test)] +mod tests { + use axum::http::Uri; + + use super::requested_url; + + #[test] + fn requested_url_keeps_query() { + let uri: Uri = "/some/path?foo=bar&baz=qux".parse().expect("valid uri"); + assert_eq!( + requested_url("https://app.example.com", &uri), + "https://app.example.com/some/path?foo=bar&baz=qux" + ); + } + + #[test] + fn requested_url_path_only() { + let uri: Uri = "/some/path".parse().expect("valid uri"); + assert_eq!( + requested_url("https://app.example.com", &uri), + "https://app.example.com/some/path" + ); + } +}