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