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
//! Authorizers are need to exchange code grants for bearer tokens.
//!
//! The role of an authorizer is the ensure the consistency and security of request in which a
//! client is willing to trade a code grant for a bearer token. As such, it will first issue grants
//! to client according to parameters given by the resource owner and the registrar. Upon a client
//! side request, it will then check the given parameters to determine the authorization of such
//! clients.
use std::collections::HashMap;
use std::sync::{MutexGuard, RwLockWriteGuard};

use super::grant::Grant;
use super::generator::TagGrant;

/// Authorizers create and manage authorization codes.
///
/// The authorization code can be traded for a bearer token at the token endpoint.
pub trait Authorizer {
    /// Create a code which allows retrieval of a bearer token at a later time.
    fn authorize(&mut self, _: Grant) -> Result<String, ()>;

    /// Retrieve the parameters associated with a token, invalidating the code in the process. In
    /// particular, a code should not be usable twice (there is no stateless implementation of an
    /// authorizer for this reason).
    fn extract(&mut self, token: &str) -> Result<Option<Grant>, ()>;
}

/// An in-memory hash map.
///
/// This authorizer saves a mapping of generated strings to their associated grants. The generator
/// is itself trait based and can be chosen during construction. It is assumed to not be possible
/// for two different grants to generate the same token in the issuer.
pub struct AuthMap<I: TagGrant = Box<dyn TagGrant + Send + Sync + 'static>> {
    tagger: I,
    usage: u64,
    tokens: HashMap<String, Grant>,
}

impl<I: TagGrant> AuthMap<I> {
    /// Create an authorizer generating tokens with the `tagger`.
    ///
    /// The token map is initially empty and is filled by methods provided in its [`Authorizer`]
    /// implementation.
    ///
    /// [`Authorizer`]: ./trait.Authorizer.html
    pub fn new(tagger: I) -> Self {
        AuthMap {
            tagger,
            usage: 0,
            tokens: HashMap::new(),
        }
    }
}

impl<'a, A: Authorizer + ?Sized> Authorizer for &'a mut A {
    fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
        (**self).authorize(grant)
    }

    fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
        (**self).extract(code)
    }
}

impl<A: Authorizer + ?Sized> Authorizer for Box<A> {
    fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
        (**self).authorize(grant)
    }

    fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
        (**self).extract(code)
    }
}

impl<'a, A: Authorizer + ?Sized> Authorizer for MutexGuard<'a, A> {
    fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
        (**self).authorize(grant)
    }

    fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
        (**self).extract(code)
    }
}

impl<'a, A: Authorizer + ?Sized> Authorizer for RwLockWriteGuard<'a, A> {
    fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
        (**self).authorize(grant)
    }

    fn extract(&mut self, code: &str) -> Result<Option<Grant>, ()> {
        (**self).extract(code)
    }
}

impl<I: TagGrant> Authorizer for AuthMap<I> {
    fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
        // The (usage, grant) tuple needs to be unique. Since this wraps after 2^64 operations, we
        // expect the validity time of the grant to have changed by then. This works when you don't
        // set your system time forward/backward ~20billion seconds, assuming ~10^9 operations per
        // second.
        let next_usage = self.usage.wrapping_add(1);
        let token = self.tagger.tag(next_usage - 1, &grant)?;
        self.tokens.insert(token.clone(), grant);
        self.usage = next_usage;
        Ok(token)
    }

    fn extract<'a>(&mut self, grant: &'a str) -> Result<Option<Grant>, ()> {
        Ok(self.tokens.remove(grant))
    }
}

#[cfg(test)]
/// Tests for authorizer implementations, including those provided here.
pub mod tests {
    use super::*;
    use chrono::Utc;
    use crate::primitives::grant::Extensions;
    use crate::primitives::generator::{Assertion, AssertionKind, RandomGenerator};

    /// Tests some invariants that should be upheld by all authorizers.
    ///
    /// Custom implementations may want to import and use this in their own tests.
    pub fn simple_test_suite(authorizer: &mut dyn Authorizer) {
        let grant = Grant {
            owner_id: "Owner".to_string(),
            client_id: "Client".to_string(),
            scope: "One two three scopes".parse().unwrap(),
            redirect_uri: "https://example.com/redirect_me".parse().unwrap(),
            until: Utc::now(),
            extensions: Extensions::new(),
        };

        let token = authorizer
            .authorize(grant.clone())
            .expect("Authorization should not fail here");
        let recovered_grant = authorizer
            .extract(&token)
            .expect("Primitive failed extracting grant")
            .expect("Could not extract grant for valid token");

        if grant != recovered_grant {
            panic!("Grant was not stored correctly");
        }

        if authorizer.extract(&token).unwrap().is_some() {
            panic!("Token must only be usable once");
        }

        // Authorize the same token again.
        let token_again = authorizer
            .authorize(grant.clone())
            .expect("Authorization should not fail here");
        // We don't produce the same token twice.
        assert_ne!(token, token_again);
    }

    #[test]
    fn random_test_suite() {
        let mut storage = AuthMap::new(RandomGenerator::new(16));
        simple_test_suite(&mut storage);
    }

    #[test]
    fn signing_test_suite() {
        let assertion = Assertion::new(
            AssertionKind::HmacSha256,
            b"7EGgy8zManReq9l/ez0AyYE+xPpcTbssgW+8gBnIv3s=",
        );
        let mut storage = AuthMap::new(assertion);
        simple_test_suite(&mut storage);
    }

    #[test]
    #[should_panic]
    fn bad_generator() {
        struct BadGenerator;
        impl TagGrant for BadGenerator {
            fn tag(&mut self, _: u64, _: &Grant) -> Result<String, ()> {
                Ok("YOLO.HowBadCanItBeToRepeatTokens?".into())
            }
        }

        let mut storage = AuthMap::new(BadGenerator);
        simple_test_suite(&mut storage);
    }
}