Skip to main content

bacnet_objects/access_control/
authorization_context.rs

1//! Mandatory application-owned facts for local authorization.
2
3use super::{
4    AccompanimentDeadline, AccompanimentTiming, AccompanimentWitness, AuthorizationOrder,
5    AuthorizationRightsPolicy, CredentialPresentation, DisableReasonPriority,
6};
7use crate::clock::ClockFrame;
8use bacnet_types::enums::AccessPassbackMode;
9use bacnet_types::primitives::ObjectIdentifier;
10use core::time::Duration;
11
12/// A known application fact or an explicit lack of evidence. No default exists.
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum AuthorizationFact<T> {
15    /// The application supplies this value for a genuinely absent property.
16    Known(T),
17    /// Required evidence is unavailable; this does not mean disabled or zero.
18    Unknown,
19}
20
21/// Which occupancy boundary a presentation crosses for one relevant zone.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum AuthorizationDirection {
24    /// Entry is checked against a nonzero upper bound.
25    Entering,
26    /// Exit is checked against a nonzero lower bound.
27    Leaving,
28}
29
30/// One application-selected relevant zone and its enforcement fallback.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct AuthorizationOccupancyZone {
33    /// Local Access Zone whose topology/count/limits are read from the database.
34    pub zone: ObjectIdentifier,
35    /// Established direction; the matching zone point list must contain the point.
36    pub direction: AuthorizationDirection,
37    /// Used only when the point omits the direction's enforcement property.
38    pub fallback_enforced: AuthorizationFact<bool>,
39}
40
41/// The application's complete relevant-zone set; the helper invents no topology.
42#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub enum AuthorizationOccupancy<'a> {
44    /// The application establishes that this presentation affects no zone bound.
45    NotApplicable,
46    /// Relevant direction/zones are not established.
47    Unknown,
48    /// All relevant zones, evaluated in this explicit order. Empty is unresolved;
49    /// use NotApplicable to state that no zone check is needed.
50    Zones(&'a [AuthorizationOccupancyZone]),
51}
52
53/// An already established passback observation bound to this transaction/zone.
54/// This helper does not reconstruct a location history.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct AuthorizationPassbackObservation {
57    /// Complete original tuple to which the observation belongs.
58    pub presentation: CredentialPresentation,
59    /// The local zone in which the observation was established.
60    pub zone: ObjectIdentifier,
61    /// Whether a violation was established before applying timeout/exemption.
62    pub violation: bool,
63    /// Last successful entry of this credential into this zone, sharing the
64    /// monotonic origin. This is not Last_Use_Time. Required to expire a violation
65    /// under a nonzero timeout; a future entry is inconsistent.
66    pub last_successful_entry: Option<Duration>,
67}
68
69/// Passback applicability and missing-property inputs (Clauses 12.32.21–22).
70/// A PASSBACK-exempt credential still reports an established SOFT violation.
71/// Unusable optional reporting evidence is retained in
72/// [`super::AuthorizationEvaluation::passback_reporting_problem`] without
73/// imposing enforcement or another required criterion on the exempt request.
74#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum AuthorizationPassback {
76    /// The application establishes no relevant passback check for this presentation.
77    NotApplicable,
78    /// The relevant zone or passback facts are unknown.
79    Unknown,
80    /// One established local zone, its settings, and presentation observation.
81    Zone {
82        /// Local Access Zone used for the check.
83        zone: ObjectIdentifier,
84        /// Used only if Passback_Mode is genuinely absent.
85        fallback_mode: AuthorizationFact<AccessPassbackMode>,
86        /// Missing Passback_Timeout is specified to mean no expiry. This
87        /// optional fallback allows application configuration where the property
88        /// is absent; None and zero both mean no expiry, in minutes.
89        fallback_timeout_minutes: Option<u32>,
90        /// Required for unexempted HARD/SOFT enforcement/reporting. Exempt SOFT
91        /// reporting uses it when available; exempt HARD and OFF do not need it.
92        observation: AuthorizationFact<AuthorizationPassbackObservation>,
93    },
94}
95
96/// Authentication outcome for one exact companion presentation.
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub enum CompanionAuthentication {
99    /// Authentication completed for this tuple; no rights grant is asserted.
100    Authenticated,
101    /// Authentication was conclusively rejected for this tuple.
102    Rejected,
103    /// Authentication has not been established.
104    Unknown,
105}
106
107/// An application attestation bound to sequence, credential, point, and time.
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub struct CompanionAuthenticationAttestation {
110    /// Full presentation tuple. Matching only credential identity is insufficient.
111    pub presentation: CredentialPresentation,
112    /// Authentication evidence, without a caller-provided access-rights decision.
113    pub authentication: CompanionAuthentication,
114}
115
116/// External verification/delay evidence at a supplied observation time.
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
118pub enum AuthorizationVerdict {
119    /// No external verdict has arrived; the verified deadline determines expiry.
120    Waiting,
121    /// The application explicitly observed expiry; an early claim is unresolved.
122    DeadlineReached,
123    /// An approval arrived at this monotonic time. It never shortens a delay.
124    Approved(Duration),
125    /// A rejection arrived at this monotonic time.
126    Rejected(Duration),
127}
128
129/// Explicit external-phase correlation and timing, when the mode requires it.
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub enum AuthorizationExternalPhase {
132    /// No phase evidence supplied; unresolved when an unexempted mode needs it.
133    NotSupplied,
134    /// Evidence for one application-owned phase of this exact presentation.
135    Observed {
136        /// Complete original presentation tuple.
137        presentation: CredentialPresentation,
138        /// Phase start, at or after presentation and no later than `now`.
139        started: Duration,
140        /// Used only if the point omits Verification_Time, in seconds when served.
141        fallback_period: AuthorizationFact<Duration>,
142        /// Explicit boundary policy, reused from accompaniment timing.
143        deadline: AccompanimentDeadline,
144        /// Waiting, a dated verdict, or an explicit expiry claim.
145        verdict: AuthorizationVerdict,
146    },
147}
148
149/// One already-authenticated local presentation and every application-owned
150/// authorization choice. There is no Default implementation or installed policy.
151///
152/// Database properties take precedence over their narrow absent-property
153/// fallbacks. Malformed, denied, or otherwise failed reads never use a fallback.
154/// All observations belong to one coherent application context; this API does
155/// not authenticate hardware, discover remote facts, or publish events.
156#[derive(Debug, Clone, Copy)]
157pub struct AuthorizationRequest<'a> {
158    /// Authenticated original tuple; this helper is not the factor engine.
159    pub original: CredentialPresentation,
160    /// Supplied local wall-clock frame used for all credential validity checks.
161    /// Finite limits require a valid coherent frame. Two open limits do not.
162    pub wall_time: Option<ClockFrame>,
163    /// Monotonic observation time, separate from BACnet wall-clock time.
164    pub now: Duration,
165    /// Every required criterion in the caller's explicit order.
166    pub order: AuthorizationOrder,
167    /// Explicit precedence among multiple coherent disable reasons.
168    pub disable_reason_priority: DisableReasonPriority,
169    /// Explicit treatment of original and companion excluded assignments.
170    pub rights_policy: AuthorizationRightsPolicy,
171    /// Point threat level if its property is genuinely absent; range 0..100.
172    /// Zero disables the comparison without reading credential authority.
173    /// Otherwise absent credential Threat_Authority means zero by specification.
174    pub fallback_threat_level: AuthorizationFact<u32>,
175    /// Point Lockout if its property is genuinely absent.
176    pub fallback_lockout: AuthorizationFact<bool>,
177    /// Complete relevant occupancy context.
178    pub occupancy: AuthorizationOccupancy<'a>,
179    /// Passback applicability, settings, and observed successful-entry evidence.
180    pub passback: AuthorizationPassback,
181    /// Witnesses consumed by the existing bounded accompaniment stage.
182    pub accompaniment_witnesses: &'a [AccompanimentWitness],
183    /// Explicit order/period/boundary policy for selected accompaniment.
184    pub accompaniment_timing: AccompanimentTiming,
185    /// Existing accompaniment traversal bound; exhaustion cannot grant access.
186    pub max_accompaniment_links: usize,
187    /// Authentication results for each companion actually relied upon.
188    pub companion_authentication: &'a [CompanionAuthenticationAttestation],
189    /// External verification/delay observation if needed by the served mode.
190    pub external_phase: AuthorizationExternalPhase,
191}