Skip to main content

quokka_admin/service/
db_auth_provider.rs

1use 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}