use std::collections::BTreeSet;
use super::super::error::AuthzResult;
use super::super::subject_directory::RoleDirectory;
use super::super::types::RuleType;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct UnknownSubject {
pub rule_type: String,
pub value: String,
pub entity: String,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub(super) struct SubjectMention {
pub(super) rule_type: String,
pub(super) value: String,
pub(super) entity: String,
}
pub(super) async fn find_unknown_subjects(
directory: Option<&dyn RoleDirectory>,
mentions: &BTreeSet<SubjectMention>,
) -> AuthzResult<Vec<UnknownSubject>> {
let Some(directory) = directory else {
return Ok(Vec::new());
};
let roles: Vec<String> = mentions
.iter()
.filter(|m| m.rule_type == RuleType::ROLE.to_string())
.map(|m| m.value.clone())
.collect();
if roles.is_empty() {
return Ok(Vec::new());
}
let missing: BTreeSet<String> = directory.unknown_roles(&roles).await?.into_iter().collect();
let mut out = Vec::new();
for mention in mentions {
if mention.rule_type != RuleType::ROLE.to_string() || !missing.contains(&mention.value) {
continue;
}
tracing::warn!(
rule_type = %mention.rule_type,
value = %mention.value,
entity = %mention.entity,
"authz rule names a subject that does not exist"
);
out.push(UnknownSubject {
rule_type: mention.rule_type.clone(),
value: mention.value.clone(),
entity: mention.entity.clone(),
});
}
Ok(out)
}