actix_web_httpauth/headers/authorization/scheme/
bearer.rs

1use std::{borrow::Cow, fmt};
2
3use actix_web::{
4    http::header::{HeaderValue, InvalidHeaderValue, TryIntoHeaderValue},
5    web::{BufMut, BytesMut},
6};
7
8use crate::headers::authorization::{errors::ParseError, scheme::Scheme};
9
10/// Credentials for `Bearer` authentication scheme, defined in [RFC 6750].
11///
12/// Should be used in combination with [`Authorization`] header.
13///
14/// [RFC 6750]: https://tools.ietf.org/html/rfc6750
15/// [`Authorization`]: crate::headers::authorization::Authorization
16#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
17pub struct Bearer {
18    token: Cow<'static, str>,
19}
20
21impl Bearer {
22    /// Creates new `Bearer` credentials with the token provided.
23    ///
24    /// # Example
25    /// ```
26    /// # use actix_web_httpauth::headers::authorization::Bearer;
27    /// let credentials = Bearer::new("mF_9.B5f-4.1JqM");
28    /// ```
29    pub fn new<T>(token: T) -> Bearer
30    where
31        T: Into<Cow<'static, str>>,
32    {
33        Bearer {
34            token: token.into(),
35        }
36    }
37
38    /// Gets reference to the credentials token.
39    pub fn token(&self) -> &str {
40        self.token.as_ref()
41    }
42}
43
44impl Scheme for Bearer {
45    fn parse(header: &HeaderValue) -> Result<Self, ParseError> {
46        // "Bearer *" length
47        if header.len() < 8 {
48            return Err(ParseError::Invalid);
49        }
50
51        let mut parts = header.to_str()?.splitn(2, ' ');
52
53        match parts.next() {
54            Some("Bearer") => {}
55            _ => return Err(ParseError::MissingScheme),
56        }
57
58        let token = parts.next().ok_or(ParseError::Invalid)?;
59
60        Ok(Bearer {
61            token: token.to_string().into(),
62        })
63    }
64}
65
66impl fmt::Debug for Bearer {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.write_fmt(format_args!("Bearer ******"))
69    }
70}
71
72impl fmt::Display for Bearer {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.write_fmt(format_args!("Bearer {}", self.token))
75    }
76}
77
78impl TryIntoHeaderValue for Bearer {
79    type Error = InvalidHeaderValue;
80
81    fn try_into_value(self) -> Result<HeaderValue, Self::Error> {
82        let mut buffer = BytesMut::with_capacity(7 + self.token.len());
83        buffer.put(&b"Bearer "[..]);
84        buffer.extend_from_slice(self.token.as_bytes());
85
86        HeaderValue::from_maybe_shared(buffer.freeze())
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_parse_header() {
96        let value = HeaderValue::from_static("Bearer mF_9.B5f-4.1JqM");
97        let scheme = Bearer::parse(&value);
98
99        assert!(scheme.is_ok());
100        let scheme = scheme.unwrap();
101        assert_eq!(scheme.token, "mF_9.B5f-4.1JqM");
102    }
103
104    #[test]
105    fn test_empty_header() {
106        let value = HeaderValue::from_static("");
107        let scheme = Bearer::parse(&value);
108
109        assert!(scheme.is_err());
110    }
111
112    #[test]
113    fn test_wrong_scheme() {
114        let value = HeaderValue::from_static("OAuthToken foo");
115        let scheme = Bearer::parse(&value);
116
117        assert!(scheme.is_err());
118    }
119
120    #[test]
121    fn test_missing_token() {
122        let value = HeaderValue::from_static("Bearer ");
123        let scheme = Bearer::parse(&value);
124
125        assert!(scheme.is_err());
126    }
127
128    #[test]
129    fn test_into_header_value() {
130        let bearer = Bearer::new("mF_9.B5f-4.1JqM");
131
132        let result = bearer.try_into_value();
133        assert!(result.is_ok());
134        assert_eq!(
135            result.unwrap(),
136            HeaderValue::from_static("Bearer mF_9.B5f-4.1JqM")
137        );
138    }
139}