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
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//! Encapsulates various shared mechanisms for handlings different grants.
use super::{Url, Time};
use super::scope::Scope;

use std::borrow::{Cow, ToOwned};
use std::collections::HashMap;
use std::collections::hash_map::Iter;
use std::rc::Rc;
use std::sync::Arc;

/// Provides a name registry for extensions.
pub trait GrantExtension {
    /// An unique identifier distinguishing this extension type for parsing and storing.
    /// Obvious choices are the registered names as administered by IANA or private identifiers.
    fn identifier(&self) -> &'static str;
}

/// Wraps the data for an extension as a string with access restrictions.
///
/// This is a generic way for extensions to store their data in a universal, encoded form. It is
/// also able to indicate the intended readers for such an extension so that backends can ensure
/// that private extension data is properly encrypted even when present in a self-encoded access
/// token.
///
/// Some extensions have semantics where the presence alone is the stored data, so storing data
/// is optional and storing no data is distinct from not attaching any extension instance at all.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
    /// An extension that the token owner is allowed to read and interpret.
    Public(Option<String>),

    /// Identifies an extenion whose content and/or existance MUST be kept secret.
    Private(Option<String>),
    // Content which is not saved on the server but initialized/interpreted from other sources.
    // foreign_content: String,
}

/// Links one or several `GrantExtension` instances to their respective data.
///
/// This also serves as a clean interface for both frontend and backend to reliably and
/// conveniently manipulate or query the stored data sets.
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct Extensions {
    extensions: HashMap<String, Value>,
}

/// Owning copy of a grant.
///
/// This can be stored in a database without worrying about lifetimes or shared across thread
/// boundaries. A reference to this can be converted to a purely referential `GrantRef`.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Grant {
    /// Identifies the owner of the resource.
    pub owner_id: String,

    /// Identifies the client to which the grant was issued.
    pub client_id: String,

    /// The scope granted to the client.
    pub scope: Scope,

    /// The redirection uri under which the client resides. The url package does indeed seem to
    /// parse valid URIs as well.
    pub redirect_uri: Url,

    /// Expiration date of the grant (Utc).
    pub until: Time,

    /// Encoded extensions existing on this Grant
    pub extensions: Extensions,
}

impl Value {
    /// Creates an extension whose presence and content can be unveiled by the token holder.
    ///
    /// Anyone in possession of the token corresponding to such a grant is potentially able to read
    /// the content of a public extension.
    pub fn public(content: Option<String>) -> Self {
        Value::Public(content)
    }

    /// Creates an extension with secret content only visible for the server.
    ///
    /// Token issuers should take special care to protect the content and the identifier of such
    /// an extension from being interpreted or correlated by the token holder.
    pub fn private(content: Option<String>) -> Value {
        Value::Private(content)
    }

    /// Inspect the public value.
    ///
    /// Returns an `Err` if this is not a public extension, `None` if the extension has no value
    /// but consists only of the key, and `Some(_)` otherwise.
    pub fn public_value(&self) -> Result<Option<&str>, ()> {
        match self {
            Value::Public(Some(content)) => Ok(Some(&content)),
            Value::Public(None) => Ok(None),
            _ => Err(()),
        }
    }

    /// Convert into the public value.
    ///
    /// Returns an `Err` if this is not a public extension, `None` if the extension has no value
    /// but consists only of the key, and `Some(_)` otherwise.
    pub fn into_public_value(self) -> Result<Option<String>, ()> {
        match self {
            Value::Public(content) => Ok(content),
            _ => Err(()),
        }
    }

    /// Inspect the private value.
    ///
    /// Returns an `Err` if this is not a private extension, `None` if the extension has no value
    /// but consists only of the key, and `Some(_)` otherwise.
    pub fn private_value(&self) -> Result<Option<&str>, ()> {
        match self {
            Value::Private(Some(content)) => Ok(Some(&content)),
            Value::Private(None) => Ok(None),
            _ => Err(()),
        }
    }

    /// Inspect the private value.
    ///
    /// Returns an `Err` if this is not a private extension, `None` if the extension has no value
    /// but consists only of the key, and `Some(_)` otherwise.
    pub fn into_private_value(self) -> Result<Option<String>, ()> {
        match self {
            Value::Private(content) => Ok(content),
            _ => Err(()),
        }
    }
}

impl Extensions {
    /// Create a new extension store.
    pub fn new() -> Extensions {
        Extensions::default()
    }

    /// Set the stored content for a `GrantExtension` instance.
    pub fn set(&mut self, extension: &dyn GrantExtension, content: Value) {
        self.extensions
            .insert(extension.identifier().to_string(), content);
    }

    /// Set content for an extension without a corresponding instance.
    pub fn set_raw(&mut self, identifier: String, content: Value) {
        self.extensions.insert(identifier, content);
    }

    /// Retrieve the stored data of an instance.
    ///
    /// This removes the data from the store to avoid possible mixups and to allow a copyless
    /// retrieval of bigger data strings.
    pub fn remove(&mut self, extension: &dyn GrantExtension) -> Option<Value> {
        self.extensions.remove(extension.identifier())
    }

    /// Iterate of the public extensions whose presence and content is not secret.
    pub fn public(&self) -> PublicExtensions {
        PublicExtensions {
            iter: self.extensions.iter(),
        }
    }

    /// Iterate of the private extensions whose presence and content must not be revealed.
    pub fn private(&self) -> PrivateExtensions {
        PrivateExtensions(self.extensions.iter())
    }
}

/// An iterator over the public extensions of a grant.
pub struct PublicExtensions<'a> {
    iter: Iter<'a, String, Value>,
}

/// An iterator over the private extensions of a grant.
///
/// Implementations which acquire an instance should take special not to leak any secrets to
/// clients and third parties.
pub struct PrivateExtensions<'a>(Iter<'a, String, Value>);

impl<'a> Iterator for PublicExtensions<'a> {
    type Item = (&'a str, Option<&'a str>);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let (key, value) = self.iter.next()?;

            if let Ok(value) = value.public_value() {
                return Some((key, value));
            }
        }
    }
}

impl<'a> Iterator for PrivateExtensions<'a> {
    type Item = (&'a str, Option<&'a str>);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let (key, value) = self.0.next()?;

            if let Ok(value) = value.private_value() {
                return Some((key, value));
            }
        }
    }
}

impl<'a, T: GrantExtension + ?Sized> GrantExtension for &'a T {
    fn identifier(&self) -> &'static str {
        (**self).identifier()
    }
}

impl<'a, T: GrantExtension + ?Sized> GrantExtension for Cow<'a, T>
where
    T: Clone + ToOwned,
{
    fn identifier(&self) -> &'static str {
        self.as_ref().identifier()
    }
}

impl<T: GrantExtension + ?Sized> GrantExtension for Box<T> {
    fn identifier(&self) -> &'static str {
        (**self).identifier()
    }
}

impl<T: GrantExtension + ?Sized> GrantExtension for Arc<T> {
    fn identifier(&self) -> &'static str {
        (**self).identifier()
    }
}

impl<T: GrantExtension + ?Sized> GrantExtension for Rc<T> {
    fn identifier(&self) -> &'static str {
        (**self).identifier()
    }
}

#[cfg(test)]
mod tests {
    use super::{Extensions, Value};

    #[test]
    fn iteration() {
        let mut extensions = Extensions::new();
        extensions.set_raw("pub".into(), Value::Public(Some("content".into())));
        extensions.set_raw("pub_none".into(), Value::Public(None));
        extensions.set_raw("priv".into(), Value::Private(Some("private".into())));
        extensions.set_raw("priv_none".into(), Value::Private(None));

        assert_eq!(
            extensions
                .public()
                .filter(|&(name, value)| name == "pub" && value == Some("content"))
                .count(),
            1
        );
        assert_eq!(
            extensions
                .public()
                .filter(|&(name, value)| name == "pub_none" && value == None)
                .count(),
            1
        );
        assert_eq!(extensions.public().count(), 2);

        assert_eq!(
            extensions
                .private()
                .filter(|&(name, value)| name == "priv" && value == Some("private"))
                .count(),
            1
        );
        assert_eq!(
            extensions
                .private()
                .filter(|&(name, value)| name == "priv_none" && value == None)
                .count(),
            1
        );
        assert_eq!(extensions.private().count(), 2);
    }
}