style: format imports and refactor ip filter authorization logic
This commit is contained in:
+15
-21
@@ -41,30 +41,24 @@ impl Middleware for ApiKeyMiddleware {
|
||||
} else {
|
||||
warn!("X-API-Key validation failed for request");
|
||||
// Return a default unauthorized response if Responder fails
|
||||
let response = Responder::unauthorized()
|
||||
.unwrap_or_else(|_| {
|
||||
// Fallback to a basic unauthorized response
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.body(http_body_util::Full::new(
|
||||
Bytes::from("Unauthorized")
|
||||
))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
let response = Responder::unauthorized().unwrap_or_else(|_| {
|
||||
// Fallback to a basic unauthorized response
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.body(http_body_util::Full::new(Bytes::from("Unauthorized")))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
MiddlewareResult::Respond(response)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
warn!("X-API-Key header missing from request");
|
||||
let response = Responder::unauthorized()
|
||||
.unwrap_or_else(|_| {
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.body(http_body_util::Full::new(
|
||||
Bytes::from("Unauthorized")
|
||||
))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
let response = Responder::unauthorized().unwrap_or_else(|_| {
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.body(http_body_util::Full::new(Bytes::from("Unauthorized")))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
MiddlewareResult::Respond(response)
|
||||
}
|
||||
}
|
||||
@@ -75,11 +69,11 @@ impl Middleware for ApiKeyMiddleware {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use http::Request;
|
||||
|
||||
#[test]
|
||||
fn test_api_key_middleware_new() {
|
||||
let middleware = ApiKeyMiddleware::new("test-key");
|
||||
assert_eq!(middleware.api_key, "test-key");
|
||||
assert!(!middleware.is_invalid_key("test-key"));
|
||||
assert!(middleware.is_invalid_key("wrong-key"));
|
||||
}
|
||||
}
|
||||
|
||||
+19
-34
@@ -5,7 +5,7 @@
|
||||
|
||||
use crate::{
|
||||
Responder,
|
||||
error::{ServerError, Result},
|
||||
error::{Result, ServerError},
|
||||
middleware::{Middleware, MiddlewareFuture, MiddlewareResult},
|
||||
};
|
||||
use http::{Request, Response};
|
||||
@@ -78,12 +78,11 @@ impl IpFilterMiddleware {
|
||||
pub fn is_authorized(&self, ip: &IpAddr) -> bool {
|
||||
// Check private ranges first (fast path for local networks)
|
||||
// Note: Only IPv4 has is_private() method
|
||||
if self.allow_private {
|
||||
if let IpAddr::V4(ipv4) = ip {
|
||||
if ipv4.is_private() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if self.allow_private
|
||||
&& let IpAddr::V4(ipv4) = ip
|
||||
&& ipv4.is_private()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Empty allowlist means "allow all"
|
||||
@@ -105,16 +104,13 @@ impl Middleware for IpFilterMiddleware {
|
||||
Some(ip) if self.is_authorized(&ip) => MiddlewareResult::Continue(req),
|
||||
_ => {
|
||||
warn!("Unauthorized IP access attempt");
|
||||
let response = Responder::unauthorized()
|
||||
.unwrap_or_else(|_| {
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.header(http::header::CONTENT_TYPE, "text/plain")
|
||||
.body(http_body_util::Full::new(
|
||||
Bytes::from("Unauthorized")
|
||||
))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
let response = Responder::unauthorized().unwrap_or_else(|_| {
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.header(http::header::CONTENT_TYPE, "text/plain")
|
||||
.body(http_body_util::Full::new(Bytes::from("Unauthorized")))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
MiddlewareResult::Respond(response)
|
||||
}
|
||||
}
|
||||
@@ -134,17 +130,14 @@ mod tests {
|
||||
|
||||
let result = IpFilterMiddleware::new(
|
||||
vec!["192.168.1.1".to_string(), "10.0.0.1".to_string()],
|
||||
false
|
||||
false,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_rejects_invalid_ip() {
|
||||
let result = IpFilterMiddleware::new(
|
||||
vec!["not-an-ip".to_string()],
|
||||
false
|
||||
);
|
||||
let result = IpFilterMiddleware::new(vec!["not-an-ip".to_string()], false);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
@@ -167,10 +160,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_specific_ip_in_allow_list() {
|
||||
let middleware = IpFilterMiddleware::new_unchecked(
|
||||
vec!["192.168.1.100".to_string()],
|
||||
false
|
||||
);
|
||||
let middleware =
|
||||
IpFilterMiddleware::new_unchecked(vec!["192.168.1.100".to_string()], false);
|
||||
let allowed_ip: IpAddr = "192.168.1.100".parse().unwrap();
|
||||
let denied_ip: IpAddr = "192.168.1.200".parse().unwrap();
|
||||
|
||||
@@ -199,10 +190,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_multiple_allowed_ips() {
|
||||
let middleware = IpFilterMiddleware::new_unchecked(
|
||||
vec![
|
||||
"192.168.1.100".to_string(),
|
||||
"192.168.1.200".to_string(),
|
||||
],
|
||||
vec!["192.168.1.100".to_string(), "192.168.1.200".to_string()],
|
||||
false,
|
||||
);
|
||||
|
||||
@@ -217,10 +205,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_ipv6_support() {
|
||||
let middleware = IpFilterMiddleware::new_unchecked(
|
||||
vec!["::1".to_string()],
|
||||
false,
|
||||
);
|
||||
let middleware = IpFilterMiddleware::new_unchecked(vec!["::1".to_string()], false);
|
||||
let ipv6_local: IpAddr = "::1".parse().unwrap();
|
||||
let ipv6_other: IpAddr = "::2".parse().unwrap();
|
||||
|
||||
|
||||
+24
-29
@@ -4,9 +4,9 @@
|
||||
//! Bearer tokens in Authorization header and access_token cookies.
|
||||
|
||||
use crate::{
|
||||
constants::{BEARER_PREFIX, FILE_EXTENSIONS, JWT_COOKIE_NAME},
|
||||
error::{ServerError, Result},
|
||||
Responder,
|
||||
constants::{BEARER_PREFIX, FILE_EXTENSIONS, JWT_COOKIE_NAME},
|
||||
error::{Result, ServerError},
|
||||
middleware::{Middleware, MiddlewareFuture, MiddlewareResult, auth_types::Claims},
|
||||
};
|
||||
use http::Request;
|
||||
@@ -29,15 +29,10 @@ impl JwtMiddleware {
|
||||
/// # Arguments
|
||||
/// * `public_key` - RSA public key in PEM format
|
||||
/// * `public_routes` - List of routes that don't require authentication
|
||||
pub fn new(
|
||||
public_key: &str,
|
||||
public_routes: Vec<String>,
|
||||
) -> Result<Self> {
|
||||
let decoding_key = DecodingKey::from_rsa_pem(public_key.as_bytes())
|
||||
.map_err(|e| ServerError::jwt_with_source(
|
||||
"Failed to parse RSA public key",
|
||||
Box::new(e),
|
||||
))?;
|
||||
pub fn new(public_key: &str, public_routes: Vec<String>) -> Result<Self> {
|
||||
let decoding_key = DecodingKey::from_rsa_pem(public_key.as_bytes()).map_err(|e| {
|
||||
ServerError::jwt_with_source("Failed to parse RSA public key", Box::new(e))
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
decoding_key,
|
||||
@@ -89,18 +84,19 @@ impl JwtMiddleware {
|
||||
}
|
||||
|
||||
/// Validates the request and extracts claims from the JWT token.
|
||||
fn validate_request(
|
||||
&self,
|
||||
req: &Request<Incoming>,
|
||||
) -> Result<Claims> {
|
||||
fn validate_request(&self, req: &Request<Incoming>) -> Result<Claims> {
|
||||
// Try to get token from cookie first
|
||||
let cookie_header = req.headers()
|
||||
.get("Cookie")
|
||||
.and_then(|v| v.to_str().ok());
|
||||
let cookie_header = req.headers().get("Cookie").and_then(|v| v.to_str().ok());
|
||||
|
||||
let token = cookie_header
|
||||
.and_then(|c| c.split(';').find(|s| s.trim().starts_with(&format!("{}=", JWT_COOKIE_NAME))))
|
||||
.map(|s| s.trim().trim_start_matches(&format!("{}=", JWT_COOKIE_NAME)))
|
||||
.and_then(|c| {
|
||||
c.split(';')
|
||||
.find(|s| s.trim().starts_with(&format!("{}=", JWT_COOKIE_NAME)))
|
||||
})
|
||||
.map(|s| {
|
||||
s.trim()
|
||||
.trim_start_matches(&format!("{}=", JWT_COOKIE_NAME))
|
||||
})
|
||||
.or_else(|| {
|
||||
req.headers()
|
||||
.get("Authorization")
|
||||
@@ -137,14 +133,13 @@ impl Middleware for JwtMiddleware {
|
||||
}
|
||||
|
||||
warn!("JWT validation failed for {}: {}", request_path, e);
|
||||
let res = Responder::unauthorized()
|
||||
.unwrap_or_else(|_| {
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.header(CONTENT_TYPE, "text/plain")
|
||||
.body(Full::new(Bytes::from("Unauthorized")))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
let res = Responder::unauthorized().unwrap_or_else(|_| {
|
||||
Response::builder()
|
||||
.status(http::StatusCode::UNAUTHORIZED)
|
||||
.header(CONTENT_TYPE, "text/plain")
|
||||
.body(Full::new(Bytes::from("Unauthorized")))
|
||||
.expect("Failed to build fallback response")
|
||||
});
|
||||
MiddlewareResult::Respond(res)
|
||||
}
|
||||
}
|
||||
@@ -153,9 +148,9 @@ impl Middleware for JwtMiddleware {
|
||||
}
|
||||
|
||||
use http::Response;
|
||||
use http::header::CONTENT_TYPE;
|
||||
use http_body_util::Full;
|
||||
use hyper::body::Bytes;
|
||||
use http::header::CONTENT_TYPE;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
Reference in New Issue
Block a user