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