quokka_admin/service/
db_auth_provider.rs1use axum::Extension;
2use quokka::{extract::Session, state::FromState};
3
4use crate::{
5 entity::{group::GroupRepository, permission::PermissionRepository, user::UserRepository},
6 middleware::{AdminAuthProvider, AuthenticatedUser, LoginResult},
7};
8
9use super::page_loader::ADMIN_USER_SESSION_KEY;
10
11#[derive(Clone, FromState)]
12pub struct DbAuthProvider {
13 user_repository: UserRepository,
14 group_repository: GroupRepository,
15 permission_repository: PermissionRepository,
16}
17
18impl<S: Send + Sync + 'static> AdminAuthProvider<S> for DbAuthProvider {
19 type AuthParams = Extension<Session>;
20
21 async fn authenticate(
22 &self,
23 params: Self::AuthParams,
24 ) -> quokka::Result<Option<crate::middleware::AuthenticatedUser>> {
25 let Ok(username) = params
26 .0
27 .get_extension::<LoginResult>(ADMIN_USER_SESSION_KEY)
28 .map(|val| val.user_identifier)
29 else {
30 return Ok(None);
31 };
32
33 let (Some(user), groups) = futures::try_join!(
34 self.user_repository.get_user_by_name(&username),
35 self.group_repository.get_group_of_user(&username)
36 )?
37 else {
38 return Ok(None);
39 };
40
41 Ok(Some(AuthenticatedUser {
42 name: user.username,
43 groups: groups.into_iter().map(|group| group.name).collect(),
44 context: Default::default(),
45 }))
46 }
47
48 async fn authorize(
49 &self,
50 user: &crate::middleware::AuthenticatedUser,
51 permission: &crate::middleware::PermissionContext,
52 ) -> quokka::Result<bool> {
53 if self
54 .permission_repository
55 .get_of_user(&user.name, &permission.verb, &permission.resource)
56 .await?
57 .is_some()
58 {
59 return Ok(true);
60 }
61
62 if futures::future::try_join_all(user.groups.iter().map(|group| {
63 self.permission_repository
64 .get_of_group(&group, &permission.verb, &permission.resource)
65 }))
66 .await?
67 .iter()
68 .any(|permission| permission.is_some())
69 {
70 return Ok(true);
71 }
72
73 Ok(false)
74 }
75}