kych

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

db_integration.rs (5832B)


      1 use anyhow::Result;
      2 use kych_oauth2_gateway_lib::db::{authorization_codes, clients, sessions, tokens};
      3 use serde_json::json;
      4 use sqlx::{PgPool, postgres::PgPoolOptions};
      5 use uuid::Uuid;
      6 
      7 async fn get_pool() -> Option<PgPool> {
      8     let url = match std::env::var("DATABASE_URL") {
      9         Ok(url) if !url.trim().is_empty() => url,
     10         _ => {
     11             eprintln!("DATABASE_URL not set; skipping DB integration tests.");
     12             return None;
     13         }
     14     };
     15 
     16     match PgPoolOptions::new().max_connections(5).connect(&url).await {
     17         Ok(pool) => Some(pool),
     18         Err(err) => {
     19             eprintln!("Failed to connect to DATABASE_URL; skipping tests: {}", err);
     20             None
     21         }
     22     }
     23 }
     24 
     25 struct TestClient {
     26     client: clients::Client,
     27     secret: String,
     28 }
     29 
     30 async fn create_test_client(pool: &PgPool) -> Result<TestClient> {
     31     let suffix = Uuid::new_v4().to_string();
     32     let client_id = format!("test-client-{}", suffix);
     33     let secret = format!("secret-{}", suffix);
     34     let verifier_url = "https://verifier.example";
     35     let redirect_uri = "https://example.com/callback";
     36     let accepted_issuer_dids = Some("did:example:issuer1,did:example:issuer2");
     37 
     38     let client = clients::register_client(
     39         pool,
     40         &client_id,
     41         &secret,
     42         verifier_url,
     43         None,
     44         redirect_uri,
     45         accepted_issuer_dids,
     46     )
     47     .await?;
     48 
     49     Ok(TestClient { client, secret })
     50 }
     51 
     52 #[tokio::test]
     53 async fn test_clients_crud() -> Result<()> {
     54     let Some(pool) = get_pool().await else { return Ok(()); };
     55 
     56     let test_client = create_test_client(&pool).await?;
     57     let client = &test_client.client;
     58 
     59     let fetched = clients::get_client_by_id(&pool, &client.client_id).await?;
     60     assert!(fetched.is_some());
     61     assert_eq!(fetched.as_ref().unwrap().id, client.id);
     62 
     63     let auth_ok = clients::authenticate_client(&pool, &client.client_id, "wrong-secret").await?;
     64     assert!(auth_ok.is_none());
     65 
     66     let auth_ok = clients::authenticate_client(&pool, &client.client_id, &test_client.secret)
     67         .await?;
     68     assert!(auth_ok.is_some());
     69 
     70     let updated = clients::update_client(
     71         &pool,
     72         client.id,
     73         Some("https://verifier.example/v2"),
     74         Some("/management/api/verifications"),
     75         Some("https://example.com/redirect2"),
     76         None,
     77     )
     78     .await?;
     79     assert_eq!(updated.redirect_uri, "https://example.com/redirect2");
     80 
     81     let all = clients::list_clients(&pool).await?;
     82     assert!(all.iter().any(|c| c.id == client.id));
     83 
     84     let deleted = clients::delete_client(&pool, client.id).await?;
     85     assert!(deleted);
     86 
     87     Ok(())
     88 }
     89 
     90 #[tokio::test]
     91 async fn test_sessions_codes_tokens_flow() -> Result<()> {
     92     let Some(pool) = get_pool().await else { return Ok(()); };
     93 
     94     let test_client = create_test_client(&pool).await?;
     95     let client = &test_client.client;
     96 
     97     let nonce = format!("nonce-{}", Uuid::new_v4());
     98     let session = sessions::create_session(&pool, &client.client_id, &nonce, 5)
     99         .await?
    100         .expect("client should exist");
    101     assert_eq!(session.nonce, nonce);
    102 
    103     let scope = "first_name last_name";
    104     let redirect_uri = "https://example.com/callback";
    105     let state = "state-123";
    106     let authorize = sessions::get_session_for_authorize(
    107         &pool,
    108         &nonce,
    109         &client.client_id,
    110         scope,
    111         redirect_uri,
    112         state,
    113     )
    114     .await?
    115     .expect("session should exist");
    116     assert_eq!(authorize.scope, scope);
    117     assert_eq!(authorize.redirect_uri.as_deref(), Some(redirect_uri));
    118     assert_eq!(authorize.state.as_deref(), Some(state));
    119 
    120     let verification_url = "https://verifier.example/verify/1";
    121     let request_id = Uuid::new_v4().to_string();
    122     let authorized = sessions::update_session_authorized(
    123         &pool,
    124         authorize.session_id,
    125         verification_url,
    126         None,
    127         &request_id,
    128         None,
    129     )
    130     .await?;
    131     assert_eq!(authorized.request_id, request_id);
    132 
    133     let authorization_code = format!("code-{}", Uuid::new_v4());
    134     let issued_code = sessions::verify_session_and_issue_code(
    135         &pool,
    136         authorize.session_id,
    137         sessions::SessionStatus::Verified,
    138         &authorization_code,
    139         10,
    140         client.id,
    141         "",
    142         Some(&json!({"vc": "data"})),
    143     )
    144     .await?;
    145     assert_eq!(issued_code, authorization_code);
    146 
    147     let code_row = authorization_codes::get_code_by_session(&pool, authorize.session_id)
    148         .await?
    149         .expect("code should exist");
    150     assert!(!code_row.used);
    151 
    152     let exchange = authorization_codes::get_code_for_token_exchange(&pool, &authorization_code)
    153         .await?
    154         .expect("code should be exchangeable");
    155     assert!(!exchange.was_already_used);
    156     assert_eq!(exchange.session_status, sessions::SessionStatus::Verified);
    157     assert!(exchange.existing_token.is_none());
    158 
    159     let exchange_again = authorization_codes::get_code_for_token_exchange(&pool, &authorization_code)
    160         .await?
    161         .expect("code still exists");
    162     assert!(exchange_again.was_already_used);
    163 
    164     let token_value = format!("token-{}", Uuid::new_v4());
    165     let token = tokens::create_token_and_complete_session(
    166         &pool,
    167         authorize.session_id,
    168         &token_value,
    169         60,
    170     )
    171     .await?;
    172     assert_eq!(token.token, token_value);
    173 
    174     let token_data = tokens::get_token_with_session(&pool, &token_value)
    175         .await?
    176         .expect("token should exist");
    177     assert!(!token_data.revoked);
    178     assert_eq!(token_data.session_status, sessions::SessionStatus::Completed);
    179 
    180     let status_data = sessions::get_session_for_status(&pool, &request_id)
    181         .await?
    182         .expect("status should exist");
    183     assert_eq!(status_data.status, sessions::SessionStatus::Completed);
    184 
    185     let _ = clients::delete_client(&pool, client.id).await?;
    186     Ok(())
    187 }