menmos_auth/
storage_node_identity.rs

1use std::fmt::Debug;
2
3use apikit::reject::HTTPError;
4
5use axum::extract::{Extension, FromRequest, Query, RequestParts, TypedHeader};
6use axum::headers;
7use axum::headers::authorization::{Authorization, Bearer};
8
9use branca::Branca;
10
11use serde::{Deserialize, Serialize};
12
13use crate::{EncryptionKey, Signature, TOKEN_TTL_SECONDS};
14
15/// Represents a storage node identity.
16///
17/// This is the body of contained in tokens used by storage nodes when they call the directory.
18#[derive(Deserialize, Serialize)]
19pub struct StorageNodeIdentity {
20    pub id: String,
21}
22
23#[async_trait::async_trait]
24impl<B: Send> FromRequest<B> for StorageNodeIdentity {
25    type Rejection = HTTPError;
26
27    async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
28        let tok_maybe = if let Ok(TypedHeader(headers::Authorization(bearer))) =
29            TypedHeader::<Authorization<Bearer>>::from_request(req).await
30        {
31            tracing::debug!("got a bearer token from authorization header");
32            Some(bearer.token().to_string())
33        } else if let Ok(Query(q)) = Query::<Signature>::from_request(req).await {
34            if q.signature.is_some() {
35                tracing::debug!("got a signature from query params");
36            }
37            q.signature
38        } else {
39            None
40        };
41
42        let token = tok_maybe.ok_or_else(|| {
43            tracing::debug!("no token found");
44            HTTPError::Forbidden
45        })?;
46
47        let Extension(EncryptionKey { key }) = Extension::<EncryptionKey>::from_request(req)
48            .await
49            .map_err(|e| {
50                tracing::warn!("no encryption key in extension layer: {}", e);
51                HTTPError::Forbidden
52            })?;
53
54        let token_decoder = Branca::new(key.as_bytes()).map_err(|e| {
55            tracing::warn!("invalid encryption key: {}", e);
56            HTTPError::Forbidden
57        })?;
58        let decoded = token_decoder
59            .decode(&token, TOKEN_TTL_SECONDS)
60            .map_err(|e| {
61                tracing::warn!("invalid branca token: {}", e);
62                HTTPError::Forbidden
63            })?;
64
65        Ok(bincode::deserialize(&decoded).map_err(|e| {
66            tracing::debug!("token deserialize error: {}", e);
67            HTTPError::Forbidden
68        })?)
69    }
70}
71
72impl Debug for StorageNodeIdentity {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        write!(f, "storage({})", &self.id)
75    }
76}