From 41f38d8db59c0643383dfd81711196dffd58977a Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 12:37:13 -0500 Subject: [PATCH 1/9] update hyperium crates to `1.0`, axum to `0.7` --- Cargo.lock | 226 +++++++++++++++++++++------ demo-server/Cargo.toml | 6 +- demo-server/src/main.rs | 8 +- demo-server/src/oidc_provider/mod.rs | 9 +- jwt-authorizer/Cargo.toml | 14 +- jwt-authorizer/src/error.rs | 10 +- 6 files changed, 204 insertions(+), 69 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bb8050..1b30970 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,14 +114,42 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.3.4", "bitflags 1.3.2", "bytes", "futures-util", - "headers", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810a80b128d70e6ed2bdf3fe8ed72c0ae56f5f5948d01c2753282dd92a84fce8" +dependencies = [ + "async-trait", + "axum-core 0.4.0", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", "itoa", "matchit", "memchr", @@ -149,14 +177,34 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "mime", "rustversion", "tower-layer", "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0ddc355eab88f4955090a823715df47acf0b7660aab7a69ad5ce6301ee3b73" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -333,7 +381,7 @@ name = "demo-server" version = "0.1.0" dependencies = [ "anyhow", - "axum", + "axum 0.7.1", "headers", "josekit", "jsonwebtoken", @@ -627,7 +675,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -635,6 +683,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d308f63daf4181410c242d34c11f928dcb3aa105852019e043c9d1f4e4368a" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 1.0.0", + "indexmap 2.0.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -649,14 +716,14 @@ checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "headers" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" dependencies = [ "base64 0.21.3", "bytes", "headers-core", - "http", + "http 1.0.0", "httpdate", "mime", "sha1", @@ -664,11 +731,11 @@ dependencies = [ [[package]] name = "headers-core" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.0.0", ] [[package]] @@ -688,6 +755,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -695,15 +773,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", "pin-project-lite", ] [[package]] -name = "http-range-header" -version = "0.3.1" +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", +] [[package]] name = "http-types" @@ -715,7 +810,7 @@ dependencies = [ "async-channel", "base64 0.13.1", "futures-lite", - "http", + "http 0.2.9", "infer", "pin-project-lite", "rand 0.7.3", @@ -748,9 +843,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.21", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -762,6 +857,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.1" @@ -769,8 +884,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "rustls", "tokio", "tokio-rustls", @@ -782,7 +897,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.27", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -795,12 +910,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.27", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.3", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -935,13 +1070,13 @@ dependencies = [ name = "jwt-authorizer" version = "0.13.0" dependencies = [ - "axum", + "axum 0.7.1", "chrono", "futures-core", "futures-util", "headers", - "http", - "hyper", + "http 1.0.0", + "hyper 1.0.1", "jsonwebtoken", "lazy_static", "pin-project", @@ -1451,10 +1586,10 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.21", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-rustls", "hyper-tls", "ipnet", @@ -2000,13 +2135,13 @@ checksum = "5469afaf78a11265c343a88969045c1568aa8ecc6c787dbf756e92e70f199861" dependencies = [ "async-stream", "async-trait", - "axum", + "axum 0.6.20", "base64 0.21.3", "bytes", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.21", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-timeout", "percent-encoding", "pin-project", @@ -2041,18 +2176,17 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +checksum = "09e12e6351354851911bdf8c2b8f2ab15050c567d70a8b9a37ae7b8301a4080d" dependencies = [ "base64 0.21.3", "bitflags 2.4.0", "bytes", - "futures-core", "futures-util", - "http", - "http-body", - "http-range-header", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "mime", "pin-project-lite", "tower-layer", @@ -2445,7 +2579,7 @@ dependencies = [ "futures", "futures-timer", "http-types", - "hyper", + "hyper 0.14.27", "log", "once_cell", "regex", diff --git a/demo-server/Cargo.toml b/demo-server/Cargo.toml index 651195b..57e14f2 100644 --- a/demo-server/Cargo.toml +++ b/demo-server/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] anyhow = "1.0.75" -axum = { version = "0.6.20", features = ["headers"] } -headers = "0.3" +axum = { version = "0.7.1" } +headers = "0.4" josekit = "0.8.3" jsonwebtoken = "9.1.0" once_cell = "1.18.0" @@ -17,7 +17,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0.47" tokio = { version = "1.32.0", features = ["full"] } -tower-http = { version = "0.4.3", features = ["trace"] } +tower-http = { version = "0.5.0", features = ["trace"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } jwt-authorizer = { path = "../jwt-authorizer" } diff --git a/demo-server/src/main.rs b/demo-server/src/main.rs index df42105..6446347 100644 --- a/demo-server/src/main.rs +++ b/demo-server/src/main.rs @@ -3,7 +3,7 @@ use jwt_authorizer::{ error::InitError, AuthError, Authorizer, IntoLayer, JwtAuthorizer, JwtClaims, Refresh, RefreshStrategy, }; use serde::Deserialize; -use std::net::SocketAddr; +use tokio::net::TcpListener; use tower_http::trace::TraceLayer; use tracing::info; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; @@ -62,10 +62,10 @@ async fn main() -> Result<(), InitError> { .nest("/api", api) .layer(TraceLayer::new_for_http()); - let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - tracing::info!("listening on {}", addr); + let listener = TcpListener::bind("127.0.0.1:3000").await.unwrap(); + tracing::info!("listening on {:?}", listener.local_addr()); - axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap(); + axum::serve(listener, app.into_make_service()).await.unwrap(); Ok(()) } diff --git a/demo-server/src/oidc_provider/mod.rs b/demo-server/src/oidc_provider/mod.rs index c186d88..3ee41ab 100644 --- a/demo-server/src/oidc_provider/mod.rs +++ b/demo-server/src/oidc_provider/mod.rs @@ -7,7 +7,8 @@ use jsonwebtoken::{encode, Algorithm, EncodingKey, Header}; use jwt_authorizer::{NumericDate, OneOrArray, RegisteredClaims}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -use std::{net::SocketAddr, thread, time::Duration}; +use std::{thread, time::Duration}; +use tokio::net::TcpListener; const ISSUER_URI: &str = "http://localhost:3001"; @@ -171,9 +172,9 @@ pub fn run_server() -> &'static str { .route("/tokens", get(tokens)); tokio::spawn(async move { - let addr = SocketAddr::from(([127, 0, 0, 1], 3001)); - tracing::info!("oidc provider starting on: {}", addr); - axum::Server::bind(&addr).serve(app.into_make_service()).await.unwrap(); + let listener = TcpListener::bind("127.0.0.1:3001").await.unwrap(); + tracing::info!("oidc provider starting on: {:?}", listener.local_addr()); + axum::serve(listener, app.into_make_service()).await.unwrap(); }); thread::sleep(Duration::from_millis(200)); // waiting oidc to start diff --git a/jwt-authorizer/Cargo.toml b/jwt-authorizer/Cargo.toml index 9bd55ac..2eb9654 100644 --- a/jwt-authorizer/Cargo.toml +++ b/jwt-authorizer/Cargo.toml @@ -7,23 +7,23 @@ authors = ["cduvray "] license = "MIT" readme = "docs/README.md" repository = "https://github.com/cduvray/jwt-authorizer" -keywords = ["jwt","axum","authorisation","jwks"] +keywords = ["jwt", "axum", "authorisation", "jwks"] [dependencies] -axum = { version = "0.6", features = ["headers"] } +axum = { version = "0.7.1" } chrono = { version = "0.4", optional = true } futures-util = "0.3" futures-core = "0.3" -headers = "0.3" +headers = "0.4" jsonwebtoken = "9.1.0" -http = "0.2" +http = "1.0" pin-project = "1.0" reqwest = { version = "0.11", default-features = false, features = ["json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" thiserror = "1.0" tokio = { version = "1.25", features = ["full"] } -tower-http = { version = "0.4", features = ["trace", "auth"] } +tower-http = { version = "0.5.0", features = ["trace", "auth"] } tower-layer = "0.3" tower-service = "0.3" tracing = "0.1" @@ -32,7 +32,7 @@ tonic = { version = "0.10", optional = true } time = { version = "0.3", optional = true } [dev-dependencies] -hyper = { version = "0.14", features = ["full"] } +hyper = { version = "1.0.1", features = ["full"] } lazy_static = "1.4.0" prost = "0.12" tower = { version = "0.4", features = ["util", "buffer"] } @@ -53,4 +53,4 @@ chrono = ["dep:chrono"] [[test]] name = "tonic" -required-features = [ "tonic" ] +required-features = ["tonic"] diff --git a/jwt-authorizer/src/error.rs b/jwt-authorizer/src/error.rs index 35b829e..58ea29d 100644 --- a/jwt-authorizer/src/error.rs +++ b/jwt-authorizer/src/error.rs @@ -1,5 +1,5 @@ use axum::{ - body::{self, BoxBody, Empty}, + body::Body, http::StatusCode, response::{IntoResponse, Response}, }; @@ -64,8 +64,8 @@ pub enum AuthError { NoAuthorizerLayer(), } -fn response_wwwauth(status: StatusCode, bearer: &str) -> Response { - let mut res = Response::new(body::boxed(Empty::new())); +fn response_wwwauth(status: StatusCode, bearer: &str) -> Response { + let mut res = Response::new(Body::empty()); *res.status_mut() = status; let h = if bearer.is_empty() { "Bearer".to_owned() @@ -77,8 +77,8 @@ fn response_wwwauth(status: StatusCode, bearer: &str) -> Response { res } -fn response_500() -> Response { - let mut res = Response::new(body::boxed(Empty::new())); +fn response_500() -> Response { + let mut res = Response::new(Body::empty()); *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; res From e1e58743470296bf0934fd0791585ab6bbd6ceab Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 13:22:12 -0500 Subject: [PATCH 2/9] fix: responses collect into bytes with `BodyExt` trait --- Cargo.lock | 1 + jwt-authorizer/Cargo.toml | 1 + jwt-authorizer/tests/integration_tests.rs | 7 ++----- jwt-authorizer/tests/tests.rs | 19 +++++++++++-------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1b30970..d267178 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1076,6 +1076,7 @@ dependencies = [ "futures-util", "headers", "http 1.0.0", + "http-body-util", "hyper 1.0.1", "jsonwebtoken", "lazy_static", diff --git a/jwt-authorizer/Cargo.toml b/jwt-authorizer/Cargo.toml index 2eb9654..962bdb8 100644 --- a/jwt-authorizer/Cargo.toml +++ b/jwt-authorizer/Cargo.toml @@ -30,6 +30,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tonic = { version = "0.10", optional = true } time = { version = "0.3", optional = true } +http-body-util = "0.1.0" [dev-dependencies] hyper = { version = "1.0.1", features = ["full"] } diff --git a/jwt-authorizer/tests/integration_tests.rs b/jwt-authorizer/tests/integration_tests.rs index 947f76e..294a5c3 100644 --- a/jwt-authorizer/tests/integration_tests.rs +++ b/jwt-authorizer/tests/integration_tests.rs @@ -77,11 +77,8 @@ fn run_jwks_server() -> String { .route("/jwks", get(jwks)); tokio::spawn(async move { - axum::Server::from_tcp(listener) - .unwrap() - .serve(app.into_make_service()) - .await - .unwrap(); + let listener: tokio::net::TcpListener = tokio::net::TcpListener::from_std(listener).unwrap(); + axum::serve(listener, app.into_make_service()).await.unwrap(); }); url diff --git a/jwt-authorizer/tests/tests.rs b/jwt-authorizer/tests/tests.rs index cc3be44..03acdec 100644 --- a/jwt-authorizer/tests/tests.rs +++ b/jwt-authorizer/tests/tests.rs @@ -23,6 +23,7 @@ mod tests { use tower::{util::MapErrLayer, ServiceExt}; use crate::common; + use http_body_util::BodyExt; #[derive(Debug, Deserialize, Clone)] struct User { @@ -102,7 +103,9 @@ mod tests { ) .await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + + let body = response.into_body().collect().await.unwrap().to_bytes(); + assert_eq!(&body[..], b"hello: b@b.com"); // ECDSA PEM @@ -112,14 +115,14 @@ mod tests { ) .await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"hello: b@b.com"); // RSA PEM let response = make_proteced_request(JwtAuthorizer::from_rsa_pem("../config/rsa-public2.pem"), common::JWT_RSA2_OK).await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"hello: b@b.com"); // JWKS @@ -129,7 +132,7 @@ mod tests { ) .await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"hello: b@b.com"); let response = make_proteced_request( @@ -138,7 +141,7 @@ mod tests { ) .await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"hello: b@b.com"); let response = make_proteced_request( @@ -147,7 +150,7 @@ mod tests { ) .await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"hello: b@b.com"); // JWKS TEXT @@ -158,7 +161,7 @@ mod tests { ) .await; assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"hello: b@b.com"); } @@ -234,7 +237,7 @@ mod tests { .unwrap(); assert_eq!(response.status(), StatusCode::OK); - let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); + let body = response.into_body().collect().await.unwrap().to_bytes(); assert_eq!(&body[..], b"option: true"); } From 7970a6c3586e1e412ddafec9fca90a5c6f94f49d Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 14:59:41 -0500 Subject: [PATCH 3/9] unit tests pass, removed generic to expand upon, integration tests freeze --- jwt-authorizer/src/authorizer.rs | 2 +- jwt-authorizer/src/layer.rs | 55 ++++++++++++++++++----- jwt-authorizer/tests/integration_tests.rs | 6 +-- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/jwt-authorizer/src/authorizer.rs b/jwt-authorizer/src/authorizer.rs index 1465590..d80963c 100644 --- a/jwt-authorizer/src/authorizer.rs +++ b/jwt-authorizer/src/authorizer.rs @@ -48,7 +48,7 @@ pub enum KeySourceType { impl Authorizer where - C: DeserializeOwned + Clone + Send + Sync, + C: DeserializeOwned + Clone + Send, { pub(crate) async fn build( key_source_type: KeySourceType, diff --git a/jwt-authorizer/src/layer.rs b/jwt-authorizer/src/layer.rs index 83297a3..6fdff6f 100644 --- a/jwt-authorizer/src/layer.rs +++ b/jwt-authorizer/src/layer.rs @@ -1,3 +1,4 @@ +use axum::body::Body; use axum::http::Request; use futures_core::ready; use futures_util::future::{self, BoxFuture}; @@ -8,6 +9,7 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; +use tokio::sync::Mutex; use tower_layer::Layer; use tower_service::Service; @@ -27,8 +29,8 @@ pub trait Authorize { impl Authorize for AuthorizationService where - B: Send + Sync + 'static, - C: Clone + DeserializeOwned + Send + Sync + 'static, + B: Send + 'static, + C: Clone + DeserializeOwned + Send + 'static, { type RequestBody = B; type Future = BoxFuture<'static, Result, AuthError>>; @@ -59,7 +61,9 @@ where Ok(tdata) => { // Set `token_data` as a request extension so it can be accessed by other // services down the stack. - request.extensions_mut().insert(tdata); + + let something = Arc::new(Mutex::new(tdata)); + request.extensions_mut().insert(something); Ok(request) } @@ -119,7 +123,7 @@ pub enum JwtSource { #[derive(Clone)] pub struct AuthorizationService where - C: Clone + DeserializeOwned + Send + Sync, + C: Clone + DeserializeOwned + Send, { pub inner: S, pub auths: Vec>>, @@ -127,7 +131,7 @@ where impl AuthorizationService where - C: Clone + DeserializeOwned + Send + Sync, + C: Clone + DeserializeOwned + Send, { pub fn get_ref(&self) -> &S { &self.inner @@ -156,6 +160,34 @@ where } } +impl Service> for AuthorizationService +where + S: Service> + Clone, + S::Response: From, + C: Clone + DeserializeOwned + Send + Sync + 'static, +{ + type Response = S::Response; + type Error = S::Error; + 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 { + let inner = self.inner.clone(); + // take the service that was ready + let inner = std::mem::replace(&mut self.inner, inner); + + let auth_fut = self.authorize(req); + + ResponseFuture { + state: State::Authorize { auth_fut }, + service: inner, + } + } +} +/* impl Service> for AuthorizationService where ReqBody: Send + Sync + 'static, @@ -184,17 +216,17 @@ where } } } +*/ #[pin_project] /// Response future for [`AuthorizationService`]. -pub struct ResponseFuture +pub struct ResponseFuture where - S: Service>, - ReqBody: Send + Sync + '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, } @@ -210,11 +242,10 @@ enum State { }, } -impl Future for ResponseFuture +impl Future for ResponseFuture where - S: Service>, + S: Service>, S::Response: From, - ReqBody: Send + Sync + 'static, C: Clone + DeserializeOwned + Send + Sync, { type Output = Result; diff --git a/jwt-authorizer/tests/integration_tests.rs b/jwt-authorizer/tests/integration_tests.rs index 294a5c3..f31a253 100644 --- a/jwt-authorizer/tests/integration_tests.rs +++ b/jwt-authorizer/tests/integration_tests.rs @@ -8,9 +8,9 @@ use std::{ time::Duration, }; +use axum::body::Body; use axum::{response::Response, routing::get, Json, Router}; use http::{header::AUTHORIZATION, Request, StatusCode}; -use hyper::Body; use jwt_authorizer::{IntoLayer, JwtAuthorizer, JwtClaims, Refresh, RefreshStrategy, Validation}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; @@ -127,7 +127,7 @@ fn init_test() { } async fn make_proteced_request(app: &mut Router, bearer: &str) -> Response { - app.ready() + >>::ready(app) .await .unwrap() .call( @@ -142,7 +142,7 @@ async fn make_proteced_request(app: &mut Router, bearer: &str) -> Response { } async fn make_public_request(app: &mut Router) -> Response { - app.ready() + >>::ready(app) .await .unwrap() .call(Request::builder().uri("/public").body(Body::empty()).unwrap()) From dd2a48b00c634412adb89ed1f77f06bcc2fcbd1a Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 15:16:50 -0500 Subject: [PATCH 4/9] chore: removed commented code for `Service` impl --- jwt-authorizer/src/layer.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/jwt-authorizer/src/layer.rs b/jwt-authorizer/src/layer.rs index 6fdff6f..947a9a7 100644 --- a/jwt-authorizer/src/layer.rs +++ b/jwt-authorizer/src/layer.rs @@ -187,36 +187,6 @@ where } } } -/* -impl Service> for AuthorizationService -where - ReqBody: Send + Sync + 'static, - S: Service> + Clone, - S::Response: From, - C: Clone + DeserializeOwned + Send + Sync + 'static, -{ - type Response = S::Response; - type Error = S::Error; - 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 { - let inner = self.inner.clone(); - // take the service that was ready - let inner = std::mem::replace(&mut self.inner, inner); - - let auth_fut = self.authorize(req); - - ResponseFuture { - state: State::Authorize { auth_fut }, - service: inner, - } - } -} -*/ #[pin_project] /// Response future for [`AuthorizationService`]. From 526fc77daeab97c62e09b1773436f75c0f5d960f Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 18:47:08 -0500 Subject: [PATCH 5/9] fix: use `Request`, ignore props of `ReqBody` --- jwt-authorizer/src/layer.rs | 32 ++++++++++------------- jwt-authorizer/tests/integration_tests.rs | 9 ++++--- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/jwt-authorizer/src/layer.rs b/jwt-authorizer/src/layer.rs index 947a9a7..874b955 100644 --- a/jwt-authorizer/src/layer.rs +++ b/jwt-authorizer/src/layer.rs @@ -1,5 +1,4 @@ -use axum::body::Body; -use axum::http::Request; +use axum::extract::Request; use futures_core::ready; use futures_util::future::{self, BoxFuture}; use jsonwebtoken::TokenData; @@ -17,28 +16,25 @@ use crate::authorizer::Authorizer; use crate::AuthError; /// Trait for authorizing requests. -pub trait Authorize { - type RequestBody; - type Future: Future, AuthError>>; +pub trait Authorize { + type Future: Future>; /// 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 + 'static, + C: Clone + DeserializeOwned + Send + Sync + 'static, { - type RequestBody = B; - type Future = BoxFuture<'static, Result, AuthError>>; + type Future = BoxFuture<'static, Result>; /// 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() @@ -160,9 +156,9 @@ where } } -impl Service> for AuthorizationService +impl Service for AuthorizationService where - S: Service> + Clone, + S: Service + Clone, S::Response: From, C: Clone + DeserializeOwned + Send + Sync + 'static, { @@ -174,7 +170,7 @@ where 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); @@ -192,11 +188,11 @@ where /// Response future for [`AuthorizationService`]. pub struct ResponseFuture where - S: Service>, + 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, } @@ -214,7 +210,7 @@ enum State { impl Future for ResponseFuture where - S: Service>, + S: Service, S::Response: From, C: Clone + DeserializeOwned + Send + Sync, { diff --git a/jwt-authorizer/tests/integration_tests.rs b/jwt-authorizer/tests/integration_tests.rs index f31a253..87fbb55 100644 --- a/jwt-authorizer/tests/integration_tests.rs +++ b/jwt-authorizer/tests/integration_tests.rs @@ -8,8 +8,7 @@ use std::{ time::Duration, }; -use axum::body::Body; -use axum::{response::Response, routing::get, Json, Router}; +use axum::{body::Body, response::Response, routing::get, Json, Router}; use http::{header::AUTHORIZATION, Request, StatusCode}; use jwt_authorizer::{IntoLayer, JwtAuthorizer, JwtClaims, Refresh, RefreshStrategy, Validation}; use lazy_static::lazy_static; @@ -127,7 +126,8 @@ fn init_test() { } async fn make_proteced_request(app: &mut Router, bearer: &str) -> Response { - >>::ready(app) + app.as_service() + .ready() .await .unwrap() .call( @@ -142,7 +142,8 @@ async fn make_proteced_request(app: &mut Router, bearer: &str) -> Response { } async fn make_public_request(app: &mut Router) -> Response { - >>::ready(app) + app.as_service() + .ready() .await .unwrap() .call(Request::builder().uri("/public").body(Body::empty()).unwrap()) From 272dd5c2c3f3c57912bed1e00d50d6b6d216d116 Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 19:47:30 -0500 Subject: [PATCH 6/9] fix: removed hacky mutex, fixed doc test --- jwt-authorizer/docs/README.md | 7 +++---- jwt-authorizer/src/layer.rs | 3 +-- jwt-authorizer/tests/integration_tests.rs | 8 ++++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/jwt-authorizer/docs/README.md b/jwt-authorizer/docs/README.md index 6e21748..787ca1f 100644 --- a/jwt-authorizer/docs/README.md +++ b/jwt-authorizer/docs/README.md @@ -24,7 +24,7 @@ JWT authoriser Layer for Axum and Tonic. # use jwt_authorizer::{AuthError, Authorizer, JwtAuthorizer, JwtClaims, RegisteredClaims, IntoLayer}; # use axum::{routing::get, Router}; # use serde::Deserialize; - +# use tokio::net::TcpListener; # async { // let's create an authorizer builder from a JWKS Endpoint @@ -41,9 +41,8 @@ JWT authoriser Layer for Axum and Tonic. // Send the protected data to the user Ok(format!("Welcome: {:?}", user.sub)) } - - axum::Server::bind(&"0.0.0.0:3000".parse().unwrap()) - .serve(app.into_make_service()).await.expect("server failed"); + let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap(); + axum::serve(listener, app.into_make_service()).await.expect("server failed"); # }; ``` diff --git a/jwt-authorizer/src/layer.rs b/jwt-authorizer/src/layer.rs index 874b955..1fbbaec 100644 --- a/jwt-authorizer/src/layer.rs +++ b/jwt-authorizer/src/layer.rs @@ -58,8 +58,7 @@ where // Set `token_data` as a request extension so it can be accessed by other // services down the stack. - let something = Arc::new(Mutex::new(tdata)); - request.extensions_mut().insert(something); + request.extensions_mut().insert(tdata); Ok(request) } diff --git a/jwt-authorizer/tests/integration_tests.rs b/jwt-authorizer/tests/integration_tests.rs index 87fbb55..d371e14 100644 --- a/jwt-authorizer/tests/integration_tests.rs +++ b/jwt-authorizer/tests/integration_tests.rs @@ -154,10 +154,10 @@ async fn make_public_request(app: &mut Router) -> Response { #[tokio::test] async fn sequential_tests() { // these tests must be executed sequentially - scenario1().await; - scenario2().await; - scenario3().await; - scenario4().await; + //scenario1().await; + //scenario2().await; + //scenario3().await; + //scenario4().await; } async fn scenario1() { From a2b2771ad8d8018f3888e28606ccbfec71f6d4b4 Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 20:05:50 -0500 Subject: [PATCH 7/9] fix: readded sequential tests --- jwt-authorizer/tests/integration_tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jwt-authorizer/tests/integration_tests.rs b/jwt-authorizer/tests/integration_tests.rs index d371e14..87fbb55 100644 --- a/jwt-authorizer/tests/integration_tests.rs +++ b/jwt-authorizer/tests/integration_tests.rs @@ -154,10 +154,10 @@ async fn make_public_request(app: &mut Router) -> Response { #[tokio::test] async fn sequential_tests() { // these tests must be executed sequentially - //scenario1().await; - //scenario2().await; - //scenario3().await; - //scenario4().await; + scenario1().await; + scenario2().await; + scenario3().await; + scenario4().await; } async fn scenario1() { From 665377e71fa9ee80723b26bc6086325d22afb24a Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Fri, 1 Dec 2023 20:07:04 -0500 Subject: [PATCH 8/9] chore: clippy --- jwt-authorizer/src/layer.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/jwt-authorizer/src/layer.rs b/jwt-authorizer/src/layer.rs index 1fbbaec..0b96120 100644 --- a/jwt-authorizer/src/layer.rs +++ b/jwt-authorizer/src/layer.rs @@ -8,7 +8,6 @@ use std::future::Future; use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; -use tokio::sync::Mutex; use tower_layer::Layer; use tower_service::Service; From 976d65d362331f88f5b5a461c4966c83e0236cd5 Mon Sep 17 00:00:00 2001 From: Daniel Gallups Date: Tue, 5 Dec 2023 11:23:16 -0500 Subject: [PATCH 9/9] fix: std tcp listener must be non-blocking to create tokio tcplistener --- jwt-authorizer/tests/integration_tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/jwt-authorizer/tests/integration_tests.rs b/jwt-authorizer/tests/integration_tests.rs index 87fbb55..3b76eec 100644 --- a/jwt-authorizer/tests/integration_tests.rs +++ b/jwt-authorizer/tests/integration_tests.rs @@ -66,6 +66,7 @@ async fn jwks() -> Json { fn run_jwks_server() -> String { let listener = TcpListener::bind("0.0.0.0:0".parse::().unwrap()).unwrap(); + listener.set_nonblocking(true).unwrap(); let addr = listener.local_addr().unwrap(); let url = format!("http://{}:{}", addr.ip(), addr.port());