oxide_auth/primitives/
authorizer.rs1use std::collections::HashMap;
9use std::sync::{MutexGuard, RwLockWriteGuard};
10
11use super::grant::Grant;
12use super::generator::TagGrant;
13
14pub trait Authorizer {
18 fn authorize(&mut self, _: Grant) -> Result<String, ()>;
20
21 fn extract(&mut self, token: &str) -> Result<Option<Grant>, ()>;
25}
26
27pub struct AuthMap<I: TagGrant = Box<dyn TagGrant + Send + Sync + 'static>> {
33 tagger: I,
34 usage: u64,
35 tokens: HashMap<String, Grant>,
36}
37
38impl<I: TagGrant> AuthMap<I> {
39 pub fn new(tagger: I) -> Self {
46 AuthMap {
47 tagger,
48 usage: 0,
49 tokens: HashMap::new(),
50 }
51 }
52}
53
54impl<'a, A: Authorizer + ?Sized> Authorizer for &'a mut A {
55 fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
56 (**self).authorize(grant)
57 }
58
59 fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
60 (**self).extract(code)
61 }
62}
63
64impl<A: Authorizer + ?Sized> Authorizer for Box<A> {
65 fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
66 (**self).authorize(grant)
67 }
68
69 fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
70 (**self).extract(code)
71 }
72}
73
74impl<'a, A: Authorizer + ?Sized> Authorizer for MutexGuard<'a, A> {
75 fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
76 (**self).authorize(grant)
77 }
78
79 fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
80 (**self).extract(code)
81 }
82}
83
84impl<'a, A: Authorizer + ?Sized> Authorizer for RwLockWriteGuard<'a, A> {
85 fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
86 (**self).authorize(grant)
87 }
88
89 fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
90 (**self).extract(code)
91 }
92}
93
94impl<I: TagGrant> Authorizer for AuthMap<I> {
95 fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
96 let next_usage = self.usage.wrapping_add(1);
101 let token = self.tagger.tag(next_usage - 1, &grant)?;
102 self.tokens.insert(token.clone(), grant);
103 self.usage = next_usage;
104 Ok(token)
105 }
106
107 fn extract<'a>(&mut self, grant: &'a str) -> Result<Option<Grant>, ()> {
108 Ok(self.tokens.remove(grant))
109 }
110}
111
112#[cfg(test)]
113pub mod tests {
115 use super::*;
116 use chrono::Utc;
117 use crate::primitives::grant::Extensions;
118 use crate::primitives::generator::{Assertion, AssertionKind, RandomGenerator};
119
120 pub fn simple_test_suite(authorizer: &mut dyn Authorizer) {
124 let grant = Grant {
125 owner_id: "Owner".to_string(),
126 client_id: "Client".to_string(),
127 scope: "One two three scopes".parse().unwrap(),
128 redirect_uri: "https://example.com/redirect_me".parse().unwrap(),
129 until: Utc::now(),
130 extensions: Extensions::new(),
131 };
132
133 let token = authorizer
134 .authorize(grant.clone())
135 .expect("Authorization should not fail here");
136 let recovered_grant = authorizer
137 .extract(&token)
138 .expect("Primitive failed extracting grant")
139 .expect("Could not extract grant for valid token");
140
141 if grant != recovered_grant {
142 panic!("Grant was not stored correctly");
143 }
144
145 if authorizer.extract(&token).unwrap().is_some() {
146 panic!("Token must only be usable once");
147 }
148
149 let token_again = authorizer
151 .authorize(grant.clone())
152 .expect("Authorization should not fail here");
153 assert_ne!(token, token_again);
155 }
156
157 #[test]
158 fn random_test_suite() {
159 let mut storage = AuthMap::new(RandomGenerator::new(16));
160 simple_test_suite(&mut storage);
161 }
162
163 #[test]
164 fn signing_test_suite() {
165 let assertion = Assertion::new(
166 AssertionKind::HmacSha256,
167 b"7EGgy8zManReq9l/ez0AyYE+xPpcTbssgW+8gBnIv3s=",
168 );
169 let mut storage = AuthMap::new(assertion);
170 simple_test_suite(&mut storage);
171 }
172
173 #[test]
174 #[should_panic]
175 fn bad_generator() {
176 struct BadGenerator;
177 impl TagGrant for BadGenerator {
178 fn tag(&mut self, _: u64, _: &Grant) -> Result<String, ()> {
179 Ok("YOLO.HowBadCanItBeToRepeatTokens?".into())
180 }
181 }
182
183 let mut storage = AuthMap::new(BadGenerator);
184 simple_test_suite(&mut storage);
185 }
186}