openapi_context/
auth.rs

1//! Authentication and authorization data structures
2
3use crate::{Push, ContextualPayload};
4use hyper::HeaderMap;
5use std::collections::BTreeSet;
6use std::string::ToString;
7use std::marker::PhantomData;
8use std::task::{Context, Poll};
9
10/// Authorization scopes.
11#[derive(Clone, Debug, PartialEq)]
12pub enum Scopes {
13    /// Some set of scopes.
14    Some(BTreeSet<String>),
15    /// All possible scopes, authorization checking disabled.
16    All,
17}
18
19/// Storage of authorization parameters for an incoming request, used for
20/// REST API authorization.
21#[derive(Clone, Debug, PartialEq)]
22pub struct Authorization {
23    /// Subject for which authorization is granted
24    /// (i.e., what may be accessed.)
25    pub subject: String,
26
27    /// Scopes for which authorization is granted
28    /// (i.e., what types of access are permitted).
29    pub scopes: Scopes,
30
31    /// Identity of the party to whom authorization was granted, if available
32    /// (i.e., who is responsible for the access).
33    ///
34    /// In an OAuth environment, this is the identity of the client which
35    /// issued an authorization request to the resource owner (end-user),
36    /// and which has been directly authorized by the resource owner
37    /// to access the protected resource. If the client delegates that
38    /// authorization to another service (e.g., a proxy or other delegate),
39    /// the `issuer` is still the original client which was authorized by
40    /// the resource owner.
41    pub issuer: Option<String>,
42}
43
44/// Storage of raw authentication data, used both for storing incoming
45/// request authentication, and for authenticating outgoing client requests.
46#[derive(Clone, Debug, PartialEq)]
47pub enum AuthData {
48    /// HTTP Basic auth.
49    Basic(headers::Authorization<headers::authorization::Basic>),
50    /// HTTP Bearer auth, used for OAuth2.
51    Bearer(headers::Authorization<headers::authorization::Bearer>),
52    /// Header-based or query parameter-based API key auth.
53    ApiKey(String),
54}
55
56impl AuthData {
57    /// Set Basic authentication
58    pub fn basic(username: &str, password: &str) -> Self {
59        AuthData::Basic(headers::Authorization::basic(
60            username,
61            password,
62        ))
63    }
64
65    /// Set Bearer token authentication
66    pub fn bearer(token: &str) -> Self {
67        AuthData::Bearer(headers::Authorization::bearer(token).unwrap())
68    }
69
70    /// Set ApiKey authentication
71    pub fn apikey(apikey: &str) -> Self {
72        AuthData::ApiKey(apikey.to_owned())
73    }
74}
75
76/// Bound for Request Context for MakeService wrappers
77pub trait RcBound: Push<Option<Authorization>> + Send + Sync + 'static {}
78
79impl<T> RcBound for T where T: Push<Option<Authorization>> + Send + Sync + 'static {}
80
81/// Retrieve an API key from a header
82pub fn api_key_from_header(headers: &HeaderMap, header: &str) -> Option<String> {
83    headers
84        .get(header)
85        .and_then(|v| v.to_str().ok())
86        .map(ToString::to_string)
87}
88
89/// Dummy Authenticator, that blindly inserts authorization data, allowing all
90/// access to an endpoint with the specified subject.
91#[derive(Debug)]
92pub struct AllowAllAuthenticatorMakeService<C> {
93    subject: String,
94    phantom: PhantomData<C>,
95}
96
97impl<C> AllowAllAuthenticatorMakeService<C> {
98    /// Create a new AddContextMakeService struct wrapping a value
99    pub fn new<T: Into<String>>(subject: T) -> Self {
100        AllowAllAuthenticatorMakeService {
101            subject: subject.into(),
102            phantom: PhantomData,
103        }
104    }
105}
106
107impl<T, C> hyper::service::Service<T> for AllowAllAuthenticatorMakeService<C> {
108    type Response = AllowAllAuthenticator<T, C>;
109    type Error = std::io::Error;
110    type Future = futures::future::Ready<Result<Self::Response, Self::Error>>;
111
112    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
113        Ok(()).into()
114    }
115
116    fn call(&mut self, inner: T) -> Self::Future {
117        futures::future::ok(AllowAllAuthenticator::new(inner, self.subject.clone()))
118    }
119}
120
121/// Middleware wrapper service, that should be used as the outermost layer in a
122/// stack of hyper services. Adds a context to a plain `hyper::Request` that can be
123/// used by subsequent layers in the stack. The `AddContextService` struct should
124/// not usually be used directly - when constructing a hyper stack use
125/// `AddContextMakeService`, which will create `AddContextService` instances as needed.
126#[derive(Debug)]
127pub struct AllowAllAuthenticator<T, C> {
128    inner: T,
129    subject: String,
130    marker: PhantomData<C>,
131}
132
133impl<T, C> AllowAllAuthenticator<T, C> {
134    /// Create a new AddContextService struct wrapping a value
135    pub fn new<U: Into<String>>(inner: T, subject: U) -> Self {
136        AllowAllAuthenticator {
137            inner: inner,
138            subject: subject.into(),
139            marker: PhantomData,
140        }
141    }
142}
143
144impl<T, C> hyper::service::Service<ContextualPayload<C>> for AllowAllAuthenticator<T, C>
145    where
146        C: RcBound,
147        C::Result: Send + Sync + 'static,
148        T: hyper::service::Service<ContextualPayload<C::Result>>,
149{
150    type Response = T::Response;
151    type Error = T::Error;
152    type Future = T::Future;
153
154    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
155        Ok(()).into()
156    }
157
158    fn call(&mut self, req: ContextualPayload<C>) -> Self::Future {
159        let auth = Authorization {
160            subject: self.subject.clone(),
161            scopes: Scopes::All,
162            issuer: None,
163        };
164        let context = req.context.push(Some(auth));
165
166        self.inner.call(ContextualPayload {
167            inner: req.inner,
168            context: context,
169        })
170    }
171}