openzeppelin_relayer/utils/
auth.rs

1use actix_web::dev::ServiceRequest;
2
3use crate::{
4    constants::{AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE_PREFIX},
5    models::SecretString,
6};
7
8/// Checks if the authorization header in the request matches the expected API key.
9///
10/// This function extracts the authorization header from the request, verifies that it starts
11/// with the expected prefix (e.g., "Bearer "), and then compares the remaining part of the header
12/// value with the expected API key.
13pub fn check_authorization_header(req: &ServiceRequest, expected_key: &SecretString) -> bool {
14    // Ensure there is exactly one Authorization header
15    let headers: Vec<_> = req.headers().get_all(AUTHORIZATION_HEADER_NAME).collect();
16    if headers.len() != 1 {
17        return false;
18    }
19
20    if let Ok(key) = headers[0].to_str() {
21        if !key.starts_with(AUTHORIZATION_HEADER_VALUE_PREFIX) {
22            return false;
23        }
24        let prefix_len = AUTHORIZATION_HEADER_VALUE_PREFIX.len();
25        let token = &key[prefix_len..];
26
27        if token.is_empty() || token.contains(' ') {
28            return false;
29        }
30
31        return &SecretString::new(token) == expected_key;
32    }
33    false
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use actix_web::test::TestRequest;
40
41    #[test]
42    fn test_check_authorization_header_success() {
43        let req = TestRequest::default()
44            .insert_header((
45                AUTHORIZATION_HEADER_NAME,
46                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "test_key"),
47            ))
48            .to_srv_request();
49
50        assert!(check_authorization_header(
51            &req,
52            &SecretString::new("test_key")
53        ));
54    }
55
56    #[test]
57    fn test_check_authorization_header_missing_header() {
58        let req = TestRequest::default().to_srv_request();
59
60        assert!(!check_authorization_header(
61            &req,
62            &SecretString::new("test_key")
63        ));
64    }
65
66    #[test]
67    fn test_check_authorization_header_invalid_prefix() {
68        let req = TestRequest::default()
69            .insert_header((AUTHORIZATION_HEADER_NAME, "InvalidPrefix test_key"))
70            .to_srv_request();
71
72        assert!(!check_authorization_header(
73            &req,
74            &SecretString::new("test_key")
75        ));
76    }
77
78    #[test]
79    fn test_check_authorization_header_invalid_key() {
80        let req = TestRequest::default()
81            .insert_header((
82                AUTHORIZATION_HEADER_NAME,
83                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "invalid_key"),
84            ))
85            .to_srv_request();
86
87        assert!(!check_authorization_header(
88            &req,
89            &SecretString::new("test_key")
90        ));
91    }
92
93    #[test]
94    fn test_check_authorization_header_multiple_bearer() {
95        let req = TestRequest::default()
96            .insert_header((
97                AUTHORIZATION_HEADER_NAME,
98                format!("Bearer Bearer {}", "test_key"),
99            ))
100            .to_srv_request();
101
102        assert!(!check_authorization_header(
103            &req,
104            &SecretString::new("test_key")
105        ));
106    }
107
108    #[test]
109    fn test_check_authorization_header_multiple_headers() {
110        let req = TestRequest::default()
111            .insert_header((
112                AUTHORIZATION_HEADER_NAME,
113                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "test_key"),
114            ))
115            .insert_header((
116                AUTHORIZATION_HEADER_NAME,
117                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "another_key"),
118            ))
119            .to_srv_request();
120
121        // Should reject multiple Authorization headers
122        assert!(!check_authorization_header(
123            &req,
124            &SecretString::new("test_key")
125        ));
126    }
127
128    #[test]
129    fn test_check_authorization_header_malformed_bearer() {
130        // Test with Bearer in token
131        let req = TestRequest::default()
132            .insert_header((AUTHORIZATION_HEADER_NAME, "Bearer Bearer token"))
133            .to_srv_request();
134
135        assert!(!check_authorization_header(
136            &req,
137            &SecretString::new("token")
138        ));
139
140        // Test with empty token
141        let req = TestRequest::default()
142            .insert_header((AUTHORIZATION_HEADER_NAME, "Bearer "))
143            .to_srv_request();
144
145        assert!(!check_authorization_header(&req, &SecretString::new("")));
146    }
147}