Start to build init openid login
This commit is contained in:
		@@ -2,5 +2,6 @@
 | 
			
		||||
 | 
			
		||||
pub mod login_token_service;
 | 
			
		||||
pub mod mail_service;
 | 
			
		||||
pub mod openid_service;
 | 
			
		||||
pub mod rate_limiter_service;
 | 
			
		||||
pub mod users_service;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										85
									
								
								geneit_backend/src/services/openid_service.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								geneit_backend/src/services/openid_service.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
//! # OpenID service
 | 
			
		||||
 | 
			
		||||
use crate::app_config::{AppConfig, OIDCProvider};
 | 
			
		||||
use crate::connections::redis_connection;
 | 
			
		||||
use crate::constants::OPEN_ID_STATE_DURATION;
 | 
			
		||||
use crate::utils::string_utils;
 | 
			
		||||
use crate::utils::time_utils::time;
 | 
			
		||||
use light_openid::primitives::OpenIDConfig;
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::io::ErrorKind;
 | 
			
		||||
use std::net::IpAddr;
 | 
			
		||||
 | 
			
		||||
thread_local! {
 | 
			
		||||
    static CONFIG_CACHES: RefCell<HashMap<String, OpenIDConfig>> = RefCell::new(Default::default());
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct OpenIDClient<'a> {
 | 
			
		||||
    prov: OIDCProvider<'a>,
 | 
			
		||||
    conf: OpenIDConfig,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
struct OpenIDState {
 | 
			
		||||
    #[serde(rename = "i")]
 | 
			
		||||
    ip: IpAddr,
 | 
			
		||||
    #[serde(rename = "e")]
 | 
			
		||||
    expire: u64,
 | 
			
		||||
    #[serde(rename = "p")]
 | 
			
		||||
    prov_id: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl OpenIDState {
 | 
			
		||||
    pub fn new(ip: IpAddr, client: &OpenIDClient) -> (String, Self) {
 | 
			
		||||
        (
 | 
			
		||||
            string_utils::rand_str(30),
 | 
			
		||||
            Self {
 | 
			
		||||
                ip,
 | 
			
		||||
                expire: time() + OPEN_ID_STATE_DURATION.as_secs(),
 | 
			
		||||
                prov_id: client.prov.id.to_string(),
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn redis_key(state: &str) -> String {
 | 
			
		||||
    format!("oidc-state-{state}")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn load_provider_info(prov_id: &str) -> anyhow::Result<OpenIDClient> {
 | 
			
		||||
    let prov = AppConfig::get()
 | 
			
		||||
        .openid_providers()
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .find(|p| p.id.eq(prov_id))
 | 
			
		||||
        .ok_or_else(|| std::io::Error::new(ErrorKind::Other, "Provider not found!"))?;
 | 
			
		||||
 | 
			
		||||
    if let Some(conf) = CONFIG_CACHES.with(|i| i.borrow().get(prov_id).cloned()) {
 | 
			
		||||
        return Ok(OpenIDClient { prov, conf });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let conf = OpenIDConfig::load_from_url(prov.configuration_url)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| std::io::Error::new(ErrorKind::Other, e.to_string()))?;
 | 
			
		||||
 | 
			
		||||
    CONFIG_CACHES.with(|i| {
 | 
			
		||||
        i.borrow_mut()
 | 
			
		||||
            .insert(prov.configuration_url.to_string(), conf.clone())
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    Ok(OpenIDClient { prov, conf })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the URL where a user should be redirected for login
 | 
			
		||||
pub async fn start_login(prov_id: &str, ip: IpAddr) -> anyhow::Result<String> {
 | 
			
		||||
    let prov = load_provider_info(prov_id).await?;
 | 
			
		||||
    let (state_key, state) = OpenIDState::new(ip, &prov);
 | 
			
		||||
    redis_connection::set_value(&redis_key(&state_key), &state, OPEN_ID_STATE_DURATION).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(prov.conf.gen_authorization_url(
 | 
			
		||||
        prov.prov.client_id,
 | 
			
		||||
        &state_key,
 | 
			
		||||
        &AppConfig::get().oidc_redirect_url,
 | 
			
		||||
    ))
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user