headers/common/
authorization.rs1use base64::engine::general_purpose::STANDARD as ENGINE;
4use base64::Engine;
5use bytes::Bytes;
6use http::{HeaderName, HeaderValue};
7
8use crate::util::HeaderValueString;
9use crate::{Error, Header};
10
11#[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(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 http::header::HeaderMap;
216
217 use super::super::{test_decode, test_encode};
218 use super::{Authorization, Basic, Bearer};
219 use crate::HeaderMapExt;
220
221 #[test]
222 fn basic_encode() {
223 let auth = Authorization::basic("Aladdin", "open sesame");
224 let headers = test_encode(auth);
225
226 assert_eq!(
227 headers["authorization"],
228 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
229 );
230 }
231
232 #[test]
233 fn basic_roundtrip() {
234 let auth = Authorization::basic("Aladdin", "open sesame");
235 let mut h = HeaderMap::new();
236 h.typed_insert(auth.clone());
237 assert_eq!(h.typed_get(), Some(auth));
238 }
239
240 #[test]
241 fn basic_encode_no_password() {
242 let auth = Authorization::basic("Aladdin", "");
243 let headers = test_encode(auth);
244
245 assert_eq!(headers["authorization"], "Basic QWxhZGRpbjo=",);
246 }
247
248 #[test]
249 fn basic_decode() {
250 let auth: Authorization<Basic> =
251 test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
252 assert_eq!(auth.0.username(), "Aladdin");
253 assert_eq!(auth.0.password(), "open sesame");
254 }
255
256 #[test]
257 fn basic_decode_case_insensitive() {
258 let auth: Authorization<Basic> =
259 test_decode(&["basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
260 assert_eq!(auth.0.username(), "Aladdin");
261 assert_eq!(auth.0.password(), "open sesame");
262 }
263
264 #[test]
265 fn basic_decode_extra_whitespaces() {
266 let auth: Authorization<Basic> =
267 test_decode(&["Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="]).unwrap();
268 assert_eq!(auth.0.username(), "Aladdin");
269 assert_eq!(auth.0.password(), "open sesame");
270 }
271
272 #[test]
273 fn basic_decode_no_password() {
274 let auth: Authorization<Basic> = test_decode(&["Basic QWxhZGRpbjo="]).unwrap();
275 assert_eq!(auth.0.username(), "Aladdin");
276 assert_eq!(auth.0.password(), "");
277 }
278
279 #[test]
280 fn bearer_encode() {
281 let auth = Authorization::bearer("fpKL54jvWmEGVoRdCNjG").unwrap();
282
283 let headers = test_encode(auth);
284
285 assert_eq!(headers["authorization"], "Bearer fpKL54jvWmEGVoRdCNjG",);
286 }
287
288 #[test]
289 fn bearer_decode() {
290 let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
291 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
292 }
293
294 #[test]
295 fn bearer_decode_case_insensitive() {
296 let auth: Authorization<Bearer> = test_decode(&["bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
297 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
298 }
299
300 #[test]
301 fn bearer_decode_extra_whitespaces() {
302 let auth: Authorization<Bearer> = test_decode(&["Bearer fpKL54jvWmEGVoRdCNjG"]).unwrap();
303 assert_eq!(auth.0.token().as_bytes(), b"fpKL54jvWmEGVoRdCNjG");
304 }
305}
306
307