Skip to content

Commit cb42003

Browse files
committed
update to tower-sessions
1 parent 1f029e7 commit cb42003

File tree

7 files changed

+149
-128
lines changed

7 files changed

+149
-128
lines changed

Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@ edition = "2021"
1616
maintenance = { status = "actively-developed" }
1717

1818
[dependencies]
19-
axum = "0.6.16"
19+
axum = "0.6.20"
2020
axum-core = "0.3.4"
21-
axum-sessions = "0.5.0"
22-
base64 = "0.21.0"
21+
base64 = "0.21.5"
2322
rand = "0.8.5"
2423
thiserror = "1.0.40"
25-
tokio = { version = "1.27.0", features = ["macros", "rt", "rt-multi-thread"] }
2624
tower = "0.4.13"
27-
tracing = "0.1.37"
25+
tower-cookies = "0.9.0"
26+
tower-sessions = "0.4.3"
27+
tracing = "0.1.40"
2828

2929
[dev-dependencies]
30+
tokio = { version = "1.27.0", features = ["macros", "rt", "rt-multi-thread"] }
3031
tokio-test = "0.4.2"
3132
tower-http = { version = "0.4.0", features = ["cors"] }

README.md

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ Consider as well to use the [crate unit tests](https://github.com/LeoniePhiline/
2828

2929
This middleware implements token transfer via [custom request headers](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers).
3030

31-
The middleware requires and is built upon [`axum_sessions`](https://docs.rs/axum-sessions/), which in turn uses [`async_session`](https://docs.rs/async-session/).
31+
The middleware requires and is built upon [`tower_sessions`](https://docs.rs/tower-sessions/).
3232

33-
The current version is built for and works with `axum 0.6.x`, `axum-sessions 0.5.x` and `async_session 3.x`.
33+
The current version is built for and works with `axum 0.6.x`, `tower-sessions 0.4.x`.
3434

3535
There will be support for `axum 0.7` and later versions.
3636

@@ -67,7 +67,7 @@ See ["Our RNGs"](https://rust-random.github.io/book/guide-rngs.html#cryptographi
6767

6868
The security of the underlying session is paramount - the CSRF prevention methods applied can only be as secure as the session carrying the server-side token.
6969

70-
- When creating your [SessionLayer](https://docs.rs/axum-sessions/latest/axum_sessions/struct.SessionLayer.html), make sure to use at least 64 bytes of cryptographically secure randomness.
70+
- When creating your [SessionManagerLayer](https://docs.rs/tower-sessions/latest/tower_sessions/struct.SessionManagerLayer.html)
7171
- Do not lower the secure defaults: Keep the session cookie's `secure` flag **on**.
7272
- Use the strictest possible same-site policy.
7373

@@ -105,16 +105,15 @@ Configure your session and CSRF protection layer in your backend application:
105105

106106
```rust
107107
use axum::{
108+
BoxError,
108109
body::Body,
109110
http::StatusCode,
110111
routing::{get, Router},
112+
error_handling::HandleErrorLayer,
111113
};
114+
use tower::ServiceBuilder;
112115
use axum_csrf_sync_pattern::{CsrfLayer, RegenerateToken};
113-
use axum_sessions::{async_session::MemoryStore, SessionLayer};
114-
use rand::RngCore;
115-
116-
let mut secret = [0; 64];
117-
rand::thread_rng().try_fill_bytes(&mut secret).unwrap();
116+
use tower_sessions::{MemoryStore, SessionManagerLayer};
118117

119118
async fn handler() -> StatusCode {
120119
StatusCode::OK
@@ -136,7 +135,12 @@ let app = Router::new()
136135
// Default: "_csrf_token"
137136
.session_key("_custom_session_key")
138137
)
139-
.layer(SessionLayer::new(MemoryStore::new(), &secret));
138+
.layer(ServiceBuilder::new()
139+
.layer(HandleErrorLayer::new(|_: BoxError| async {
140+
StatusCode::BAD_REQUEST
141+
}))
142+
.layer(SessionManagerLayer::new(MemoryStore::default())));
143+
140144

141145
// Use hyper to run `app` as service and expose on a local port or socket.
142146
```
@@ -175,37 +179,41 @@ Configure your CORS layer, session and CSRF protection layer in your backend app
175179

176180
```rust
177181
use axum::{
182+
BoxError,
178183
body::Body,
179184
http::{header, Method, StatusCode},
180185
routing::{get, Router},
186+
error_handling::HandleErrorLayer,
181187
};
188+
use tower::ServiceBuilder;
182189
use axum_csrf_sync_pattern::{CsrfLayer, RegenerateToken};
183-
use axum_sessions::{async_session::MemoryStore, SessionLayer};
184-
use rand::RngCore;
190+
use tower_sessions::{MemoryStore, SessionManagerLayer};
185191
use tower_http::cors::{AllowOrigin, CorsLayer};
186192

187-
let mut secret = [0; 64];
188-
rand::thread_rng().try_fill_bytes(&mut secret).unwrap();
189-
190193
async fn handler() -> StatusCode {
191194
StatusCode::OK
192195
}
193196

194197
let app = Router::new()
195-
.route("/", get(handler).post(handler))
196-
.layer(
197-
// See example above for custom layer configuration.
198-
CsrfLayer::new()
199-
)
200-
.layer(SessionLayer::new(MemoryStore::new(), &secret))
201-
.layer(
202-
CorsLayer::new()
203-
.allow_origin(AllowOrigin::list(["https://www.example.com".parse().unwrap()]))
204-
.allow_methods([Method::GET, Method::POST])
205-
.allow_headers([header::CONTENT_TYPE, "X-CSRF-TOKEN".parse().unwrap()])
206-
.allow_credentials(true)
207-
.expose_headers(["X-CSRF-TOKEN".parse().unwrap()]),
208-
);
198+
.route("/", get(handler).post(handler))
199+
.layer(
200+
// See example above for custom layer configuration.
201+
CsrfLayer::new()
202+
)
203+
.layer(ServiceBuilder::new()
204+
.layer(HandleErrorLayer::new(|_: BoxError| async {
205+
StatusCode::BAD_REQUEST
206+
}))
207+
.layer(SessionManagerLayer::new(MemoryStore::default()))
208+
.layer(
209+
CorsLayer::new()
210+
.allow_origin(AllowOrigin::list(["https://www.example.com".parse().rap()]))
211+
.allow_methods([Method::GET, Method::POST])
212+
.allow_headers([header::CONTENT_TYPE, "X-CSRF-TOKEN".parse().unwrap()])
213+
.allow_credentials(true)
214+
.expose_headers(["X-CSRF-TOKEN".parse().unwrap()]),
215+
)
216+
);
209217

210218
// Use hyper to run `app` as service and expose on a local port or socket.
211219
```

examples/cross-site/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ publish = false
88
[dependencies]
99
axum = "0.6.16"
1010
axum-csrf-sync-pattern = { path = "../../" }
11-
axum-sessions = "0.5.0"
11+
tower-sessions = "0.4.3"
1212
color-eyre = "0.6.2"
13-
rand = "0.8.5"
1413
tokio = { version = "1.27.0", features = ["macros", "rt", "rt-multi-thread"] }
1514
tower = "0.4.13"
1615
tower-http = { version = "0.4.0", features = ["cors"] }

examples/cross-site/src/main.rs

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
use std::net::SocketAddr;
22

33
use axum::{
4+
BoxError,
45
http::{header, Method, StatusCode},
56
response::IntoResponse,
67
routing::{get, Router},
8+
error_handling::HandleErrorLayer,
79
Server,
810
};
11+
use tower::ServiceBuilder;
912
use axum_csrf_sync_pattern::CsrfLayer;
10-
use axum_sessions::{async_session::MemoryStore, SessionLayer};
13+
use tower_sessions::{MemoryStore, SessionManagerLayer};
1114
use color_eyre::eyre::{self, eyre, WrapErr};
12-
use rand::RngCore;
1315
use tower_http::cors::{AllowOrigin, CorsLayer};
1416

1517
#[tokio::main]
@@ -33,41 +35,41 @@ async fn main() -> eyre::Result<()> {
3335
};
3436

3537
let backend = async {
36-
let mut secret = [0; 64];
37-
rand::thread_rng()
38-
.try_fill_bytes(&mut secret)
39-
.wrap_err("Failed to generate session seed.")?;
40-
4138
let app = Router::new()
4239
.route("/", get(get_token).post(post_handler))
4340
.layer(CsrfLayer::new())
44-
.layer(SessionLayer::new(MemoryStore::new(), &secret))
45-
.layer(
46-
CorsLayer::new()
47-
.allow_origin(AllowOrigin::list([
48-
// Allow CORS requests from our frontend.
49-
"http://127.0.0.1:3000"
50-
.parse()
51-
.wrap_err("Failed to parse socket address.")?,
52-
]))
53-
// Allow GET and POST methods. Adjust to your needs.
54-
.allow_methods([Method::GET, Method::POST])
55-
.allow_headers([
56-
// Allow incoming CORS requests to use the Content-Type header,
57-
header::CONTENT_TYPE,
58-
// as well as the `CsrfLayer` default request header.
59-
"X-CSRF-TOKEN"
41+
.layer(ServiceBuilder::new()
42+
.layer(HandleErrorLayer::new(|_: BoxError| async {
43+
StatusCode::BAD_REQUEST
44+
}))
45+
.layer(SessionManagerLayer::new(MemoryStore::default()))
46+
.layer(
47+
CorsLayer::new()
48+
.allow_origin(AllowOrigin::list([
49+
// Allow CORS requests from our frontend.
50+
"http://127.0.0.1:3000"
51+
.parse()
52+
.wrap_err("Failed to parse socket address.")?,
53+
]))
54+
// Allow GET and POST methods. Adjust to your needs.
55+
.allow_methods([Method::GET, Method::POST])
56+
.allow_headers([
57+
// Allow incoming CORS requests to use the Content-Type header,
58+
header::CONTENT_TYPE,
59+
// as well as the `CsrfLayer` default request header.
60+
"X-CSRF-TOKEN"
61+
.parse()
62+
.wrap_err("Failed to parse token header.")?,
63+
])
64+
// Allow CORS requests with session cookies.
65+
.allow_credentials(true)
66+
// Instruct the browser to allow JavaScript on the configured origin
67+
// to read the `CsrfLayer` default response header.
68+
.expose_headers(["X-CSRF-TOKEN"
6069
.parse()
61-
.wrap_err("Failed to parse token header.")?,
62-
])
63-
// Allow CORS requests with session cookies.
64-
.allow_credentials(true)
65-
// Instruct the browser to allow JavaScript on the configured origin
66-
// to read the `CsrfLayer` default response header.
67-
.expose_headers(["X-CSRF-TOKEN"
68-
.parse()
69-
.wrap_err("Failed to parse token header.")?]),
70-
);
70+
.wrap_err("Failed to parse token header.")?]),
71+
));
72+
7173

7274
serve(app, 4000).await?;
7375

examples/same-site/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ publish = false
88
[dependencies]
99
axum = "0.6.16"
1010
axum-csrf-sync-pattern = { path = "../../" }
11-
axum-sessions = "0.5.0"
11+
tower-sessions = "0.4.3"
1212
color-eyre = "0.6.2"
13-
rand = "0.8.5"
1413
tokio = { version = "1.27.0", features = ["macros", "rt", "rt-multi-thread"] }
1514
tower = "0.4.13"
1615
tracing-subscriber = "0.3.16"

examples/same-site/src/main.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use axum::{
2+
BoxError,
23
http::{header, StatusCode},
34
response::IntoResponse,
45
routing::get,
6+
error_handling::HandleErrorLayer,
57
Server,
68
};
9+
use tower::ServiceBuilder;
710
use axum_csrf_sync_pattern::CsrfLayer;
8-
use axum_sessions::{async_session::MemoryStore, SessionLayer};
11+
use tower_sessions::{MemoryStore, SessionManagerLayer};
912
use color_eyre::eyre::{self, eyre, WrapErr};
10-
use rand::RngCore;
1113

1214
#[tokio::main]
1315
async fn main() -> eyre::Result<()> {
@@ -20,15 +22,14 @@ async fn main() -> eyre::Result<()> {
2022
.map_err(|e| eyre!(e))
2123
.wrap_err("Failed to initialize tracing-subscriber.")?;
2224

23-
let mut secret = [0; 64];
24-
rand::thread_rng()
25-
.try_fill_bytes(&mut secret)
26-
.wrap_err("Failed to generate session seed.")?;
27-
2825
let app = axum::Router::new()
2926
.route("/", get(index).post(handler))
3027
.layer(CsrfLayer::new())
31-
.layer(SessionLayer::new(MemoryStore::new(), &secret));
28+
.layer(ServiceBuilder::new()
29+
.layer(HandleErrorLayer::new(|_: BoxError| async {
30+
StatusCode::BAD_REQUEST
31+
}))
32+
.layer(SessionManagerLayer::new(MemoryStore::default())));
3233

3334
// Visit "http://127.0.0.1:3000/" in your browser.
3435
Server::try_bind(

0 commit comments

Comments
 (0)