openzeppelin_relayer/utils/
auth.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use actix_web::dev::ServiceRequest;

use crate::{
    constants::{AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_VALUE_PREFIX},
    models::SecretString,
};

/// Checks if the authorization header in the request matches the expected API key.
///
/// This function extracts the authorization header from the request, verifies that it starts
/// with the expected prefix (e.g., "Bearer "), and then compares the remaining part of the header
/// value with the expected API key.
pub fn check_authorization_header(req: &ServiceRequest, expected_key: &SecretString) -> bool {
    // Ensure there is exactly one Authorization header
    let headers: Vec<_> = req.headers().get_all(AUTHORIZATION_HEADER_NAME).collect();
    if headers.len() != 1 {
        return false;
    }

    if let Ok(key) = headers[0].to_str() {
        if !key.starts_with(AUTHORIZATION_HEADER_VALUE_PREFIX) {
            return false;
        }
        let prefix_len = AUTHORIZATION_HEADER_VALUE_PREFIX.len();
        let token = &key[prefix_len..];

        if token.is_empty() || token.contains(' ') {
            return false;
        }

        return &SecretString::new(token) == expected_key;
    }
    false
}

#[cfg(test)]
mod tests {
    use super::*;
    use actix_web::test::TestRequest;

    #[test]
    fn test_check_authorization_header_success() {
        let req = TestRequest::default()
            .insert_header((
                AUTHORIZATION_HEADER_NAME,
                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "test_key"),
            ))
            .to_srv_request();

        assert!(check_authorization_header(
            &req,
            &SecretString::new("test_key")
        ));
    }

    #[test]
    fn test_check_authorization_header_missing_header() {
        let req = TestRequest::default().to_srv_request();

        assert!(!check_authorization_header(
            &req,
            &SecretString::new("test_key")
        ));
    }

    #[test]
    fn test_check_authorization_header_invalid_prefix() {
        let req = TestRequest::default()
            .insert_header((AUTHORIZATION_HEADER_NAME, "InvalidPrefix test_key"))
            .to_srv_request();

        assert!(!check_authorization_header(
            &req,
            &SecretString::new("test_key")
        ));
    }

    #[test]
    fn test_check_authorization_header_invalid_key() {
        let req = TestRequest::default()
            .insert_header((
                AUTHORIZATION_HEADER_NAME,
                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "invalid_key"),
            ))
            .to_srv_request();

        assert!(!check_authorization_header(
            &req,
            &SecretString::new("test_key")
        ));
    }

    #[test]
    fn test_check_authorization_header_multiple_bearer() {
        let req = TestRequest::default()
            .insert_header((
                AUTHORIZATION_HEADER_NAME,
                format!("Bearer Bearer {}", "test_key"),
            ))
            .to_srv_request();

        assert!(!check_authorization_header(
            &req,
            &SecretString::new("test_key")
        ));
    }

    #[test]
    fn test_check_authorization_header_multiple_headers() {
        let req = TestRequest::default()
            .insert_header((
                AUTHORIZATION_HEADER_NAME,
                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "test_key"),
            ))
            .insert_header((
                AUTHORIZATION_HEADER_NAME,
                format!("{}{}", AUTHORIZATION_HEADER_VALUE_PREFIX, "another_key"),
            ))
            .to_srv_request();

        // Should reject multiple Authorization headers
        assert!(!check_authorization_header(
            &req,
            &SecretString::new("test_key")
        ));
    }

    #[test]
    fn test_check_authorization_header_malformed_bearer() {
        // Test with Bearer in token
        let req = TestRequest::default()
            .insert_header((AUTHORIZATION_HEADER_NAME, "Bearer Bearer token"))
            .to_srv_request();

        assert!(!check_authorization_header(
            &req,
            &SecretString::new("token")
        ));

        // Test with empty token
        let req = TestRequest::default()
            .insert_header((AUTHORIZATION_HEADER_NAME, "Bearer "))
            .to_srv_request();

        assert!(!check_authorization_header(&req, &SecretString::new("")));
    }
}