use crate::{Push, ContextualPayload};
use hyper::HeaderMap;
use std::collections::BTreeSet;
use std::string::ToString;
use std::marker::PhantomData;
use std::task::{Context, Poll};
#[derive(Clone, Debug, PartialEq)]
pub enum Scopes {
Some(BTreeSet<String>),
All,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Authorization {
pub subject: String,
pub scopes: Scopes,
pub issuer: Option<String>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum AuthData {
Basic(headers::Authorization<headers::authorization::Basic>),
Bearer(headers::Authorization<headers::authorization::Bearer>),
ApiKey(String),
}
impl AuthData {
pub fn basic(username: &str, password: &str) -> Self {
AuthData::Basic(headers::Authorization::basic(
username,
password,
))
}
pub fn bearer(token: &str) -> Self {
AuthData::Bearer(headers::Authorization::bearer(token).unwrap())
}
pub fn apikey(apikey: &str) -> Self {
AuthData::ApiKey(apikey.to_owned())
}
}
pub trait RcBound: Push<Option<Authorization>> + Send + Sync + 'static {}
impl<T> RcBound for T where T: Push<Option<Authorization>> + Send + Sync + 'static {}
pub fn api_key_from_header(headers: &HeaderMap, header: &str) -> Option<String> {
headers
.get(header)
.and_then(|v| v.to_str().ok())
.map(ToString::to_string)
}
#[derive(Debug)]
pub struct AllowAllAuthenticatorMakeService<C> {
subject: String,
phantom: PhantomData<C>,
}
impl<C> AllowAllAuthenticatorMakeService<C> {
pub fn new<T: Into<String>>(subject: T) -> Self {
AllowAllAuthenticatorMakeService {
subject: subject.into(),
phantom: PhantomData,
}
}
}
impl<T, C> hyper::service::Service<T> for AllowAllAuthenticatorMakeService<C> {
type Response = AllowAllAuthenticator<T, C>;
type Error = std::io::Error;
type Future = futures::future::Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(()).into()
}
fn call(&mut self, inner: T) -> Self::Future {
futures::future::ok(AllowAllAuthenticator::new(inner, self.subject.clone()))
}
}
#[derive(Debug)]
pub struct AllowAllAuthenticator<T, C> {
inner: T,
subject: String,
marker: PhantomData<C>,
}
impl<T, C> AllowAllAuthenticator<T, C> {
pub fn new<U: Into<String>>(inner: T, subject: U) -> Self {
AllowAllAuthenticator {
inner: inner,
subject: subject.into(),
marker: PhantomData,
}
}
}
impl<T, C> hyper::service::Service<ContextualPayload<C>> for AllowAllAuthenticator<T, C>
where
C: RcBound,
C::Result: Send + Sync + 'static,
T: hyper::service::Service<ContextualPayload<C::Result>>,
{
type Response = T::Response;
type Error = T::Error;
type Future = T::Future;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Ok(()).into()
}
fn call(&mut self, req: ContextualPayload<C>) -> Self::Future {
let auth = Authorization {
subject: self.subject.clone(),
scopes: Scopes::All,
issuer: None,
};
let context = req.context.push(Some(auth));
self.inner.call(ContextualPayload {
inner: req.inner,
context: context,
})
}
}