kych

OAuth 2.0 API for Swiyu to enable Taler integration of Swiyu for KYC (experimental)
Log | Files | Refs

commit abdaebd3a58a4b85526c79405a580bc3e71a930f
parent 1e1b7469f38554b2e5c871071bc25df2bbedb0bb
Author: Henrique Chan Carvalho Machado <henriqueccmachado@tecnico.ulisboa.pt>
Date:   Sun, 26 Oct 2025 00:33:09 +0200

oauth2_gateway: omit hardcoded Client/Verifier config; will move to DB

Diffstat:
Moauth2_gateway/config.example.ini | 16+++++++++-------
Moauth2_gateway/src/config.rs | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 149 insertions(+), 48 deletions(-)

diff --git a/oauth2_gateway/config.example.ini b/oauth2_gateway/config.example.ini @@ -1,11 +1,12 @@ +# OAuth2 Gateway Configuration +# +# NOTE: Client-specific configuration (notification URLs, verifier URLs) is stored +# in the database, not in this file. + [server] host = 127.0.0.1 port = 8080 -[exchange] -base_url = https://exchange.example.com -notification_endpoint = /oauth2gw/kyc/notify - -[verifier] -base_url = https://verifier.example.com -management_api_path = /management/api/verifications +[database] +# PostgreSQL connection string +url = postgresql://oauth2gw:password@localhost/oauth2gw +\ No newline at end of file diff --git a/oauth2_gateway/src/config.rs b/oauth2_gateway/src/config.rs @@ -6,8 +6,7 @@ use std::path::Path; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { pub server: ServerConfig, - pub exchange: ExchangeConfig, - pub verifier: VerifierConfig, + pub database: DatabaseConfig, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -17,15 +16,8 @@ pub struct ServerConfig { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ExchangeConfig { - pub base_url: String, - pub notification_endpoint: String, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct VerifierConfig { - pub base_url: String, - pub management_api_path: String, +pub struct DatabaseConfig { + pub url: String, } impl Config { @@ -50,42 +42,149 @@ impl Config { .context("Invalid port")?, }; - // Exchange section - let exchange_section = ini - .section(Some("exchange")) - .context("Missing [exchange] section")?; + // Database section + let database_section = ini + .section(Some("database")) + .context("Missing [database] section")?; - let exchange = ExchangeConfig { - base_url: exchange_section - .get("base_url") - .context("Missing exchange.base_url")? - .to_string(), - notification_endpoint: exchange_section - .get("notification_endpoint") - .unwrap_or("/oauth2gw/kyc/notify") - .to_string(), - }; - - // Verifier section - let verifier_section = ini - .section(Some("verifier")) - .context("Missing [verifier] section")?; - - let verifier = VerifierConfig { - base_url: verifier_section - .get("base_url") - .context("Missing verifier.base_url")? - .to_string(), - management_api_path: verifier_section - .get("management_api_path") - .unwrap_or("/management/api/verifications") + let database = DatabaseConfig { + url: database_section + .get("url") + .context("Missing database.url")? .to_string(), }; Ok(Config { server, - exchange, - verifier, + database, }) } } + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Write; + use tempfile::NamedTempFile; + + #[test] + fn test_config_load_valid() { + let mut temp_file = NamedTempFile::new().unwrap(); + writeln!( + temp_file, + r#" +[server] +host = 0.0.0.0 +port = 3000 + +[database] +url = postgresql://localhost/oauth2gw_test +"# + ) + .unwrap(); + + let config = Config::from_file(temp_file.path()).unwrap(); + + assert_eq!(config.server.host, "0.0.0.0"); + assert_eq!(config.server.port, 3000); + assert_eq!(config.database.url, "postgresql://localhost/oauth2gw_test"); + } + + #[test] + fn test_config_defaults() { + let mut temp_file = NamedTempFile::new().unwrap(); + writeln!( + temp_file, + r#" +[server] +# host and port not specified, should use defaults + +[database] +url = postgresql://localhost/oauth2gw +"# + ) + .unwrap(); + + let config = Config::from_file(temp_file.path()).unwrap(); + + assert_eq!(config.server.host, "127.0.0.1"); + assert_eq!(config.server.port, 8080); + } + + #[test] + fn test_config_missing_server_section() { + let mut temp_file = NamedTempFile::new().unwrap(); + writeln!( + temp_file, + r#" +[database] +url = postgresql://localhost/oauth2gw +"# + ) + .unwrap(); + + let result = Config::from_file(temp_file.path()); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("server")); + } + + #[test] + fn test_config_missing_database_section() { + let mut temp_file = NamedTempFile::new().unwrap(); + writeln!( + temp_file, + r#" +[server] +host = 127.0.0.1 +port = 8080 +"# + ) + .unwrap(); + + let result = Config::from_file(temp_file.path()); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("database")); + } + + #[test] + fn test_config_missing_database_url() { + let mut temp_file = NamedTempFile::new().unwrap(); + writeln!( + temp_file, + r#" +[server] +host = 127.0.0.1 +port = 8080 + +[database] +# url is missing +"# + ) + .unwrap(); + + let result = Config::from_file(temp_file.path()); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("database.url")); + } + + #[test] + fn test_config_invalid_port() { + let mut temp_file = NamedTempFile::new().unwrap(); + writeln!( + temp_file, + r#" +[server] +host = 127.0.0.1 +port = not_a_number + +[database] +url = postgresql://localhost/oauth2gw +"# + ) + .unwrap(); + + let result = Config::from_file(temp_file.path()); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("port")); + } +}