1 //! Authorization header and types.
2 
3 use base64;
4 use bytes::Bytes;
5 
6 use {HeaderValue};
7 use util::HeaderValueString;
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 ///
19 /// ```text
20 /// Authorization = credentials
21 /// ```
22 ///
23 /// # Example values
24 /// * `Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==`
25 /// * `Bearer fpKL54jvWmEGVoRdCNjG`
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// # extern crate headers;
31 /// use headers::Authorization;
32 ///
33 /// let basic = Authorization::basic("Aladdin", "open sesame");
34 /// let bearer = Authorization::bearer("some-opaque-token").unwrap();
35 /// ```
36 ///
37 #[derive(Clone, PartialEq, Debug)]
38 pub struct Authorization<C: Credentials>(pub C);
39 
40 impl Authorization<Basic> {
41     /// Create a `Basic` authorization header.
basic(username: &str, password: &str) -> Self42     pub fn basic(username: &str, password: &str) -> Self {
43         let colon_pos = username.len();
44         let decoded = format!("{}:{}", username, password);
45 
46         Authorization(Basic {
47             decoded,
48             colon_pos,
49         })
50     }
51 }
52 
53 impl Authorization<Bearer> {
54     /// Try to create a `Bearer` authorization header.
bearer(token: &str) -> Result<Self, InvalidBearerToken>55     pub fn bearer(token: &str) -> Result<Self, InvalidBearerToken>  {
56         HeaderValueString::from_string(format!("Bearer {}", token))
57             .map(|val| Authorization(Bearer(val)))
58             .ok_or_else(|| InvalidBearerToken { _inner: () })
59     }
60 }
61 
62 impl<C: Credentials> ::Header for Authorization<C> {
name() -> &'static ::HeaderName63     fn name() -> &'static ::HeaderName {
64         &::http::header::AUTHORIZATION
65     }
66 
decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error>67     fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
68         values
69             .next()
70             .and_then(|val| {
71                 let slice = val.as_bytes();
72                 if slice.starts_with(C::SCHEME.as_bytes())
73                     && slice.len() > C::SCHEME.len()
74                     && slice[C::SCHEME.len()] == b' ' {
75                     C::decode(val)
76                         .map(Authorization)
77                 } else {
78                     None
79                 }
80             })
81             .ok_or_else(::Error::invalid)
82     }
83 
encode<E: Extend<::HeaderValue>>(&self, values: &mut E)84     fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
85         let value = self.0.encode();
86         debug_assert!(
87             value.as_bytes().starts_with(C::SCHEME.as_bytes()),
88             "Credentials::encode should include its scheme: scheme = {:?}, encoded = {:?}",
89             C::SCHEME,
90             value,
91         );
92 
93         values.extend(::std::iter::once(value));
94     }
95 }
96 
97 /// Credentials to be used in the `Authorization` header.
98 pub trait Credentials: Sized {
99     /// The scheme identify the format of these credentials.
100     ///
101     /// This is the static string that always prefixes the actual credentials,
102     /// like `"Basic"` in basic authorization.
103     const SCHEME: &'static str;
104 
105     /// Try to decode the credentials from the `HeaderValue`.
106     ///
107     /// The `SCHEME` will be the first part of the `value`.
decode(value: &HeaderValue) -> Option<Self>108     fn decode(value: &HeaderValue) -> Option<Self>;
109 
110     /// Encode the credentials to a `HeaderValue`.
111     ///
112     /// The `SCHEME` must be the first part of the `value`.
encode(&self) -> HeaderValue113     fn encode(&self) -> HeaderValue;
114 }
115 
116 /// Credential holder for Basic Authentication
117 #[derive(Clone, PartialEq, Debug)]
118 pub struct Basic {
119     decoded: String,
120     colon_pos: usize,
121 }
122 
123 impl Basic {
124     /// View the decoded username.
username(&self) -> &str125     pub fn username(&self) -> &str {
126         &self.decoded[..self.colon_pos]
127     }
128 
129     /// View the decoded password.
password(&self) -> &str130     pub fn password(&self) -> &str {
131         &self.decoded[self.colon_pos + 1..]
132     }
133 }
134 
135 impl Credentials for Basic {
136     const SCHEME: &'static str = "Basic";
137 
decode(value: &HeaderValue) -> Option<Self>138     fn decode(value: &HeaderValue) -> Option<Self> {
139         debug_assert!(
140             value.as_bytes().starts_with(b"Basic "),
141             "HeaderValue to decode should start with \"Basic ..\", received = {:?}",
142             value,
143         );
144 
145         let bytes = &value.as_bytes()["Basic ".len()..];
146         let non_space_pos = bytes.iter().position(|b| *b != b' ')?;
147         let bytes = &bytes[non_space_pos..];
148         let bytes = base64::decode(bytes).ok()?;
149 
150         let decoded = String::from_utf8(bytes).ok()?;
151 
152         let colon_pos = decoded.find(':')?;
153 
154         Some(Basic {
155             decoded,
156             colon_pos,
157         })
158     }
159 
encode(&self) -> HeaderValue160     fn encode(&self) -> HeaderValue {
161         let mut encoded = String::from("Basic ");
162         base64::encode_config_buf(&self.decoded, base64::STANDARD, &mut encoded);
163 
164         let bytes = Bytes::from(encoded);
165         HeaderValue::from_shared(bytes)
166             .expect("base64 encoding is always a valid HeaderValue")
167     }
168 }
169 
170 #[derive(Clone, PartialEq, Debug)]
171 /// Token holder for Bearer Authentication, most often seen with oauth
172 pub struct Bearer(HeaderValueString);
173 
174 impl Bearer {
175     /// View the token part as a `&str`.
token(&self) -> &str176     pub fn token(&self) -> &str {
177         &self.0.as_str()["Bearer ".len() ..]
178     }
179 }
180 
181 impl Credentials for Bearer {
182     const SCHEME: &'static str = "Bearer";
183 
decode(value: &HeaderValue) -> Option<Self>184     fn decode(value: &HeaderValue) -> Option<Self> {
185         debug_assert!(
186             value.as_bytes().starts_with(b"Bearer "),
187             "HeaderValue to decode should start with \"Bearer ..\", received = {:?}",
188             value,
189         );
190 
191         HeaderValueString::from_val(value)
192             .ok()
193             .map(Bearer)
194     }
195 
encode(&self) -> HeaderValue196     fn encode(&self) -> HeaderValue {
197         (&self.0).into()
198     }
199 }
200 
201 error_type!(InvalidBearerToken);
202 
203 
204 #[cfg(test)]
205 mod tests {
206     use ::HeaderMapExt;
207     use http::header::HeaderMap;
208     use super::{Authorization, Basic, Bearer};
209     use super::super::{test_decode, test_encode};
210 
211     #[test]
basic_encode()212     fn basic_encode() {
213         let auth = Authorization::basic("Aladdin", "open sesame");
214         let headers = test_encode(auth);
215 
216         assert_eq!(
217             headers["authorization"],
218             "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
219         );
220     }
221 
222     #[test]
basic_roundtrip()223     fn basic_roundtrip() {
224         let auth = Authorization::basic("Aladdin", "open sesame");
225         let mut h = HeaderMap::new();
226         h.typed_insert(auth.clone());
227         assert_eq!(h.typed_get(), Some(auth));
228     }
229 
230     #[test]
basic_encode_no_password()231     fn basic_encode_no_password() {
232         let auth = Authorization::basic("Aladdin", "");
233         let headers = test_encode(auth);
234 
235         assert_eq!(
236             headers["authorization"],
237             "Basic QWxhZGRpbjo=",
238         );
239     }
240 
241     #[test]
basic_decode()242     fn basic_decode() {
243         let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
244         assert_eq!(auth.0.username(), "Aladdin");
245         assert_eq!(auth.0.password(), "open sesame");
246     }
247 
248     #[test]
basic_decode_no_password()249     fn basic_decode_no_password() {
250         let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjo="]).unwrap();
251         assert_eq!(auth.0.username(), "Aladdin");
252         assert_eq!(auth.0.password(), "");
253     }
254 
255     #[test]
bearer_encode()256     fn bearer_encode() {
257         let auth = Authorization::bearer("fpKL54jvWmEGVoRdCNjG").unwrap();
258 
259         let headers = test_encode(auth);
260 
261         assert_eq!(
262             headers["authorization"],
263             "Bearer fpKL54jvWmEGVoRdCNjG",
264         );
265     }
266 
267     #[test]
bearer_decode()268     fn bearer_decode() {
269         let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
270         assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
271     }
272 }
273 
274 //bench_header!(raw, Authorization<String>, { vec![b"foo bar baz".to_vec()] });
275 //bench_header!(basic, Authorization<Basic>, { vec![b"Basic QWxhZGRpbjpuIHNlc2FtZQ==".to_vec()] });
276 //bench_header!(bearer, Authorization<Bearer>, { vec![b"Bearer fpKL54jvWmEGVoRdCNjG".to_vec()] });
277