diff options
author | boasting-squirrel <boasting.squirrel@gmail.com> | 2019-02-12 19:20:57 +0000 |
---|---|---|
committer | boasting-squirrel <boasting.squirrel@gmail.com> | 2019-02-12 19:20:57 +0000 |
commit | 066535edaefa2c1f34531d8be5ad280d914a9edd (patch) | |
tree | b2a5192caf92387cded9f92955344aa43ca15b44 /src/auth.rs | |
parent | Merge pull request #30 from boastful-squirrel/sorting (diff) | |
download | miniserve-066535edaefa2c1f34531d8be5ad280d914a9edd.tar.gz miniserve-066535edaefa2c1f34531d8be5ad280d914a9edd.zip |
Split project into multiple files
Diffstat (limited to '')
-rw-r--r-- | src/auth.rs | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..5d0bcaa --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,77 @@ +use actix_web::http::header; +use actix_web::middleware::{Middleware, Response}; +use actix_web::{HttpRequest, HttpResponse, Result}; + +use crate::config; + +pub struct Auth; + +pub enum BasicAuthError { + Base64DecodeError, + InvalidUsernameFormat, +} + +#[derive(Clone, Debug)] +pub struct BasicAuthParams { + pub username: String, + pub password: String, +} + +/// Decode a HTTP basic auth string into a tuple of username and password. +pub fn parse_basic_auth( + authorization_header: &header::HeaderValue, +) -> Result<BasicAuthParams, BasicAuthError> { + let basic_removed = authorization_header.to_str().unwrap().replace("Basic ", ""); + let decoded = base64::decode(&basic_removed).map_err(|_| BasicAuthError::Base64DecodeError)?; + let decoded_str = String::from_utf8_lossy(&decoded); + let strings: Vec<&str> = decoded_str.splitn(2, ':').collect(); + if strings.len() != 2 { + return Err(BasicAuthError::InvalidUsernameFormat); + } + Ok(BasicAuthParams { + username: strings[0].to_owned(), + password: strings[1].to_owned(), + }) +} + +impl Middleware<config::MiniserveConfig> for Auth { + fn response( + &self, + req: &HttpRequest<config::MiniserveConfig>, + resp: HttpResponse, + ) -> Result<Response> { + if let Some(ref required_auth) = req.state().auth { + if let Some(auth_headers) = req.headers().get(header::AUTHORIZATION) { + let auth_req = match parse_basic_auth(auth_headers) { + Ok(auth_req) => auth_req, + Err(BasicAuthError::Base64DecodeError) => { + return Ok(Response::Done(HttpResponse::BadRequest().body(format!( + "Error decoding basic auth base64: '{}'", + auth_headers.to_str().unwrap() + )))); + } + Err(BasicAuthError::InvalidUsernameFormat) => { + return Ok(Response::Done( + HttpResponse::BadRequest().body("Invalid basic auth format"), + )); + } + }; + if auth_req.username != required_auth.username + || auth_req.password != required_auth.password + { + let new_resp = HttpResponse::Forbidden().finish(); + return Ok(Response::Done(new_resp)); + } + } else { + let new_resp = HttpResponse::Unauthorized() + .header( + header::WWW_AUTHENTICATE, + header::HeaderValue::from_static("Basic realm=\"miniserve\""), + ) + .finish(); + return Ok(Response::Done(new_resp)); + } + } + Ok(Response::Done(resp)) + } +} |