Files
servme/src/middleware/api_key.rs
T

76 lines
2.5 KiB
Rust

//! API Key authentication middleware.
//!
//! Validates requests by checking for a valid API key in the X-API-Key header.
use crate::{
Responder,
middleware::{Middleware, MiddlewareFuture, MiddlewareResult},
};
use http::{Request, Response};
use hyper::body::{Bytes, Incoming};
use log::warn;
/// Middleware that validates API key authentication via X-API-Key header.
pub struct ApiKeyMiddleware {
api_key: String,
}
impl ApiKeyMiddleware {
/// Creates a new ApiKeyMiddleware with the specified expected API key.
pub fn new(api_key: &str) -> Self {
Self {
api_key: api_key.to_string(),
}
}
/// Checks if the given API key is invalid.
pub fn is_invalid_key(&self, key: &str) -> bool {
key != self.api_key
}
}
impl Middleware for ApiKeyMiddleware {
fn run(&self, req: Request<Incoming>) -> MiddlewareFuture<'_> {
Box::pin(async move {
match req.headers().get("X-API-Key") {
Some(header) => {
if header == self.api_key.as_str() {
MiddlewareResult::Continue(req)
} else {
warn!("X-API-Key validation failed for 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")
});
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")
});
MiddlewareResult::Respond(response)
}
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_key_middleware_new() {
let middleware = ApiKeyMiddleware::new("test-key");
assert!(!middleware.is_invalid_key("test-key"));
assert!(middleware.is_invalid_key("wrong-key"));
}
}