use ahash::{HashMap, HashMapExt};
use serde::ser::SerializeMap;
use sonic_rs::{JsonValueTrait, Value};
use crate::plugins::hooks;
use super::super::api::plugin::{RequestContextPluginRead, RequestContextPluginWrite};
use super::super::deser::RequestContextValueExt;
use super::RequestContextDomain;
use super::RequestContextError;
pub trait CanWriteAuthorization {}
impl CanWriteAuthorization for hooks::OnGraphqlAnalysis {}
pub(crate) const REQUIRED_POLICIES_KEY: &str = "hive::authorization::required_policies";
#[derive(Debug, Clone, Default)]
pub struct AuthorizationContext {
pub required_policies: Option<HashMap<String, Option<bool>>>,
}
impl AuthorizationContext {
fn set_required_policies_value(&mut self, value: Value) -> Result<(), RequestContextError> {
if value.is_null() {
self.required_policies = None;
return Ok(());
}
let object = value.expect_object(
REQUIRED_POLICIES_KEY,
"object mapping policy names to booleans or null",
)?;
let mut policies = HashMap::with_capacity(object.len());
for (policy, decision) in object.iter() {
let decision = if decision.is_null() {
None
} else {
Some(decision.expect_bool(
REQUIRED_POLICIES_KEY,
"object mapping policy names to booleans or null",
)?)
};
policies.insert(policy.to_string(), decision);
}
self.required_policies = Some(policies);
Ok(())
}
}
pub struct RequestContextAuthorizationRead<'a> {
context: &'a AuthorizationContext,
}
impl RequestContextAuthorizationRead<'_> {
pub fn required_policies(&self) -> Option<&HashMap<String, Option<bool>>> {
self.context.required_policies.as_ref()
}
}
pub struct RequestContextAuthorizationWrite<'a> {
context: &'a mut AuthorizationContext,
}
impl RequestContextAuthorizationWrite<'_> {
pub fn set_policy_decision(&mut self, policy: impl Into<String>, granted: bool) -> &mut Self {
self.context
.required_policies
.get_or_insert_with(HashMap::default)
.insert(policy.into(), Some(granted));
self
}
}
impl<Hook> RequestContextPluginRead<Hook> {
pub fn authorization(&self) -> RequestContextAuthorizationRead<'_> {
RequestContextAuthorizationRead {
context: &self.snapshot.authorization,
}
}
}
impl<Hook: CanWriteAuthorization> RequestContextPluginWrite<'_, Hook> {
pub fn authorization(&mut self) -> RequestContextAuthorizationWrite<'_> {
RequestContextAuthorizationWrite {
context: &mut self.context.authorization,
}
}
}
impl RequestContextDomain for AuthorizationContext {
const DOMAIN_PREFIX: &'static str = "hive::authorization::";
fn set_key_value(&mut self, key: &str, value: Value) -> Result<(), RequestContextError> {
match key {
REQUIRED_POLICIES_KEY => self.set_required_policies_value(value),
_ => self.unknown_key(key),
}
}
super::impl_domain_serde!(
REQUIRED_POLICIES_KEY => required_policies,
);
}