use std::collections::HashMap;
use super::grant::Grant;
use super::generator::TokenGenerator;
pub trait Authorizer {
fn authorize(&mut self, Grant) -> Result<String, ()>;
fn extract(&mut self, &str) -> Option<Grant>;
}
pub struct Storage<I: TokenGenerator> {
issuer: I,
tokens: HashMap<String, Grant>
}
impl<I: TokenGenerator> Storage<I> {
pub fn new(issuer: I) -> Storage<I> {
Storage {issuer: issuer, tokens: HashMap::new()}
}
}
impl<I: TokenGenerator> Authorizer for Storage<I> {
fn authorize(&mut self, grant: Grant) -> Result<String, ()> {
let token = self.issuer.generate(&grant)?;
self.tokens.insert(token.clone(), grant);
Ok(token)
}
fn extract<'a>(&mut self, grant: &'a str) -> Option<Grant> {
self.tokens.remove(grant)
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use chrono::Utc;
use primitives::grant::Extensions;
pub fn simple_test_suite(authorizer: &mut 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("Could not extract grant for valid token");
if grant != recovered_grant {
panic!("Grant was not stored correctly");
}
if authorizer.extract(&token).is_some() {
panic!("Token must only be usable once");
}
}
#[test]
fn test_storage() {
use primitives::generator::{Assertion, RandomGenerator};
use ring::hmac::SigningKey;
use ring::digest::SHA256;
let mut storage = Storage::new(RandomGenerator::new(16));
simple_test_suite(&mut storage);
let assertion_token_instance = Assertion::new(
SigningKey::new(&SHA256, b"7EGgy8zManReq9l/ez0AyYE+xPpcTbssgW+8gBnIv3s="));
let mut storage = Storage::new(assertion_token_instance.tag("authorizer"));
simple_test_suite(&mut storage);
}
}