use std::future::Future;
use std::pin::Pin;
use crate::types::Context;
use crate::Error;
pub trait AuthorizationClient: Send + Sync {
fn check(
&self,
subject: &str,
permission: &str,
resource: &str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + '_>>;
fn check_with_context(
&self,
subject: &str,
permission: &str,
resource: &str,
context: &Context,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + '_>>;
}
#[cfg(test)]
mod tests {
use super::*;
struct TestClient {
allow_all: bool,
}
impl AuthorizationClient for TestClient {
fn check(
&self,
_subject: &str,
_permission: &str,
_resource: &str,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + '_>> {
let result = self.allow_all;
Box::pin(async move { Ok(result) })
}
fn check_with_context(
&self,
_subject: &str,
_permission: &str,
_resource: &str,
_context: &Context,
) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + '_>> {
let result = self.allow_all;
Box::pin(async move { Ok(result) })
}
}
#[tokio::test]
async fn test_trait_object() {
let client: Box<dyn AuthorizationClient> = Box::new(TestClient { allow_all: true });
let result = client.check("user:alice", "view", "doc:1").await;
assert!(result.unwrap());
}
#[tokio::test]
async fn test_deny() {
let client = TestClient { allow_all: false };
let result = client.check("user:alice", "view", "doc:1").await;
assert!(!result.unwrap());
}
#[tokio::test]
async fn test_check_with_context() {
let client = TestClient { allow_all: true };
let context = Context::new().with("env", "test");
let result = client
.check_with_context("user:alice", "view", "doc:1", &context)
.await;
assert!(result.unwrap());
}
#[tokio::test]
async fn test_check_with_context_deny() {
let client = TestClient { allow_all: false };
let context = Context::new().with("env", "prod");
let result = client
.check_with_context("user:alice", "view", "doc:1", &context)
.await;
assert!(!result.unwrap());
}
}