aster_forge_middleware/axum/
security_headers.rs1pub use crate::shared::security_headers::{
3 REFERRER_POLICY_VALUE, X_CONTENT_TYPE_OPTIONS_VALUE, X_FRAME_OPTIONS_VALUE,
4};
5use axum::{extract::Request, middleware::Next, response::Response};
6use http::header::{HeaderName, HeaderValue};
7
8pub async fn security_headers(request: Request, next: Next) -> Response {
10 let mut response = next.run(request).await;
11 for (name, value) in [
12 ("x-frame-options", X_FRAME_OPTIONS_VALUE),
13 ("referrer-policy", REFERRER_POLICY_VALUE),
14 ("x-content-type-options", X_CONTENT_TYPE_OPTIONS_VALUE),
15 ] {
16 response
17 .headers_mut()
18 .entry(HeaderName::from_static(name))
19 .or_insert(HeaderValue::from_static(value));
20 }
21 response
22}
23
24#[cfg(test)]
25mod tests {
26 use super::*;
27 use axum::{Router, body::Body, middleware, response::IntoResponse, routing::get};
28 use http::{Request as HttpRequest, StatusCode};
29 use tower::ServiceExt;
30
31 #[tokio::test]
32 async fn adds_defaults_and_preserves_explicit_product_headers_on_errors() {
33 let router = Router::new()
34 .route("/", get(|| async { "called" }))
35 .route(
36 "/strict",
37 get(|| async {
38 let mut response = StatusCode::BAD_REQUEST.into_response();
39 response
40 .headers_mut()
41 .insert("referrer-policy", HeaderValue::from_static("no-referrer"));
42 response
43 .headers_mut()
44 .insert("x-frame-options", HeaderValue::from_static("DENY"));
45 response
46 }),
47 )
48 .layer(middleware::from_fn(security_headers));
49 for (path, referrer, frame, status) in [
50 (
51 "/",
52 REFERRER_POLICY_VALUE,
53 X_FRAME_OPTIONS_VALUE,
54 StatusCode::OK,
55 ),
56 ("/strict", "no-referrer", "DENY", StatusCode::BAD_REQUEST),
57 (
58 "/missing",
59 REFERRER_POLICY_VALUE,
60 X_FRAME_OPTIONS_VALUE,
61 StatusCode::NOT_FOUND,
62 ),
63 ] {
64 let response = router
65 .clone()
66 .oneshot(
67 HttpRequest::builder()
68 .uri(path)
69 .body(Body::empty())
70 .unwrap(),
71 )
72 .await
73 .unwrap();
74 assert_eq!(response.status(), status);
75 assert_eq!(response.headers()["referrer-policy"], referrer);
76 assert_eq!(response.headers()["x-frame-options"], frame);
77 assert_eq!(
78 response.headers()["x-content-type-options"],
79 X_CONTENT_TYPE_OPTIONS_VALUE
80 );
81 }
82 }
83}