async auth

This commit is contained in:
ad hoc 2022-03-02 19:20:57 +01:00
parent d6400aef27
commit af8a5f2c21
No known key found for this signature in database
GPG Key ID: 4F00A782990CC643

View File

@ -2,28 +2,88 @@ mod error;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Deref; use std::ops::Deref;
use std::pin::Pin;
use actix_web::FromRequest; use actix_web::FromRequest;
use futures::future::err; use futures::future::err;
use futures::future::{ok, Ready}; use futures::Future;
use meilisearch_error::ResponseError; use meilisearch_error::{Code, ResponseError};
use error::AuthenticationError; use error::AuthenticationError;
use meilisearch_auth::{AuthController, AuthFilter}; use meilisearch_auth::{AuthController, AuthFilter};
pub struct GuardedData<T, D> { pub struct GuardedData<P, D> {
data: D, data: D,
filters: AuthFilter, filters: AuthFilter,
_marker: PhantomData<T>, _marker: PhantomData<P>,
} }
impl<T, D> GuardedData<T, D> { impl<P, D> GuardedData<P, D> {
pub fn filters(&self) -> &AuthFilter { pub fn filters(&self) -> &AuthFilter {
&self.filters &self.filters
} }
async fn auth_bearer(
auth: AuthController,
token: String,
index: Option<String>,
data: Option<D>,
) -> Result<Self, ResponseError>
where
P: Policy + 'static,
{
match Self::authenticate(auth, token, index).await? {
(_, Some(filters)) => match data {
Some(data) => Ok(Self {
data,
filters,
_marker: PhantomData,
}),
None => Err(AuthenticationError::IrretrievableState.into()),
},
(token, None) => {
let token = token.to_string();
Err(AuthenticationError::InvalidToken(token).into())
}
}
}
async fn auth_token(auth: AuthController, data: Option<D>) -> Result<Self, ResponseError>
where
P: Policy + 'static,
{
match Self::authenticate(auth, "", None).await?.1 {
Some(filters) => match data {
Some(data) => Ok(Self {
data,
filters,
_marker: PhantomData,
}),
None => Err(AuthenticationError::IrretrievableState.into()),
},
None => Err(AuthenticationError::MissingAuthorizationHeader.into()),
}
}
async fn authenticate<S>(
auth: AuthController,
token: S,
index: Option<String>,
) -> Result<(S, Option<AuthFilter>), ResponseError>
where
P: Policy + 'static,
S: AsRef<str> + 'static + Send,
{
Ok(tokio::task::spawn_blocking(move || {
let res = P::authenticate(auth, token.as_ref(), index.as_deref());
(token, res)
})
.await
.map_err(|e| ResponseError::from_msg(e.to_string(), Code::Internal))?)
}
} }
impl<T, D> Deref for GuardedData<T, D> { impl<P, D> Deref for GuardedData<P, D> {
type Target = D; type Target = D;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -34,7 +94,7 @@ impl<T, D> Deref for GuardedData<T, D> {
impl<P: Policy + 'static, D: 'static + Clone> FromRequest for GuardedData<P, D> { impl<P: Policy + 'static, D: 'static + Clone> FromRequest for GuardedData<P, D> {
type Error = ResponseError; type Error = ResponseError;
type Future = Ready<Result<Self, Self::Error>>; type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
fn from_request( fn from_request(
req: &actix_web::HttpRequest, req: &actix_web::HttpRequest,
@ -51,40 +111,25 @@ impl<P: Policy + 'static, D: 'static + Clone> FromRequest for GuardedData<P, D>
// TODO: find a less hardcoded way? // TODO: find a less hardcoded way?
let index = req.match_info().get("index_uid"); let index = req.match_info().get("index_uid");
match type_token.next() { match type_token.next() {
Some(token) => match P::authenticate(auth, token, index) { Some(token) => Box::pin(Self::auth_bearer(
Some(filters) => match req.app_data::<D>().cloned() { auth,
Some(data) => ok(Self { token.to_string(),
data, index.map(String::from),
filters, req.app_data::<D>().cloned(),
_marker: PhantomData, )),
}), None => Box::pin(err(AuthenticationError::InvalidToken(
None => err(AuthenticationError::IrretrievableState.into()), "unknown".to_string(),
}, )
None => { .into())),
let token = token.to_string();
err(AuthenticationError::InvalidToken(token).into())
}
},
None => {
err(AuthenticationError::InvalidToken("unknown".to_string()).into())
}
} }
} }
_otherwise => err(AuthenticationError::MissingAuthorizationHeader.into()), _otherwise => {
}, Box::pin(err(AuthenticationError::MissingAuthorizationHeader.into()))
None => match P::authenticate(auth, "", None) { }
Some(filters) => match req.app_data::<D>().cloned() {
Some(data) => ok(Self {
data,
filters,
_marker: PhantomData,
}),
None => err(AuthenticationError::IrretrievableState.into()),
},
None => err(AuthenticationError::MissingAuthorizationHeader.into()),
}, },
None => Box::pin(Self::auth_token(auth, req.app_data::<D>().cloned())),
}, },
None => err(AuthenticationError::IrretrievableState.into()), None => Box::pin(err(AuthenticationError::IrretrievableState.into())),
} }
} }
} }