Skip to main content

hoprd_api/middleware/
preconditions.rs

1use std::str::FromStr;
2
3use axum::{
4    extract::{OriginalUri, Request, State},
5    http::{
6        HeaderMap,
7        header::{AUTHORIZATION, HeaderName},
8        status::StatusCode,
9    },
10    middleware::Next,
11    response::IntoResponse,
12};
13
14use crate::{ApiErrorStatus, Auth, InternalState};
15
16pub(crate) async fn authenticate(
17    State(state): State<InternalState>,
18    _uri: OriginalUri,
19    headers: HeaderMap,
20    request: Request,
21    next: Next,
22) -> impl IntoResponse {
23    let auth = state.auth.clone();
24
25    let x_auth_header = HeaderName::from_str("x-auth-token").expect("Invalid header name: x-auth-token");
26
27    let is_authorized = match auth.as_ref() {
28        Auth::Token(expected_token) => {
29            let auth_headers = headers
30                .iter()
31                .filter_map(|(n, v)| {
32                    (AUTHORIZATION.eq(n) || x_auth_header.eq(n))
33                        .then_some((n, v.to_str().expect("Invalid header value")))
34                })
35                .collect::<Vec<_>>();
36
37            // Use "Authorization Bearer <token>" and "X-Auth-Token <token>" headers
38            !auth_headers.is_empty()
39                && (auth_headers.contains(&(&AUTHORIZATION, &format!("Bearer {expected_token}")))
40                    || auth_headers.contains(&(&x_auth_header, expected_token)))
41        }
42        Auth::None => true,
43    };
44
45    if !is_authorized {
46        return (StatusCode::UNAUTHORIZED, ApiErrorStatus::Unauthorized).into_response();
47    }
48
49    // Go forward to the next middleware or request handler
50    next.run(request).await
51}