outposts/proxy: include query string in post-authentication redirect (#25043)

providers/proxy: include query string in post-authentication redirect

Closes: #24966
This commit is contained in:
Dominic Roy
2026-08-13 06:40:50 -04:00
committed by GitHub
parent 06d90d0f38
commit 5ca02ca26e
3 changed files with 53 additions and 1 deletions

View File

@@ -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, ".")

View File

@@ -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()

View File

@@ -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"
);
}
}