pub trait ServerPolicy:
Send
+ Sync
+ 'static {
// Provided methods
fn decides_mutations(&self) -> bool { ... }
fn authorize_mutation(&self, context: &MutationAuthorizationContext) -> bool { ... }
fn authorize_life_safety_operation(
&self,
context: &LifeSafetyOperationAuthorizationContext,
) -> bool { ... }
fn authorize_device_communication_control(
&self,
context: &DeviceCommunicationControlAuthorizationContext,
) -> bool { ... }
fn authorize_audit_notification(
&self,
context: &AuditNotificationAuthorizationContext,
) -> bool { ... }
fn authorize_unconfirmed_audit_notification(
&self,
context: &UnconfirmedAuditNotificationAuthorizationContext,
) -> bool { ... }
}Expand description
The server’s authorization decisions, each with a documented default.
See the module documentation for what it covers, the principal
each context carries and the calling rules. Install one with
policy(..) on a server builder, or in
ServerConfig::policy.
Without any policy installed, the server behaves as these defaults do,
except that it allows a covered mutation without decoding it for
authorization first; so does a policy whose
decides_mutations is false.
Arc<P> and Box<P> are policies when P is, so one policy can be
shared or boxed.
Provided Methods§
Sourcefn decides_mutations(&self) -> bool
fn decides_mutations(&self) -> bool
Whether authorize_mutation decides
anything (default: true).
When false, the server never asks it: each covered mutation is
allowed without being decoded for authorization first, and counted as
allowed before the handler runs, exactly as with no policy. A policy
that only decides LifeSafetyOperation or Audit receipt returns false
so that mutations keep that path. The server may read it more than
once for one request, so it must give the same answer for the
policy’s lifetime.
Whether to carry out one covered mutation (default: allow).
Asked after DeviceCommunicationControl’s checks, request admission,
service decoding and element validation, and before any database
change, COV or event work, or Audit record. A denial writes no Audit
record; it is counted in BACnetServer::mutation_decision_counters
and answered SERVICES / SERVICE_REQUEST_DENIED.
MutationPolicy::DenyAll
denies without asking.
WritePropertyMultiple asks once per decoded, validated element, in wire order, up to the first it denies, all before the database is write-locked and with no database guard held (#2032); the writes follow under the lock. A denial, or a malformed later element, leaves the elements before it written. Since every element is asked about first, the policy can be asked about an element the request never reaches, when an earlier one fails as it is written. An element whose object appears between the decisions and the writes, so it was never asked about, is denied. The other confirmed services ask once, for the whole decoded request, also with no database guard held.
Every call for a received request runs on Tokio’s blocking pool while
the request waits (#2032), so a policy that blocks delays only that
request: it holds no runtime worker, and BACnetServer::stop ends
without waiting for it (the abandoned call finishes on its own and is
ignored). That costs one trip to the pool per request (a
WritePropertyMultiple’s elements share one; WriteGroup makes one per
Channel), so keep the policy quick all the same. A call that never
returns keeps its blocking thread after stop(), and a Tokio runtime
waits for blocking tasks when it shuts down, so such a policy keeps
the process from exiting. The other authorize_* methods for a
received request run the same way.
An inbound WriteGroup asks once per Channel it would write, with no database guard held, no invoke ID and the unconfirmed service in the context. A denial skips that Channel silently (nothing answers an unconfirmed request) and writes no Audit record; the other Channels are decided on their own (#1319).
Whether to carry out a LifeSafetyOperation (default: deny).
Asked after the request is validated and its object found, with no
database guard held, on Tokio’s blocking pool as
authorize_mutation is (#2032). A denial
is answered SERVICES / SERVICE_REQUEST_DENIED before the object
changes.
Whether to carry out a DeviceCommunicationControl request (default: allow).
Asked after decoding, the password, the deprecated DISABLE refusal,
the static DccPolicy and the source
restriction; a request any of them refuses never reaches the policy.
For DISABLE_INITIATION the disable rate limit is charged only after
the policy allows, so a denied requester spends none of that shared
budget. Asked with no lock held, on Tokio’s blocking pool as
authorize_mutation is (#2032), before
the timer is replaced or the state changes. A denial is answered SERVICES /
SERVICE_REQUEST_DENIED, changes neither the state nor a running
timer, writes no Audit record and is counted in
BACnetServer::dcc_outcome_counters as policy_denied_total, which
also counts the static source and rate-limit refusals.
Whether to store a ConfirmedAuditNotification in the configured Audit Log sink (default: deny).
Asked after the request is decoded and checked against completed
receipts, with no database guard held, on Tokio’s blocking pool as
authorize_mutation is (#2032). A denial
is answered SERVICES / SERVICE_REQUEST_DENIED and stores nothing.
Whether to store an UnconfirmedAuditNotification in the configured Audit Log sink (default: deny).
Asked after the request is decoded, with no database guard held, on
Tokio’s blocking pool as
authorize_mutation is (#2032). A denial
drops the request silently and stores nothing.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".