making auth sync since that suffices for now and makes the code simpler

This commit is contained in:
Lennart
2024-03-15 22:40:04 +01:00
parent 4f1a59b66d
commit efeec7d1d4
5 changed files with 35 additions and 55 deletions

View File

@@ -1,7 +1,7 @@
use actix_web::{http::StatusCode, HttpResponse}; use actix_web::{http::StatusCode, HttpResponse};
use derive_more::{Display, Error}; use derive_more::{Display, Error};
#[derive(Debug, Display, Error)] #[derive(Debug, Display, Error, Clone)]
pub enum Error { pub enum Error {
#[display(fmt = "Internal server error")] #[display(fmt = "Internal server error")]
InternalError, InternalError,

View File

@@ -1,9 +1,10 @@
use actix_web::{dev::Payload, web::Data, FromRequest, HttpRequest}; use actix_web::{dev::Payload, web::Data, FromRequest, HttpRequest};
use futures_util::{Future, FutureExt}; use futures_util::Future;
use std::marker::PhantomData; use std::{marker::PhantomData, task::Poll};
use std::pin::Pin;
use super::{CheckAuthentication, AuthInfo}; use crate::error::Error;
use super::{AuthInfo, CheckAuthentication};
pub struct AuthInfoExtractor<A: CheckAuthentication> { pub struct AuthInfoExtractor<A: CheckAuthentication> {
pub inner: AuthInfo, pub inner: AuthInfo,
@@ -19,28 +20,21 @@ impl<T: CheckAuthentication> From<AuthInfo> for AuthInfoExtractor<T> {
} }
} }
pub struct AuthInfoExtractorFuture<A> pub struct AuthInfoExtractorFuture<A: CheckAuthentication>(Result<AuthInfo, Error>, PhantomData<A>);
where
A: CheckAuthentication,
{
future: Pin<Box<A::Future>>,
}
impl<A> Future for AuthInfoExtractorFuture<A> impl<A: CheckAuthentication> Future for AuthInfoExtractorFuture<A> {
where type Output = Result<AuthInfoExtractor<A>, Error>;
A: CheckAuthentication,
{
type Output = Result<AuthInfoExtractor<A>, A::Error>;
fn poll( fn poll(
self: std::pin::Pin<&mut Self>, self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>, _cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> { ) -> std::task::Poll<Self::Output> {
match self.get_mut().future.poll_unpin(cx) { match &self.0 {
std::task::Poll::Pending => std::task::Poll::Pending, Ok(auth_info) => Poll::Ready(Ok(AuthInfoExtractor {
std::task::Poll::Ready(result) => { inner: auth_info.clone(),
std::task::Poll::Ready(result.map(|auth_info| auth_info.into())) _provider_type: PhantomData,
} })),
Err(err) => Poll::Ready(Err(err.clone())),
} }
} }
} }
@@ -49,14 +43,12 @@ impl<A> FromRequest for AuthInfoExtractor<A>
where where
A: CheckAuthentication, A: CheckAuthentication,
{ {
type Error = A::Error; type Error = Error;
type Future = AuthInfoExtractorFuture<A>; type Future = AuthInfoExtractorFuture<A>;
fn extract(req: &HttpRequest) -> Self::Future { fn extract(req: &HttpRequest) -> Self::Future {
let a = req.app_data::<Data<A>>().unwrap().validate(req); let result = req.app_data::<Data<A>>().unwrap().validate(req);
Self::Future { AuthInfoExtractorFuture(result, PhantomData)
future: Box::pin(a),
}
} }
fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future {
Self::extract(req) Self::extract(req)

View File

@@ -1,6 +1,6 @@
use crate::error::Error;
use actix_web::{http::header::Header, HttpRequest}; use actix_web::{http::header::Header, HttpRequest};
use actix_web_httpauth::headers::authorization::{Authorization, Basic}; use actix_web_httpauth::headers::authorization::{Authorization, Basic};
use futures_util::future::{err, ok, Ready};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
@@ -22,10 +22,7 @@ pub struct HtpasswdAuthConfig {
} }
impl CheckAuthentication for HtpasswdAuth { impl CheckAuthentication for HtpasswdAuth {
type Error = crate::error::Error; fn validate(&self, req: &HttpRequest) -> Result<AuthInfo, Error> {
type Future = Ready<Result<AuthInfo, Self::Error>>;
fn validate(&self, req: &HttpRequest) -> Self::Future {
if let Ok(auth) = Authorization::<Basic>::parse(req) { if let Ok(auth) = Authorization::<Basic>::parse(req) {
let user_id = auth.as_ref().user_id(); let user_id = auth.as_ref().user_id();
// Map None to empty password // Map None to empty password
@@ -34,19 +31,19 @@ impl CheckAuthentication for HtpasswdAuth {
let user_config = if let Some(user_config) = self.config.users.get(user_id) { let user_config = if let Some(user_config) = self.config.users.get(user_id) {
user_config user_config
} else { } else {
return err(crate::error::Error::Unauthorized); return Err(crate::error::Error::Unauthorized);
}; };
if let Err(e) = password_auth::verify_password(password, &user_config.password) { if let Err(e) = password_auth::verify_password(password, &user_config.password) {
dbg!(e); dbg!(e);
return err(crate::error::Error::Unauthorized); return Err(crate::error::Error::Unauthorized);
} }
ok(AuthInfo { Ok(AuthInfo {
user_id: user_id.to_string(), user_id: user_id.to_string(),
}) })
} else { } else {
err(crate::error::Error::Unauthorized) Err(crate::error::Error::Unauthorized)
} }
} }
} }

View File

@@ -1,6 +1,6 @@
use actix_web::{HttpRequest, ResponseError}; use actix_web::HttpRequest;
use futures_util::{future::Ready, Future};
use crate::error::Error;
pub use extractor::AuthInfoExtractor; pub use extractor::AuthInfoExtractor;
pub use htpasswd::{HtpasswdAuth, HtpasswdAuthConfig}; pub use htpasswd::{HtpasswdAuth, HtpasswdAuthConfig};
pub use none::NoneAuth; pub use none::NoneAuth;
@@ -9,17 +9,13 @@ pub mod extractor;
pub mod htpasswd; pub mod htpasswd;
pub mod none; pub mod none;
#[derive(Clone)]
pub struct AuthInfo { pub struct AuthInfo {
pub user_id: String, pub user_id: String,
} }
pub trait CheckAuthentication: Send + Sync + 'static { pub trait CheckAuthentication: Send + Sync + 'static {
type Error: ResponseError; fn validate(&self, req: &HttpRequest) -> Result<AuthInfo, Error>
type Future: Future<Output = Result<AuthInfo, Self::Error>>
where
Self: Sized;
fn validate(&self, req: &HttpRequest) -> Self::Future
where where
Self: Sized; Self: Sized;
} }
@@ -31,10 +27,7 @@ pub enum AuthProvider {
} }
impl CheckAuthentication for AuthProvider { impl CheckAuthentication for AuthProvider {
type Error = crate::error::Error; fn validate(&self, req: &HttpRequest) -> Result<AuthInfo, Error>
type Future = Ready<Result<AuthInfo, Self::Error>>;
fn validate(&self, req: &HttpRequest) -> Self::Future
where where
Self: Sized, Self: Sized,
{ {

View File

@@ -1,6 +1,7 @@
use actix_web::{http::header::Header, HttpRequest}; use actix_web::{http::header::Header, HttpRequest};
use actix_web_httpauth::headers::authorization::{Authorization, Basic}; use actix_web_httpauth::headers::authorization::{Authorization, Basic};
use futures_util::future::{err, ok, Ready};
use crate::error::Error;
use super::{AuthInfo, CheckAuthentication}; use super::{AuthInfo, CheckAuthentication};
@@ -8,16 +9,13 @@ use super::{AuthInfo, CheckAuthentication};
pub struct NoneAuth; pub struct NoneAuth;
impl CheckAuthentication for NoneAuth { impl CheckAuthentication for NoneAuth {
type Error = crate::error::Error; fn validate(&self, req: &HttpRequest) -> Result<AuthInfo, Error> {
type Future = Ready<Result<AuthInfo, Self::Error>>;
fn validate(&self, req: &HttpRequest) -> Self::Future {
if let Ok(auth) = Authorization::<Basic>::parse(req) { if let Ok(auth) = Authorization::<Basic>::parse(req) {
ok(AuthInfo { Ok(AuthInfo {
user_id: auth.as_ref().user_id().to_string(), user_id: auth.as_ref().user_id().to_string(),
}) })
} else { } else {
err(crate::error::Error::Unauthorized) Err(crate::error::Error::Unauthorized)
} }
} }
} }