Skip to main content

haste_server/auth_n/middleware/
project_access.rs

1use crate::{
2    auth_n::middleware::jwt::User,
3    extract::path_tenant::{ProjectIdentifier, TenantIdentifier},
4};
5use axum::{Extension, extract::Request, middleware::Next, response::Response};
6use axum_extra::extract::Cached;
7use haste_fhir_model::r4::generated::terminology::IssueType;
8use haste_fhir_operation_error::OperationOutcomeError;
9use std::sync::Arc;
10
11pub async fn project_access(
12    Cached(TenantIdentifier { tenant }): Cached<TenantIdentifier>,
13    Cached(ProjectIdentifier { project }): Cached<ProjectIdentifier>,
14    // run the `HeaderMap` extractor
15    Extension(user): Extension<Arc<User>>,
16    // you can also add more extractors here but the last
17    // extractor must implement `FromRequest` which
18    // `Request` does
19    request: Request,
20    next: Next,
21) -> Result<Response, OperationOutcomeError> {
22    if user.claims.tenant != tenant {
23        return Err(OperationOutcomeError::error(
24            IssueType::Forbidden(None),
25            format!("User does not have access to tenant '{}'.", tenant),
26        ));
27    }
28
29    let Some(user_project) = &user.claims.project else {
30        return Err(OperationOutcomeError::error(
31            IssueType::Forbidden(None),
32            format!("User does not have access to project '{}'.", project),
33        ));
34    };
35
36    if user_project != &project {
37        return Err(OperationOutcomeError::error(
38            IssueType::Forbidden(None),
39            format!("User does not have access to project '{}'.", project),
40        ));
41    }
42
43    Ok(next.run(request).await)
44}