oxide-auth 0.2.0

A OAuth2 server library, for use in combination with iron or other frontends, featuring a set of configurable and pluggable backends.
Documentation
use super::frontend::*;
use primitives::generator::TokenGenerator;
use primitives::registrar::PreGrant;
use primitives::grant::Grant;

use std::borrow::Cow;
use std::collections::HashMap;

use url::Url;

struct CraftedRequest {
    query: Option<HashMap<String, Vec<String>>>,
    urlbody: Option<HashMap<String, Vec<String>>>,
    auth: Option<String>,
}

#[derive(Debug)]
enum CraftedResponse {
    Redirect(Url),
    Text(String),
    Json(String),
    RedirectFromError(Url),
    ClientError(Box<CraftedResponse>),
    Unauthorized(Box<CraftedResponse>),
    Authorization(Box<CraftedResponse>, String),
}

impl WebRequest for CraftedRequest {
    type Response = CraftedResponse;
    type Error = OAuthError;

    fn query(&mut self) -> Result<Cow<HashMap<String, Vec<String>>>, ()> {
        self.query.as_ref().map(Cow::Borrowed).ok_or(())
    }

    fn urlbody(&mut self) -> Result<Cow<HashMap<String, Vec<String>>>, ()> {
        self.urlbody.as_ref().map(Cow::Borrowed).ok_or(())
    }

    fn authheader(&mut self) -> Result<Option<Cow<str>>, ()> {
        Ok(self.auth.as_ref().map(|bearer| bearer.as_str().into()))
    }
}

impl WebResponse for CraftedResponse {
    type Error = OAuthError;
    fn redirect(url: Url) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::Redirect(url))
    }

    fn text(text: &str) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::Text(text.to_string()))
    }

    fn json(data: &str) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::Json(data.to_string()))
    }

    fn redirect_error(target: ErrorUrl) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::RedirectFromError(target.into()))
    }

    fn as_client_error(self) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::ClientError(self.into()))
    }

    fn as_unauthorized(self) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::Unauthorized(self.into()))
    }

    fn with_authorization(self, kind: &str) -> Result<Self, OAuthError> {
        Ok(CraftedResponse::Authorization(self.into(), kind.to_string()))
    }
}

struct TestGenerator(String);

impl TokenGenerator for TestGenerator {
    fn generate(&self, _grant: &Grant) -> Result<String, ()> {
        Ok(self.0.clone())
    }
}

struct Allow(String);
struct Deny;

impl OwnerAuthorizer for Allow {
    type Request = CraftedRequest;
    fn get_owner_authorization(&self, _: &mut CraftedRequest, _: &PreGrant)
    -> Result<(Authentication, CraftedResponse), OAuthError> {
        Ok((Authentication::Authenticated(self.0.clone()), CraftedResponse::Text("".to_string())))
    }
}

impl OwnerAuthorizer for Deny {
    type Request = CraftedRequest;
    fn get_owner_authorization(&self, _: &mut CraftedRequest, _: &PreGrant)
    -> Result<(Authentication, CraftedResponse), OAuthError> {
        Ok((Authentication::Failed, CraftedResponse::Text("".to_string())))
    }
}

trait ToSingleValueQuery {
    fn to_single_value_query(self) -> HashMap<String, Vec<String>>;
}

impl<'r, I, K, V> ToSingleValueQuery for I where
    I: Iterator<Item=&'r (K, V)>,
    K: AsRef<str> + 'r,
    V: AsRef<str> + 'r {
    fn to_single_value_query(self) -> HashMap<String, Vec<String>> {
        self.map(|&(ref k, ref v)| (k.as_ref().to_string(), vec![v.as_ref().to_string()])).collect()
    }
}

pub mod defaults {
    pub const EXAMPLE_CLIENT_ID: &str = "ClientId";
    pub const EXAMPLE_OWNER_ID: &str = "Owner";
    pub const EXAMPLE_PASSPHRASE: &str = "VGhpcyBpcyBhIHZlcnkgc2VjdXJlIHBhc3NwaHJhc2UK";
    pub const EXAMPLE_REDIRECT_URI: &str = "https://client.example/endpoint";
    pub const EXAMPLE_SCOPE: &str = "example default";
}

/// Test the authorization code flow.
mod authorization_code;
/// Test the access token flow.
mod access_token;
/// Test the guard flow.
mod resource_guard;
/// Test functionality of pkce.
mod pkce;