Private
Public Access
1
0

feat: Complete Azure SSO implementation (v0.1.3)

- Add SSO session cleanup task (10-min expiry, 60s purge interval)
- Change callback to redirect to frontend with tokens as query params
- Add sso_callback_url to SecurityConfig with serde default
- Add SsoCallbackPage.tsx for handling SSO callback redirects
- Add /auth/sso/callback public route to App.tsx
- Add Sign in with Microsoft Azure button to LoginPage
- Replace insecure decode_jwt_payload with verify_id_token
- Implement JWKS caching (1-hour TTL) and RSA signature verification
- Validate iss, aud, exp claims on id_token
- Add jsonwebtoken dependency to pm-web crate
- Update config.example.toml with sso_callback_url setting
- Add sso_callback_url to settings response (read-only from TOML)
This commit is contained in:
2026-05-12 17:01:20 +00:00
parent 08add28b80
commit 86a6c714d4
18 changed files with 561 additions and 239 deletions

View File

@ -40,6 +40,7 @@ pub struct SettingsResponse {
pub ip_whitelist: Vec<String>,
pub web_tls_strategy: String,
pub notification: NotificationConfig,
pub sso_callback_url: String,
}
#[derive(Debug, Serialize, Deserialize)]
@ -202,6 +203,7 @@ fn build_settings_response(
email_from: get("notification_email_from"),
recipients,
},
sso_callback_url: get("sso_callback_url"),
}
}
@ -269,6 +271,9 @@ async fn get_settings(
) -> Result<Json<SettingsResponse>, (StatusCode, Json<Value>)> {
admin_only(&auth)?;
let cfg = load_system_config(&state.db).await?;
// Inject read-only config values from TOML file (not stored in DB)
let mut cfg = cfg;
cfg.insert("sso_callback_url".to_string(), state.config.security.sso_callback_url.clone());
let azure = fetch_azure_sso_config(&state.db).await?;
Ok(Json(build_settings_response(&cfg, azure)))
}
@ -488,6 +493,9 @@ async fn update_settings(
// Return updated settings
let cfg = load_system_config(&state.db).await?;
// Inject read-only config values from TOML file (not stored in DB)
let mut cfg = cfg;
cfg.insert("sso_callback_url".to_string(), state.config.security.sso_callback_url.clone());
let azure = fetch_azure_sso_config(&state.db).await?;
Ok(Json(build_settings_response(&cfg, azure)))
}