Skip to main content

rocketmq_auth/credential_rotation/
model.rs

1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::BreakGlassReason;
16use super::CredentialDescriptor;
17use super::CredentialId;
18
19/// Request-path source that accepted a proof.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum CredentialVerificationSource {
22    /// The active credential accepted the proof.
23    Active,
24    /// The retiring credential accepted the proof during its overlap window.
25    Retiring,
26    /// The enabled emergency credential accepted the proof.
27    BreakGlass,
28}
29
30/// Accepted proof, identifying the credential, rotation generation, and source.
31#[derive(Clone, PartialEq, Eq)]
32pub struct CredentialVerification {
33    pub(super) credential_id: CredentialId,
34    pub(super) generation: u64,
35    pub(super) source: CredentialVerificationSource,
36}
37
38impl std::fmt::Debug for CredentialVerification {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        f.debug_struct("CredentialVerification")
41            .field("credential_id", &"[REDACTED]")
42            .field("generation", &self.generation)
43            .field("source", &self.source)
44            .finish()
45    }
46}
47
48impl CredentialVerification {
49    /// Returns the identifier of the credential that accepted the proof.
50    pub fn credential_id(&self) -> &CredentialId {
51        &self.credential_id
52    }
53
54    /// Returns the rotation generation used to verify the proof.
55    pub const fn generation(&self) -> u64 {
56        self.generation
57    }
58
59    /// Returns the credential source that accepted the proof.
60    pub const fn source(&self) -> CredentialVerificationSource {
61        self.source
62    }
63}
64
65/// Previous active credential retained until the overlap window ends.
66#[derive(Clone, PartialEq, Eq)]
67pub struct RetiringCredentialSnapshot {
68    pub(super) credential: CredentialDescriptor,
69    pub(super) accept_until_unix_seconds: u64,
70}
71
72impl std::fmt::Debug for RetiringCredentialSnapshot {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        f.debug_struct("RetiringCredentialSnapshot")
75            .field("credential", &"[REDACTED]")
76            .field("accept_until_unix_seconds", &self.accept_until_unix_seconds)
77            .finish()
78    }
79}
80
81impl RetiringCredentialSnapshot {
82    /// Returns the retiring credential's descriptor without its secret material.
83    pub fn credential(&self) -> &CredentialDescriptor {
84        &self.credential
85    }
86
87    /// Returns the exclusive end of the overlap window, in Unix seconds.
88    pub const fn accept_until_unix_seconds(&self) -> u64 {
89        self.accept_until_unix_seconds
90    }
91}
92
93/// Activation state of the emergency credential in a rotation snapshot.
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub enum BreakGlassStatus {
96    /// No emergency credential is configured.
97    NotConfigured,
98    /// An emergency credential is configured but has no active enablement.
99    Disabled {
100        /// Descriptor of the configured emergency credential.
101        credential: CredentialDescriptor,
102    },
103    /// An emergency credential has an enablement with an expiry and audit reason.
104    Enabled {
105        /// Descriptor of the enabled emergency credential.
106        credential: CredentialDescriptor,
107        /// Exclusive enablement expiry, in Unix seconds.
108        expires_at_unix_seconds: u64,
109        /// Recorded reason for enabling emergency access.
110        reason: BreakGlassReason,
111    },
112}
113
114/// Immutable view of one credential-rotation generation without secret material.
115#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct CredentialRotationSnapshot {
117    pub(super) generation: u64,
118    pub(super) active: CredentialDescriptor,
119    pub(super) retiring: Option<RetiringCredentialSnapshot>,
120    pub(super) revoked: Vec<CredentialId>,
121    pub(super) break_glass: BreakGlassStatus,
122}
123
124impl CredentialRotationSnapshot {
125    /// Returns the generation shared by all state in this snapshot.
126    pub const fn generation(&self) -> u64 {
127        self.generation
128    }
129
130    /// Returns the active credential's descriptor.
131    pub fn active(&self) -> &CredentialDescriptor {
132        &self.active
133    }
134
135    /// Returns the previous active credential and overlap deadline, if retained.
136    pub fn retiring(&self) -> Option<&RetiringCredentialSnapshot> {
137        self.retiring.as_ref()
138    }
139
140    /// Returns credential identifiers denied verification in this generation.
141    pub fn revoked(&self) -> &[CredentialId] {
142        &self.revoked
143    }
144
145    /// Returns the configured emergency credential's activation state.
146    pub const fn break_glass(&self) -> &BreakGlassStatus {
147        &self.break_glass
148    }
149}