authorized/lib.rs
1
2//! Authorized is a library helping you authorize behaviour on struct by defining allowed or denied
3//! scopes.
4//!
5//! You can use this to only expose field's value to authorized scopes
6
7#![warn(
8 clippy::all,
9 // clippy::restriction,
10 clippy::pedantic,
11 clippy::nursery,
12 // clippy::cargo
13)]
14#![recursion_limit = "256"]
15
16
17pub mod scope;
18
19mod error;
20mod result;
21#[cfg(feature = "with_serde")]
22mod serde;
23
24pub mod prelude;
25
26use scope::IntoScope;
27use scope::Scope;
28
29use error::*;
30use result::*;
31
32pub type UnAuthorizedFields<'a> = Vec<&'a str>;
33
34pub trait Authorizable {
35 type Authorized;
36
37 fn filter_unauthorized_fields<'a>(&'a self, scope: &Scope) -> UnAuthorizedFields<'a>;
38 fn authorize<'a>(
39 &'a self,
40 authorizer: &Scope,
41 ) -> Result<AuthorizedResult<'a, Self::Authorized>, AuthorizedError>;
42}
43
44
45/// Authorizor exposed mthods to help you authorize structures which implement
46/// [Authorizable](trait.Authorizable.html) trait.
47pub struct Authorizor {}
48
49impl Authorizor {
50 /// Create an authorized version of the input structure validated by the scope implementing
51 /// [`IntoScope`](scope/trait.IntoScope.html).
52 ///
53 /// It returns an [`AuthorizedResult`](struct.AuthorizedResult.html) which allow you to know
54 /// which fields have been secured and if the whole structure is authorized or not.
55 pub fn authorize<'a, A: Authorizable, T: IntoScope>(
56 inner: &'a A,
57 scope: &T,
58 ) -> Result<AuthorizedResult<'a, A::Authorized>, AuthorizedError> {
59 let scope: Scope = scope.into_scope()?;
60
61 inner.authorize(&scope)
62 }
63}
64
65pub trait Authorized {
66 #[cfg(feature = "with_serde")]
67 type Source: Authorizable + ::serde::ser::Serialize;
68 #[cfg(not(feature = "with_serde"))]
69 type Source: Authorizable;
70
71 fn build_serialize_struct<E>(&self, unauthorized_fields: &[&str]) -> Result<Self::Source, E>;
72}
73
74// #[cfg(test)]
75// mod tests {
76// use super::*;
77
78// #[test]
79// fn it_works() {
80// let based_user = MyUser {
81// name: "name".into(),
82// pass: "pass".into(),
83// email: "email".into(),
84// };
85
86// let user: AuthorizedResult<AuthorizedUser> = based_user
87// .authorize(&"user read:user".parse::<Scope>().unwrap())
88// .unwrap();
89
90// assert_eq!(user.status, AuthorizationStatus::Authorized);
91// assert_eq!(user.inner.name, Some("name".to_owned()));
92// assert_eq!(user.inner.pass, Some("pass".to_owned()));
93
94// let json = serde_json::to_string(&user).unwrap();
95// assert_eq!(
96// json,
97// serde_json::to_string(&json!({"name": "name"})).unwrap()
98// );
99
100// let user: AuthorizedResult<AuthorizedUser> = based_user
101// .authorize(&"guest".parse::<Scope>().unwrap())
102// .unwrap();
103
104// assert_eq!(user.status, AuthorizationStatus::UnAuthorized);
105
106// assert_eq!(user.inner.name, None);
107// assert_eq!(user.inner.pass, None);
108
109// let json = serde_json::to_string(&user).unwrap();
110// assert_eq!(json, serde_json::to_string(&json!({})).unwrap());
111
112// let user: AuthorizedResult<AuthorizedUser> = based_user
113// .authorize(&"read:user admin".parse::<Scope>().unwrap())
114// .unwrap();
115
116// assert_eq!(user.status, AuthorizationStatus::Authorized);
117// assert_eq!(user.inner.name, Some("name".to_owned()));
118// assert_eq!(user.inner.pass, Some("pass".to_owned()));
119
120// let json = serde_json::to_string(&user).unwrap();
121// assert_eq!(
122// json,
123// serde_json::to_string(&json!({"name": "name", "pass": "pass"})).unwrap()
124// );
125
126// let user = Authorizor::authorize(&based_user, "read:user admin").unwrap();
127
128// assert_eq!(user.status, AuthorizationStatus::Authorized);
129// assert_eq!(user.inner.name, Some("name".to_owned()));
130// assert_eq!(user.inner.pass, Some("pass".to_owned()));
131
132// let json = serde_json::to_string(&user).unwrap();
133// assert_eq!(
134// json,
135// serde_json::to_string(&json!({"name": "name", "pass": "pass"})).unwrap()
136// );
137// }
138// }