Skip to main content

signstar_config/config/file/
impl_all.rs

1//! Impls for [`UserBackendConnection`] and [`Config`] when using all HSM backends.
2//!
3//! # Note
4//!
5//! This module with `impl` blocks is only used, if all HSM backend features are used:
6//!
7//! - `nethsm`: for NetHSM backends
8//! - `yubihsm2`: for YubiHSM2 backends
9
10use std::collections::HashSet;
11
12use signstar_common::backend::BackendType;
13use signstar_crypto::{
14    AdministrativeSecretHandling,
15    NonAdministrativeSecretHandling,
16    traits::UserWithPassphrase,
17};
18
19use crate::{
20    config::{
21        AuthorizedKeyEntry,
22        Config,
23        ConfigAuthorizedKeyEntries,
24        ConfigBuilder,
25        ConfigSystemUserData,
26        ConfigSystemUserIds,
27        MappingAuthorizedKeyEntry,
28        MappingBackendUserSecrets,
29        MappingSystemUserId,
30        SystemConfig,
31        SystemUserData,
32        SystemUserId,
33        UserBackendConnection,
34        UserBackendConnectionFilter,
35        traits::NonAdminBackendUserIdFilter,
36    },
37    nethsm::NetHsmUserMapping,
38    yubihsm2::YubiHsm2UserMapping,
39};
40
41impl UserBackendConnection {
42    /// Returns the administrative secret handling of this [`UserBackendConnection`].
43    pub fn admin_secret_handling(&self) -> AdministrativeSecretHandling {
44        match self {
45            Self::NetHsm {
46                admin_secret_handling,
47                ..
48            } => *admin_secret_handling,
49            Self::YubiHsm2 {
50                admin_secret_handling,
51                ..
52            } => *admin_secret_handling,
53        }
54    }
55
56    /// Returns the non-administrative secret handling of this [`UserBackendConnection`].
57    pub fn non_admin_secret_handling(&self) -> NonAdministrativeSecretHandling {
58        match self {
59            Self::NetHsm {
60                non_admin_secret_handling,
61                ..
62            } => *non_admin_secret_handling,
63            Self::YubiHsm2 {
64                non_admin_secret_handling,
65                ..
66            } => *non_admin_secret_handling,
67        }
68    }
69
70    /// Creates on-disk secrets for non-administrative backend users of the mapping.
71    ///
72    /// # Note
73    ///
74    /// Delegates to [`MappingBackendUserSecrets::create_non_admin_backend_user_secrets`].
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if [`MappingBackendUserSecrets::create_non_admin_backend_user_secrets`]
79    /// fails.
80    pub fn create_non_admin_backend_user_secrets(
81        &self,
82    ) -> Result<Option<Vec<Box<dyn UserWithPassphrase>>>, crate::Error> {
83        match self {
84            Self::NetHsm {
85                non_admin_secret_handling,
86                mapping,
87                ..
88            } => mapping.create_non_admin_backend_user_secrets(*non_admin_secret_handling),
89            Self::YubiHsm2 {
90                non_admin_secret_handling,
91                mapping,
92                ..
93            } => mapping.create_non_admin_backend_user_secrets(*non_admin_secret_handling),
94        }
95    }
96
97    /// Loads secrets for each backend user matching a `filter`.
98    ///
99    /// # Note
100    ///
101    /// Delegates to [`MappingBackendUserSecrets::load_non_admin_backend_user_secrets`].
102    ///
103    /// # Errors
104    ///
105    /// Returns an error if [`MappingBackendUserSecrets::load_non_admin_backend_user_secrets`]
106    /// fails.
107    pub fn load_non_admin_backend_user_secrets(
108        &self,
109        filter: NonAdminBackendUserIdFilter,
110    ) -> Result<Option<Vec<Box<dyn UserWithPassphrase>>>, crate::Error> {
111        match self {
112            Self::NetHsm {
113                non_admin_secret_handling,
114                mapping,
115                ..
116            } => mapping.load_non_admin_backend_user_secrets(*non_admin_secret_handling, filter),
117            Self::YubiHsm2 {
118                non_admin_secret_handling,
119                mapping,
120                ..
121            } => mapping.load_non_admin_backend_user_secrets(*non_admin_secret_handling, filter),
122        }
123    }
124}
125
126impl MappingSystemUserId for UserBackendConnection {
127    fn system_user_id(&self) -> Option<&SystemUserId> {
128        match self {
129            Self::NetHsm { mapping, .. } => mapping.system_user_id(),
130            Self::YubiHsm2 { mapping, .. } => mapping.system_user_id(),
131        }
132    }
133}
134
135impl MappingAuthorizedKeyEntry for UserBackendConnection {
136    fn authorized_key_entry(&self) -> Option<&AuthorizedKeyEntry> {
137        match self {
138            Self::NetHsm { mapping, .. } => mapping.authorized_key_entry(),
139            Self::YubiHsm2 { mapping, .. } => mapping.authorized_key_entry(),
140        }
141    }
142}
143
144impl Config {
145    /// Returns the optional [`UserBackendConnection`] matching a [`SystemUserId`].
146    pub fn user_backend_connection(&self, user: &SystemUserId) -> Option<UserBackendConnection> {
147        if let Some(nethsm_config) = self.nethsm.as_ref()
148            && let Some(mapping) = nethsm_config
149                .mappings()
150                .iter()
151                .find(|mapping| mapping.system_user_id().is_some_and(|id| id == user))
152        {
153            return Some(UserBackendConnection::NetHsm {
154                admin_secret_handling: *self.system.admin_secret_handling(),
155                non_admin_secret_handling: *self.system.non_admin_secret_handling(),
156                connections: nethsm_config.connections().clone(),
157                mapping: mapping.clone(),
158            });
159        }
160
161        if let Some(yubihsm2_config) = self.yubihsm2.as_ref()
162            && let Some(mapping) = yubihsm2_config
163                .mappings()
164                .iter()
165                .find(|mapping| mapping.system_user_id().is_some_and(|id| id == user))
166        {
167            return Some(UserBackendConnection::YubiHsm2 {
168                admin_secret_handling: *self.system.admin_secret_handling(),
169                non_admin_secret_handling: *self.system.non_admin_secret_handling(),
170                connections: yubihsm2_config.connections().clone(),
171                mapping: mapping.clone(),
172            });
173        }
174
175        None
176    }
177
178    /// Returns a list of [`UserBackendConnection`] objects matching a set of `filters`.
179    ///
180    /// If no `filters` are provided, returns all available [`UserBackendConnection`] objects of all
181    /// backends.
182    ///
183    /// Beyond filtering for specific backend types, it is possible to only return administrative or
184    /// non-administrative objects.
185    pub fn user_backend_connections(
186        &self,
187        filters: &[UserBackendConnectionFilter],
188    ) -> Vec<UserBackendConnection> {
189        let mut user_backend_connections = Vec::new();
190
191        if let Some(nethsm_config) = &self.nethsm
192            && (filters.is_empty()
193                || filters.contains(&UserBackendConnectionFilter::Backend(BackendType::NetHsm))
194                || !filters
195                    .iter()
196                    .any(|filter| matches!(filter, UserBackendConnectionFilter::Backend(_))))
197        {
198            let mappings = nethsm_config
199                .mappings()
200                .iter()
201                .filter(|mapping| {
202                    filters.is_empty()
203                        || (matches!(mapping, NetHsmUserMapping::Admin(_))
204                            && filters.contains(&UserBackendConnectionFilter::Admin))
205                        || (!matches!(mapping, NetHsmUserMapping::Admin(_))
206                            && filters.contains(&UserBackendConnectionFilter::NonAdmin))
207                })
208                .collect::<Vec<_>>();
209            for mapping in mappings {
210                user_backend_connections.push(UserBackendConnection::NetHsm {
211                    admin_secret_handling: *self.system.admin_secret_handling(),
212                    non_admin_secret_handling: *self.system.non_admin_secret_handling(),
213                    connections: nethsm_config.connections().clone(),
214                    mapping: mapping.clone(),
215                });
216            }
217        }
218
219        if let Some(yubihsm2_config) = &self.yubihsm2
220            && (filters.is_empty()
221                || filters.contains(&UserBackendConnectionFilter::Backend(BackendType::YubiHsm2))
222                || !filters
223                    .iter()
224                    .any(|filter| matches!(filter, UserBackendConnectionFilter::Backend(_))))
225        {
226            let mappings = yubihsm2_config
227                .mappings()
228                .iter()
229                .filter(|mapping| {
230                    filters.is_empty()
231                        || (matches!(mapping, YubiHsm2UserMapping::Admin { .. })
232                            && filters.contains(&UserBackendConnectionFilter::Admin))
233                        || (!matches!(mapping, YubiHsm2UserMapping::Admin { .. })
234                            && filters.contains(&UserBackendConnectionFilter::NonAdmin))
235                })
236                .collect::<Vec<_>>();
237            for mapping in mappings {
238                user_backend_connections.push(UserBackendConnection::YubiHsm2 {
239                    admin_secret_handling: *self.system.admin_secret_handling(),
240                    non_admin_secret_handling: *self.system.non_admin_secret_handling(),
241                    connections: yubihsm2_config.connections().clone(),
242                    mapping: mapping.clone(),
243                });
244            }
245        }
246
247        user_backend_connections
248    }
249}
250
251impl ConfigAuthorizedKeyEntries for Config {
252    fn authorized_key_entries(&self) -> HashSet<&AuthorizedKeyEntry> {
253        let mut output = self.system.authorized_key_entries();
254        if let Some(nethsm) = &self.nethsm {
255            output.extend(nethsm.authorized_key_entries());
256        }
257        if let Some(yubihsm2) = &self.yubihsm2 {
258            output.extend(yubihsm2.authorized_key_entries());
259        }
260
261        output
262    }
263}
264
265impl<'a> ConfigSystemUserData<'a> for Config {
266    fn system_user_data(&'a self) -> HashSet<SystemUserData<'a>> {
267        let mut output = HashSet::new();
268
269        for mapping in self.system.mappings() {
270            output.insert(mapping.into());
271        }
272
273        if let Some(config) = self.nethsm() {
274            for mapping in config.mappings() {
275                output.insert(mapping.into());
276            }
277        }
278
279        if let Some(config) = self.yubihsm2() {
280            for mapping in config.mappings() {
281                output.insert(mapping.into());
282            }
283        }
284
285        output
286    }
287}
288
289impl ConfigSystemUserIds for Config {
290    fn system_user_ids(&self) -> HashSet<&SystemUserId> {
291        let mut output = self.system.system_user_ids();
292        if let Some(nethsm) = &self.nethsm {
293            output.extend(nethsm.system_user_ids());
294        }
295        if let Some(yubihsm2) = &self.yubihsm2 {
296            output.extend(yubihsm2.system_user_ids());
297        }
298
299        output
300    }
301}
302
303impl ConfigBuilder {
304    /// Creates a new [`ConfigBuilder`].
305    pub fn new(system: SystemConfig) -> Self {
306        Self(Config {
307            system,
308            nethsm: None,
309            yubihsm2: None,
310        })
311    }
312}