use std::collections::BTreeMap;
use std::sync::Arc;
use super::org::OrgId;
use super::org_grant::{OrgAudienceSecret, OrgCapabilityGrant};
use super::org_routing_registry::GrantMovementFence;
use crate::adapter::net::identity::{EntityId, MAX_TOKEN_CLOCK_SKEW_SECS};
pub const MAX_PROVIDER_GRANT_AUDIENCES: usize = 256;
pub const MAX_CONSUMER_GRANT_AUDIENCES: usize = 256;
pub struct GrantAudienceRecord {
grant: OrgCapabilityGrant,
secret: OrgAudienceSecret,
install_seq: u64,
}
impl GrantAudienceRecord {
pub fn grant(&self) -> &OrgCapabilityGrant {
&self.grant
}
pub fn install_seq(&self) -> u64 {
self.install_seq
}
pub(crate) fn with_install_seq(mut self, install_seq: u64) -> Self {
self.install_seq = install_seq;
self
}
pub fn secret(&self) -> &OrgAudienceSecret {
&self.secret
}
pub fn grant_id(&self) -> &[u8; 32] {
&self.grant.grant_id
}
pub fn audience_handle(&self) -> &[u8; 32] {
&self.secret.audience_handle
}
}
impl std::fmt::Debug for GrantAudienceRecord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GrantAudienceRecord")
.field("grant", &self.grant)
.field("secret", &self.secret)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GrantAudienceInstallError {
NoAuthority,
GrantInvalid,
GrantNotCurrent,
MissingDiscover,
NoDiscoveryBinding,
SecretMismatch,
WrongProviderIssuer,
ProviderNotCovered,
WrongConsumerGrantee,
Conflict,
AtCapacity,
IdSpaceExhausted,
}
impl std::fmt::Display for GrantAudienceInstallError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
GrantAudienceInstallError::NoAuthority => "no node authority installed",
GrantAudienceInstallError::GrantInvalid => "grant signature or structure invalid",
GrantAudienceInstallError::GrantNotCurrent => "grant expired or not yet valid",
GrantAudienceInstallError::MissingDiscover => "grant lacks DISCOVER rights",
GrantAudienceInstallError::NoDiscoveryBinding => "grant carries no discovery binding",
GrantAudienceInstallError::SecretMismatch => "audience secret does not match the grant",
GrantAudienceInstallError::WrongProviderIssuer => {
"grant issuer org is not this provider's owner org"
}
GrantAudienceInstallError::ProviderNotCovered => {
"grant target scope does not cover this provider"
}
GrantAudienceInstallError::WrongConsumerGrantee => {
"grant grantee org is not this consumer's owner org"
}
GrantAudienceInstallError::Conflict => {
"a different grant is already installed under this grant id"
}
GrantAudienceInstallError::AtCapacity => "grant-audience registry at capacity",
GrantAudienceInstallError::IdSpaceExhausted => {
"consumer grant identity space exhausted"
}
};
f.write_str(s)
}
}
impl std::error::Error for GrantAudienceInstallError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ConsumerAudienceLease {
grant_id: [u8; 32],
install_seq: u64,
}
impl ConsumerAudienceLease {
pub(crate) fn new(grant_id: [u8; 32], install_seq: u64) -> Self {
Self {
grant_id,
install_seq,
}
}
pub fn grant_id(&self) -> &[u8; 32] {
&self.grant_id
}
pub fn install_seq(&self) -> u64 {
self.install_seq
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConsumerAudienceInstall {
Installed(ConsumerAudienceLease),
AlreadyPresent,
}
#[derive(Default)]
pub struct OrgAudienceLeases {
entries: parking_lot::Mutex<std::collections::HashMap<[u8; 32], LeaseEntry>>,
}
pub(crate) struct LeaseEntry {
count: usize,
owned: Option<ConsumerAudienceLease>,
}
impl OrgAudienceLeases {
#[doc(hidden)]
pub fn len(&self) -> usize {
self.entries.lock().len()
}
#[doc(hidden)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[doc(hidden)]
pub fn entry_for_test(&self, grant_id: &[u8; 32]) -> Option<(usize, bool)> {
self.entries
.lock()
.get(grant_id)
.map(|e| (e.count, e.owned.is_some()))
}
pub(crate) fn lock_entries(
&self,
) -> parking_lot::MutexGuard<'_, std::collections::HashMap<[u8; 32], LeaseEntry>> {
self.entries.lock()
}
}
impl LeaseEntry {
pub(crate) fn new_owned(lease: ConsumerAudienceLease) -> Self {
Self {
count: 1,
owned: Some(lease),
}
}
pub(crate) fn new_borrowed() -> Self {
Self {
count: 1,
owned: None,
}
}
pub(crate) fn retain(&mut self) {
self.count += 1;
}
pub(crate) fn release(&mut self) -> (bool, Option<ConsumerAudienceLease>) {
self.count = self.count.saturating_sub(1);
if self.count > 0 {
return (false, None);
}
(true, self.owned.take())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GrantAudienceInstalled {
Installed,
AlreadyPresent,
}
#[derive(Default, Clone, Debug)]
struct GrantAudienceRecords {
by_grant_id: BTreeMap<[u8; 32], Arc<GrantAudienceRecord>>,
}
impl GrantAudienceRecords {
fn get(&self, grant_id: &[u8; 32]) -> Option<&Arc<GrantAudienceRecord>> {
self.by_grant_id.get(grant_id)
}
fn len(&self) -> usize {
self.by_grant_id.len()
}
fn records(&self) -> impl Iterator<Item = &Arc<GrantAudienceRecord>> {
self.by_grant_id.values()
}
fn reserve(
&self,
record: &GrantAudienceRecord,
capacity: usize,
now_secs: u64,
) -> Result<Reserved, GrantAudienceInstallError> {
let grant_id = *record.grant_id();
if let Some(existing) = self.by_grant_id.get(&grant_id) {
return if records_identical(existing, record) {
Ok(Reserved::Noop)
} else {
Err(GrantAudienceInstallError::Conflict)
};
}
let mut next = self.by_grant_id.clone();
if next.len() >= capacity {
let horizon = now_secs.saturating_sub(MAX_TOKEN_CLOCK_SKEW_SECS);
let before = next.len();
next.retain(|_, r| r.grant().not_after > horizon);
let swept = before - next.len();
if swept > 8 {
tracing::warn!(
swept,
remaining = next.len(),
"org grant registry: capacity sweep reclaimed an unusually \
large number of installed records at once; if this was not \
a mass expiry, check for a wall-clock jump",
);
}
if next.len() >= capacity {
return Err(GrantAudienceInstallError::AtCapacity);
}
}
Ok(Reserved::Ready(Self { by_grant_id: next }))
}
fn without(&self, grant_id: &[u8; 32]) -> Option<Self> {
if !self.by_grant_id.contains_key(grant_id) {
return None;
}
let mut next = self.by_grant_id.clone();
next.remove(grant_id);
Some(Self { by_grant_id: next })
}
}
enum Reserved {
Noop,
Ready(GrantAudienceRecords),
}
#[derive(Debug)]
pub(crate) enum PreparedInstall {
Noop,
Ready(Box<PreparedSlot>),
}
#[derive(Debug)]
pub(crate) struct PreparedSlot {
next: GrantAudienceRecords,
candidate: Box<GrantAudienceRecord>,
}
impl PreparedSlot {
fn finish_with_install_seq(mut self, install_seq: u64) -> GrantAudienceRecords {
let record = Arc::new((*self.candidate).with_install_seq(install_seq));
self.next.by_grant_id.insert(*record.grant_id(), record);
self.next
}
}
fn records_identical(existing: &GrantAudienceRecord, incoming: &GrantAudienceRecord) -> bool {
existing.grant == incoming.grant
&& existing.secret.audience_handle == incoming.secret.audience_handle
&& constant_time_eq_32(
existing.secret.discovery_key(),
incoming.secret.discovery_key(),
)
}
fn constant_time_eq_32(a: &[u8; 32], b: &[u8; 32]) -> bool {
let mut diff = 0u8;
for i in 0..32 {
diff |= a[i] ^ b[i];
}
std::hint::black_box(diff) == 0
}
fn validate_common(
grant: OrgCapabilityGrant,
secret: OrgAudienceSecret,
now_secs: u64,
skew_secs: u64,
) -> Result<GrantAudienceRecord, GrantAudienceInstallError> {
grant
.verify()
.map_err(|_| GrantAudienceInstallError::GrantInvalid)?;
grant
.is_valid_at_with_skew(now_secs, skew_secs)
.map_err(|_| GrantAudienceInstallError::GrantNotCurrent)?;
if !grant.permits_discover() {
return Err(GrantAudienceInstallError::MissingDiscover);
}
if grant.discovery.is_none() {
return Err(GrantAudienceInstallError::NoDiscoveryBinding);
}
if !secret.matches_grant(&grant) {
return Err(GrantAudienceInstallError::SecretMismatch);
}
Ok(GrantAudienceRecord {
grant,
secret,
install_seq: 0,
})
}
pub(crate) fn validate_provider_record(
grant: OrgCapabilityGrant,
secret: OrgAudienceSecret,
provider_owner_org: &OrgId,
provider_entity: &EntityId,
now_secs: u64,
skew_secs: u64,
) -> Result<GrantAudienceRecord, GrantAudienceInstallError> {
let record = validate_common(grant, secret, now_secs, skew_secs)?;
if &record.grant.issuer_org != provider_owner_org {
return Err(GrantAudienceInstallError::WrongProviderIssuer);
}
if !record
.grant
.target_scope
.covers(provider_entity, Some(provider_owner_org))
{
return Err(GrantAudienceInstallError::ProviderNotCovered);
}
Ok(record)
}
pub(crate) fn grant_active_for_emission(
grant: &OrgCapabilityGrant,
provider_entity: &EntityId,
provider_owner_org: &OrgId,
now_secs: u64,
skew_secs: u64,
) -> bool {
grant.is_valid_at_with_skew(now_secs, skew_secs).is_ok()
&& &grant.issuer_org == provider_owner_org
&& grant
.target_scope
.covers(provider_entity, Some(provider_owner_org))
}
pub(crate) fn validate_consumer_record(
grant: OrgCapabilityGrant,
secret: OrgAudienceSecret,
consumer_owner_org: &OrgId,
now_secs: u64,
skew_secs: u64,
) -> Result<GrantAudienceRecord, GrantAudienceInstallError> {
let record = validate_common(grant, secret, now_secs, skew_secs)?;
if &record.grant.grantee_org != consumer_owner_org {
return Err(GrantAudienceInstallError::WrongConsumerGrantee);
}
Ok(record)
}
#[derive(Default, Debug)]
pub struct ProviderGrantSnapshot(GrantAudienceRecords);
impl ProviderGrantSnapshot {
pub const CAPACITY: usize = MAX_PROVIDER_GRANT_AUDIENCES;
pub fn empty() -> Self {
Self::default()
}
pub fn get(&self, grant_id: &[u8; 32]) -> Option<&Arc<GrantAudienceRecord>> {
self.0.get(grant_id)
}
pub fn records(&self) -> impl Iterator<Item = &Arc<GrantAudienceRecord>> {
self.0.records()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.len() == 0
}
pub(crate) fn with_record(
&self,
record: Arc<GrantAudienceRecord>,
now_secs: u64,
) -> Result<Option<Self>, GrantAudienceInstallError> {
match self.0.reserve(&record, Self::CAPACITY, now_secs)? {
Reserved::Noop => Ok(None),
Reserved::Ready(mut next) => {
next.by_grant_id.insert(*record.grant_id(), record);
Ok(Some(Self(next)))
}
}
}
pub(crate) fn without(&self, grant_id: &[u8; 32]) -> Option<Self> {
self.0.without(grant_id).map(Self)
}
}
#[derive(Debug)]
pub struct ConsumerGrantSnapshot {
records: GrantAudienceRecords,
revision: GrantMovementFence,
}
impl Default for ConsumerGrantSnapshot {
fn default() -> Self {
Self {
records: GrantAudienceRecords::default(),
revision: GrantMovementFence::Publication(0),
}
}
}
impl ConsumerGrantSnapshot {
pub const CAPACITY: usize = MAX_CONSUMER_GRANT_AUDIENCES;
pub fn empty() -> Self {
Self::default()
}
pub(crate) fn revision(&self) -> GrantMovementFence {
self.revision
}
pub(crate) fn stamped(mut self, revision: GrantMovementFence) -> Self {
self.revision = revision;
self
}
pub fn get(&self, grant_id: &[u8; 32]) -> Option<&Arc<GrantAudienceRecord>> {
self.records.get(grant_id)
}
pub fn records(&self) -> impl Iterator<Item = &Arc<GrantAudienceRecord>> {
self.records.records()
}
pub fn len(&self) -> usize {
self.records.len()
}
pub fn is_empty(&self) -> bool {
self.records.len() == 0
}
pub(crate) fn prepare_install(
&self,
record: GrantAudienceRecord,
now_secs: u64,
) -> Result<PreparedInstall, GrantAudienceInstallError> {
match self.records.reserve(&record, Self::CAPACITY, now_secs)? {
Reserved::Noop => Ok(PreparedInstall::Noop),
Reserved::Ready(next) => Ok(PreparedInstall::Ready(Box::new(PreparedSlot {
next,
candidate: Box::new(record),
}))),
}
}
pub(crate) fn finish_install(slot: PreparedSlot, install_seq: u64) -> Self {
Self {
records: slot.finish_with_install_seq(install_seq),
revision: GrantMovementFence::Publication(0),
}
}
pub(crate) fn without(&self, grant_id: &[u8; 32]) -> Option<Self> {
self.records.without(grant_id).map(|records| Self {
records,
revision: self.revision,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::adapter::net::behavior::org::{current_timestamp, OrgKeypair};
use crate::adapter::net::behavior::org_grant::{
CapabilityAuthorityId, GrantRights, GrantTargetScope,
};
use crate::adapter::net::identity::EntityKeypair;
const SKEW: u64 = 60;
fn provider_kp() -> EntityKeypair {
EntityKeypair::from_bytes([0x21u8; 32])
}
fn provider_entity() -> EntityId {
provider_kp().entity_id().clone()
}
fn org_b() -> OrgKeypair {
OrgKeypair::from_bytes([0x42u8; 32])
}
fn org_a() -> OrgKeypair {
OrgKeypair::from_bytes([0x77u8; 32])
}
fn cap() -> CapabilityAuthorityId {
CapabilityAuthorityId::for_tag("nrpc:billing")
}
fn canonical_pair() -> (OrgCapabilityGrant, OrgAudienceSecret) {
let (grant, secret) = OrgCapabilityGrant::try_issue(
&org_b(),
org_a().org_id(),
cap(),
GrantRights::DISCOVER.union(GrantRights::INVOKE),
GrantTargetScope::ExactNode(provider_entity()),
3600,
)
.expect("issue grant");
(grant, secret.expect("DISCOVER mints a secret"))
}
#[test]
fn valid_canonical_pair_installs_both_roles() {
let now = current_timestamp();
let (g, s) = canonical_pair();
let record =
validate_provider_record(g, s, &org_b().org_id(), &provider_entity(), now, SKEW)
.expect("provider record valid");
assert_eq!(record.grant().grantee_org, org_a().org_id());
let (g, s) = canonical_pair();
let record = validate_consumer_record(g, s, &org_a().org_id(), now, SKEW)
.expect("consumer record valid");
assert_eq!(record.grant().issuer_org, org_b().org_id());
}
#[test]
fn grant_active_for_emission_rechecks_window_issuer_and_target() {
let issuer = org_b();
let owner = issuer.org_id();
let provider = provider_entity();
let exact = GrantTargetScope::ExactNode(provider.clone());
let mk = |not_before: u64, not_after: u64, target: GrantTargetScope| {
OrgCapabilityGrant::issue_at(
&issuer,
[1u8; 32],
org_a().org_id(),
cap(),
GrantRights::INVOKE,
target,
None,
not_before,
not_after,
7,
)
};
let now = 10_000u64;
let skew = 0u64;
assert!(grant_active_for_emission(
&mk(now - 100, now + 100, exact.clone()),
&provider,
&owner,
now,
skew
));
assert!(!grant_active_for_emission(
&mk(now + 50, now + 100, exact.clone()),
&provider,
&owner,
now,
skew
));
assert!(!grant_active_for_emission(
&mk(now - 100, now, exact.clone()),
&provider,
&owner,
now,
skew
));
assert!(!grant_active_for_emission(
&mk(now - 100, now + 100, exact.clone()),
&provider,
&org_a().org_id(),
now,
skew
));
let other = EntityKeypair::from_bytes([0x44u8; 32]).entity_id().clone();
assert!(!grant_active_for_emission(
&mk(now - 100, now + 100, GrantTargetScope::ExactNode(other)),
&provider,
&owner,
now,
skew
));
}
#[test]
fn provider_install_refuses_wrong_issuer_and_target() {
let now = current_timestamp();
let (g, s) = canonical_pair();
assert_eq!(
validate_provider_record(g, s, &org_a().org_id(), &provider_entity(), now, SKEW)
.unwrap_err(),
GrantAudienceInstallError::WrongProviderIssuer
);
let other = EntityKeypair::from_bytes([0x33u8; 32]).entity_id().clone();
let (g, s) = OrgCapabilityGrant::try_issue(
&org_b(),
org_a().org_id(),
cap(),
GrantRights::DISCOVER,
GrantTargetScope::ExactNode(other),
3600,
)
.expect("issue");
let s = s.expect("secret");
assert_eq!(
validate_provider_record(g, s, &org_b().org_id(), &provider_entity(), now, SKEW)
.unwrap_err(),
GrantAudienceInstallError::ProviderNotCovered
);
}
#[test]
fn consumer_install_refuses_wrong_grantee() {
let now = current_timestamp();
let (g, s) = canonical_pair();
assert_eq!(
validate_consumer_record(g, s, &org_b().org_id(), now, SKEW).unwrap_err(),
GrantAudienceInstallError::WrongConsumerGrantee
);
}
#[test]
fn invoke_only_grant_is_refused() {
let now = current_timestamp();
let (grant, secret) = OrgCapabilityGrant::try_issue(
&org_b(),
org_a().org_id(),
cap(),
GrantRights::INVOKE,
GrantTargetScope::ExactNode(provider_entity()),
3600,
)
.expect("issue invoke-only");
assert!(secret.is_none(), "INVOKE-only mints no secret");
let (_g2, other_secret) = canonical_pair();
assert_eq!(
validate_consumer_record(grant, other_secret, &org_a().org_id(), now, SKEW)
.unwrap_err(),
GrantAudienceInstallError::MissingDiscover
);
}
#[test]
fn mismatched_secret_is_refused() {
let now = current_timestamp();
let (grant, _secret) = canonical_pair();
let (_other_grant, other_secret) = OrgCapabilityGrant::try_issue(
&org_b(),
org_a().org_id(),
CapabilityAuthorityId::for_tag("nrpc:other"),
GrantRights::DISCOVER,
GrantTargetScope::ExactNode(provider_entity()),
3600,
)
.expect("issue other");
let other_secret = other_secret.expect("secret");
assert_eq!(
validate_consumer_record(grant, other_secret, &org_a().org_id(), now, SKEW)
.unwrap_err(),
GrantAudienceInstallError::SecretMismatch
);
}
fn provider_record() -> Arc<GrantAudienceRecord> {
let now = current_timestamp();
let (g, s) = canonical_pair();
Arc::new(
validate_provider_record(g, s, &org_b().org_id(), &provider_entity(), now, SKEW)
.expect("valid"),
)
}
#[test]
fn install_is_idempotent_and_conflict_is_refused() {
let now = current_timestamp();
let snap = ProviderGrantSnapshot::empty();
let record = provider_record();
let grant_id = *record.grant_id();
let snap = snap
.with_record(Arc::clone(&record), now)
.expect("install ok")
.expect("a new snapshot was produced");
assert_eq!(snap.len(), 1);
assert!(snap.get(&grant_id).is_some());
assert!(
snap.with_record(Arc::clone(&record), now)
.expect("idempotent ok")
.is_none(),
"identical re-install produces no new snapshot"
);
let (mut clashing_grant, _s) = canonical_pair();
clashing_grant.grant_id = grant_id;
let (_g, foreign_secret) = OrgCapabilityGrant::try_issue(
&org_b(),
org_a().org_id(),
CapabilityAuthorityId::for_tag("nrpc:clash"),
GrantRights::DISCOVER,
GrantTargetScope::ExactNode(provider_entity()),
3600,
)
.expect("issue");
let foreign_secret = foreign_secret.expect("secret");
let clashing = Arc::new(GrantAudienceRecord {
grant: clashing_grant,
secret: foreign_secret,
install_seq: 0,
});
assert_eq!(
snap.with_record(clashing, now).unwrap_err(),
GrantAudienceInstallError::Conflict
);
}
fn distinct_provider_record(index: u64, ttl_secs: u64) -> Arc<GrantAudienceRecord> {
let now = current_timestamp();
let mut seed = [0u8; 32];
seed[..8].copy_from_slice(&index.to_le_bytes());
let target = EntityKeypair::from_bytes(seed).entity_id().clone();
let (grant, secret) = OrgCapabilityGrant::try_issue(
&org_b(),
org_a().org_id(),
cap(),
GrantRights::DISCOVER,
GrantTargetScope::ExactNode(target.clone()),
ttl_secs,
)
.expect("issue");
let secret = secret.expect("secret");
Arc::new(
validate_provider_record(grant, secret, &org_b().org_id(), &target, now, SKEW)
.expect("valid"),
)
}
#[test]
fn capacity_is_fail_closed_and_never_evicts_active() {
let now = current_timestamp();
let mut snap = ProviderGrantSnapshot::empty();
for index in 0..ProviderGrantSnapshot::CAPACITY as u64 {
snap = snap
.with_record(distinct_provider_record(index, 3600), now)
.expect("install ok")
.expect("new snapshot");
}
assert_eq!(snap.len(), ProviderGrantSnapshot::CAPACITY);
assert_eq!(
snap.with_record(distinct_provider_record(u64::MAX, 3600), now)
.unwrap_err(),
GrantAudienceInstallError::AtCapacity
);
assert_eq!(snap.len(), ProviderGrantSnapshot::CAPACITY);
}
#[test]
fn capacity_reclaims_only_expired_records() {
let base = current_timestamp();
let mut snap = ProviderGrantSnapshot::empty();
for index in 0..ProviderGrantSnapshot::CAPACITY as u64 {
snap = snap
.with_record(distinct_provider_record(index, 120), base)
.expect("ok")
.expect("new");
}
assert_eq!(snap.len(), ProviderGrantSnapshot::CAPACITY);
let later = base + 10_000;
let fresh = snap
.with_record(distinct_provider_record(u64::MAX, 3600), later)
.expect("ok")
.expect("new after reclaim");
assert_eq!(fresh.len(), 1, "expired records were reclaimed");
}
#[test]
fn remove_is_a_noop_when_absent_and_releases_the_record_when_present() {
let now = current_timestamp();
let record = provider_record();
let grant_id = *record.grant_id();
let snap = ProviderGrantSnapshot::empty()
.with_record(Arc::clone(&record), now)
.expect("ok")
.expect("new");
assert!(snap.without(&[0xEE; 32]).is_none());
let removed = snap.without(&grant_id).expect("removed");
assert!(removed.is_empty());
drop(snap);
assert_eq!(Arc::strong_count(&record), 1);
assert_eq!(record.grant_id(), &grant_id);
}
}