use std::{borrow::Cow, fmt}; use actix_web::{ http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue}, web::{BufMut, BytesMut}, }; use crate::headers::authorization::{errors::ParseError, scheme::Scheme}; /// Credentials for `Bearer` authentication scheme, defined in [RFC 6750]. /// /// Should be used in combination with [`Authorization`] header. /// /// [RFC 6750]: https://tools.ietf.org/html/rfc6750 /// [`Authorization`]: crate::headers::authorization::Authorization #[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] pub struct Bearer { token: Cow<'static, str>, } impl Bearer { /// Creates new `Bearer` credentials with the token provided. /// /// # Example /// ``` /// # use actix_web_httpauth::headers::authorization::Bearer; /// let credentials = Bearer::new("mF_9.B5f-4.1JqM"); /// ``` pub fn new(token: T) -> Bearer where T: Into>, { Bearer { token: token.into(), } } /// Gets reference to the credentials token. pub fn token(&self) -> &str { self.token.as_ref() } } impl Scheme for Bearer { fn parse(header: &HeaderValue) -> Result { // "Bearer *" length if header.len() < 8 { return Err(ParseError::Invalid); } let mut parts = header.to_str()?.splitn(2, ' '); match parts.next() { Some("Bearer") => {} _ => return Err(ParseError::MissingScheme), } let token = parts.next().ok_or(ParseError::Invalid)?; Ok(Bearer { token: token.to_string().into(), }) } } impl fmt::Debug for Bearer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("Bearer ******")) } } impl fmt::Display for Bearer { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("Bearer {}", self.token)) } } impl TryIntoHeaderValue for Bearer { type Error = InvalidHeaderValue; fn try_into_value(self) -> Result { let mut buffer = BytesMut::with_capacity(7 + self.token.len()); buffer.put(&b"Bearer "[..]); buffer.extend_from_slice(self.token.as_bytes()); HeaderValue::from_maybe_shared(buffer.freeze()) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_header() { let value = HeaderValue::from_static("Bearer mF_9.B5f-4.1JqM"); let scheme = Bearer::parse(&value); assert!(scheme.is_ok()); let scheme = scheme.unwrap(); assert_eq!(scheme.token, "mF_9.B5f-4.1JqM"); } #[test] fn test_empty_header() { let value = HeaderValue::from_static(""); let scheme = Bearer::parse(&value); assert!(scheme.is_err()); } #[test] fn test_wrong_scheme() { let value = HeaderValue::from_static("OAuthToken foo"); let scheme = Bearer::parse(&value); assert!(scheme.is_err()); } #[test] fn test_missing_token() { let value = HeaderValue::from_static("Bearer "); let scheme = Bearer::parse(&value); assert!(scheme.is_err()); } #[test] fn test_into_header_value() { let bearer = Bearer::new("mF_9.B5f-4.1JqM"); let result = bearer.try_into_value(); assert!(result.is_ok()); assert_eq!( result.unwrap(), HeaderValue::from_static("Bearer mF_9.B5f-4.1JqM") ); } }