kych

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

commit eb9f58ce4af8cb2ba25265d698cb68ecd8eaff8e
parent d9edb3f48a3e48244654baf0dfbe100fb65f531b
Author: Henrique Chan Carvalho Machado <henriqueccmachado@tecnico.ulisboa.pt>
Date:   Sun, 19 Oct 2025 19:43:16 +0200

oauth2_gateway: implemented tests for basic functionality

Diffstat:
Moauth2_gateway/Cargo.toml | 10++++++++++
Aoauth2_gateway/src/lib.rs | 5+++++
Moauth2_gateway/src/main.rs | 18+++++-------------
Aoauth2_gateway/tests/api_tests.rs | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 136 insertions(+), 13 deletions(-)

diff --git a/oauth2_gateway/Cargo.toml b/oauth2_gateway/Cargo.toml @@ -3,9 +3,18 @@ name = "oauth2-gateway" version = "0.0.1" edition = "2024" +[lib] # For tests +name = "oauth2_gateway" +path = "src/lib.rs" + +[[bin]] +name = "oauth2-gateway" +path = "src/main.rs" + [dependencies] # Web framework axum = "0.8.6" +axum-test = "18.1.0" tokio = { version = "1.48.0", features = ["full"] } tower = "0.5" tower-http = { version = "0.6.6", features = ["trace"] } @@ -31,3 +40,4 @@ tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } # Error handling anyhow = "1.0.100" + diff --git a/oauth2_gateway/src/lib.rs b/oauth2_gateway/src/lib.rs @@ -0,0 +1,4 @@ +pub mod config; +pub mod handlers; +pub mod models; +pub mod state; +\ No newline at end of file diff --git a/oauth2_gateway/src/main.rs b/oauth2_gateway/src/main.rs @@ -1,19 +1,12 @@ +use oauth2_gateway::{config::Config, handlers, state::AppState}; +use clap::Parser; +use tower_http::trace::TraceLayer; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use anyhow::Result; use axum::{ routing::{get, post}, Router, }; -use clap::Parser; -use tower_http::trace::TraceLayer; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - -mod config; -mod handlers; -mod models; -mod state; - -use config::Config; -use state::AppState; #[derive(Parser, Debug)] #[command(version)] @@ -40,7 +33,6 @@ async fn main() -> Result<()> { let config = Config::from_file(&args.config)?; - // Share config between modules let state = AppState::new(config.clone()); let app = Router::new() @@ -49,7 +41,7 @@ async fn main() -> Result<()> { .route("/authorize/{nonce}", get(handlers::authorize)) .route("/token", post(handlers::token)) .route("/info", get(handlers::info)) - .route("/notify/{client_id}", post(handlers::notification_webhook)) + .route("/notification/{client_id}", post(handlers::notification_webhook)) .layer(TraceLayer::new_for_http()) .with_state(state); diff --git a/oauth2_gateway/tests/api_tests.rs b/oauth2_gateway/tests/api_tests.rs @@ -0,0 +1,116 @@ +use axum::{routing::*, Router}; +use axum_test::TestServer; +use oauth2_gateway::{config::*, handlers, models::*, state::AppState}; +use serde_json::json; + +fn create_test_app() -> Router { + let config = Config { + server: ServerConfig { + host: "127.0.0.1".to_string(), + port: 8080, + }, + exchange: ExchangeConfig { + base_url: "http://test-exchange.com".to_string(), + notification_endpoint: "/notify".to_string(), + }, + verifier: VerifierConfig { + base_url: "http://test-verifier.com".to_string(), + management_api_path: "/api".to_string(), + }, + }; + + let state = AppState::new(config); + + Router::new() + .route("/health", get(handlers::health_check)) + .route("/setup/{client_id}", post(handlers::setup)) + .route("/authorize/{nonce}", get(handlers::authorize)) + .route("/token", post(handlers::token)) + .route("/info", get(handlers::info)) + .route("/notification/{client_id}", post(handlers::notification_webhook)) + .with_state(state) +} + +#[tokio::test] +async fn test_health_check() { + let app = create_test_app(); + let server = TestServer::new(app).unwrap(); + + let response = server.get("/health").await; + + response.assert_status_ok(); + response.assert_json(&json!({ + "status": "healthy", + "service": "oauth2-gateway", + // "version": env!("CARGO_PKG_VERSION") + })); +} + +#[tokio::test] +async fn test_setup_endpoint() { + let app = create_test_app(); + let server = TestServer::new(app).unwrap(); + + let response = server + .post("/setup/test-client") + .json(&json!({ + "scope": "first_name last_name age_over_18" + })) + .await; + + response.assert_status_ok(); + + // Check response has a nonce + let body: SetupResponse = response.json(); + assert!(!body.nonce.is_empty()); + println!("Generated nonce: {}", body.nonce); +} + +#[tokio::test] +async fn test_setup_different_clients() { + let app = create_test_app(); + let server = TestServer::new(app).unwrap(); + + let response1 = server + .post("/setup/client-1") + .json(&json!({"scope": "first_name"})) + .await; + + let response2 = server + .post("/setup/client-2") + .json(&json!({"scope": "last_name"})) + .await; + + response1.assert_status_ok(); + response2.assert_status_ok(); + + let nonce1: SetupResponse = response1.json(); + let nonce2: SetupResponse = response2.json(); + + assert_ne!(nonce1.nonce, nonce2.nonce); +} + +#[tokio::test] +async fn test_authorize_endpoint() { + let app = create_test_app(); + let server = TestServer::new(app).unwrap(); + + // Get a nonce from setup + let setup_response = server + .post("/setup/test-client") + .json(&json!({"scope": "test"})) + .await; + + let setup: SetupResponse = setup_response.json(); + + // Authorize with that nonce + let response = server + .get(&format!("/authorize/{}", setup.nonce)) + .await; + + response.assert_status_ok(); + + let body: AuthorizeResponse = response.json(); + assert!(!body.verification_url.is_empty()); + println!("Verification URL: {}", body.verification_url); +}