Bladeren bron

Psgl auth db (#1095)

* feat(cdk-mintd): add dedicated auth database configuration support
thesimplekid 3 weken geleden
bovenliggende
commit
df2f9d1c2a

+ 1 - 0
crates/cdk-integration-tests/src/bin/start_regtest_mints.rs

@@ -295,6 +295,7 @@ fn create_ldk_settings(
         fake_wallet: None,
         grpc_processor: None,
         database: cdk_mintd::config::Database::default(),
+        auth_database: None,
         mint_management_rpc: None,
         prometheus: None,
         auth: None,

+ 3 - 0
crates/cdk-integration-tests/src/shared.rs

@@ -219,6 +219,7 @@ pub fn create_fake_wallet_settings(
             engine: DatabaseEngine::from_str(database).expect("valid database"),
             postgres: None,
         },
+        auth_database: None,
         mint_management_rpc: None,
         auth: None,
         prometheus: Some(Default::default()),
@@ -268,6 +269,7 @@ pub fn create_cln_settings(
         fake_wallet: None,
         grpc_processor: None,
         database: cdk_mintd::config::Database::default(),
+        auth_database: None,
         mint_management_rpc: None,
         auth: None,
         prometheus: Some(Default::default()),
@@ -315,6 +317,7 @@ pub fn create_lnd_settings(
         fake_wallet: None,
         grpc_processor: None,
         database: cdk_mintd::config::Database::default(),
+        auth_database: None,
         mint_management_rpc: None,
         auth: None,
         prometheus: Some(Default::default()),

+ 13 - 0
crates/cdk-mintd/example.config.toml

@@ -74,6 +74,19 @@ max_connections = 20
 # Connection timeout in seconds (optional, defaults to 10)
 connection_timeout_seconds = 10
 
+# Auth database configuration (optional, only used when auth is enabled)
+[auth_database.postgres]
+# PostgreSQL connection URL for authentication database
+# Can also be set via CDK_MINTD_AUTH_POSTGRES_URL environment variable
+# Environment variables take precedence over config file settings
+url = "postgresql://user:password@localhost:5432/cdk_mint_auth"
+# TLS mode: "disable", "prefer", "require" (optional, defaults to "disable")
+tls_mode = "disable"
+# Maximum number of connections in the pool (optional, defaults to 20)
+max_connections = 20
+# Connection timeout in seconds (optional, defaults to 10)
+connection_timeout_seconds = 10
+
 [ln]
 # Required ln backend `cln`, `lnd`, `fakewallet`, 'lnbits', 'ldknode'
 ln_backend = "fakewallet"

+ 26 - 0
crates/cdk-mintd/src/config.rs

@@ -367,6 +367,30 @@ pub struct Database {
     pub postgres: Option<PostgresConfig>,
 }
 
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct AuthDatabase {
+    pub postgres: Option<PostgresAuthConfig>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PostgresAuthConfig {
+    pub url: String,
+    pub tls_mode: Option<String>,
+    pub max_connections: Option<usize>,
+    pub connection_timeout_seconds: Option<u64>,
+}
+
+impl Default for PostgresAuthConfig {
+    fn default() -> Self {
+        Self {
+            url: String::new(),
+            tls_mode: Some("disable".to_string()),
+            max_connections: Some(20),
+            connection_timeout_seconds: Some(10),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct PostgresConfig {
     pub url: String,
@@ -457,6 +481,8 @@ pub struct Settings {
     pub fake_wallet: Option<FakeWallet>,
     pub grpc_processor: Option<GrpcProcessor>,
     pub database: Database,
+    #[cfg(feature = "auth")]
+    pub auth_database: Option<AuthDatabase>,
     #[cfg(feature = "management-rpc")]
     pub mint_management_rpc: Option<MintManagementRpc>,
     pub auth: Option<Auth>,

+ 33 - 1
crates/cdk-mintd/src/env_vars/database.rs

@@ -2,13 +2,19 @@
 
 use std::env;
 
-use crate::config::PostgresConfig;
+use crate::config::{PostgresAuthConfig, PostgresConfig};
 
 pub const ENV_POSTGRES_URL: &str = "CDK_MINTD_POSTGRES_URL";
 pub const ENV_POSTGRES_TLS_MODE: &str = "CDK_MINTD_POSTGRES_TLS_MODE";
 pub const ENV_POSTGRES_MAX_CONNECTIONS: &str = "CDK_MINTD_POSTGRES_MAX_CONNECTIONS";
 pub const ENV_POSTGRES_CONNECTION_TIMEOUT: &str = "CDK_MINTD_POSTGRES_CONNECTION_TIMEOUT_SECONDS";
 
+pub const ENV_AUTH_POSTGRES_URL: &str = "CDK_MINTD_AUTH_POSTGRES_URL";
+pub const ENV_AUTH_POSTGRES_TLS_MODE: &str = "CDK_MINTD_AUTH_POSTGRES_TLS_MODE";
+pub const ENV_AUTH_POSTGRES_MAX_CONNECTIONS: &str = "CDK_MINTD_AUTH_POSTGRES_MAX_CONNECTIONS";
+pub const ENV_AUTH_POSTGRES_CONNECTION_TIMEOUT: &str =
+    "CDK_MINTD_AUTH_POSTGRES_CONNECTION_TIMEOUT_SECONDS";
+
 impl PostgresConfig {
     pub fn from_env(mut self) -> Self {
         // Check for new PostgreSQL URL env var first, then fallback to legacy DATABASE_URL
@@ -38,3 +44,29 @@ impl PostgresConfig {
         self
     }
 }
+
+impl PostgresAuthConfig {
+    pub fn from_env(mut self) -> Self {
+        if let Ok(url) = env::var(ENV_AUTH_POSTGRES_URL) {
+            self.url = url;
+        }
+
+        if let Ok(tls_mode) = env::var(ENV_AUTH_POSTGRES_TLS_MODE) {
+            self.tls_mode = Some(tls_mode);
+        }
+
+        if let Ok(max_connections) = env::var(ENV_AUTH_POSTGRES_MAX_CONNECTIONS) {
+            if let Ok(parsed) = max_connections.parse::<usize>() {
+                self.max_connections = Some(parsed);
+            }
+        }
+
+        if let Ok(timeout) = env::var(ENV_AUTH_POSTGRES_CONNECTION_TIMEOUT) {
+            if let Ok(parsed) = timeout.parse::<u64>() {
+                self.connection_timeout_seconds = Some(parsed);
+            }
+        }
+
+        self
+    }
+}

+ 15 - 0
crates/cdk-mintd/src/env_vars/mod.rs

@@ -75,6 +75,21 @@ impl Settings {
             );
         }
 
+        // Parse auth database configuration from environment variables (when auth is enabled)
+        #[cfg(feature = "auth")]
+        {
+            self.auth_database = Some(crate::config::AuthDatabase {
+                postgres: Some(
+                    self.auth_database
+                        .clone()
+                        .unwrap_or_default()
+                        .postgres
+                        .unwrap_or_default()
+                        .from_env(),
+                ),
+            });
+        }
+
         self.info = self.info.clone().from_env();
         self.mint_info = self.mint_info.clone().from_env();
         self.ln = self.ln.clone().from_env();

+ 35 - 7
crates/cdk-mintd/src/lib.rs

@@ -43,7 +43,7 @@ use cdk_common::database::DynMintDatabase;
 #[cfg(feature = "prometheus")]
 use cdk_common::payment::MetricsMintPayment;
 use cdk_common::payment::MintPayment;
-#[cfg(feature = "auth")]
+#[cfg(all(feature = "auth", feature = "postgres"))]
 use cdk_postgres::MintPgAuthDatabase;
 #[cfg(feature = "postgres")]
 use cdk_postgres::MintPgDatabase;
@@ -663,16 +663,20 @@ async fn setup_authentication(
             DatabaseEngine::Postgres => {
                 #[cfg(feature = "postgres")]
                 {
-                    // Get the PostgreSQL configuration, ensuring it exists
-                    let pg_config = settings.database.postgres.as_ref().ok_or_else(|| {
-                        anyhow!("PostgreSQL configuration is required when using PostgreSQL engine")
+                    // Require dedicated auth database configuration - no fallback to main database
+                    let auth_db_config = settings.auth_database.as_ref().ok_or_else(|| {
+                        anyhow!("Auth database configuration is required when using PostgreSQL with authentication. Set [auth_database] section in config file or CDK_MINTD_AUTH_POSTGRES_URL environment variable")
+                    })?;
+
+                    let auth_pg_config = auth_db_config.postgres.as_ref().ok_or_else(|| {
+                        anyhow!("PostgreSQL auth database configuration is required when using PostgreSQL with authentication. Set [auth_database.postgres] section in config file or CDK_MINTD_AUTH_POSTGRES_URL environment variable")
                     })?;
 
-                    if pg_config.url.is_empty() {
-                        bail!("PostgreSQL URL is required for auth database. Set it in config file [database.postgres] section or via CDK_MINTD_POSTGRES_URL/CDK_MINTD_DATABASE_URL environment variable");
+                    if auth_pg_config.url.is_empty() {
+                        bail!("Auth database PostgreSQL URL is required and cannot be empty. Set it in config file [auth_database.postgres] section or via CDK_MINTD_AUTH_POSTGRES_URL environment variable");
                     }
 
-                    Arc::new(MintPgAuthDatabase::new(pg_config.url.as_str()).await?)
+                    Arc::new(MintPgAuthDatabase::new(auth_pg_config.url.as_str()).await?)
                 }
                 #[cfg(not(feature = "postgres"))]
                 {
@@ -1188,3 +1192,27 @@ pub async fn run_mintd_with_shutdown(
     )
     .await
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_postgres_auth_url_validation() {
+        // Test that the auth database config requires explicit configuration
+
+        // Test empty URL
+        let auth_config = config::PostgresAuthConfig {
+            url: "".to_string(),
+            ..Default::default()
+        };
+        assert!(auth_config.url.is_empty());
+
+        // Test non-empty URL
+        let auth_config = config::PostgresAuthConfig {
+            url: "postgresql://user:password@localhost:5432/auth_db".to_string(),
+            ..Default::default()
+        };
+        assert!(!auth_config.url.is_empty());
+    }
+}

+ 7 - 0
crates/cdk-postgres/start_db_for_test.sh

@@ -27,4 +27,11 @@ docker exec -e PGPASSWORD="${DB_PASS}" "${CONTAINER_NAME}" \
 docker exec -e PGPASSWORD="${DB_PASS}" "${CONTAINER_NAME}" \
   psql -U "${DB_USER}" -d "${DB_NAME}" -c "CREATE DATABASE mintdb_auth;"
 
+# Export environment variables for both main and auth databases
 export DATABASE_URL="host=localhost user=${DB_USER} password=${DB_PASS} dbname=${DB_NAME} port=${DB_PORT}"
+export CDK_MINTD_POSTGRES_URL="postgresql://${DB_USER}:${DB_PASS}@localhost:${DB_PORT}/mintdb"
+export CDK_MINTD_AUTH_POSTGRES_URL="postgresql://${DB_USER}:${DB_PASS}@localhost:${DB_PORT}/mintdb_auth"
+
+echo "Database URLs configured:"
+echo "Main database: ${CDK_MINTD_POSTGRES_URL}"
+echo "Auth database: ${CDK_MINTD_AUTH_POSTGRES_URL}"

+ 4 - 2
crates/cdk-sql-common/src/mint/auth/mod.rs

@@ -198,9 +198,11 @@ where
         for (endpoint, auth) in protected_endpoints.iter() {
             if let Err(err) = query(
                 r#"
-                 INSERT OR REPLACE INTO protected_endpoints
+                 INSERT INTO protected_endpoints
                  (endpoint, auth)
-                 VALUES (:endpoint, :auth);
+                 VALUES (:endpoint, :auth)
+                 ON CONFLICT (endpoint) DO UPDATE SET
+                 auth = EXCLUDED.auth;
                  "#,
             )?
             .bind("endpoint", serde_json::to_string(endpoint)?)