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