101 lines
2.8 KiB
Rust
101 lines
2.8 KiB
Rust
use axum::http::{HeaderMap, StatusCode};
|
|
use tracing::warn;
|
|
|
|
use crate::state::AppState;
|
|
|
|
pub fn require_bootstrap_auth(
|
|
state: &AppState,
|
|
headers: &HeaderMap,
|
|
) -> Result<(), (StatusCode, String)> {
|
|
if state.config.allow_unauthenticated {
|
|
return Ok(());
|
|
}
|
|
|
|
let expected = match state.config.bootstrap_token.as_deref() {
|
|
Some(token) if !token.is_empty() => token,
|
|
_ => {
|
|
return Err((
|
|
StatusCode::SERVICE_UNAVAILABLE,
|
|
"bootstrap token not configured".to_string(),
|
|
))
|
|
}
|
|
};
|
|
|
|
let provided = extract_token(headers);
|
|
if provided.as_deref() == Some(expected) {
|
|
return Ok(());
|
|
}
|
|
|
|
Err((
|
|
StatusCode::UNAUTHORIZED,
|
|
"invalid bootstrap token".to_string(),
|
|
))
|
|
}
|
|
|
|
pub fn require_admin_auth(
|
|
state: &AppState,
|
|
headers: &HeaderMap,
|
|
) -> Result<(), (StatusCode, String)> {
|
|
if state.config.allow_unauthenticated {
|
|
return Ok(());
|
|
}
|
|
|
|
let expected = match state.config.admin_token.as_deref() {
|
|
Some(token) if !token.is_empty() => token,
|
|
_ => {
|
|
if !state.config.allow_admin_fallback {
|
|
return Err((
|
|
StatusCode::SERVICE_UNAVAILABLE,
|
|
"admin token not configured".to_string(),
|
|
));
|
|
}
|
|
|
|
match state.config.bootstrap_token.as_deref() {
|
|
Some(token) if !token.is_empty() => {
|
|
warn!("admin token not configured; falling back to bootstrap token");
|
|
token
|
|
}
|
|
_ => {
|
|
return Err((
|
|
StatusCode::SERVICE_UNAVAILABLE,
|
|
"admin token not configured".to_string(),
|
|
))
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
let provided = extract_token(headers);
|
|
if provided.as_deref() == Some(expected) {
|
|
return Ok(());
|
|
}
|
|
|
|
Err((StatusCode::UNAUTHORIZED, "invalid admin token".to_string()))
|
|
}
|
|
|
|
fn extract_token(headers: &HeaderMap) -> Option<String> {
|
|
if let Some(value) = headers.get("x-deployer-token") {
|
|
if let Ok(token) = value.to_str() {
|
|
let trimmed = token.trim();
|
|
if !trimmed.is_empty() {
|
|
return Some(trimmed.to_string());
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(value) = headers.get("authorization") {
|
|
if let Ok(auth) = value.to_str() {
|
|
let trimmed = auth.trim();
|
|
if let Some((scheme, rest)) = trimmed.split_once(' ') {
|
|
if scheme.eq_ignore_ascii_case("bearer") {
|
|
let token = rest.trim();
|
|
if !token.is_empty() {
|
|
return Some(token.to_string());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|