Skip to main content

minco_http/
authorization.rs

1use http::StatusCode;
2use minco_contract::ContractAuthorizationPolicy;
3
4use crate::{ApiFailure, Principal};
5
6/// Enforce generated authentication, permission and scope requirements.
7///
8/// This boundary is deliberately coarse and performs no database, tenancy,
9/// ownership or business-state checks. Applications retain those checks.
10pub fn authorize_operation(
11    principal: Option<&Principal>,
12    policy: &ContractAuthorizationPolicy,
13    request_id: &str,
14) -> Result<(), ApiFailure> {
15    if policy.anonymous {
16        return Ok(());
17    }
18    let Some(principal) = principal else {
19        return Err(ApiFailure::new(
20            StatusCode::UNAUTHORIZED,
21            "unauthenticated",
22            "Authentication required",
23            "A valid bearer credential is required for this operation.",
24            request_id,
25        ));
26    };
27
28    let permissions_allowed = policy
29        .permissions
30        .iter()
31        .all(|permission| principal.has_permission(permission));
32    let scopes_allowed = policy.alternatives.is_empty()
33        || policy.alternatives.iter().any(|alternative| {
34            alternative
35                .scopes
36                .iter()
37                .all(|scope| principal.has_scope(scope))
38        });
39    if permissions_allowed && scopes_allowed {
40        Ok(())
41    } else {
42        Err(ApiFailure::new(
43            StatusCode::FORBIDDEN,
44            "forbidden",
45            "Forbidden",
46            "The authenticated principal is not permitted to perform this operation.",
47            request_id,
48        ))
49    }
50}