use std::collections::BTreeMap; use actix_web::{get, HttpResponse}; use actix_web::web::{Data, Query}; use jwt::{PKeyWithDigest, VerifyWithKey}; use log::{debug, error}; use openssl::hash::MessageDigest; use openssl::pkey::PKey; use serde::Deserialize; use crate::AppState; use crate::config::CONFIG; use crate::error::{APIError, APIErrorsResponse}; #[derive(Deserialize)] pub struct CallbackQueryParams { pub token: String, pub realm: String } #[get("/callback")] pub async fn callback(query: Query, state: Data) -> HttpResponse { // verify token from auth provider API // 1. load the public key let realm = match CONFIG.realms.get(&query.realm) { Some(r) => r, None => { error!("realm not found"); return HttpResponse::Unauthorized().json(APIErrorsResponse { errors: vec![ APIError { code: "ERR_UNKNOWN_REALM".to_string(), message: "Unknown realm".to_string(), path: None, } ], }) } }; let rs256_pub_key = PKeyWithDigest { digest: MessageDigest::sha256(), key: PKey::public_key_from_pem(realm.public_key.as_bytes()).unwrap() }; let token: BTreeMap = match query.token.verify_with_key(&rs256_pub_key) { Ok(tkn) => tkn, Err(e) => { error!("[callback] token verify error: {}", e); return generic_unauthorized(); } }; let realm = match token.get("realm").ok_or(generic_unauthorized()) { Ok(r) => r, Err(e) => return e }; let realm_local_id = match token.get("realm_native_id").ok_or(generic_unauthorized()) { Ok(r) => r, Err(e) => return e }; debug!("got authenticated realm native authorization: authenticated as {}:{}", realm, realm_local_id); HttpResponse::Ok().finish() } fn generic_unauthorized() -> HttpResponse { HttpResponse::Unauthorized().json(APIErrorsResponse { errors: vec![ APIError { code: "ERR_INVALID_STATE".to_string(), message: "Unknown/invalid login state".to_string(), path: None, } ], }) }