summaryrefslogtreecommitdiff
path: root/vendor/tower-http/src/auth
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-15 16:37:08 -0600
committermo khan <mo@mokhan.ca>2025-07-17 16:30:22 -0600
commit45df4d0d9b577fecee798d672695fe24ff57fb1b (patch)
tree1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/tower-http/src/auth
parentf94f79608393d4ab127db63cc41668445ef6b243 (diff)
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based authorization system with SpiceDB's relation-based authorization. Key changes: - Migrate from Rust to Go implementation - Replace Cedar policies with SpiceDB schema and relationships - Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks - Update build system and dependencies for Go ecosystem - Maintain Envoy integration for external authorization This change enables more flexible permission modeling through SpiceDB's Google Zanzibar inspired relation-based system, supporting complex hierarchical permissions that were difficult to express in Cedar. Breaking change: Existing Cedar policies and Rust-based configuration will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/tower-http/src/auth')
-rw-r--r--vendor/tower-http/src/auth/add_authorization.rs267
-rw-r--r--vendor/tower-http/src/auth/async_require_authorization.rs385
-rw-r--r--vendor/tower-http/src/auth/mod.rs13
-rw-r--r--vendor/tower-http/src/auth/require_authorization.rs404
4 files changed, 0 insertions, 1069 deletions
diff --git a/vendor/tower-http/src/auth/add_authorization.rs b/vendor/tower-http/src/auth/add_authorization.rs
deleted file mode 100644
index 246c13b6..00000000
--- a/vendor/tower-http/src/auth/add_authorization.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-//! Add authorization to requests using the [`Authorization`] header.
-//!
-//! [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-//!
-//! # Example
-//!
-//! ```
-//! use tower_http::validate_request::{ValidateRequestHeader, ValidateRequestHeaderLayer};
-//! use tower_http::auth::AddAuthorizationLayer;
-//! use http::{Request, Response, StatusCode, header::AUTHORIZATION};
-//! use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
-//! use http_body_util::Full;
-//! use bytes::Bytes;
-//! # async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! # Ok(Response::new(Full::default()))
-//! # }
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! # let service_that_requires_auth = ValidateRequestHeader::basic(
-//! # tower::service_fn(handle),
-//! # "username",
-//! # "password",
-//! # );
-//! let mut client = ServiceBuilder::new()
-//! // Use basic auth with the given username and password
-//! .layer(AddAuthorizationLayer::basic("username", "password"))
-//! .service(service_that_requires_auth);
-//!
-//! // Make a request, we don't have to add the `Authorization` header manually
-//! let response = client
-//! .ready()
-//! .await?
-//! .call(Request::new(Full::default()))
-//! .await?;
-//!
-//! assert_eq!(StatusCode::OK, response.status());
-//! # Ok(())
-//! # }
-//! ```
-
-use base64::Engine as _;
-use http::{HeaderValue, Request, Response};
-use std::{
- convert::TryFrom,
- task::{Context, Poll},
-};
-use tower_layer::Layer;
-use tower_service::Service;
-
-const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD;
-
-/// Layer that applies [`AddAuthorization`] which adds authorization to all requests using the
-/// [`Authorization`] header.
-///
-/// See the [module docs](crate::auth::add_authorization) for an example.
-///
-/// You can also use [`SetRequestHeader`] if you have a use case that isn't supported by this
-/// middleware.
-///
-/// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-/// [`SetRequestHeader`]: crate::set_header::SetRequestHeader
-#[derive(Debug, Clone)]
-pub struct AddAuthorizationLayer {
- value: HeaderValue,
-}
-
-impl AddAuthorizationLayer {
- /// Authorize requests using a username and password pair.
- ///
- /// The `Authorization` header will be set to `Basic {credentials}` where `credentials` is
- /// `base64_encode("{username}:{password}")`.
- ///
- /// Since the username and password is sent in clear text it is recommended to use HTTPS/TLS
- /// with this method. However use of HTTPS/TLS is not enforced by this middleware.
- pub fn basic(username: &str, password: &str) -> Self {
- let encoded = BASE64.encode(format!("{}:{}", username, password));
- let value = HeaderValue::try_from(format!("Basic {}", encoded)).unwrap();
- Self { value }
- }
-
- /// Authorize requests using a "bearer token". Commonly used for OAuth 2.
- ///
- /// The `Authorization` header will be set to `Bearer {token}`.
- ///
- /// # Panics
- ///
- /// Panics if the token is not a valid [`HeaderValue`].
- pub fn bearer(token: &str) -> Self {
- let value =
- HeaderValue::try_from(format!("Bearer {}", token)).expect("token is not valid header");
- Self { value }
- }
-
- /// Mark the header as [sensitive].
- ///
- /// This can for example be used to hide the header value from logs.
- ///
- /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
- #[allow(clippy::wrong_self_convention)]
- pub fn as_sensitive(mut self, sensitive: bool) -> Self {
- self.value.set_sensitive(sensitive);
- self
- }
-}
-
-impl<S> Layer<S> for AddAuthorizationLayer {
- type Service = AddAuthorization<S>;
-
- fn layer(&self, inner: S) -> Self::Service {
- AddAuthorization {
- inner,
- value: self.value.clone(),
- }
- }
-}
-
-/// Middleware that adds authorization all requests using the [`Authorization`] header.
-///
-/// See the [module docs](crate::auth::add_authorization) for an example.
-///
-/// You can also use [`SetRequestHeader`] if you have a use case that isn't supported by this
-/// middleware.
-///
-/// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-/// [`SetRequestHeader`]: crate::set_header::SetRequestHeader
-#[derive(Debug, Clone)]
-pub struct AddAuthorization<S> {
- inner: S,
- value: HeaderValue,
-}
-
-impl<S> AddAuthorization<S> {
- /// Authorize requests using a username and password pair.
- ///
- /// The `Authorization` header will be set to `Basic {credentials}` where `credentials` is
- /// `base64_encode("{username}:{password}")`.
- ///
- /// Since the username and password is sent in clear text it is recommended to use HTTPS/TLS
- /// with this method. However use of HTTPS/TLS is not enforced by this middleware.
- pub fn basic(inner: S, username: &str, password: &str) -> Self {
- AddAuthorizationLayer::basic(username, password).layer(inner)
- }
-
- /// Authorize requests using a "bearer token". Commonly used for OAuth 2.
- ///
- /// The `Authorization` header will be set to `Bearer {token}`.
- ///
- /// # Panics
- ///
- /// Panics if the token is not a valid [`HeaderValue`].
- pub fn bearer(inner: S, token: &str) -> Self {
- AddAuthorizationLayer::bearer(token).layer(inner)
- }
-
- define_inner_service_accessors!();
-
- /// Mark the header as [sensitive].
- ///
- /// This can for example be used to hide the header value from logs.
- ///
- /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
- #[allow(clippy::wrong_self_convention)]
- pub fn as_sensitive(mut self, sensitive: bool) -> Self {
- self.value.set_sensitive(sensitive);
- self
- }
-}
-
-impl<S, ReqBody, ResBody> Service<Request<ReqBody>> for AddAuthorization<S>
-where
- S: Service<Request<ReqBody>, Response = Response<ResBody>>,
-{
- type Response = S::Response;
- type Error = S::Error;
- type Future = S::Future;
-
- fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
- self.inner.poll_ready(cx)
- }
-
- fn call(&mut self, mut req: Request<ReqBody>) -> Self::Future {
- req.headers_mut()
- .insert(http::header::AUTHORIZATION, self.value.clone());
- self.inner.call(req)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::test_helpers::Body;
- use crate::validate_request::ValidateRequestHeaderLayer;
- use http::{Response, StatusCode};
- use std::convert::Infallible;
- use tower::{BoxError, Service, ServiceBuilder, ServiceExt};
-
- #[tokio::test]
- async fn basic() {
- // service that requires auth for all requests
- let svc = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::basic("foo", "bar"))
- .service_fn(echo);
-
- // make a client that adds auth
- let mut client = AddAuthorization::basic(svc, "foo", "bar");
-
- let res = client
- .ready()
- .await
- .unwrap()
- .call(Request::new(Body::empty()))
- .await
- .unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn token() {
- // service that requires auth for all requests
- let svc = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::bearer("foo"))
- .service_fn(echo);
-
- // make a client that adds auth
- let mut client = AddAuthorization::bearer(svc, "foo");
-
- let res = client
- .ready()
- .await
- .unwrap()
- .call(Request::new(Body::empty()))
- .await
- .unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn making_header_sensitive() {
- let svc = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::bearer("foo"))
- .service_fn(|request: Request<Body>| async move {
- let auth = request.headers().get(http::header::AUTHORIZATION).unwrap();
- assert!(auth.is_sensitive());
-
- Ok::<_, Infallible>(Response::new(Body::empty()))
- });
-
- let mut client = AddAuthorization::bearer(svc, "foo").as_sensitive(true);
-
- let res = client
- .ready()
- .await
- .unwrap()
- .call(Request::new(Body::empty()))
- .await
- .unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- async fn echo(req: Request<Body>) -> Result<Response<Body>, BoxError> {
- Ok(Response::new(req.into_body()))
- }
-}
diff --git a/vendor/tower-http/src/auth/async_require_authorization.rs b/vendor/tower-http/src/auth/async_require_authorization.rs
deleted file mode 100644
index fda9abea..00000000
--- a/vendor/tower-http/src/auth/async_require_authorization.rs
+++ /dev/null
@@ -1,385 +0,0 @@
-//! Authorize requests using the [`Authorization`] header asynchronously.
-//!
-//! [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-//!
-//! # Example
-//!
-//! ```
-//! use tower_http::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest};
-//! use http::{Request, Response, StatusCode, header::AUTHORIZATION};
-//! use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
-//! use futures_core::future::BoxFuture;
-//! use bytes::Bytes;
-//! use http_body_util::Full;
-//!
-//! #[derive(Clone, Copy)]
-//! struct MyAuth;
-//!
-//! impl<B> AsyncAuthorizeRequest<B> for MyAuth
-//! where
-//! B: Send + Sync + 'static,
-//! {
-//! type RequestBody = B;
-//! type ResponseBody = Full<Bytes>;
-//! type Future = BoxFuture<'static, Result<Request<B>, Response<Self::ResponseBody>>>;
-//!
-//! fn authorize(&mut self, mut request: Request<B>) -> Self::Future {
-//! Box::pin(async {
-//! if let Some(user_id) = check_auth(&request).await {
-//! // Set `user_id` as a request extension so it can be accessed by other
-//! // services down the stack.
-//! request.extensions_mut().insert(user_id);
-//!
-//! Ok(request)
-//! } else {
-//! let unauthorized_response = Response::builder()
-//! .status(StatusCode::UNAUTHORIZED)
-//! .body(Full::<Bytes>::default())
-//! .unwrap();
-//!
-//! Err(unauthorized_response)
-//! }
-//! })
-//! }
-//! }
-//!
-//! async fn check_auth<B>(request: &Request<B>) -> Option<UserId> {
-//! // ...
-//! # None
-//! }
-//!
-//! #[derive(Debug, Clone)]
-//! struct UserId(String);
-//!
-//! async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! // Access the `UserId` that was set in `on_authorized`. If `handle` gets called the
-//! // request was authorized and `UserId` will be present.
-//! let user_id = request
-//! .extensions()
-//! .get::<UserId>()
-//! .expect("UserId will be there if request was authorized");
-//!
-//! println!("request from {:?}", user_id);
-//!
-//! Ok(Response::new(Full::default()))
-//! }
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! let service = ServiceBuilder::new()
-//! // Authorize requests using `MyAuth`
-//! .layer(AsyncRequireAuthorizationLayer::new(MyAuth))
-//! .service_fn(handle);
-//! # Ok(())
-//! # }
-//! ```
-//!
-//! Or using a closure:
-//!
-//! ```
-//! use tower_http::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest};
-//! use http::{Request, Response, StatusCode};
-//! use tower::{Service, ServiceExt, ServiceBuilder, BoxError};
-//! use futures_core::future::BoxFuture;
-//! use http_body_util::Full;
-//! use bytes::Bytes;
-//!
-//! async fn check_auth<B>(request: &Request<B>) -> Option<UserId> {
-//! // ...
-//! # None
-//! }
-//!
-//! #[derive(Debug)]
-//! struct UserId(String);
-//!
-//! async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! # todo!();
-//! // ...
-//! }
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! let service = ServiceBuilder::new()
-//! .layer(AsyncRequireAuthorizationLayer::new(|request: Request<Full<Bytes>>| async move {
-//! if let Some(user_id) = check_auth(&request).await {
-//! Ok(request)
-//! } else {
-//! let unauthorized_response = Response::builder()
-//! .status(StatusCode::UNAUTHORIZED)
-//! .body(Full::<Bytes>::default())
-//! .unwrap();
-//!
-//! Err(unauthorized_response)
-//! }
-//! }))
-//! .service_fn(handle);
-//! # Ok(())
-//! # }
-//! ```
-
-use http::{Request, Response};
-use pin_project_lite::pin_project;
-use std::{
- future::Future,
- mem,
- pin::Pin,
- task::{ready, Context, Poll},
-};
-use tower_layer::Layer;
-use tower_service::Service;
-
-/// Layer that applies [`AsyncRequireAuthorization`] which authorizes all requests using the
-/// [`Authorization`] header.
-///
-/// See the [module docs](crate::auth::async_require_authorization) for an example.
-///
-/// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-#[derive(Debug, Clone)]
-pub struct AsyncRequireAuthorizationLayer<T> {
- auth: T,
-}
-
-impl<T> AsyncRequireAuthorizationLayer<T> {
- /// Authorize requests using a custom scheme.
- pub fn new(auth: T) -> AsyncRequireAuthorizationLayer<T> {
- Self { auth }
- }
-}
-
-impl<S, T> Layer<S> for AsyncRequireAuthorizationLayer<T>
-where
- T: Clone,
-{
- type Service = AsyncRequireAuthorization<S, T>;
-
- fn layer(&self, inner: S) -> Self::Service {
- AsyncRequireAuthorization::new(inner, self.auth.clone())
- }
-}
-
-/// Middleware that authorizes all requests using the [`Authorization`] header.
-///
-/// See the [module docs](crate::auth::async_require_authorization) for an example.
-///
-/// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-#[derive(Clone, Debug)]
-pub struct AsyncRequireAuthorization<S, T> {
- inner: S,
- auth: T,
-}
-
-impl<S, T> AsyncRequireAuthorization<S, T> {
- define_inner_service_accessors!();
-}
-
-impl<S, T> AsyncRequireAuthorization<S, T> {
- /// Authorize requests using a custom scheme.
- ///
- /// The `Authorization` header is required to have the value provided.
- pub fn new(inner: S, auth: T) -> AsyncRequireAuthorization<S, T> {
- Self { inner, auth }
- }
-
- /// Returns a new [`Layer`] that wraps services with an [`AsyncRequireAuthorizationLayer`]
- /// middleware.
- ///
- /// [`Layer`]: tower_layer::Layer
- pub fn layer(auth: T) -> AsyncRequireAuthorizationLayer<T> {
- AsyncRequireAuthorizationLayer::new(auth)
- }
-}
-
-impl<ReqBody, ResBody, S, Auth> Service<Request<ReqBody>> for AsyncRequireAuthorization<S, Auth>
-where
- Auth: AsyncAuthorizeRequest<ReqBody, ResponseBody = ResBody>,
- S: Service<Request<Auth::RequestBody>, Response = Response<ResBody>> + Clone,
-{
- type Response = Response<ResBody>;
- type Error = S::Error;
- type Future = ResponseFuture<Auth, S, ReqBody>;
-
- fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
- self.inner.poll_ready(cx)
- }
-
- fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
- let mut inner = self.inner.clone();
- let authorize = self.auth.authorize(req);
- // mem::swap due to https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services
- mem::swap(&mut self.inner, &mut inner);
-
- ResponseFuture {
- state: State::Authorize { authorize },
- service: inner,
- }
- }
-}
-
-pin_project! {
- /// Response future for [`AsyncRequireAuthorization`].
- pub struct ResponseFuture<Auth, S, ReqBody>
- where
- Auth: AsyncAuthorizeRequest<ReqBody>,
- S: Service<Request<Auth::RequestBody>>,
- {
- #[pin]
- state: State<Auth::Future, S::Future>,
- service: S,
- }
-}
-
-pin_project! {
- #[project = StateProj]
- enum State<A, SFut> {
- Authorize {
- #[pin]
- authorize: A,
- },
- Authorized {
- #[pin]
- fut: SFut,
- },
- }
-}
-
-impl<Auth, S, ReqBody, B> Future for ResponseFuture<Auth, S, ReqBody>
-where
- Auth: AsyncAuthorizeRequest<ReqBody, ResponseBody = B>,
- S: Service<Request<Auth::RequestBody>, Response = Response<B>>,
-{
- type Output = Result<Response<B>, S::Error>;
-
- fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
- let mut this = self.project();
-
- loop {
- match this.state.as_mut().project() {
- StateProj::Authorize { authorize } => {
- let auth = ready!(authorize.poll(cx));
- match auth {
- Ok(req) => {
- let fut = this.service.call(req);
- this.state.set(State::Authorized { fut })
- }
- Err(res) => {
- return Poll::Ready(Ok(res));
- }
- };
- }
- StateProj::Authorized { fut } => {
- return fut.poll(cx);
- }
- }
- }
- }
-}
-
-/// Trait for authorizing requests.
-pub trait AsyncAuthorizeRequest<B> {
- /// The type of request body returned by `authorize`.
- ///
- /// Set this to `B` unless you need to change the request body type.
- type RequestBody;
-
- /// The body type used for responses to unauthorized requests.
- type ResponseBody;
-
- /// The Future type returned by `authorize`
- type Future: Future<Output = Result<Request<Self::RequestBody>, Response<Self::ResponseBody>>>;
-
- /// Authorize the request.
- ///
- /// If the future resolves to `Ok(request)` then the request is allowed through, otherwise not.
- fn authorize(&mut self, request: Request<B>) -> Self::Future;
-}
-
-impl<B, F, Fut, ReqBody, ResBody> AsyncAuthorizeRequest<B> for F
-where
- F: FnMut(Request<B>) -> Fut,
- Fut: Future<Output = Result<Request<ReqBody>, Response<ResBody>>>,
-{
- type RequestBody = ReqBody;
- type ResponseBody = ResBody;
- type Future = Fut;
-
- fn authorize(&mut self, request: Request<B>) -> Self::Future {
- self(request)
- }
-}
-
-#[cfg(test)]
-mod tests {
- #[allow(unused_imports)]
- use super::*;
- use crate::test_helpers::Body;
- use futures_core::future::BoxFuture;
- use http::{header, StatusCode};
- use tower::{BoxError, ServiceBuilder, ServiceExt};
-
- #[derive(Clone, Copy)]
- struct MyAuth;
-
- impl<B> AsyncAuthorizeRequest<B> for MyAuth
- where
- B: Send + 'static,
- {
- type RequestBody = B;
- type ResponseBody = Body;
- type Future = BoxFuture<'static, Result<Request<B>, Response<Self::ResponseBody>>>;
-
- fn authorize(&mut self, request: Request<B>) -> Self::Future {
- Box::pin(async move {
- let authorized = request
- .headers()
- .get(header::AUTHORIZATION)
- .and_then(|auth| auth.to_str().ok()?.strip_prefix("Bearer "))
- == Some("69420");
-
- if authorized {
- Ok(request)
- } else {
- Err(Response::builder()
- .status(StatusCode::UNAUTHORIZED)
- .body(Body::empty())
- .unwrap())
- }
- })
- }
- }
-
- #[tokio::test]
- async fn require_async_auth_works() {
- let mut service = ServiceBuilder::new()
- .layer(AsyncRequireAuthorizationLayer::new(MyAuth))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::AUTHORIZATION, "Bearer 69420")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn require_async_auth_401() {
- let mut service = ServiceBuilder::new()
- .layer(AsyncRequireAuthorizationLayer::new(MyAuth))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::AUTHORIZATION, "Bearer deez")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
- }
-
- async fn echo(req: Request<Body>) -> Result<Response<Body>, BoxError> {
- Ok(Response::new(req.into_body()))
- }
-}
diff --git a/vendor/tower-http/src/auth/mod.rs b/vendor/tower-http/src/auth/mod.rs
deleted file mode 100644
index fc8c2308..00000000
--- a/vendor/tower-http/src/auth/mod.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//! Authorization related middleware.
-
-pub mod add_authorization;
-pub mod async_require_authorization;
-pub mod require_authorization;
-
-#[doc(inline)]
-pub use self::{
- add_authorization::{AddAuthorization, AddAuthorizationLayer},
- async_require_authorization::{
- AsyncAuthorizeRequest, AsyncRequireAuthorization, AsyncRequireAuthorizationLayer,
- },
-};
diff --git a/vendor/tower-http/src/auth/require_authorization.rs b/vendor/tower-http/src/auth/require_authorization.rs
deleted file mode 100644
index 7aa1a87f..00000000
--- a/vendor/tower-http/src/auth/require_authorization.rs
+++ /dev/null
@@ -1,404 +0,0 @@
-//! Authorize requests using [`ValidateRequest`].
-//!
-//! [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
-//!
-//! # Example
-//!
-//! ```
-//! use tower_http::validate_request::{ValidateRequest, ValidateRequestHeader, ValidateRequestHeaderLayer};
-//! use http::{Request, Response, StatusCode, header::AUTHORIZATION};
-//! use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
-//! use bytes::Bytes;
-//! use http_body_util::Full;
-//!
-//! async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
-//! Ok(Response::new(Full::default()))
-//! }
-//!
-//! # #[tokio::main]
-//! # async fn main() -> Result<(), BoxError> {
-//! let mut service = ServiceBuilder::new()
-//! // Require the `Authorization` header to be `Bearer passwordlol`
-//! .layer(ValidateRequestHeaderLayer::bearer("passwordlol"))
-//! .service_fn(handle);
-//!
-//! // Requests with the correct token are allowed through
-//! let request = Request::builder()
-//! .header(AUTHORIZATION, "Bearer passwordlol")
-//! .body(Full::default())
-//! .unwrap();
-//!
-//! let response = service
-//! .ready()
-//! .await?
-//! .call(request)
-//! .await?;
-//!
-//! assert_eq!(StatusCode::OK, response.status());
-//!
-//! // Requests with an invalid token get a `401 Unauthorized` response
-//! let request = Request::builder()
-//! .body(Full::default())
-//! .unwrap();
-//!
-//! let response = service
-//! .ready()
-//! .await?
-//! .call(request)
-//! .await?;
-//!
-//! assert_eq!(StatusCode::UNAUTHORIZED, response.status());
-//! # Ok(())
-//! # }
-//! ```
-//!
-//! Custom validation can be made by implementing [`ValidateRequest`].
-
-use crate::validate_request::{ValidateRequest, ValidateRequestHeader, ValidateRequestHeaderLayer};
-use base64::Engine as _;
-use http::{
- header::{self, HeaderValue},
- Request, Response, StatusCode,
-};
-use std::{fmt, marker::PhantomData};
-
-const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD;
-
-impl<S, ResBody> ValidateRequestHeader<S, Basic<ResBody>> {
- /// Authorize requests using a username and password pair.
- ///
- /// The `Authorization` header is required to be `Basic {credentials}` where `credentials` is
- /// `base64_encode("{username}:{password}")`.
- ///
- /// Since the username and password is sent in clear text it is recommended to use HTTPS/TLS
- /// with this method. However use of HTTPS/TLS is not enforced by this middleware.
- pub fn basic(inner: S, username: &str, value: &str) -> Self
- where
- ResBody: Default,
- {
- Self::custom(inner, Basic::new(username, value))
- }
-}
-
-impl<ResBody> ValidateRequestHeaderLayer<Basic<ResBody>> {
- /// Authorize requests using a username and password pair.
- ///
- /// The `Authorization` header is required to be `Basic {credentials}` where `credentials` is
- /// `base64_encode("{username}:{password}")`.
- ///
- /// Since the username and password is sent in clear text it is recommended to use HTTPS/TLS
- /// with this method. However use of HTTPS/TLS is not enforced by this middleware.
- pub fn basic(username: &str, password: &str) -> Self
- where
- ResBody: Default,
- {
- Self::custom(Basic::new(username, password))
- }
-}
-
-impl<S, ResBody> ValidateRequestHeader<S, Bearer<ResBody>> {
- /// Authorize requests using a "bearer token". Commonly used for OAuth 2.
- ///
- /// The `Authorization` header is required to be `Bearer {token}`.
- ///
- /// # Panics
- ///
- /// Panics if the token is not a valid [`HeaderValue`].
- pub fn bearer(inner: S, token: &str) -> Self
- where
- ResBody: Default,
- {
- Self::custom(inner, Bearer::new(token))
- }
-}
-
-impl<ResBody> ValidateRequestHeaderLayer<Bearer<ResBody>> {
- /// Authorize requests using a "bearer token". Commonly used for OAuth 2.
- ///
- /// The `Authorization` header is required to be `Bearer {token}`.
- ///
- /// # Panics
- ///
- /// Panics if the token is not a valid [`HeaderValue`].
- pub fn bearer(token: &str) -> Self
- where
- ResBody: Default,
- {
- Self::custom(Bearer::new(token))
- }
-}
-
-/// Type that performs "bearer token" authorization.
-///
-/// See [`ValidateRequestHeader::bearer`] for more details.
-pub struct Bearer<ResBody> {
- header_value: HeaderValue,
- _ty: PhantomData<fn() -> ResBody>,
-}
-
-impl<ResBody> Bearer<ResBody> {
- fn new(token: &str) -> Self
- where
- ResBody: Default,
- {
- Self {
- header_value: format!("Bearer {}", token)
- .parse()
- .expect("token is not a valid header value"),
- _ty: PhantomData,
- }
- }
-}
-
-impl<ResBody> Clone for Bearer<ResBody> {
- fn clone(&self) -> Self {
- Self {
- header_value: self.header_value.clone(),
- _ty: PhantomData,
- }
- }
-}
-
-impl<ResBody> fmt::Debug for Bearer<ResBody> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Bearer")
- .field("header_value", &self.header_value)
- .finish()
- }
-}
-
-impl<B, ResBody> ValidateRequest<B> for Bearer<ResBody>
-where
- ResBody: Default,
-{
- type ResponseBody = ResBody;
-
- fn validate(&mut self, request: &mut Request<B>) -> Result<(), Response<Self::ResponseBody>> {
- match request.headers().get(header::AUTHORIZATION) {
- Some(actual) if actual == self.header_value => Ok(()),
- _ => {
- let mut res = Response::new(ResBody::default());
- *res.status_mut() = StatusCode::UNAUTHORIZED;
- Err(res)
- }
- }
- }
-}
-
-/// Type that performs basic authorization.
-///
-/// See [`ValidateRequestHeader::basic`] for more details.
-pub struct Basic<ResBody> {
- header_value: HeaderValue,
- _ty: PhantomData<fn() -> ResBody>,
-}
-
-impl<ResBody> Basic<ResBody> {
- fn new(username: &str, password: &str) -> Self
- where
- ResBody: Default,
- {
- let encoded = BASE64.encode(format!("{}:{}", username, password));
- let header_value = format!("Basic {}", encoded).parse().unwrap();
- Self {
- header_value,
- _ty: PhantomData,
- }
- }
-}
-
-impl<ResBody> Clone for Basic<ResBody> {
- fn clone(&self) -> Self {
- Self {
- header_value: self.header_value.clone(),
- _ty: PhantomData,
- }
- }
-}
-
-impl<ResBody> fmt::Debug for Basic<ResBody> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Basic")
- .field("header_value", &self.header_value)
- .finish()
- }
-}
-
-impl<B, ResBody> ValidateRequest<B> for Basic<ResBody>
-where
- ResBody: Default,
-{
- type ResponseBody = ResBody;
-
- fn validate(&mut self, request: &mut Request<B>) -> Result<(), Response<Self::ResponseBody>> {
- match request.headers().get(header::AUTHORIZATION) {
- Some(actual) if actual == self.header_value => Ok(()),
- _ => {
- let mut res = Response::new(ResBody::default());
- *res.status_mut() = StatusCode::UNAUTHORIZED;
- res.headers_mut()
- .insert(header::WWW_AUTHENTICATE, "Basic".parse().unwrap());
- Err(res)
- }
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::validate_request::ValidateRequestHeaderLayer;
-
- #[allow(unused_imports)]
- use super::*;
- use crate::test_helpers::Body;
- use http::header;
- use tower::{BoxError, ServiceBuilder, ServiceExt};
- use tower_service::Service;
-
- #[tokio::test]
- async fn valid_basic_token() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::basic("foo", "bar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(
- header::AUTHORIZATION,
- format!("Basic {}", BASE64.encode("foo:bar")),
- )
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn invalid_basic_token() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::basic("foo", "bar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(
- header::AUTHORIZATION,
- format!("Basic {}", BASE64.encode("wrong:credentials")),
- )
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
-
- let www_authenticate = res.headers().get(header::WWW_AUTHENTICATE).unwrap();
- assert_eq!(www_authenticate, "Basic");
- }
-
- #[tokio::test]
- async fn valid_bearer_token() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::bearer("foobar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::AUTHORIZATION, "Bearer foobar")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::OK);
- }
-
- #[tokio::test]
- async fn basic_auth_is_case_sensitive_in_prefix() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::basic("foo", "bar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(
- header::AUTHORIZATION,
- format!("basic {}", BASE64.encode("foo:bar")),
- )
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
- }
-
- #[tokio::test]
- async fn basic_auth_is_case_sensitive_in_value() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::basic("foo", "bar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(
- header::AUTHORIZATION,
- format!("Basic {}", BASE64.encode("Foo:bar")),
- )
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
- }
-
- #[tokio::test]
- async fn invalid_bearer_token() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::bearer("foobar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::AUTHORIZATION, "Bearer wat")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
- }
-
- #[tokio::test]
- async fn bearer_token_is_case_sensitive_in_prefix() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::bearer("foobar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::AUTHORIZATION, "bearer foobar")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
- }
-
- #[tokio::test]
- async fn bearer_token_is_case_sensitive_in_token() {
- let mut service = ServiceBuilder::new()
- .layer(ValidateRequestHeaderLayer::bearer("foobar"))
- .service_fn(echo);
-
- let request = Request::get("/")
- .header(header::AUTHORIZATION, "Bearer Foobar")
- .body(Body::empty())
- .unwrap();
-
- let res = service.ready().await.unwrap().call(request).await.unwrap();
-
- assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
- }
-
- async fn echo(req: Request<Body>) -> Result<Response<Body>, BoxError> {
- Ok(Response::new(req.into_body()))
- }
-}