oxide_auth/primitives/grant.rs
1//! Encapsulates various shared mechanisms for handlings different grants.
2use super::{Url, Time};
3use super::scope::Scope;
4
5use std::borrow::{Cow, ToOwned};
6use std::collections::HashMap;
7use std::collections::hash_map::Iter;
8use std::rc::Rc;
9use std::sync::Arc;
10
11/// Provides a name registry for extensions.
12pub trait GrantExtension {
13 /// An unique identifier distinguishing this extension type for parsing and storing.
14 /// Obvious choices are the registered names as administered by IANA or private identifiers.
15 fn identifier(&self) -> &'static str;
16}
17
18/// Wraps the data for an extension as a string with access restrictions.
19///
20/// This is a generic way for extensions to store their data in a universal, encoded form. It is
21/// also able to indicate the intended readers for such an extension so that backends can ensure
22/// that private extension data is properly encrypted even when present in a self-encoded access
23/// token.
24///
25/// Some extensions have semantics where the presence alone is the stored data, so storing data
26/// is optional and storing no data is distinct from not attaching any extension instance at all.
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub enum Value {
29 /// An extension that the token owner is allowed to read and interpret.
30 Public(Option<String>),
31
32 /// Identifies an extenion whose content and/or existance MUST be kept secret.
33 Private(Option<String>),
34 // Content which is not saved on the server but initialized/interpreted from other sources.
35 // foreign_content: String,
36}
37
38/// Links one or several `GrantExtension` instances to their respective data.
39///
40/// This also serves as a clean interface for both frontend and backend to reliably and
41/// conveniently manipulate or query the stored data sets.
42#[derive(Clone, Default, Debug, PartialEq, Eq)]
43pub struct Extensions {
44 extensions: HashMap<String, Value>,
45}
46
47/// Owning copy of a grant.
48///
49/// This can be stored in a database without worrying about lifetimes or shared across thread
50/// boundaries. A reference to this can be converted to a purely referential `GrantRef`.
51#[derive(Clone, Debug, PartialEq, Eq)]
52pub struct Grant {
53 /// Identifies the owner of the resource.
54 pub owner_id: String,
55
56 /// Identifies the client to which the grant was issued.
57 pub client_id: String,
58
59 /// The scope granted to the client.
60 pub scope: Scope,
61
62 /// The redirection uri under which the client resides. The url package does indeed seem to
63 /// parse valid URIs as well.
64 pub redirect_uri: Url,
65
66 /// Expiration date of the grant (Utc).
67 pub until: Time,
68
69 /// Encoded extensions existing on this Grant
70 pub extensions: Extensions,
71}
72
73impl Value {
74 /// Creates an extension whose presence and content can be unveiled by the token holder.
75 ///
76 /// Anyone in possession of the token corresponding to such a grant is potentially able to read
77 /// the content of a public extension.
78 pub fn public(content: Option<String>) -> Self {
79 Value::Public(content)
80 }
81
82 /// Creates an extension with secret content only visible for the server.
83 ///
84 /// Token issuers should take special care to protect the content and the identifier of such
85 /// an extension from being interpreted or correlated by the token holder.
86 pub fn private(content: Option<String>) -> Value {
87 Value::Private(content)
88 }
89
90 /// Inspect the public value.
91 ///
92 /// Returns an `Err` if this is not a public extension, `None` if the extension has no value
93 /// but consists only of the key, and `Some(_)` otherwise.
94 pub fn public_value(&self) -> Result<Option<&str>, ()> {
95 match self {
96 Value::Public(Some(content)) => Ok(Some(&content)),
97 Value::Public(None) => Ok(None),
98 _ => Err(()),
99 }
100 }
101
102 /// Convert into the public value.
103 ///
104 /// Returns an `Err` if this is not a public extension, `None` if the extension has no value
105 /// but consists only of the key, and `Some(_)` otherwise.
106 pub fn into_public_value(self) -> Result<Option<String>, ()> {
107 match self {
108 Value::Public(content) => Ok(content),
109 _ => Err(()),
110 }
111 }
112
113 /// Inspect the private value.
114 ///
115 /// Returns an `Err` if this is not a private extension, `None` if the extension has no value
116 /// but consists only of the key, and `Some(_)` otherwise.
117 pub fn private_value(&self) -> Result<Option<&str>, ()> {
118 match self {
119 Value::Private(Some(content)) => Ok(Some(&content)),
120 Value::Private(None) => Ok(None),
121 _ => Err(()),
122 }
123 }
124
125 /// Inspect the private value.
126 ///
127 /// Returns an `Err` if this is not a private extension, `None` if the extension has no value
128 /// but consists only of the key, and `Some(_)` otherwise.
129 pub fn into_private_value(self) -> Result<Option<String>, ()> {
130 match self {
131 Value::Private(content) => Ok(content),
132 _ => Err(()),
133 }
134 }
135}
136
137impl Extensions {
138 /// Create a new extension store.
139 pub fn new() -> Extensions {
140 Extensions::default()
141 }
142
143 /// Set the stored content for a `GrantExtension` instance.
144 pub fn set(&mut self, extension: &dyn GrantExtension, content: Value) {
145 self.extensions
146 .insert(extension.identifier().to_string(), content);
147 }
148
149 /// Set content for an extension without a corresponding instance.
150 pub fn set_raw(&mut self, identifier: String, content: Value) {
151 self.extensions.insert(identifier, content);
152 }
153
154 /// Retrieve the stored data of an instance.
155 ///
156 /// This removes the data from the store to avoid possible mixups and to allow a copyless
157 /// retrieval of bigger data strings.
158 pub fn remove(&mut self, extension: &dyn GrantExtension) -> Option<Value> {
159 self.extensions.remove(extension.identifier())
160 }
161
162 /// Iterate of the public extensions whose presence and content is not secret.
163 pub fn public(&self) -> PublicExtensions {
164 PublicExtensions {
165 iter: self.extensions.iter(),
166 }
167 }
168
169 /// Iterate of the private extensions whose presence and content must not be revealed.
170 pub fn private(&self) -> PrivateExtensions {
171 PrivateExtensions(self.extensions.iter())
172 }
173}
174
175/// An iterator over the public extensions of a grant.
176pub struct PublicExtensions<'a> {
177 iter: Iter<'a, String, Value>,
178}
179
180/// An iterator over the private extensions of a grant.
181///
182/// Implementations which acquire an instance should take special not to leak any secrets to
183/// clients and third parties.
184pub struct PrivateExtensions<'a>(Iter<'a, String, Value>);
185
186impl<'a> Iterator for PublicExtensions<'a> {
187 type Item = (&'a str, Option<&'a str>);
188
189 fn next(&mut self) -> Option<Self::Item> {
190 loop {
191 let (key, value) = self.iter.next()?;
192
193 if let Ok(value) = value.public_value() {
194 return Some((key, value));
195 }
196 }
197 }
198}
199
200impl<'a> Iterator for PrivateExtensions<'a> {
201 type Item = (&'a str, Option<&'a str>);
202
203 fn next(&mut self) -> Option<Self::Item> {
204 loop {
205 let (key, value) = self.0.next()?;
206
207 if let Ok(value) = value.private_value() {
208 return Some((key, value));
209 }
210 }
211 }
212}
213
214impl<'a, T: GrantExtension + ?Sized> GrantExtension for &'a T {
215 fn identifier(&self) -> &'static str {
216 (**self).identifier()
217 }
218}
219
220impl<'a, T: GrantExtension + ?Sized> GrantExtension for Cow<'a, T>
221where
222 T: Clone + ToOwned,
223{
224 fn identifier(&self) -> &'static str {
225 self.as_ref().identifier()
226 }
227}
228
229impl<T: GrantExtension + ?Sized> GrantExtension for Box<T> {
230 fn identifier(&self) -> &'static str {
231 (**self).identifier()
232 }
233}
234
235impl<T: GrantExtension + ?Sized> GrantExtension for Arc<T> {
236 fn identifier(&self) -> &'static str {
237 (**self).identifier()
238 }
239}
240
241impl<T: GrantExtension + ?Sized> GrantExtension for Rc<T> {
242 fn identifier(&self) -> &'static str {
243 (**self).identifier()
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::{Extensions, Value};
250
251 #[test]
252 fn iteration() {
253 let mut extensions = Extensions::new();
254 extensions.set_raw("pub".into(), Value::Public(Some("content".into())));
255 extensions.set_raw("pub_none".into(), Value::Public(None));
256 extensions.set_raw("priv".into(), Value::Private(Some("private".into())));
257 extensions.set_raw("priv_none".into(), Value::Private(None));
258
259 assert_eq!(
260 extensions
261 .public()
262 .filter(|&(name, value)| name == "pub" && value == Some("content"))
263 .count(),
264 1
265 );
266 assert_eq!(
267 extensions
268 .public()
269 .filter(|&(name, value)| name == "pub_none" && value == None)
270 .count(),
271 1
272 );
273 assert_eq!(extensions.public().count(), 2);
274
275 assert_eq!(
276 extensions
277 .private()
278 .filter(|&(name, value)| name == "priv" && value == Some("private"))
279 .count(),
280 1
281 );
282 assert_eq!(
283 extensions
284 .private()
285 .filter(|&(name, value)| name == "priv_none" && value == None)
286 .count(),
287 1
288 );
289 assert_eq!(extensions.private().count(), 2);
290 }
291}