diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b2197e..8572b7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,16 +28,25 @@ jobs: components: clippy - run: cargo clippy --all-targets --all-features -- -D warnings + msrv: + name: Minimal rust version + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install Rust + uses: dtolnay/rust-toolchain@master + with: + toolchain: "1.73" + - name: Build System Info + run: cargo build --lib --all-features + tests: name: Tests runs-on: ${{ matrix.os }} strategy: matrix: - build: [pinned, stable, nightly] + build: [stable, nightly] include: - - build: pinned - os: ubuntu-22.04 - rust: 1.68.0 - build: stable os: ubuntu-22.04 rust: stable diff --git a/Cargo.lock b/Cargo.lock index a4ab419..8a001e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,34 +108,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 0.1.2", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "axum" version = "0.7.5" @@ -143,13 +115,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" dependencies = [ "async-trait", - "axum-core 0.4.3", + "axum-core", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "itoa", "matchit", @@ -170,23 +142,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.3" @@ -196,8 +151,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -235,12 +190,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -370,7 +319,7 @@ name = "demo-server" version = "0.1.0" dependencies = [ "anyhow", - "axum 0.7.5", + "axum", "headers", "josekit", "jsonwebtoken", @@ -600,25 +549,6 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.4.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.6" @@ -630,7 +560,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap 2.4.0", "slab", "tokio", @@ -659,7 +589,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http 1.1.0", + "http", "httpdate", "mime", "sha1", @@ -671,7 +601,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.1.0", + "http", ] [[package]] @@ -680,17 +610,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -702,17 +621,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -720,7 +628,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -731,8 +639,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -748,30 +656,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.4.1" @@ -781,9 +665,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -800,8 +684,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.4.1", + "http", + "hyper", "hyper-util", "rustls", "rustls-native-certs", @@ -814,14 +698,15 @@ dependencies = [ [[package]] name = "hyper-timeout" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ - "hyper 0.14.30", + "hyper", + "hyper-util", "pin-project-lite", "tokio", - "tokio-io-timeout", + "tower-service", ] [[package]] @@ -832,7 +717,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -849,9 +734,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -921,9 +806,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -980,14 +865,14 @@ dependencies = [ name = "jwt-authorizer" version = "0.14.0" dependencies = [ - "axum 0.7.5", + "axum", "chrono", "futures-core", "futures-util", "headers", - "http 1.1.0", + "http", "http-body-util", - "hyper 1.4.1", + "hyper", "jsonwebtoken", "lazy_static", "pin-project", @@ -1191,7 +1076,7 @@ version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -1348,9 +1233,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +checksum = "e13db3d3fde688c61e2446b4d843bc27a7e8af269a69440c0308021dc92333cc" dependencies = [ "bytes", "prost-derive", @@ -1358,9 +1243,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "18bec9b0adc4eba778b33684b7ba3e7137789434769ee3ce3930463ef904cfca" dependencies = [ "anyhow", "itertools", @@ -1462,7 +1347,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -1520,11 +1405,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-rustls", "hyper-tls", "hyper-util", @@ -1591,7 +1476,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1685,7 +1570,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -1873,7 +1758,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658bc6ee10a9b4fcf576e9b0819d95ec16f4d2c02d39fd83ac1c8789785c4a42" dependencies = [ - "bitflags 2.6.0", + "bitflags", "core-foundation", "system-configuration-sys", ] @@ -1995,16 +1880,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" version = "2.4.0" @@ -2063,23 +1938,26 @@ dependencies = [ [[package]] name = "tonic" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +checksum = "38659f4a91aba8598d27821589f5db7dddd94601e7a01b1e485a50e5484c7401" dependencies = [ "async-stream", "async-trait", - "axum 0.6.20", - "base64 0.21.7", + "axum", + "base64 0.22.1", "bytes", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.30", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", "hyper-timeout", + "hyper-util", "percent-encoding", "pin-project", "prost", + "socket2", "tokio", "tokio-stream", "tower", @@ -2115,10 +1993,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ "base64 0.21.7", - "bitflags 2.6.0", + "bitflags", "bytes", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -2524,9 +2402,9 @@ dependencies = [ "base64 0.21.7", "deadpool", "futures", - "http 1.1.0", + "http", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-util", "log", "once_cell", diff --git a/jwt-authorizer/Cargo.toml b/jwt-authorizer/Cargo.toml index e6d4622..2ae32d9 100644 --- a/jwt-authorizer/Cargo.toml +++ b/jwt-authorizer/Cargo.toml @@ -28,14 +28,14 @@ tower-layer = "0.3" tower-service = "0.3" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } -tonic = { version = "0.10", optional = true } +tonic = { version = "0.12", optional = true } time = { version = "0.3", optional = true } http-body-util = "0.1.1" [dev-dependencies] hyper = { version = "1.3.1", features = ["full"] } lazy_static = "1.4.0" -prost = "0.12" +prost = "0.13" tower = { version = "0.4.13", features = ["util", "buffer"] } wiremock = "0.6.0" diff --git a/jwt-authorizer/src/builder.rs b/jwt-authorizer/src/builder.rs index d1ec1bb..5f8799d 100644 --- a/jwt-authorizer/src/builder.rs +++ b/jwt-authorizer/src/builder.rs @@ -222,7 +222,7 @@ where self } - /// Build axum layer + /// Build layer #[deprecated(since = "0.10.0", note = "please use `IntoLayer::into_layer()` instead")] pub async fn layer(self) -> Result, InitError> { let val = self.validation.unwrap_or_default(); diff --git a/jwt-authorizer/src/error.rs b/jwt-authorizer/src/error.rs index 58ea29d..56f0a92 100644 --- a/jwt-authorizer/src/error.rs +++ b/jwt-authorizer/src/error.rs @@ -129,7 +129,7 @@ impl From for Response { tonic::Status::unauthenticated("error=\"no_authorizer_layer\"") } } - .to_http() + .into_http() } } diff --git a/jwt-authorizer/src/layer.rs b/jwt-authorizer/src/layer.rs index 0b96120..7ccde38 100644 --- a/jwt-authorizer/src/layer.rs +++ b/jwt-authorizer/src/layer.rs @@ -1,6 +1,6 @@ -use axum::extract::Request; use futures_core::ready; use futures_util::future::{self, BoxFuture}; +use http::Request; use jsonwebtoken::TokenData; use pin_project::pin_project; use serde::de::DeserializeOwned; @@ -15,25 +15,26 @@ use crate::authorizer::Authorizer; use crate::AuthError; /// Trait for authorizing requests. -pub trait Authorize { - type Future: Future>; +pub trait Authorize { + type Future: Future, AuthError>>; /// Authorize the request. /// /// If the future resolves to `Ok(request)` then the request is allowed through, otherwise not. - fn authorize(&self, request: Request) -> Self::Future; + fn authorize(&self, request: Request) -> Self::Future; } -impl Authorize for AuthorizationService +impl Authorize for AuthorizationService where + B: Send + 'static, C: Clone + DeserializeOwned + Send + Sync + 'static, { - type Future = BoxFuture<'static, Result>; + type Future = BoxFuture<'static, Result, AuthError>>; /// The authorizers are sequentially applied (check_auth) until one of them validates the token. /// If no authorizer validates the token the request is rejected. /// - fn authorize(&self, mut request: Request) -> Self::Future { + fn authorize(&self, mut request: Request) -> Self::Future { let tkns_auths: Vec<(String, Arc>)> = self .auths .iter() @@ -154,21 +155,22 @@ where } } -impl Service for AuthorizationService +impl Service> for AuthorizationService where - S: Service + Clone, + B: Send + 'static, + S: Service> + Clone, S::Response: From, C: Clone + DeserializeOwned + Send + Sync + 'static, { type Response = S::Response; type Error = S::Error; - type Future = ResponseFuture; + type Future = ResponseFuture; fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { self.inner.poll_ready(cx) } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let inner = self.inner.clone(); // take the service that was ready let inner = std::mem::replace(&mut self.inner, inner); @@ -184,13 +186,14 @@ where #[pin_project] /// Response future for [`AuthorizationService`]. -pub struct ResponseFuture +pub struct ResponseFuture where - S: Service, + B: Send + 'static, + S: Service>, C: Clone + DeserializeOwned + Send + Sync + 'static, { #[pin] - state: State< as Authorize>::Future, S::Future>, + state: State< as Authorize>::Future, S::Future>, service: S, } @@ -206,9 +209,10 @@ enum State { }, } -impl Future for ResponseFuture +impl Future for ResponseFuture where - S: Service, + B: Send, + S: Service>, S::Response: From, C: Clone + DeserializeOwned + Send + Sync, { diff --git a/jwt-authorizer/tests/tonic.rs b/jwt-authorizer/tests/tonic.rs index 9523762..158ca6d 100644 --- a/jwt-authorizer/tests/tonic.rs +++ b/jwt-authorizer/tests/tonic.rs @@ -1,11 +1,11 @@ use std::{sync::Once, task::Poll}; -use axum::body::HttpBody; +use axum::extract::Request; use futures_core::future::BoxFuture; use http::header::AUTHORIZATION; use jwt_authorizer::{layer::AuthorizationService, IntoLayer, JwtAuthorizer, Validation}; use serde::{Deserialize, Serialize}; -use tonic::{server::UnaryService, transport::NamedService, IntoRequest, Status}; +use tonic::{server::NamedService, server::UnaryService, IntoRequest, Status}; use tower::{buffer::Buffer, Service}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; @@ -50,7 +50,7 @@ struct GreeterServer { expected_sub: String, } -impl Service> for GreeterServer { +impl Service> for GreeterServer { type Response = http::Response; type Error = std::convert::Infallible; type Future = BoxFuture<'static, Result>; @@ -59,7 +59,7 @@ impl Service> for GreeterServer { Poll::Ready(Ok(())) } - fn call(&mut self, req: http::Request) -> Self::Future { + fn call(&mut self, req: http::Request) -> Self::Future { let token = req.extensions().get::>().unwrap(); assert_eq!(token.claims.sub, self.expected_sub); match req.uri().path() { @@ -69,7 +69,7 @@ impl Service> for GreeterServer { }), p => { let p = p.to_string(); - Box::pin(async move { Ok(Status::unimplemented(p).to_http()) }) + Box::pin(async move { Ok(Status::unimplemented(p).into_http()) }) } } } @@ -82,7 +82,7 @@ impl NamedService for GreeterServer { async fn app( jwt_auth: JwtAuthorizer, expected_sub: String, -) -> AuthorizationService>, User> { +) -> AuthorizationService>, User> { let layer = jwt_auth.build().await.unwrap().into_layer(); tonic::transport::Server::builder() .layer(layer) @@ -102,62 +102,22 @@ fn init_test() { }); } -// The grpc client produces a http request with a tonic boxbody that the transport is meant to sent out, while the server side -// expects to receive a http request with a hyper body.. This simple wrapper converts from one to -// the other. -struct GrpcWrapper -where - S: Service> + Clone, -{ - inner: S, -} - -impl Service> for GrpcWrapper -where - S: Service> + Clone + Send + 'static, - S::Future: Send, -{ - type Response = S::Response; - type Error = S::Error; - type Future = BoxFuture<'static, Result>; - - fn poll_ready(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, req: http::Request) -> Self::Future { - let inner = self.inner.clone(); - // take the service that was ready - let mut inner = std::mem::replace(&mut self.inner, inner); - Box::pin(async move { - let (parts, mut body) = req.into_parts(); - let mut data = Vec::new(); - while let Some(d) = body.data().await { - let d = d.unwrap(); - data.extend_from_slice(&d) - } - inner - .call(http::Request::from_parts(parts, axum::body::Body::from(data))) - .await - }) - } -} - -async fn make_protected_request( +async fn make_protected_request( app: AuthorizationService, bearer: Option<&str>, message: &str, ) -> Result, Status> where S: Service< - http::Request, + http::Request, Response = http::Response, Error = tower::BoxError, > + Send + + Clone + 'static, S::Future: Send, { - let mut grpc = tonic::client::Grpc::new(GrpcWrapper { inner: app }); + let mut grpc = tonic::client::Grpc::new(app); let mut request = HelloMessage { message: message.to_string(),