use std::collections::HashMap;
use subtle::ConstantTimeEq;
#[derive(Debug, Clone)]
pub struct OidcClient {
pub client_id: String,
pub client_secret: Option<String>,
pub redirect_uris: Vec<String>,
pub allowed_scopes: Vec<String>,
}
impl OidcClient {
pub fn allows_redirect(&self, uri: &str) -> bool {
self.redirect_uris.iter().any(|u| u == uri)
}
pub fn requires_pkce(&self) -> bool {
self.client_secret.is_none()
}
}
#[derive(Debug, Clone)]
pub struct ClientAuth {
pub client_id: String,
pub client_secret: Option<String>,
}
#[derive(Default)]
pub struct OidcClientRegistry {
clients: HashMap<String, OidcClient>,
}
impl OidcClientRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(mut self, client: OidcClient) -> Self {
self.clients.insert(client.client_id.clone(), client);
self
}
pub fn get(&self, client_id: &str) -> Option<&OidcClient> {
self.clients.get(client_id)
}
pub fn authenticate(&self, auth: &ClientAuth) -> Option<&OidcClient> {
let client = self.clients.get(&auth.client_id)?;
match (&client.client_secret, &auth.client_secret) {
(Some(expected), Some(presented)) => {
let ok: bool = expected.as_bytes().ct_eq(presented.as_bytes()).into();
ok.then_some(client)
}
(None, None) => Some(client),
_ => None,
}
}
}