1use crate::header::PROXY_AUTHENTICATE;
6use crate::headers::authorization::Authority;
7use crate::headers::{HeaderMapExt, ProxyAuthorization, authorization::Credentials};
8use crate::{Request, Response, StatusCode};
9use rama_core::error::{BoxError, ErrorContext as _};
10use rama_core::extensions::{Extension, ExtensionsRef};
11use rama_core::{Layer, Service};
12use rama_http_types::body::OptionalBody;
13use rama_net::user::UserId;
14use rama_utils::macros::define_inner_service_accessors;
15use std::fmt;
16use std::marker::PhantomData;
17
18pub struct ProxyAuthLayer<A, C, L = ()> {
22 proxy_auth: A,
23 allow_anonymous: bool,
24 _phantom: PhantomData<fn(C, L) -> ()>,
25}
26
27impl<A: fmt::Debug, C, L> fmt::Debug for ProxyAuthLayer<A, C, L> {
28 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29 f.debug_struct("ProxyAuthLayer")
30 .field("proxy_auth", &self.proxy_auth)
31 .field(
32 "_phantom",
33 &format_args!("{}", std::any::type_name::<fn(C, L) -> ()>()),
34 )
35 .finish()
36 }
37}
38
39impl<A: Clone, C, L> Clone for ProxyAuthLayer<A, C, L> {
40 fn clone(&self) -> Self {
41 Self {
42 proxy_auth: self.proxy_auth.clone(),
43 allow_anonymous: self.allow_anonymous,
44 _phantom: PhantomData,
45 }
46 }
47}
48
49impl<A, C> ProxyAuthLayer<A, C, ()> {
50 pub const fn new(proxy_auth: A) -> Self {
52 Self {
53 proxy_auth,
54 allow_anonymous: false,
55 _phantom: PhantomData,
56 }
57 }
58
59 rama_utils::macros::generate_set_and_with! {
60 pub fn allow_anonymous(mut self, allow_anonymous: bool) -> Self {
62 self.allow_anonymous = allow_anonymous;
63 self
64 }
65 }
66}
67
68impl<A, C, L> ProxyAuthLayer<A, C, L> {
69 pub fn with_labels<L2>(self) -> ProxyAuthLayer<A, C, L2> {
79 ProxyAuthLayer {
80 proxy_auth: self.proxy_auth,
81 allow_anonymous: self.allow_anonymous,
82 _phantom: PhantomData,
83 }
84 }
85}
86
87impl<A, C, L, S> Layer<S> for ProxyAuthLayer<A, C, L>
88where
89 A: Authority<C, L> + Clone,
90 C: Credentials + Clone + Send + Sync + 'static,
91{
92 type Service = ProxyAuthService<A, C, S, L>;
93
94 fn layer(&self, inner: S) -> Self::Service {
95 ProxyAuthService::new(self.proxy_auth.clone(), inner)
96 .with_allow_anonymous(self.allow_anonymous)
97 }
98
99 fn into_layer(self, inner: S) -> Self::Service {
100 ProxyAuthService::new(self.proxy_auth, inner).with_allow_anonymous(self.allow_anonymous)
101 }
102}
103
104pub struct ProxyAuthService<A, C, S, L = ()> {
112 proxy_auth: A,
113 allow_anonymous: bool,
114 inner: S,
115 _phantom: PhantomData<fn(C, L) -> ()>,
116}
117
118impl<A, C, S, L> ProxyAuthService<A, C, S, L> {
119 pub const fn new(proxy_auth: A, inner: S) -> Self {
121 Self {
122 proxy_auth,
123 allow_anonymous: false,
124 inner,
125 _phantom: PhantomData,
126 }
127 }
128
129 rama_utils::macros::generate_set_and_with! {
130 pub fn allow_anonymous(mut self, allow_anonymous: bool) -> Self {
132 self.allow_anonymous = allow_anonymous;
133 self
134 }
135 }
136
137 define_inner_service_accessors!();
138}
139
140impl<A: fmt::Debug, C, S: fmt::Debug, L> fmt::Debug for ProxyAuthService<A, C, S, L> {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 f.debug_struct("ProxyAuthService")
143 .field("proxy_auth", &self.proxy_auth)
144 .field("allow_anonymous", &self.allow_anonymous)
145 .field("inner", &self.inner)
146 .field(
147 "_phantom",
148 &format_args!("{}", std::any::type_name::<fn(C, L) -> ()>()),
149 )
150 .finish()
151 }
152}
153
154impl<A: Clone, C, S: Clone, L> Clone for ProxyAuthService<A, C, S, L> {
155 fn clone(&self) -> Self {
156 Self {
157 proxy_auth: self.proxy_auth.clone(),
158 allow_anonymous: self.allow_anonymous,
159 inner: self.inner.clone(),
160 _phantom: PhantomData,
161 }
162 }
163}
164
165impl<A, C, L, S, ReqBody, ResBody> Service<Request<ReqBody>> for ProxyAuthService<A, C, S, L>
166where
167 A: Authority<C, L>,
168 C: Credentials + Extension + Clone,
169 S: Service<Request<ReqBody>, Output = Response<ResBody>, Error: Into<BoxError>>,
170 L: 'static,
171 ReqBody: Send + 'static,
172 ResBody: Send + 'static,
173{
174 type Output = Response<OptionalBody<ResBody>>;
175 type Error = BoxError;
176
177 async fn serve(&self, req: Request<ReqBody>) -> Result<Self::Output, Self::Error> {
178 if let Some(credentials) = req
179 .headers()
180 .typed_get::<ProxyAuthorization<C>>()
181 .map(|h| h.0)
182 .or_else(|| req.extensions().get_ref::<C>().cloned())
183 {
184 if let Some(ext) = self.proxy_auth.authorized(credentials).await {
185 req.extensions().extend(&ext);
186 Ok(self
187 .inner
188 .serve(req)
189 .await
190 .into_box_error()?
191 .map(OptionalBody::some))
192 } else {
193 Ok(Response::builder()
194 .status(StatusCode::PROXY_AUTHENTICATION_REQUIRED)
195 .header(PROXY_AUTHENTICATE, C::SCHEME)
196 .body(OptionalBody::none())
197 .context("create auth-required response")?)
198 }
199 } else if self.allow_anonymous {
200 req.extensions().insert(UserId::Anonymous);
201 Ok(self
202 .inner
203 .serve(req)
204 .await
205 .into_box_error()?
206 .map(OptionalBody::some))
207 } else {
208 Ok(Response::builder()
209 .status(StatusCode::PROXY_AUTHENTICATION_REQUIRED)
210 .header(PROXY_AUTHENTICATE, C::SCHEME)
211 .body(OptionalBody::none())
212 .context("create auth-required response")?)
213 }
214 }
215}