Thomas Eizinger
3 years ago
committed by
GitHub
11 changed files with 246 additions and 27 deletions
@ -1,3 +1,6 @@ |
|||||
[workspace] |
[workspace] |
||||
members = ["cfd_protocol", "daemon"] |
members = ["cfd_protocol", "daemon"] |
||||
resolver = "2" |
resolver = "2" |
||||
|
|
||||
|
[patch.crates-io] |
||||
|
rocket = { git = "https://github.com/SergioBenitez/Rocket" } # Need to patch rocket dependency of `rocket_basicauth` until there is an official release. |
||||
|
@ -0,0 +1,84 @@ |
|||||
|
use hex::FromHexError; |
||||
|
use rocket::http::Status; |
||||
|
use rocket::outcome::{try_outcome, IntoOutcome}; |
||||
|
use rocket::request::{FromRequest, Outcome}; |
||||
|
use rocket::{Request, State}; |
||||
|
use rocket_basicauth::{BasicAuth, BasicAuthError}; |
||||
|
use std::fmt; |
||||
|
use std::str::FromStr; |
||||
|
|
||||
|
/// A request guard that can be included in handler definitions to enforce authentication.
|
||||
|
pub struct Authenticated {} |
||||
|
|
||||
|
#[derive(Debug)] |
||||
|
pub enum Error { |
||||
|
UnknownUser(String), |
||||
|
BadPassword, |
||||
|
InvalidEncoding(FromHexError), |
||||
|
BadBasicAuthHeader(BasicAuthError), |
||||
|
/// The auth password was not configured in Rocket's state.
|
||||
|
MissingPassword, |
||||
|
NoAuthHeader, |
||||
|
} |
||||
|
|
||||
|
#[derive(PartialEq)] |
||||
|
pub struct Password([u8; 32]); |
||||
|
|
||||
|
impl From<[u8; 32]> for Password { |
||||
|
fn from(bytes: [u8; 32]) -> Self { |
||||
|
Self(bytes) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
impl fmt::Display for Password { |
||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
|
write!(f, "{}", hex::encode(self.0)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
impl FromStr for Password { |
||||
|
type Err = FromHexError; |
||||
|
|
||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> { |
||||
|
let mut bytes = [0u8; 32]; |
||||
|
hex::decode_to_slice(s, &mut bytes)?; |
||||
|
|
||||
|
Ok(Self(bytes)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#[rocket::async_trait] |
||||
|
impl<'r> FromRequest<'r> for Authenticated { |
||||
|
type Error = Error; |
||||
|
|
||||
|
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> { |
||||
|
let basic_auth = try_outcome!(req |
||||
|
.guard::<BasicAuth>() |
||||
|
.await |
||||
|
.map_failure(|(status, error)| (status, Error::BadBasicAuthHeader(error))) |
||||
|
.forward_then(|()| Outcome::Failure((Status::Unauthorized, Error::NoAuthHeader)))); |
||||
|
let password = try_outcome!(req |
||||
|
.guard::<&'r State<Password>>() |
||||
|
.await |
||||
|
.map_failure(|(status, _)| (status, Error::MissingPassword))); |
||||
|
|
||||
|
if basic_auth.username != "maker" { |
||||
|
return Outcome::Failure(( |
||||
|
Status::Unauthorized, |
||||
|
Error::UnknownUser(basic_auth.username), |
||||
|
)); |
||||
|
} |
||||
|
|
||||
|
if &try_outcome!(basic_auth |
||||
|
.password |
||||
|
.parse::<Password>() |
||||
|
.map_err(Error::InvalidEncoding) |
||||
|
.into_outcome(Status::BadRequest)) |
||||
|
!= password.inner() |
||||
|
{ |
||||
|
return Outcome::Failure((Status::Unauthorized, Error::BadPassword)); |
||||
|
} |
||||
|
|
||||
|
Outcome::Success(Authenticated {}) |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue