1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! Enables implementation of role based access control.
//! Since any concrete implementation will usually be fairly application specific,
//! The [RbacConfig], [RbacResourceSpec] and [RbacRoleSpec] types provide components for
//! resource organisation and role management. Actual access control can be set up using
//! the [Authorizer] trait. See its documentation for a sample implementation.
//! #### Rbac config example:
//! ```yaml
//! ```
//!
use async_trait;
pub use ;
use Error;
use IntoResponses;
/// The server could not authorize the request
;
/// A trait for implementing request authorization.
///
/// #### Example
///
/// Assuming an `AuthContext` type holding `claims` exists and, for example,
/// a middleware calls the [authorize](Authorizer::authorize) method, passing an
/// [RbacConfig] holding resource definitions identified by unix-style `glob` patterns,
/// the implementation could look like this:
///
/// ```
/// # use async_trait::async_trait;
/// # use actix_web::http::Method;
/// # use restrepo::security::{AccessForbiddenError, Authorizer, RbacConfig};
/// # use glob::Pattern;
/// # struct Claims {roles: Vec<String>};
/// # struct AuthContext {claims: Claims, url: String, method: Method};
/// #[async_trait]
/// impl Authorizer<RbacConfig<String>, (), AccessForbiddenError> for AuthContext {
/// async fn authorize(
/// &self,
/// authz_config: &RbacConfig<String>,
/// ) -> Result<(), AccessForbiddenError> {
/// let access = authz_config
/// .roles()
/// .iter()
/// .filter_map(|(name, role)| {
/// role.accessible_resources()
/// .get(&self.method)
/// .iter()
/// .any(|idents| {
/// idents
/// .iter()
/// .filter_map(|ident| Pattern::new(ident).ok())
/// .any(|pattern| pattern.matches(&self.url))
/// })
/// .then_some(name)
/// })
/// .any(|name| self.claims.roles.contains(name));
/// match access {
/// true => return Ok(()),
/// false => {
/// return Err(AccessForbiddenError(
/// "Not authorized to access resource".to_string(),
/// ))
/// }
/// }
/// }
/// }
///```