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