mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-09 03:20:56 +00:00
fix(auth): stop demo mode from overriding authentication
The demo router hardcoded AuthMode::Disabled, which caused /auth/config and /auth/me to lie and let demo endpoints be reached without a session whenever the fabro-demo=1 cookie was set. With the cookie set on a GitHub-configured server, /login rendered "Paste your dev token" with no input and no GitHub button because /auth/config returned empty methods. Have the demo router inherit the real AuthMode so demo mode is purely a data-source toggle: authentication is identical regardless of the cookie. Update the translate test that locked in the old bypass, add a companion test for the authed happy path, and add a regression test that /auth/config returns real methods under the demo cookie. As defense in depth, the login page now renders an explicit "no authentication method is configured" state when methods is empty instead of the misleading dev-token prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
64e4239534
commit
710f9869f0
6 changed files with 66 additions and 6 deletions
|
|
@ -40,7 +40,9 @@ export default function AuthLogin({ loaderData }: any) {
|
|||
<p className="mt-3 text-center text-sm/6 text-fg-3 text-pretty">
|
||||
{hasGitHub
|
||||
? "Authenticate with your GitHub account to continue."
|
||||
: "Paste your dev token to continue."}
|
||||
: hasDevToken
|
||||
? "Paste your dev token to continue."
|
||||
: "No authentication method is configured on this server."}
|
||||
</p>
|
||||
<div className="mt-6 space-y-4">
|
||||
{hasGitHub ? (
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_router_routes_demo_cookie_to_demo_handler_without_credentials() {
|
||||
async fn full_router_rejects_demo_cookie_without_credentials() {
|
||||
let state = test_state();
|
||||
let app = server::build_router_with_options(
|
||||
state,
|
||||
|
|
@ -568,7 +568,37 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_status!(response, StatusCode::OK).await;
|
||||
assert_status!(response, StatusCode::UNAUTHORIZED).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn full_router_routes_demo_cookie_to_demo_handler_with_session() {
|
||||
let state = test_state();
|
||||
let cookie = session_cookie(&github_session(), state.as_ref());
|
||||
let app = server::build_router_with_options(
|
||||
Arc::clone(&state),
|
||||
&auth_mode(),
|
||||
Arc::new(crate::ip_allowlist::IpAllowlistConfig::default()),
|
||||
RouterOptions::default(),
|
||||
);
|
||||
|
||||
let response = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.method("POST")
|
||||
.uri("/api/v1/health/diagnostics")
|
||||
.header(header::COOKIE, format!("{cookie}; fabro-demo=1"))
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let body = response_json!(response).await;
|
||||
assert_eq!(
|
||||
body["sections"][0]["checks"][0]["summary"], "demo configured",
|
||||
"demo handler should have served /health/diagnostics",
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
|
|
@ -975,7 +975,7 @@ pub fn build_router_with_options(
|
|||
|
||||
let demo_router = Router::new()
|
||||
.nest("/api/v1", api_common.clone().merge(demo_routes()))
|
||||
.layer(axum::Extension(AuthMode::Disabled))
|
||||
.layer(axum::Extension(auth_mode.clone()))
|
||||
.layer(axum::Extension(Arc::clone(&github_endpoints)))
|
||||
.with_state(state.clone());
|
||||
|
||||
|
|
|
|||
|
|
@ -1117,6 +1117,34 @@ mod tests {
|
|||
assert_eq!(body, json!({ "methods": ["dev-token"] }));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn auth_config_returns_real_methods_when_demo_cookie_set() {
|
||||
let state = server::create_test_app_state_with_session_key(
|
||||
github_settings("https://fabro.example"),
|
||||
Some("web-auth-test-key-material-0123456789"),
|
||||
false,
|
||||
);
|
||||
let app = server::build_router_with_options(
|
||||
state,
|
||||
&github_auth_mode(),
|
||||
Arc::new(crate::ip_allowlist::IpAllowlistConfig::default()),
|
||||
server::RouterOptions::default(),
|
||||
);
|
||||
|
||||
let response = app
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri("/api/v1/auth/config")
|
||||
.header(header::COOKIE, "fabro-demo=1")
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let body = response_json!(response).await;
|
||||
assert_eq!(body, json!({ "methods": ["github"] }));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn login_github_sets_secure_state_cookie_for_https_web_url() {
|
||||
let app = test_auth_router_with_settings(
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
2
lib/crates/fabro-spa/assets/index.html
generated
2
lib/crates/fabro-spa/assets/index.html
generated
|
|
@ -58,7 +58,7 @@
|
|||
<script type="module" src="/assets/chunk-sadshphz.js"></script>
|
||||
<script type="module" src="/assets/chunk-pmthkscp.js"></script>
|
||||
<script type="module" src="/assets/chunk-v61ks9f7.js"></script>
|
||||
<script type="module" src="/assets/entry-nabtzckk.js"></script>
|
||||
<script type="module" src="/assets/entry-q11nrnd3.js"></script>
|
||||
<script type="module" src="/assets/chunk-n1k68xa8.js"></script>
|
||||
<script type="module" src="/assets/chunk-rsph5pvm.js"></script>
|
||||
<script type="module" src="/assets/chunk-9t57pdty.js"></script>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue