use super::{AuthZ, Authorizer, Context};
use crate::actix::auth::authorization::AuthorizerExt;
use crate::auth::AuthError;
use async_trait::async_trait;
use drogue_client::user::v1::authz::AuthorizationRequest;
use drogue_client::user::{self, v1::authz::Outcome};
#[derive(Clone, Debug)]
pub struct ApplicationAuthorizer {
pub client: user::v1::Client,
pub permission: user::v1::authz::Permission,
pub app_param: String,
}
impl ApplicationAuthorizer {
pub fn wrapping(
user_auth: Option<user::v1::Client>,
permission: user::v1::authz::Permission,
) -> AuthZ {
AuthZ::new(
user_auth
.map(|client| ApplicationAuthorizer {
client,
permission,
app_param: "application".to_string(),
})
.or_else_allow(),
)
}
}
#[async_trait(?Send)]
impl Authorizer for ApplicationAuthorizer {
async fn authorize(&self, context: &Context<'_>) -> Result<Option<Outcome>, AuthError> {
let user = &context.identity;
let application = match context.request.match_info().get(&self.app_param) {
Some(application) => application,
None => {
return Err(AuthError::InvalidRequest(
"Missing 'application' information".to_string(),
));
}
};
log::debug!(
"Authorizing - user: {:?}, app: {}, permission: {:?}",
user,
application,
&self.permission
);
let response = self
.client
.authorize(AuthorizationRequest {
application: application.to_string(),
permission: self.permission,
user_id: user.user_id().map(ToString::to_string),
roles: user.roles().clone(),
})
.await
.map_err(|e| AuthError::Internal(e.to_string()))?;
log::debug!("Outcome: {:?}", response);
match response.outcome {
Outcome::Allow => Ok(Some(Outcome::Allow)),
Outcome::Deny => Err(AuthError::NotFound(
String::from("Application"),
application.to_string(),
)),
}
}
}