use crate::{EvalCtx, Policy, PolicyEvalResult};
use async_trait::async_trait;
pub struct RbacPolicy<S, F1, F2> {
required_roles_resolver: F1,
user_roles_resolver: F2,
_marker: std::marker::PhantomData<S>,
}
impl<S, F1, F2> RbacPolicy<S, F1, F2> {
pub fn new(required_roles_resolver: F1, user_roles_resolver: F2) -> Self {
Self {
required_roles_resolver,
user_roles_resolver,
_marker: std::marker::PhantomData,
}
}
}
#[async_trait]
impl<S, R, A, C, F1, F2> Policy<S, R, A, C> for RbacPolicy<S, F1, F2>
where
S: Sync + Send,
R: Sync + Send,
A: Sync + Send,
C: Sync + Send,
F1: Fn(&R, &A) -> Vec<uuid::Uuid> + Sync + Send,
F2: Fn(&S) -> Vec<uuid::Uuid> + Sync + Send,
{
async fn evaluate(&self, ctx: &EvalCtx<'_, S, R, A, C>) -> PolicyEvalResult {
let required_roles = (self.required_roles_resolver)(ctx.resource, ctx.action);
let user_roles = (self.user_roles_resolver)(ctx.subject);
let has_role = required_roles.iter().any(|role| user_roles.contains(role));
if has_role {
ctx.grant("User has required role")
} else {
ctx.deny("User doesn't have required role")
}
}
fn policy_type(&self) -> std::borrow::Cow<'static, str> {
std::borrow::Cow::Borrowed("RbacPolicy")
}
}