headers/common/
authorization.rs
1use base64::engine::general_purpose::STANDARD as ENGINE;
4use base64::Engine;
5use bytes::Bytes;
6
7use util::HeaderValueString;
8use HeaderValue;
9
10#[derive(Clone, PartialEq, Debug)]
39pub struct Authorization<C: Credentials>(pub C);
40
41impl Authorization<Basic> {
42 pub fn basic(username: &str, password: &str) -> Self {
44 let colon_pos = username.len();
45 let decoded = format!("{}:{}", username, password);
46
47 Authorization(Basic { decoded, colon_pos })
48 }
49
50 pub fn username(&self) -> &str {
52 self.0.username()
53 }
54
55 pub fn password(&self) -> &str {
57 self.0.password()
58 }
59}
60
61impl Authorization<Bearer> {
62 pub fn bearer(token: &str) -> Result<Self, InvalidBearerToken> {
64 HeaderValueString::from_string(format!("Bearer {}", token))
65 .map(|val| Authorization(Bearer(val)))
66 .ok_or_else(|| InvalidBearerToken { _inner: () })
67 }
68
69 pub fn token(&self) -> &str {
71 self.0.token()
72 }
73}
74
75impl<C: Credentials> ::Header for Authorization<C> {
76 fn name() -> &'static ::HeaderName {
77 &::http::header::AUTHORIZATION
78 }
79
80 fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
81 values
82 .next()
83 .and_then(|val| {
84 let slice = val.as_bytes();
85 if slice.len() > C::SCHEME.len()
86 && slice[C::SCHEME.len()] == b' '
87 && slice[..C::SCHEME.len()].eq_ignore_ascii_case(C::SCHEME.as_bytes())
88 {
89 C::decode(val).map(Authorization)
90 } else {
91 None
92 }
93 })
94 .ok_or_else(::Error::invalid)
95 }
96
97 fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
98 let mut value = self.0.encode();
99 value.set_sensitive(true);
100 debug_assert!(
101 value.as_bytes().starts_with(C::SCHEME.as_bytes()),
102 "Credentials::encode should include its scheme: scheme = {:?}, encoded = {:?}",
103 C::SCHEME,
104 value,
105 );
106
107 values.extend(::std::iter::once(value));
108 }
109}
110
111pub trait Credentials: Sized {
113 const SCHEME: &'static str;
118
119 fn decode(value: &HeaderValue) -> Option<Self>;
123
124 fn encode(&self) -> HeaderValue;
128}
129
130#[derive(Clone, PartialEq, Debug)]
132pub struct Basic {
133 decoded: String,
134 colon_pos: usize,
135}
136
137impl Basic {
138 pub fn username(&self) -> &str {
140 &self.decoded[..self.colon_pos]
141 }
142
143 pub fn password(&self) -> &str {
145 &self.decoded[self.colon_pos + 1..]
146 }
147}
148
149impl Credentials for Basic {
150 const SCHEME: &'static str = "Basic";
151
152 fn decode(value: &HeaderValue) -> Option<Self> {
153 debug_assert!(
154 value.as_bytes()[..Self::SCHEME.len()].eq_ignore_ascii_case(Self::SCHEME.as_bytes()),
155 "HeaderValue to decode should start with \"Basic ..\", received = {:?}",
156 value,
157 );
158
159 let bytes = &value.as_bytes()["Basic ".len()..];
160 let non_space_pos = bytes.iter().position(|b| *b != b' ')?;
161 let bytes = &bytes[non_space_pos..];
162
163 let bytes = ENGINE.decode(bytes).ok()?;
164
165 let decoded = String::from_utf8(bytes).ok()?;
166
167 let colon_pos = decoded.find(':')?;
168
169 Some(Basic { decoded, colon_pos })
170 }
171
172 fn encode(&self) -> HeaderValue {
173 let mut encoded = String::from("Basic ");
174 ENGINE.encode_string(&self.decoded, &mut encoded);
175
176 let bytes = Bytes::from(encoded);
177 HeaderValue::from_maybe_shared(bytes)
178 .expect("base64 encoding is always a valid HeaderValue")
179 }
180}
181
182#[derive(Clone, PartialEq, Debug)]
183pub struct Bearer(HeaderValueString);
185
186impl Bearer {
187 pub fn token(&self) -> &str {
189 self.0.as_str()["Bearer ".len()..].trim_start()
190 }
191}
192
193impl Credentials for Bearer {
194 const SCHEME: &'static str = "Bearer";
195
196 fn decode(value: &HeaderValue) -> Option<Self> {
197 debug_assert!(
198 value.as_bytes()[..Self::SCHEME.len()].eq_ignore_ascii_case(Self::SCHEME.as_bytes()),
199 "HeaderValue to decode should start with \"Bearer ..\", received = {:?}",
200 value,
201 );
202
203 HeaderValueString::from_val(value).ok().map(Bearer)
204 }
205
206 fn encode(&self) -> HeaderValue {
207 (&self.0).into()
208 }
209}
210
211error_type!(InvalidBearerToken);
212
213#[cfg(test)]
214mod tests {
215 use super::super::{test_decode, test_encode};
216 use super::{Authorization, Basic, Bearer};
217 use http::header::HeaderMap;
218 use HeaderMapExt;
219
220 #[test]
221 fn basic_encode() {
222 let auth = Authorization::basic("Aladdin", "open sesame");
223 let headers = test_encode(auth);
224
225 assert_eq!(
226 headers["authorization"],
227 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
228 );
229 }
230
231 #[test]
232 fn basic_roundtrip() {
233 let auth = Authorization::basic("Aladdin", "open sesame");
234 let mut h = HeaderMap::new();
235 h.typed_insert(auth.clone());
236 assert_eq!(h.typed_get(), Some(auth));
237 }
238
239 #[test]
240 fn basic_encode_no_password() {
241 let auth = Authorization::basic("Aladdin", "");
242 let headers = test_encode(auth);
243
244 assert_eq!(headers["authorization"], "Basic QWxhZGRpbjo=",);
245 }
246
247 #[test]
248 fn basic_decode() {
249 let auth: Authorization<Basic> =
250 test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
251 assert_eq!(auth.0.username(), "Aladdin");
252 assert_eq!(auth.0.password(), "open sesame");
253 }
254
255 #[test]
256 fn basic_decode_case_insensitive() {
257 let auth: Authorization<Basic> =
258 test_decode(&["basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
259 assert_eq!(auth.0.username(), "Aladdin");
260 assert_eq!(auth.0.password(), "open sesame");
261 }
262
263 #[test]
264 fn basic_decode_extra_whitespaces() {
265 let auth: Authorization<Basic> =
266 test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
267 assert_eq!(auth.0.username(), "Aladdin");
268 assert_eq!(auth.0.password(), "open sesame");
269 }
270
271 #[test]
272 fn basic_decode_no_password() {
273 let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjo="]).unwrap();
274 assert_eq!(auth.0.username(), "Aladdin");
275 assert_eq!(auth.0.password(), "");
276 }
277
278 #[test]
279 fn bearer_encode() {
280 let auth = Authorization::bearer("fpKL54jvWmEGVoRdCNjG").unwrap();
281
282 let headers = test_encode(auth);
283
284 assert_eq!(headers["authorization"], "Bearer fpKL54jvWmEGVoRdCNjG",);
285 }
286
287 #[test]
288 fn bearer_decode() {
289 let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
290 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
291 }
292
293 #[test]
294 fn bearer_decode_case_insensitive() {
295 let auth: Authorization<Bearer> = test_decode(&["bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
296 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
297 }
298
299 #[test]
300 fn bearer_decode_extra_whitespaces() {
301 let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
302 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
303 }
304}
305
306