mco_http/header/common/
authorization.rs

1use std::any::Any;
2use std::fmt::{self, Display};
3use std::str::{FromStr, from_utf8};
4use std::ops::{Deref, DerefMut};
5use base64::{Engine};
6use base64::engine::general_purpose::STANDARD;
7use crate::header::{Header, HeaderFormat};
8
9/// `Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.2)
10///
11/// The `Authorization` header field allows a user agent to authenticate
12/// itself with an origin server -- usually, but not necessarily, after
13/// receiving a 401 (Unauthorized) response.  Its value consists of
14/// credentials containing the authentication information of the user
15/// agent for the realm of the resource being requested.
16///
17/// # ABNF
18/// ```plain
19/// Authorization = credentials
20/// ```
21///
22/// # Example values
23/// * `Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==`
24/// * `Bearer fpKL54jvWmEGVoRdCNjG`
25///
26/// # Examples
27/// ```
28/// use mco_http::header::{Headers, Authorization};
29///
30/// let mut headers = Headers::new();
31/// headers.set(Authorization("let me in".to_owned()));
32/// ```
33/// ```
34/// use mco_http::header::{Headers, Authorization, Basic};
35///
36/// let mut headers = Headers::new();
37/// headers.set(
38///    Authorization(
39///        Basic {
40///            username: "Aladdin".to_owned(),
41///            password: Some("open sesame".to_owned())
42///        }
43///    )
44/// );
45/// ```
46/// ```
47/// use mco_http::header::{Headers, Authorization, Bearer};
48///
49/// let mut headers = Headers::new();
50/// headers.set(
51///    Authorization(
52///        Bearer {
53///            token: "QWxhZGRpbjpvcGVuIHNlc2FtZQ".to_owned()
54///        }
55///    )
56/// );
57/// ```
58#[derive(Clone, PartialEq, Debug)]
59pub struct Authorization<S: Scheme>(pub S);
60
61impl<S: Scheme> Deref for Authorization<S> {
62    type Target = S;
63
64    fn deref(&self) -> &S {
65        &self.0
66    }
67}
68
69impl<S: Scheme> DerefMut for Authorization<S> {
70    fn deref_mut(&mut self) -> &mut S {
71        &mut self.0
72    }
73}
74
75impl<S: Scheme + Any> Header for Authorization<S> where <S as FromStr>::Err: 'static {
76    fn header_name() -> &'static str {
77        "Authorization"
78    }
79
80    fn parse_header(raw: &[Vec<u8>]) -> crate::Result<Authorization<S>> {
81        if raw.len() != 1 {
82            return Err(crate::Error::Header);
83        }
84        let header = from_utf8(unsafe { &raw.get_unchecked(0)[..] })?;
85        if let Some(scheme) = <S as Scheme>::scheme() {
86            if header.starts_with(scheme) && header.len() > scheme.len() + 1 {
87                match header[scheme.len() + 1..].parse::<S>().map(Authorization) {
88                    Ok(h) => Ok(h),
89                    Err(_) => Err(crate::Error::Header)
90                }
91            } else {
92                Err(crate::Error::Header)
93            }
94        } else {
95            match header.parse::<S>().map(Authorization) {
96                Ok(h) => Ok(h),
97                Err(_) => Err(crate::Error::Header)
98            }
99        }
100    }
101}
102
103impl<S: Scheme + Any> HeaderFormat for Authorization<S> where <S as FromStr>::Err: 'static {
104    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
105        if let Some(scheme) = <S as Scheme>::scheme() {
106            write!(f, "{} ", scheme)?
107        };
108        self.0.fmt_scheme(f)
109    }
110}
111
112/// An Authorization scheme to be used in the header.
113pub trait Scheme: FromStr + fmt::Debug + Clone + Send + Sync {
114    /// An optional Scheme name.
115    ///
116    /// Will be replaced with an associated constant once available.
117    fn scheme() -> Option<&'static str>;
118    /// Format the Scheme data into a header value.
119    fn fmt_scheme(&self, _: &mut fmt::Formatter) -> fmt::Result;
120}
121
122impl Scheme for String {
123    fn scheme() -> Option<&'static str> {
124        None
125    }
126
127    fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result {
128        Display::fmt(self, f)
129    }
130}
131
132/// Credential holder for Basic Authentication
133#[derive(Clone, PartialEq, Debug)]
134pub struct Basic {
135    /// The username as a possibly empty string
136    pub username: String,
137    /// The password. `None` if the `:` delimiter character was not
138    /// part of the parsed input.
139    pub password: Option<String>
140}
141
142impl Scheme for Basic {
143    fn scheme() -> Option<&'static str> {
144        Some("Basic")
145    }
146
147    fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result {
148        //FIXME: serialize::base64 could use some Debug implementation, so
149        //that we don't have to allocate a new string here just to write it
150        //to the formatter.
151        let mut text = self.username.clone();
152        text.push(':');
153        if let Some(ref pass) = self.password {
154            text.push_str(&pass[..]);
155        }
156
157        f.write_str(&STANDARD.encode(text.as_bytes()))
158    }
159}
160
161impl FromStr for Basic {
162    type Err = crate::Error;
163    fn from_str(s: &str) -> crate::Result<Basic> {
164        match STANDARD.decode(s) {
165            Ok(decoded) => match String::from_utf8(decoded) {
166                Ok(text) => {
167                    let parts = &mut text.split(':');
168                    let user = match parts.next() {
169                        Some(part) => part.to_owned(),
170                        None => return Err(crate::Error::Header)
171                    };
172                    let password = match parts.next() {
173                        Some(part) => Some(part.to_owned()),
174                        None => None
175                    };
176                    Ok(Basic {
177                        username: user,
178                        password: password
179                    })
180                },
181                Err(e) => {
182                    debug!("Basic::from_utf8 error={:?}", e);
183                    Err(crate::Error::Header)
184                }
185            },
186            Err(e) => {
187                debug!("Basic::from_base64 error={:?}", e);
188                Err(crate::Error::Header)
189            }
190        }
191    }
192}
193
194#[derive(Clone, PartialEq, Debug)]
195///Token holder for Bearer Authentication, most often seen with oauth
196pub struct Bearer {
197	///Actual bearer token as a string
198	pub token: String
199}
200
201impl Scheme for Bearer {
202	fn scheme() -> Option<&'static str> {
203		Some("Bearer")
204	}
205
206	fn fmt_scheme(&self, f: &mut fmt::Formatter) -> fmt::Result {
207		write!(f, "{}", self.token)
208	}
209}
210
211impl FromStr for Bearer {
212	type Err = crate::Error;
213	fn from_str(s: &str) -> crate::Result<Bearer> {
214		Ok(Bearer { token: s.to_owned()})
215	}
216}
217
218#[cfg(test)]
219mod tests {
220    use super::{Authorization, Basic, Bearer};
221    use super::super::super::{Headers, Header};
222
223    #[test]
224    fn test_raw_auth() {
225        let mut headers = Headers::new();
226        headers.set(Authorization("foo bar baz".to_owned()));
227        assert_eq!(headers.to_string(), "Authorization: foo bar baz\r\n".to_owned());
228    }
229
230    #[test]
231    fn test_raw_auth_parse() {
232        let header: Authorization<String> = Header::parse_header(
233            &[b"foo bar baz".to_vec()]).unwrap();
234        assert_eq!(header.0, "foo bar baz");
235    }
236
237    #[test]
238    fn test_basic_auth() {
239        let mut headers = Headers::new();
240        headers.set(Authorization(
241            Basic { username: "Aladdin".to_owned(), password: Some("open sesame".to_owned()) }));
242        assert_eq!(
243            headers.to_string(),
244            "Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n".to_owned());
245    }
246
247    #[test]
248    fn test_basic_auth_no_password() {
249        let mut headers = Headers::new();
250        headers.set(Authorization(Basic { username: "Aladdin".to_owned(), password: None }));
251        assert_eq!(headers.to_string(), "Authorization: Basic QWxhZGRpbjo=\r\n".to_owned());
252    }
253
254    #[test]
255    fn test_basic_auth_parse() {
256        let auth: Authorization<Basic> = Header::parse_header(
257            &[b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".to_vec()]).unwrap();
258        assert_eq!(auth.0.username, "Aladdin");
259        assert_eq!(auth.0.password, Some("open sesame".to_owned()));
260    }
261
262    #[test]
263    fn test_basic_auth_parse_no_password() {
264        let auth: Authorization<Basic> = Header::parse_header(
265            &[b"Basic QWxhZGRpbjo=".to_vec()]).unwrap();
266        assert_eq!(auth.0.username, "Aladdin");
267        assert_eq!(auth.0.password, Some("".to_owned()));
268    }
269
270	#[test]
271    fn test_bearer_auth() {
272        let mut headers = Headers::new();
273        headers.set(Authorization(
274            Bearer { token: "fpKL54jvWmEGVoRdCNjG".to_owned() }));
275        assert_eq!(
276            headers.to_string(),
277            "Authorization: Bearer fpKL54jvWmEGVoRdCNjG\r\n".to_owned());
278    }
279
280    #[test]
281    fn test_bearer_auth_parse() {
282        let auth: Authorization<Bearer> = Header::parse_header(
283            &[b"Bearer fpKL54jvWmEGVoRdCNjG".to_vec()]).unwrap();
284        assert_eq!(auth.0.token, "fpKL54jvWmEGVoRdCNjG");
285    }
286}
287
288bench_header!(raw, Authorization<String>, { vec![b"foo bar baz".to_vec()] });
289bench_header!(basic, Authorization<Basic>, { vec![b"Basic QWxhZGRpbjpuIHNlc2FtZQ==".to_vec()] });
290bench_header!(bearer, Authorization<Bearer>, { vec![b"Bearer fpKL54jvWmEGVoRdCNjG".to_vec()] });