use axum::Extension;
use quokka::{extract::Session, state::FromState};
use crate::{
entity::{group::GroupRepository, permission::PermissionRepository, user::UserRepository},
middleware::{AdminAuthProvider, AuthenticatedUser, LoginResult},
};
use super::page_loader::ADMIN_USER_SESSION_KEY;
#[derive(Clone, FromState)]
pub struct DbAuthProvider {
user_repository: UserRepository,
group_repository: GroupRepository,
permission_repository: PermissionRepository,
}
impl<S: Send + Sync + 'static> AdminAuthProvider<S> for DbAuthProvider {
type AuthParams = Extension<Session>;
async fn authenticate(
&self,
params: Self::AuthParams,
) -> quokka::Result<Option<crate::middleware::AuthenticatedUser>> {
let Ok(username) = params
.0
.get_extension::<LoginResult>(ADMIN_USER_SESSION_KEY)
.map(|val| val.user_identifier)
else {
return Ok(None);
};
let (Some(user), groups) = futures::try_join!(
self.user_repository.get_user_by_name(&username),
self.group_repository.get_group_of_user(&username)
)?
else {
return Ok(None);
};
Ok(Some(AuthenticatedUser {
name: user.username,
groups: groups.into_iter().map(|group| group.name).collect(),
context: Default::default(),
}))
}
async fn authorize(
&self,
user: &crate::middleware::AuthenticatedUser,
permission: &crate::middleware::PermissionContext,
) -> quokka::Result<bool> {
if self
.permission_repository
.get_of_user(&user.name, &permission.verb, &permission.resource)
.await?
.is_some()
{
return Ok(true);
}
if futures::future::try_join_all(user.groups.iter().map(|group| {
self.permission_repository
.get_of_group(&group, &permission.verb, &permission.resource)
}))
.await?
.iter()
.any(|permission| permission.is_some())
{
return Ok(true);
}
Ok(false)
}
}