diff --git a/src/server/oidc.rs b/src/server/oidc.rs index 043429f..8dcc032 100644 --- a/src/server/oidc.rs +++ b/src/server/oidc.rs @@ -33,6 +33,13 @@ type OidcClient = CoreClient< >; pub struct Oidc { + /// `None` when `KANIDM_URL` is unset: a content-only instance with + /// sign-in disabled - auth routes answer 503, everything public + /// renders as usual. + inner: Option, +} + +struct OidcInner { client: OidcClient, http: openidconnect::reqwest::Client, } @@ -45,7 +52,13 @@ const REDIRECT_KEY: &str = "oidc_post_login_redirect"; impl Oidc { /// Discovers the provider and builds the client from environment: /// `KANIDM_URL`, `OAUTH2_CLIENT_ID`, `OAUTH2_CLIENT_SECRET`, `PUBLIC_URL`. + /// With `KANIDM_URL` unset, sign-in is disabled instead of fatal - + /// the shape of a public content instance without a review desk. pub async fn from_env() -> anyhow::Result { + if std::env::var("KANIDM_URL").is_err() { + tracing::warn!("KANIDM_URL not set - sign-in disabled on this instance"); + return Ok(Self { inner: None }); + } let kanidm_url = require_env("KANIDM_URL")?; let client_id = require_env("OAUTH2_CLIENT_ID")?; let client_secret = require_env("OAUTH2_CLIENT_SECRET")?; @@ -75,7 +88,16 @@ impl Oidc { ) .set_redirect_uri(redirect); - Ok(Self { client, http }) + Ok(Self { + inner: Some(OidcInner { client, http }), + }) + } + + fn configured(&self) -> Result<&OidcInner, HandlerError> { + self.inner.as_ref().ok_or(( + StatusCode::SERVICE_UNAVAILABLE, + "sign-in is not configured on this instance".to_string(), + )) } } @@ -118,10 +140,10 @@ pub async fn login( session.insert(REDIRECT_KEY, redirect).await.map_err(internal)?; } + let oidc = state.oidc.configured()?; let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); - let (auth_url, csrf_state, nonce) = state - .oidc + let (auth_url, csrf_state, nonce) = oidc .client .authorize_url( CoreAuthenticationFlow::AuthorizationCode, @@ -182,7 +204,7 @@ pub async fn callback( )); } - let oidc = &state.oidc; + let oidc = state.oidc.configured()?; let token_response = oidc .client .exchange_code(AuthorizationCode::new(params.code))