1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
use actix_web::http::header;
use actix_web::middleware::{Middleware, Response};
use actix_web::{HttpRequest, HttpResponse, Result};
pub struct Auth;
/// HTTP Basic authentication errors
pub enum BasicAuthError {
Base64DecodeError,
InvalidUsernameFormat,
}
#[derive(Clone, Debug)]
/// HTTP Basic authentication parameters
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<crate::MiniserveConfig> for Auth {
fn response(
&self,
req: &HttpRequest<crate::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))
}
}
|