use std::sync::Arc;
use crate::error::{IdentityError, Result};
use crate::federation::IdTokenVerifier;
use crate::session::{RefreshStore, SessionIndex};
pub struct BackChannelLogout {
verifier: Arc<dyn IdTokenVerifier>,
refresh: Arc<dyn RefreshStore>,
sessions: Option<Arc<dyn SessionIndex>>,
}
impl BackChannelLogout {
pub fn new(verifier: Arc<dyn IdTokenVerifier>, refresh: Arc<dyn RefreshStore>) -> Self {
Self {
verifier,
refresh,
sessions: None,
}
}
pub fn with_sessions(mut self, sessions: Arc<dyn SessionIndex>) -> Self {
self.sessions = Some(sessions);
self
}
pub async fn handle(&self, logout_token: &str) -> Result<String> {
let verified = self.verifier.verify(logout_token, None).await?;
let is_logout_event = verified
.extra
.get("events")
.and_then(|v| v.as_object())
.map(|m| m.contains_key("http://schemas.openid.net/event/backchannel-logout"))
.unwrap_or(false);
if !is_logout_event {
return Err(IdentityError::InvalidToken);
}
if verified.nonce.is_some() {
return Err(IdentityError::InvalidToken);
}
let sub = verified.sub;
self.refresh.revoke_all(&sub).await?;
if let Some(sessions) = &self.sessions {
sessions.revoke_all(&sub).await?;
}
Ok(sub)
}
}