diff --git a/.env.example b/.env.example deleted file mode 100644 index 2f4ae554..00000000 --- a/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -FLEET_AUTH_ISSUER_URL= -FLEET_AUTH_AUTHORIZE_URL= -FLEET_AUTH_TOKEN_URL= -FLEET_AUTH_CLIENT_ID= -FLEET_AUTH_REDIRECT_URI= -FLEET_AUTH_SCOPE= -FLEET_AUTH_TRUSTED_AUDIENCES= diff --git a/examples/fleet_auth_callout/src/lib.rs b/examples/fleet_auth_callout/src/lib.rs index c2d4c9bf..a87cb37e 100644 --- a/examples/fleet_auth_callout/src/lib.rs +++ b/examples/fleet_auth_callout/src/lib.rs @@ -759,7 +759,7 @@ pub async fn mint_access_token( access_token: String, } let tr: TokenResponse = resp.json().await.context("parse token response")?; - if std::env::var("FLEET_AUTH_CALLOUT_DEBUG_TOKENS").is_ok() + if std::env::var("HARMONY_SSO_CALLOUT_DEBUG_TOKENS").is_ok() && let Some(payload_b64) = tr.access_token.split('.').nth(1) { use base64::Engine; diff --git a/fleet/harmony-fleet-operator/dev.sh b/fleet/harmony-fleet-operator/dev.sh index 812f8272..a73268bf 100644 --- a/fleet/harmony-fleet-operator/dev.sh +++ b/fleet/harmony-fleet-operator/dev.sh @@ -1,12 +1,12 @@ #!/bin/bash export BASE_URL=http://localhost:18080 -export FLEET_AUTH_ZITADEL_BASE=https://sso-stg.cb1.nationtech.io -export FLEET_AUTH_CLIENT_ID=372626218874372917 -export FLEET_AUTH_SCOPE="openid profile email" -export FLEET_AUTH_LOGOUT_REDIRECT_URI="http://localhost:18080/" -export FLEET_OPERATOR_COOKIE_KEY_B64=6eKVpj88jwIcmaJajPfohdaIXhSPlfYCrHaOfymTcIWBAIadvhg7NHpMo5vPSMy90vac3cq2liWe1naSgkbaYg== -export FLEET_AUTH_TRUSTED_AUDIENCES=371639797493596981,371683318111994677,372626218874372917,371639797157987125 +export HARMONY_SSO_ZITADEL_BASE=https://sso-stg.cb1.nationtech.io +export HARMONY_SSO_CLIENT_ID=372626218874372917 +export HARMONY_SSO_SCOPE="openid profile email" +export HARMONY_SSO_LOGOUT_REDIRECT_URI="http://localhost:18080/" +export HARMONY_COOKIE_KEY_B64=6eKVpj88jwIcmaJajPfohdaIXhSPlfYCrHaOfymTcIWBAIadvhg7NHpMo5vPSMy90vac3cq2liWe1naSgkbaYg== +export HARMONY_SSO_TRUSTED_AUDIENCES=371639797493596981,371683318111994677,372626218874372917,371639797157987125 export BASE_URL=http://localhost:18080 export RUST_LOG=debug diff --git a/harmony_zitadel_auth/src/axum_login_flow.rs b/harmony_zitadel_auth/src/axum_login_flow.rs index 96a9391f..0a61613e 100644 --- a/harmony_zitadel_auth/src/axum_login_flow.rs +++ b/harmony_zitadel_auth/src/axum_login_flow.rs @@ -9,8 +9,8 @@ use base64::engine::general_purpose::URL_SAFE_NO_PAD; use crate::config::ZitadelAuthConfig; use crate::jwks::JwksCache; use crate::login::{ - AuthCallbackQuery, RawAuthCallbackQuery, TokenResponse, build_login_attempt, build_logout_url, - exchange_code_for_token, jwt_exp, validate_callback_state, + AuthCallbackQuery, LoginQuery, RawAuthCallbackQuery, TokenResponse, build_login_attempt, + build_logout_url, exchange_code_for_token, jwt_exp, valid_next, validate_callback_state, }; use crate::session::LoginAttemptCookie; @@ -23,8 +23,9 @@ pub const HARMONY_SESSION_COOKIE: &str = "harmony_fleet_session"; pub async fn login_handler( jar: PrivateCookieJar, State(config): State, + Query(query): Query, ) -> Response { - match build_login_response(jar, &config) { + match build_login_response(jar, &config, query) { Ok(r) => r.into_response(), Err(e) => auth_error_response(e), } @@ -33,9 +34,16 @@ pub async fn login_handler( fn build_login_response( jar: PrivateCookieJar, config: &ZitadelAuthConfig, + query: LoginQuery, ) -> Result { let attempt = build_login_attempt(config)?; - let cookie_payload = LoginAttemptCookie::from(&attempt); + let mut cookie_payload = LoginAttemptCookie::from(&attempt); + cookie_payload.next = Some( + query + .next + .filter(|next| valid_next(next)) + .unwrap_or_else(|| "/".to_string()), + ); let cookie_value = URL_SAFE_NO_PAD.encode(serde_json::to_vec(&cookie_payload)?); let mut builder = Cookie::build((LOGIN_ATTEMPT_COOKIE, cookie_value)) @@ -113,7 +121,12 @@ async fn build_callback_response( } let session_jar = session_jar.add(session_cookie(&tokens, config)); - Ok((jar, session_jar, Redirect::to("/")).into_response()) + let next = attempt + .next + .as_deref() + .filter(|next| valid_next(next)) + .unwrap_or("/"); + Ok((jar, session_jar, Redirect::to(next)).into_response()) } AuthCallbackQuery::Failure { error, diff --git a/harmony_zitadel_auth/src/config.rs b/harmony_zitadel_auth/src/config.rs index 52019426..34e81415 100644 --- a/harmony_zitadel_auth/src/config.rs +++ b/harmony_zitadel_auth/src/config.rs @@ -33,13 +33,13 @@ impl ZitadelAuthConfig { } } -pub const ZITADEL_BASE_ENV: &str = "FLEET_AUTH_ZITADEL_BASE"; +pub const ZITADEL_BASE_ENV: &str = "HARMONY_SSO_ZITADEL_BASE"; pub const BASE_URL_ENV: &str = "BASE_URL"; -pub const CLIENT_ID_ENV: &str = "FLEET_AUTH_CLIENT_ID"; -pub const SCOPE_ENV: &str = "FLEET_AUTH_SCOPE"; -pub const TRUSTED_AUDIENCES_ENV: &str = "FLEET_AUTH_TRUSTED_AUDIENCES"; -pub const LOGOUT_REDIRECT_URI_ENV: &str = "FLEET_AUTH_LOGOUT_REDIRECT_URI"; -pub const COOKIE_KEY_ENV: &str = "FLEET_OPERATOR_COOKIE_KEY_B64"; +pub const CLIENT_ID_ENV: &str = "HARMONY_SSO_CLIENT_ID"; +pub const SCOPE_ENV: &str = "HARMONY_SSO_SCOPE"; +pub const TRUSTED_AUDIENCES_ENV: &str = "HARMONY_SSO_TRUSTED_AUDIENCES"; +pub const LOGOUT_REDIRECT_URI_ENV: &str = "HARMONY_SSO_LOGOUT_REDIRECT_URI"; +pub const COOKIE_KEY_ENV: &str = "HARMONY_COOKIE_KEY_B64"; pub fn config_from_env() -> ZitadelAuthConfig { ZitadelAuthConfig { diff --git a/harmony_zitadel_auth/src/lib.rs b/harmony_zitadel_auth/src/lib.rs index f5cd0e78..ff232b35 100644 --- a/harmony_zitadel_auth/src/lib.rs +++ b/harmony_zitadel_auth/src/lib.rs @@ -15,9 +15,9 @@ pub use config::{ pub use jwks::JwksCache; pub use login::{ - AuthCallbackQuery, LoginAttempt, RawAuthCallbackQuery, TokenResponse, ValidatedUser, + AuthCallbackQuery, LoginAttempt, LoginQuery, RawAuthCallbackQuery, TokenResponse, ValidatedUser, build_login_attempt, build_logout_url, exchange_code_for_token, jwt_exp, - validate_callback_state, validate_id_token, + valid_next, validate_callback_state, validate_id_token, }; pub use session::{LoginAttemptCookie, VerifiedSession}; diff --git a/harmony_zitadel_auth/src/login.rs b/harmony_zitadel_auth/src/login.rs index c92aae1b..a87c8578 100644 --- a/harmony_zitadel_auth/src/login.rs +++ b/harmony_zitadel_auth/src/login.rs @@ -37,6 +37,11 @@ pub struct TokenResponse { pub expires_in: Option, } +#[derive(Debug, Deserialize)] +pub struct LoginQuery { + pub next: Option, +} + #[derive(Debug, Deserialize)] pub struct RawAuthCallbackQuery { pub code: Option, @@ -63,10 +68,15 @@ impl From<&LoginAttempt> for LoginAttemptCookie { state: attempt.state.clone(), pkce_code_verifier: attempt.pkce_code_verifier.clone(), nonce: attempt.nonce.clone(), + next: None, } } } +pub fn valid_next(next: &str) -> bool { + next.starts_with('/') && !next.starts_with("//") && !next.chars().any(char::is_control) +} + impl TryFrom for AuthCallbackQuery { type Error = anyhow::Error; diff --git a/harmony_zitadel_auth/src/session.rs b/harmony_zitadel_auth/src/session.rs index 8e5f73c3..68f9dbf9 100644 --- a/harmony_zitadel_auth/src/session.rs +++ b/harmony_zitadel_auth/src/session.rs @@ -18,4 +18,5 @@ pub struct LoginAttemptCookie { pub state: String, pub pkce_code_verifier: String, pub nonce: String, + pub next: Option, }