Skip to main content

rama_http/layer/
dpi_proxy_credential.rs

1//! Middleware that extracts credentials for an egress proxy
2//! found in the Proxy-Authorization header of a passthrough request.
3//!
4//! See for more information: [`DpiProxyCredentialExtractor`]
5
6use crate::Request;
7use crate::headers::{HeaderMapExt, ProxyAuthorization};
8use rama_core::extensions::ExtensionsRef;
9use rama_core::telemetry::tracing;
10use rama_core::{Layer, Service};
11use rama_http_types::proxy::is_req_http_proxy_connect;
12use rama_net::user::credentials::DpiProxyCredential;
13use rama_net::user::{Basic, Bearer, ProxyCredential};
14use rama_utils::macros::define_inner_service_accessors;
15
16#[derive(Debug, Clone, Default)]
17#[non_exhaustive]
18/// Layer that applies the [`DpiProxyCredentialExtractor`] middleware.
19pub struct DpiProxyCredentialExtractorLayer;
20
21impl DpiProxyCredentialExtractorLayer {
22    #[inline(always)]
23    /// Creates a new [`DpiProxyCredentialExtractorLayer`].
24    pub const fn new() -> Self {
25        Self
26    }
27}
28
29impl<S> Layer<S> for DpiProxyCredentialExtractorLayer {
30    type Service = DpiProxyCredentialExtractor<S>;
31
32    #[inline(always)]
33    fn layer(&self, inner: S) -> Self::Service {
34        DpiProxyCredentialExtractor::new(inner)
35    }
36}
37
38#[derive(Debug, Clone)]
39/// Middleware that extracts credentials for an egress proxy
40/// found in the Proxy-Authorization header of a passthrough request.
41///
42/// This is useful for MITM proxies such as transparent (L4) proxies, to keep track of used
43/// proxy credentials for meta purposes.
44pub struct DpiProxyCredentialExtractor<S> {
45    inner: S,
46}
47
48impl<S> DpiProxyCredentialExtractor<S> {
49    #[inline(always)]
50    /// Creates a new [`DpiProxyCredentialExtractor`].
51    pub const fn new(inner: S) -> Self {
52        Self { inner }
53    }
54
55    define_inner_service_accessors!();
56}
57
58impl<S, ReqBody> Service<Request<ReqBody>> for DpiProxyCredentialExtractor<S>
59where
60    S: Service<Request<ReqBody>>,
61    ReqBody: Send + 'static,
62{
63    type Output = S::Output;
64    type Error = S::Error;
65
66    async fn serve(&self, req: Request<ReqBody>) -> Result<Self::Output, Self::Error> {
67        if is_req_http_proxy_connect(&req) {
68            tracing::trace!("DpiProxyCredentialExtractor: try to extract proxy authorization data");
69
70            if let Some(ProxyAuthorization::<Basic>(credentials)) = req.headers().typed_get() {
71                tracing::debug!(
72                    "DpiProxyCredentialExtractor: extracted Basic proxy auth: inserted in req extensions"
73                );
74                req.extensions()
75                    .insert(DpiProxyCredential(ProxyCredential::Basic(credentials)));
76            } else if let Some(ProxyAuthorization::<Bearer>(token)) = req.headers().typed_get() {
77                tracing::debug!(
78                    "DpiProxyCredentialExtractor: extracted Bearer proxy auth: inserted in req extensions"
79                );
80                req.extensions()
81                    .insert(DpiProxyCredential(ProxyCredential::Bearer(token)));
82            }
83        }
84
85        self.inner.serve(req).await
86    }
87}