bacnet_objects/access_control/
authorization.rs1use super::*;
4use crate::database::ObjectDatabase;
5use bacnet_types::enums::{AuthorizationExemption, AuthorizationMode, ObjectType};
6
7#[path = "authorization_checks.rs"]
8mod checks;
9#[path = "authorization_credential.rs"]
10mod credential;
11#[path = "authorization_phase.rs"]
12mod phase;
13#[path = "authorization_read.rs"]
14mod read;
15#[path = "authorization_rights.rs"]
16mod rights;
17
18pub fn evaluate_authorization(
56 db: &ObjectDatabase,
57 request: AuthorizationRequest<'_>,
58) -> Result<AuthorizationEvaluation, Error> {
59 read::object(
60 db,
61 request.original.credential,
62 ObjectType::ACCESS_CREDENTIAL,
63 )?;
64 read::object(db, request.original.point, ObjectType::ACCESS_POINT)?;
65 let mut result = AuthorizationEvaluation {
66 original: request.original,
67 mode: None,
68 outcome: AuthorizationOutcome::NoAuthorization,
69 checks: Vec::new(),
70 rights: None,
71 accompaniment: None,
72 credentials: Vec::new(),
73 companion_diagnostics: Vec::new(),
74 passback_reporting_problem: None,
75 events: Vec::new(),
76 };
77 let mode = match read::mode(db, request.original.point) {
78 Ok(mode) => mode,
79 Err(problem) => {
80 result.record(
81 AuthorizationStage::Admission,
82 AuthorizationCheckOutcome::Unresolved(problem),
83 );
84 return Ok(result);
85 }
86 };
87 result.mode = Some(mode);
88 if mode == AuthorizationMode::NONE {
89 return Ok(result);
90 }
91 if request.now < request.original.at {
92 result.record(
93 AuthorizationStage::Admission,
94 AuthorizationCheckOutcome::Unresolved(AuthorizationProblem::Context(
95 "original presentation is after observation time",
96 )),
97 );
98 return Ok(result);
99 }
100 let exemptions = match read::exemptions(db, request.original.credential) {
101 Ok(exemptions) => exemptions,
102 Err(problem) => {
103 result.record(
104 AuthorizationStage::Admission,
105 AuthorizationCheckOutcome::Unresolved(problem),
106 );
107 return Ok(result);
108 }
109 };
110 for check in request.order.checks() {
111 let outcome = match *check {
112 AuthorizationCheck::Credential => {
113 credential::check(db, &request, request.original, &mut result).map(|denial| {
114 denial.map_or(AuthorizationCheckOutcome::Passed, |(_, event)| {
115 AuthorizationCheckOutcome::Denied(event)
116 })
117 })
118 }
119 AuthorizationCheck::AccessRights => {
120 rights::check(db, &request, mode, &exemptions, &mut result)
121 }
122 other => checks::check(db, &request, mode, &exemptions, other, &mut result),
123 }
124 .unwrap_or_else(AuthorizationCheckOutcome::Unresolved);
125 if !result.record(AuthorizationStage::Criterion(*check), outcome) {
126 return Ok(result);
127 }
128 }
129 if let Some((stage, outcome)) = phase::check(db, &request, mode, &exemptions, &mut result)
130 && !result.record(stage, outcome)
131 {
132 return Ok(result);
133 }
134 result.outcome = AuthorizationOutcome::Granted;
135 result.event(AccessEvent::GRANTED, request.original);
136 Ok(result)
137}
138
139impl AuthorizationEvaluation {
140 fn record(&mut self, stage: AuthorizationStage, outcome: AuthorizationCheckOutcome) -> bool {
141 self.checks.push(AuthorizationCheckEvidence {
142 stage,
143 outcome: outcome.clone(),
144 });
145 match outcome {
146 AuthorizationCheckOutcome::Passed
147 | AuthorizationCheckOutcome::Exempt(_)
148 | AuthorizationCheckOutcome::NotApplicable => true,
149 AuthorizationCheckOutcome::Denied(access_event) => {
150 self.outcome = AuthorizationOutcome::Denied {
151 stage,
152 access_event,
153 };
154 self.event(access_event, self.original);
155 false
156 }
157 AuthorizationCheckOutcome::Pending => {
158 self.outcome = AuthorizationOutcome::Pending(stage);
159 false
160 }
161 AuthorizationCheckOutcome::Unresolved(problem) => {
162 self.outcome = AuthorizationOutcome::Unresolved { stage, problem };
163 false
164 }
165 }
166 }
167
168 fn event(&mut self, access_event: AccessEvent, presentation: CredentialPresentation) {
169 self.events.push(AuthorizationEventIntent {
170 original: self.original,
171 access_event,
172 presentation,
173 });
174 }
175}