This commit is contained in:
Mateusz Gruszczyński committed 2026-10-27 12:18:20 +01:00
1 parent 62b7574553
commit e364392659
47 files changed
+2164 -257

No files matched your search

+1 -2
View File
@@ -267,7 +267,6 @@ fn finish_headers(
request_id: &str,
active: &[crate::vhost::Listener],
) {
// Global security headers form a baseline; explicitly set vhost values take precedence.
snapshot
.global_security
.headers
@@ -283,7 +282,7 @@ fn finish_headers(
.map(|f| &f.diagnostic_headers)
.unwrap_or(&snapshot.envelope.config.diagnostic_headers)
.apply(response.headers_mut(), request_id);
if frontend.is_some_and(|f| f.tinyauth.is_some() || f.basic_auth.is_some()) {
if frontend.is_some_and(|f| f.auth_provider.is_some() || f.basic_auth.is_some()) {
response.headers_mut().insert(
"cache-control",
HeaderValue::from_static("private, no-store"),
+2
View File
@@ -26,6 +26,8 @@ fn disabled_cache_retains_reason_without_matching_force_rules_or_reparsing_heade
"admin_control_plane",
"basic_auth",
"tinyauth",
"authelia",
"authentik",
"sticky_cookie",
"request_upgrade",
] {
+3 -3
View File
@@ -127,8 +127,8 @@ let policy_reason = if admin_control_plane {
Some("admin_control_plane")
} else if frontend.is_some_and(|f| f.basic_auth.is_some()) {
Some("basic_auth")
} else if frontend.is_some_and(|f| f.tinyauth.is_some()) {
Some("tinyauth")
} else if let Some(provider) = frontend.and_then(|f| f.auth_provider.as_ref()) {
Some(provider.id())
} else if route
.pool
.as_ref()
@@ -244,7 +244,7 @@ context.apply_upstream(
.as_ref()
.is_none_or(|frontend| frontend.forward_client_ip),
);
if let Some(auth) = frontend.and_then(|f| f.tinyauth.as_ref()) {
if let Some(auth) = frontend.and_then(|f| f.auth_provider.as_ref()) {
auth.strip_identity(request.headers_mut());
}
if let Some(identity) = identity {
+1 -1
View File
@@ -23,7 +23,7 @@
let transform_settings = route.frontend.as_ref().map(|frontend| &frontend.transform);
let scope = route.frontend.as_ref().map(|frontend| frontend.id.as_str()).unwrap_or("");
let enabled = cache_settings.active_for(route.cache)
&& frontend.is_none_or(|frontend| frontend.basic_auth.is_none() && frontend.tinyauth.is_none());
&& frontend.is_none_or(|frontend| frontend.basic_auth.is_none() && frontend.auth_provider.is_none());
if let Some(exchange) = request.extensions().get::<Arc<Exchange>>() {
exchange.set_cache_enabled(enabled);
exchange.set_transform_enabled(transform_settings.is_some_and(|settings| settings.enabled));
+26 -4
View File
@@ -2,9 +2,13 @@ async fn forward(
State(state): State<Arc<App>>,
Extension(peer): Extension<PeerAddr>,
Extension(local): Extension<LocalAddr>,
request: Request,
mut request: Request,
) -> Response {
forward_request(state, peer, local, request).await
let cookies = crate::auth_provider::CookieSink::default();
request.extensions_mut().insert(cookies.clone());
let mut response = forward_request(state, peer, local, request).await;
cookies.apply(&mut response);
response
}
async fn forward_request(
@@ -197,7 +201,7 @@ async fn forward_request(
tls,
&original_host,
request.uri(),
frontend.is_some_and(|frontend| frontend.tinyauth.is_some()),
frontend.is_some_and(|frontend| frontend.auth_provider.is_some()),
request
.extensions()
.get::<Arc<crate::forwarding::PeerFormatting>>()
@@ -464,6 +468,18 @@ async fn forward_request(
.filter(|route| route.error_fallback.is_some())
.map(|_| ErrorFallbackRequest::capture(&request, &snapshot));
let admin_cookie = headers::strip_admin_cookie(request.headers_mut());
if let Some(auth) = frontend.and_then(|frontend| frontend.auth_provider.as_ref()) {
if auth.reserved_path(&path) {
return match auth.serve_reserved(request, &context, &state.shutdown) {
Some(response) => response.await,
None => error(
StatusCode::BAD_GATEWAY,
"RustProxy: authentication route unavailable\n",
),
};
}
}
let basic_identity = if let Some(auth) = frontend.and_then(|f| f.basic_auth.as_ref()) {
match auth
.authorize(
@@ -487,14 +503,20 @@ async fn forward_request(
"RustProxy: WebSocket access is disabled for this host\n",
);
}
let identity = if let Some(auth) = frontend.and_then(|f| f.tinyauth.as_ref()) {
let identity = if let Some(auth) = frontend.and_then(|f| f.auth_provider.as_ref()) {
auth.strip_identity(request.headers_mut());
let cookies = request
.extensions()
.get::<crate::auth_provider::CookieSink>()
.cloned()
.unwrap_or_default();
match auth
.authorize(
request.headers(),
request.method(),
&context,
&state.shutdown,
&cookies,
)
.await
{
+21 -3
View File
@@ -37,7 +37,7 @@ fn should_replace_error_page(response: &Response, minimal_welcome: bool) -> bool
.is_none()
&& response
.extensions()
.get::<crate::tinyauth::AuthenticationFailure>()
.get::<crate::auth_provider::AuthenticationResponse>()
.is_none()
}
@@ -285,7 +285,7 @@ async fn observe(State(state): State<Arc<App>>, mut request: Request, next: Next
.is_none()
&& response
.extensions()
.get::<crate::tinyauth::AuthenticationFailure>()
.get::<crate::auth_provider::AuthenticationResponse>()
.is_none()
{
apply_response_rules(
@@ -385,7 +385,7 @@ async fn observe(State(state): State<Arc<App>>, mut request: Request, next: Next
.is_none()
&& response
.extensions()
.get::<crate::tinyauth::AuthenticationFailure>()
.get::<crate::auth_provider::AuthenticationResponse>()
.is_none()
{
let outcome = match exchange.cache_status.load(Ordering::Relaxed) {
@@ -513,3 +513,21 @@ fn effective_host(request: &Request, tls: bool) -> Result<HeaderValue, ()> {
request.headers().get(HOST).cloned().ok_or(())
}
}
#[cfg(test)]
mod auth_provider_page_interception_tests {
use super::*;
#[test]
fn provider_failures_and_redirects_bypass_custom_http_error_pages() {
for kind in [
crate::auth_provider::GatewayFailure::Connection,
crate::auth_provider::GatewayFailure::Timeout,
crate::auth_provider::GatewayFailure::Verification,
] {
let response = crate::auth_provider::gateway_failure("Future", kind);
assert!(!should_replace_error_page(&response, false));
}
let response = crate::auth_provider::deny(StatusCode::UNAUTHORIZED);
assert!(!should_replace_error_page(&response, false));
}
}