feat(directory): read admin credentials from ~/.gb-setup-credentials
Some checks failed
BotServer CI / build (push) Failing after 5m3s
Some checks failed
BotServer CI / build (push) Failing after 5m3s
- Updated setup_directory() to read credentials from saved file - Added read_saved_credentials() to parse ~/.gb-setup-credentials - Added get_admin_credentials() to try multiple sources - Removed default credentials approach (doesn't work) - Improved error messages with solution steps This matches the working approach from commit 86cfccc2 where credentials were saved during first bootstrap and reused for OAuth client creation on subsequent runs.
This commit is contained in:
parent
eb5c12c466
commit
2a6c599c75
1 changed files with 84 additions and 82 deletions
|
|
@ -135,6 +135,13 @@ fn extract_initial_admin_from_log(log_path: &std::path::Path) -> Option<(String,
|
|||
None
|
||||
}
|
||||
|
||||
/// Admin credentials structure
|
||||
#[cfg(feature = "directory")]
|
||||
struct AdminCredentials {
|
||||
email: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
/// Initialize Directory (Zitadel) with default admin user and OAuth application
|
||||
/// This should be called after Zitadel has started and is responding
|
||||
#[cfg(feature = "directory")]
|
||||
|
|
@ -159,96 +166,91 @@ pub async fn setup_directory() -> anyhow::Result<crate::core::package_manager::s
|
|||
}
|
||||
}
|
||||
|
||||
// Try multiple approaches to get initial admin credentials
|
||||
let log_path = PathBuf::from(&stack_path).join("logs/zitadel.log");
|
||||
// Try to get credentials from multiple sources
|
||||
let credentials = get_admin_credentials(&stack_path).await?;
|
||||
|
||||
// Approach 1: Try to extract credentials from Zitadel log
|
||||
let admin_credentials = extract_initial_admin_from_log(&log_path);
|
||||
|
||||
// Approach 2: Try well-known default credentials for initial Zitadel setup
|
||||
// Zitadel's default initial admin credentials (if any)
|
||||
let default_credentials = [
|
||||
// Try common default patterns
|
||||
("admin@localhost", "Password1!"),
|
||||
("zitadel-admin@localhost", "Password1!"),
|
||||
("admin", "admin"),
|
||||
];
|
||||
|
||||
// Find working credentials
|
||||
let working_credentials = if let Some((email, password)) = admin_credentials {
|
||||
log::info!("Using credentials extracted from Zitadel log");
|
||||
Some((email, password))
|
||||
} else {
|
||||
// Try default credentials
|
||||
log::info!("Attempting to authenticate with default Zitadel credentials...");
|
||||
let mut found = None;
|
||||
for (email, password) in default_credentials.iter() {
|
||||
if let Ok(true) = test_zitadel_credentials(&base_url, email, password).await {
|
||||
log::info!("Successfully authenticated with default credentials: {}", email);
|
||||
found = Some((email.to_string(), password.to_string()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
found
|
||||
};
|
||||
|
||||
let mut directory_setup = if let Some((email, password)) = working_credentials {
|
||||
log::info!("Using admin credentials for Directory setup: {}", email);
|
||||
crate::core::package_manager::setup::DirectorySetup::with_admin_credentials(
|
||||
base_url,
|
||||
config_path.clone(),
|
||||
email,
|
||||
password,
|
||||
)
|
||||
} else {
|
||||
// No credentials found - provide helpful error message
|
||||
log::error!("═══════════════════════════════════════════════════════════════");
|
||||
log::error!("❌ FAILED TO GET ZITADEL ADMIN CREDENTIALS");
|
||||
log::error!("═══════════════════════════════════════════════════════════════");
|
||||
log::error!("Could not extract credentials from Zitadel logs at:",);
|
||||
log::error!(" {}", log_path.display());
|
||||
log::error!("");
|
||||
log::error!("Please check the Zitadel logs manually for initial admin credentials:");
|
||||
log::error!(" tail -100 {}", log_path.display());
|
||||
log::error!("");
|
||||
log::error!("Then create the config file manually at:");
|
||||
log::error!(" {}", config_path.display());
|
||||
log::error!("═══════════════════════════════════════════════════════════════");
|
||||
|
||||
anyhow::bail!(
|
||||
"Failed to obtain Zitadel admin credentials. Check logs at {}",
|
||||
log_path.display()
|
||||
);
|
||||
};
|
||||
let mut directory_setup = crate::core::package_manager::setup::DirectorySetup::with_admin_credentials(
|
||||
base_url,
|
||||
config_path.clone(),
|
||||
credentials.email,
|
||||
credentials.password,
|
||||
);
|
||||
|
||||
directory_setup.initialize().await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to initialize directory: {}", e))
|
||||
}
|
||||
|
||||
/// Test if Zitadel credentials are valid by attempting to get an access token
|
||||
/// Get admin credentials from multiple sources
|
||||
#[cfg(feature = "directory")]
|
||||
async fn test_zitadel_credentials(base_url: &str, username: &str, password: &str) -> anyhow::Result<bool> {
|
||||
use reqwest::Client;
|
||||
async fn get_admin_credentials(stack_path: &str) -> anyhow::Result<AdminCredentials> {
|
||||
// Approach 1: Read from ~/.gb-setup-credentials (most reliable - from first bootstrap)
|
||||
if let Some(creds) = read_saved_credentials() {
|
||||
log::info!("Using credentials from ~/.gb-setup-credentials");
|
||||
return Ok(creds);
|
||||
}
|
||||
|
||||
let client = Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.build()
|
||||
.unwrap_or_else(|_| Client::new());
|
||||
// Approach 2: Try to extract from Zitadel logs (fallback)
|
||||
let log_path = std::path::PathBuf::from(stack_path).join("logs/directory/zitadel.log");
|
||||
if let Some((email, password)) = extract_initial_admin_from_log(&log_path) {
|
||||
log::info!("Using credentials extracted from Zitadel log");
|
||||
return Ok(AdminCredentials { email, password });
|
||||
}
|
||||
|
||||
let token_url = format!("{}/oauth/v2/token", base_url);
|
||||
let params = [
|
||||
("grant_type", "password".to_string()),
|
||||
("username", username.to_string()),
|
||||
("password", password.to_string()),
|
||||
("scope", "openid profile email".to_string()),
|
||||
];
|
||||
// Approach 3: Error with helpful message
|
||||
log::error!("═══════════════════════════════════════════════════════════════");
|
||||
log::error!("❌ FAILED TO GET ZITADEL ADMIN CREDENTIALS");
|
||||
log::error!("═══════════════════════════════════════════════════════════════");
|
||||
log::error!("Could not find credentials in:");
|
||||
log::error!(" - ~/.gb-setup-credentials");
|
||||
log::error!(" - {}/logs/directory/zitadel.log", stack_path);
|
||||
log::error!("");
|
||||
log::error!("SOLUTION: Run a fresh bootstrap to create initial admin user:");
|
||||
log::error!(" 1. Delete .env and botserver-stack/conf/system/.bootstrap_completed");
|
||||
log::error!(" 2. Run: ./reset.sh");
|
||||
log::error!(" 3. Admin credentials will be displayed and saved");
|
||||
log::error!("═══════════════════════════════════════════════════════════════");
|
||||
|
||||
let response = client
|
||||
.post(&token_url)
|
||||
.form(¶ms)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("Failed to test credentials: {}", e))?;
|
||||
|
||||
Ok(response.status().is_success())
|
||||
anyhow::bail!("No admin credentials found. Run fresh bootstrap to create them.")
|
||||
}
|
||||
|
||||
/// Read credentials from ~/.gb-setup-credentials file
|
||||
#[cfg(feature = "directory")]
|
||||
fn read_saved_credentials() -> Option<AdminCredentials> {
|
||||
let home = std::env::var("HOME").ok()?;
|
||||
let creds_path = std::path::PathBuf::from(&home).join(".gb-setup-credentials");
|
||||
|
||||
if !creds_path.exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let content = std::fs::read_to_string(&creds_path).ok()?;
|
||||
|
||||
// Parse credentials from file
|
||||
let mut username = None;
|
||||
let mut password = None;
|
||||
let mut email = None;
|
||||
|
||||
for line in content.lines() {
|
||||
if line.contains("Username:") {
|
||||
username = line.split("Username:")
|
||||
.nth(1)
|
||||
.map(|s| s.trim().to_string());
|
||||
}
|
||||
if line.contains("Password:") {
|
||||
password = line.split("Password:")
|
||||
.nth(1)
|
||||
.map(|s| s.trim().to_string());
|
||||
}
|
||||
if line.contains("Email:") {
|
||||
email = line.split("Email:")
|
||||
.nth(1)
|
||||
.map(|s| s.trim().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(_username), Some(password), Some(email)) = (username, password, email) {
|
||||
Some(AdminCredentials { email, password })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue