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