aboutsummaryrefslogtreecommitdiffstats
path: root/src/auth.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/auth.rs74
1 files changed, 51 insertions, 23 deletions
diff --git a/src/auth.rs b/src/auth.rs
index 1a913d5..7c77758 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -1,8 +1,9 @@
-use actix_web::dev::ServiceRequest;
+use actix_web::dev::{Service, ServiceRequest, ServiceResponse};
use actix_web::http::{header, StatusCode};
-use actix_web::{HttpRequest, HttpResponse, Result};
-use actix_web_httpauth::extractors::basic::BasicAuth;
+use actix_web::{HttpRequest, HttpResponse};
+use futures::future::Either;
use sha2::{Digest, Sha256, Sha512};
+use std::future::{ready, Future};
use crate::errors::{self, ContextualError};
use crate::renderer;
@@ -14,12 +15,16 @@ pub struct BasicAuthParams {
pub password: String,
}
-impl From<BasicAuth> for BasicAuthParams {
- fn from(auth: BasicAuth) -> Self {
- Self {
+impl BasicAuthParams {
+ fn try_from_request(req: &HttpRequest) -> actix_web::Result<Self> {
+ use actix_web::http::header::Header;
+ use actix_web_httpauth::headers::authorization::{Authorization, Basic};
+
+ let auth = Authorization::<Basic>::parse(req)?.into_scheme();
+ Ok(Self {
username: auth.user_id().to_string(),
password: auth.password().unwrap_or(&"".into()).to_string(),
- }
+ })
}
}
@@ -72,25 +77,48 @@ pub fn get_hash<T: Digest>(text: &str) -> Vec<u8> {
hasher.finalize().to_vec()
}
-pub async fn handle_auth(req: ServiceRequest, cred: BasicAuth) -> Result<ServiceRequest> {
+/// When authentication succedes, return the request to be passed to downstream services.
+/// Otherwise, return an error response
+fn handle_auth(req: ServiceRequest) -> Result<ServiceRequest, ServiceResponse> {
let (req, pl) = req.into_parts();
let required_auth = &req.app_data::<crate::MiniserveConfig>().unwrap().auth;
- if match_auth(cred.into(), required_auth) {
- Ok(ServiceRequest::from_parts(req, pl).unwrap_or_else(|_| unreachable!()))
- } else {
- Err(HttpResponse::Unauthorized()
- .header(
- header::WWW_AUTHENTICATE,
- header::HeaderValue::from_static("Basic realm=\"miniserve\""),
- )
- .body(build_unauthorized_response(
- &req,
- ContextualError::InvalidHttpCredentials,
- true,
- StatusCode::UNAUTHORIZED,
- ))
- .into())
+ if required_auth.is_empty() {
+ // auth is disabled by configuration
+ return Ok(ServiceRequest::from_parts(req, pl));
+ } else if let Ok(cred) = BasicAuthParams::try_from_request(&req) {
+ if match_auth(cred, required_auth) {
+ return Ok(ServiceRequest::from_parts(req, pl));
+ }
+ }
+
+ // auth failed; render and return the error response
+ let resp = HttpResponse::Unauthorized()
+ .append_header((
+ header::WWW_AUTHENTICATE,
+ header::HeaderValue::from_static("Basic realm=\"miniserve\""),
+ ))
+ .body(build_unauthorized_response(
+ &req,
+ ContextualError::InvalidHttpCredentials,
+ true,
+ StatusCode::UNAUTHORIZED,
+ ));
+
+ Err(ServiceResponse::new(req, resp))
+}
+
+pub fn auth_middleware<S>(
+ req: ServiceRequest,
+ srv: &S,
+) -> impl Future<Output = actix_web::Result<ServiceResponse>> + 'static
+where
+ S: Service<ServiceRequest, Response = ServiceResponse, Error = actix_web::Error>,
+ S::Future: 'static,
+{
+ match handle_auth(req) {
+ Ok(req) => Either::Left(srv.call(req)),
+ Err(resp) => Either::Right(ready(Ok(resp))),
}
}