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<CallbackQueryParams>, state: Data<AppState>) -> 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<String, String> = 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,
}
],
})
}