fix: auth login domain resolution with --domain flag
Domain resolves from: --domain flag > cached token > config production_host > cluster discovery. Clear error when none available.
This commit is contained in:
63
src/auth.rs
63
src/auth.rs
@@ -103,6 +103,49 @@ struct OidcDiscovery {
|
|||||||
token_endpoint: String,
|
token_endpoint: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve the domain for authentication, trying multiple sources.
|
||||||
|
async fn resolve_domain(explicit: Option<&str>) -> Result<String> {
|
||||||
|
// 1. Explicit --domain flag
|
||||||
|
if let Some(d) = explicit {
|
||||||
|
if !d.is_empty() {
|
||||||
|
return Ok(d.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Cached token domain (already logged in to a domain)
|
||||||
|
if let Ok(tokens) = read_cache() {
|
||||||
|
if !tokens.domain.is_empty() {
|
||||||
|
crate::output::ok(&format!("Using cached domain: {}", tokens.domain));
|
||||||
|
return Ok(tokens.domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Config: derive from production_host
|
||||||
|
let config = crate::config::load_config();
|
||||||
|
if !config.production_host.is_empty() {
|
||||||
|
let host = &config.production_host;
|
||||||
|
let raw = host.split('@').last().unwrap_or(host);
|
||||||
|
let raw = raw.split(':').next().unwrap_or(raw);
|
||||||
|
// Take the last 2+ segments as the domain (e.g. admin.sunbeam.pt -> sunbeam.pt)
|
||||||
|
let parts: Vec<&str> = raw.split('.').collect();
|
||||||
|
if parts.len() >= 2 {
|
||||||
|
let domain = format!("{}.{}", parts[parts.len() - 2], parts[parts.len() - 1]);
|
||||||
|
return Ok(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Try cluster discovery (may fail if not connected)
|
||||||
|
match crate::kube::get_domain().await {
|
||||||
|
Ok(d) if !d.is_empty() && !d.starts_with(".") => return Ok(d),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(SunbeamError::config(
|
||||||
|
"Could not determine domain. Use --domain flag, or configure with:\n \
|
||||||
|
sunbeam config set --host user@your-server.example.com"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
async fn discover_oidc(domain: &str) -> Result<OidcDiscovery> {
|
async fn discover_oidc(domain: &str) -> Result<OidcDiscovery> {
|
||||||
let url = format!("https://auth.{domain}/.well-known/openid-configuration");
|
let url = format!("https://auth.{domain}/.well-known/openid-configuration");
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
@@ -403,25 +446,11 @@ pub async fn get_token() -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Interactive browser-based OAuth2 login.
|
/// Interactive browser-based OAuth2 login.
|
||||||
pub async fn cmd_auth_login() -> Result<()> {
|
pub async fn cmd_auth_login(domain_override: Option<&str>) -> Result<()> {
|
||||||
crate::output::step("Authenticating with Hydra");
|
crate::output::step("Authenticating with Hydra");
|
||||||
|
|
||||||
// Resolve domain
|
// Resolve domain: explicit flag > cached token domain > config > cluster discovery
|
||||||
let config = crate::config::load_config();
|
let domain = resolve_domain(domain_override).await?;
|
||||||
let domain = if !config.production_host.is_empty() {
|
|
||||||
// Extract domain from production host if available
|
|
||||||
let host = &config.production_host;
|
|
||||||
let raw = host.split('@').last().unwrap_or(host);
|
|
||||||
let raw = raw.split(':').next().unwrap_or(raw);
|
|
||||||
// If it looks like an IP or hostname, try to get domain from cluster
|
|
||||||
if raw.contains('.') && !raw.chars().next().unwrap_or('0').is_ascii_digit() {
|
|
||||||
raw.to_string()
|
|
||||||
} else {
|
|
||||||
crate::kube::get_domain().await?
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
crate::kube::get_domain().await?
|
|
||||||
};
|
|
||||||
|
|
||||||
crate::output::ok(&format!("Domain: {domain}"));
|
crate::output::ok(&format!("Domain: {domain}"));
|
||||||
|
|
||||||
|
|||||||
10
src/cli.rs
10
src/cli.rs
@@ -168,7 +168,11 @@ pub enum Verb {
|
|||||||
#[derive(Subcommand, Debug)]
|
#[derive(Subcommand, Debug)]
|
||||||
pub enum AuthAction {
|
pub enum AuthAction {
|
||||||
/// Log in via browser (OAuth2 authorization code flow).
|
/// Log in via browser (OAuth2 authorization code flow).
|
||||||
Login,
|
Login {
|
||||||
|
/// Domain to authenticate against (e.g. sunbeam.pt).
|
||||||
|
#[arg(long)]
|
||||||
|
domain: Option<String>,
|
||||||
|
},
|
||||||
/// Log out (remove cached tokens).
|
/// Log out (remove cached tokens).
|
||||||
Logout,
|
Logout,
|
||||||
/// Show current authentication status.
|
/// Show current authentication status.
|
||||||
@@ -1002,7 +1006,9 @@ pub async fn dispatch() -> Result<()> {
|
|||||||
None => {
|
None => {
|
||||||
crate::auth::cmd_auth_status().await
|
crate::auth::cmd_auth_status().await
|
||||||
}
|
}
|
||||||
Some(AuthAction::Login) => crate::auth::cmd_auth_login().await,
|
Some(AuthAction::Login { domain }) => {
|
||||||
|
crate::auth::cmd_auth_login(domain.as_deref()).await
|
||||||
|
}
|
||||||
Some(AuthAction::Logout) => crate::auth::cmd_auth_logout().await,
|
Some(AuthAction::Logout) => crate::auth::cmd_auth_logout().await,
|
||||||
Some(AuthAction::Status) => crate::auth::cmd_auth_status().await,
|
Some(AuthAction::Status) => crate::auth::cmd_auth_status().await,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user