nethsm_config/mapping.rs
1use std::collections::HashSet;
2
3#[cfg(doc)]
4use nethsm::NetHsm;
5use nethsm::{Connection, KeyId, SigningKeySetup, UserId};
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 AdministrativeSecretHandling,
10 AuthorizedKeyEntry,
11 AuthorizedKeyEntryList,
12 HermeticParallelConfig,
13 NonAdministrativeSecretHandling,
14 SystemUserId,
15 SystemWideUserId,
16};
17
18/// Errors related to mapping
19#[derive(Debug, thiserror::Error)]
20pub enum Error {
21 /// A duplicate top-level [`KeyId`]
22 #[error("Duplicate top-level NetHsm key {key}")]
23 DuplicateKey { key: KeyId },
24
25 /// A duplicate namespaced [`KeyId`]
26 #[error("Duplicate NetHsm key {key} in namespace {namespace}")]
27 DuplicateKeyInNamespace { namespace: String, key: KeyId },
28
29 /// A duplicate [`UserId`]
30 #[error("Duplicate NetHsm user {nethsm_user}")]
31 DuplicateNetHsmUser { nethsm_user: UserId },
32
33 /// A [`UserId`] is used both for a user in the [`Metrics`][`nethsm::UserRole::Metrics`] and
34 /// [`Operator`][`nethsm::UserRole::Operator`] role
35 #[error("The NetHsm user {metrics_user} is both in the Metrics and Operator role!")]
36 MetricsAlsoOperator { metrics_user: SystemWideUserId },
37}
38
39/// A set of users with unique [`UserId`]s, used for metrics retrieval
40///
41/// This struct tracks a user that is intended for the use in the
42/// [`Metrics`][`nethsm::UserRole::Metrics`] role and a list of users, that are intended to be used
43/// in the [`Operator`][`nethsm::UserRole::Operator`] role.
44#[derive(Clone, Debug, Deserialize, Hash, Eq, PartialEq, Serialize)]
45pub struct NetHsmMetricsUsers {
46 metrics_user: SystemWideUserId,
47 operator_users: Vec<UserId>,
48}
49
50impl NetHsmMetricsUsers {
51 /// Creates a new [`NetHsmMetricsUsers`]
52 ///
53 /// # Error
54 ///
55 /// Returns an error, if the provided [`UserId`] of the `metrics_user` is duplicated in the
56 /// provided `operator_users`.
57 ///
58 /// # Examples
59 ///
60 /// ```
61 /// use nethsm_config::NetHsmMetricsUsers;
62 ///
63 /// # fn main() -> testresult::TestResult {
64 /// NetHsmMetricsUsers::new(
65 /// "metrics1".parse()?,
66 /// vec!["user1".parse()?, "user2".parse()?],
67 /// )?;
68 ///
69 /// // this fails because there are duplicate UserIds
70 /// assert!(
71 /// NetHsmMetricsUsers::new(
72 /// "metrics1".parse()?,
73 /// vec!["metrics1".parse()?, "user2".parse()?,],
74 /// )
75 /// .is_err()
76 /// );
77 /// # Ok(())
78 /// # }
79 /// ```
80 pub fn new(metrics_user: SystemWideUserId, operator_users: Vec<UserId>) -> Result<Self, Error> {
81 // prevent duplicate metrics and operator users
82 if operator_users.contains(&metrics_user.clone().into()) {
83 return Err(Error::MetricsAlsoOperator { metrics_user });
84 }
85
86 Ok(Self {
87 metrics_user,
88 operator_users,
89 })
90 }
91
92 /// Returns all tracked [`UserId`]s of the [`NetHsmMetricsUsers`]
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// use nethsm::UserId;
98 /// use nethsm_config::NetHsmMetricsUsers;
99 ///
100 /// # fn main() -> testresult::TestResult {
101 /// let nethsm_metrics_users = NetHsmMetricsUsers::new(
102 /// "metrics1".parse()?,
103 /// vec!["user1".parse()?, "user2".parse()?],
104 /// )?;
105 ///
106 /// assert_eq!(
107 /// nethsm_metrics_users.get_users(),
108 /// vec![
109 /// UserId::new("metrics1".to_string())?,
110 /// UserId::new("user1".to_string())?,
111 /// UserId::new("user2".to_string())?
112 /// ]
113 /// );
114 /// # Ok(())
115 /// # }
116 /// ```
117 pub fn get_users(&self) -> Vec<UserId> {
118 [
119 vec![self.metrics_user.clone().into()],
120 self.operator_users.clone(),
121 ]
122 .concat()
123 }
124}
125
126/// User mapping between system users and [`NetHsm`][`nethsm::NetHsm`] users
127#[derive(Clone, Debug, Deserialize, Hash, Eq, PartialEq, Serialize)]
128pub enum UserMapping {
129 /// A NetHsm user in the Administrator role, without a system user mapped to it
130 #[serde(rename = "nethsm_only_admin")]
131 NetHsmOnlyAdmin(UserId),
132
133 /// A system user, with SSH access, mapped to a system-wide [`NetHsm`][`nethsm::NetHsm`] user
134 /// in the Backup role
135 #[serde(rename = "system_nethsm_backup")]
136 SystemNetHsmBackup {
137 nethsm_user: SystemWideUserId,
138 ssh_authorized_key: AuthorizedKeyEntry,
139 system_user: SystemUserId,
140 },
141
142 /// A system user, with SSH access, mapped to a system-wide [`NetHsm`][`nethsm::NetHsm`] user
143 /// in the Metrics role and `n` users in the Operator role with read-only access to zero or
144 /// more keys
145 #[serde(rename = "system_nethsm_metrics")]
146 SystemNetHsmMetrics {
147 nethsm_users: NetHsmMetricsUsers,
148 ssh_authorized_key: AuthorizedKeyEntry,
149 system_user: SystemUserId,
150 },
151
152 /// A system user, with SSH access, mapped to a [`NetHsm`][`nethsm::NetHsm`] user in the
153 /// Operator role with access to a single signing key.
154 ///
155 /// Signing key and NetHSM user are mapped using a tag.
156 #[serde(rename = "system_nethsm_operator_signing")]
157 SystemNetHsmOperatorSigning {
158 nethsm_user: UserId,
159 nethsm_key_setup: SigningKeySetup,
160 ssh_authorized_key: AuthorizedKeyEntry,
161 system_user: SystemUserId,
162 tag: String,
163 },
164
165 /// A system user, without SSH access, mapped to a system-wide [`NetHsm`][`nethsm::NetHsm`]
166 /// user in the Metrics role and one or more NetHsm users in the Operator role with
167 /// read-only access to zero or more keys
168 #[serde(rename = "hermetic_system_nethsm_metrics")]
169 HermeticSystemNetHsmMetrics {
170 nethsm_users: NetHsmMetricsUsers,
171 system_user: SystemUserId,
172 },
173
174 /// A system user, with SSH access for one or more SSH keys, not mapped to any NetHsm user,
175 /// used for downloading shares of a shared secret
176 #[serde(rename = "system_only_share_download")]
177 SystemOnlyShareDownload {
178 system_user: SystemUserId,
179 ssh_authorized_keys: AuthorizedKeyEntryList,
180 },
181
182 /// A system user, with SSH access for one or more SSH keys, not mapped to any NetHsm user,
183 /// used for uploading shares of a shared secret
184 #[serde(rename = "system_only_share_upload")]
185 SystemOnlyShareUpload {
186 system_user: SystemUserId,
187 ssh_authorized_keys: AuthorizedKeyEntryList,
188 },
189
190 /// A system user, with SSH access for one or more SSH keys, not mapped to any NetHsm user,
191 /// used for downloading WireGuard configuration
192 #[serde(rename = "system_only_wireguard_download")]
193 SystemOnlyWireGuardDownload {
194 system_user: SystemUserId,
195 ssh_authorized_keys: AuthorizedKeyEntryList,
196 },
197}
198
199impl UserMapping {
200 /// Returns the optional system user of the mapping
201 ///
202 /// # Examples
203 ///
204 /// ```
205 /// use nethsm_config::{AuthorizedKeyEntryList, SystemUserId, UserMapping};
206 ///
207 /// # fn main() -> testresult::TestResult {
208 /// let mapping = UserMapping::SystemOnlyShareDownload {
209 /// system_user: "user1".parse()?,
210 /// ssh_authorized_keys: AuthorizedKeyEntryList::new(vec!["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?])?,
211 /// };
212 /// assert_eq!(mapping.get_system_user(), Some(&SystemUserId::new("user1".to_string())?));
213 ///
214 /// let mapping = UserMapping::NetHsmOnlyAdmin("user1".parse()?);
215 /// assert_eq!(mapping.get_system_user(), None);
216 /// # Ok(())
217 /// # }
218 /// ```
219 pub fn get_system_user(&self) -> Option<&SystemUserId> {
220 match self {
221 UserMapping::NetHsmOnlyAdmin(_) => None,
222 UserMapping::SystemNetHsmBackup {
223 nethsm_user: _,
224 ssh_authorized_key: _,
225 system_user,
226 }
227 | UserMapping::SystemNetHsmOperatorSigning {
228 nethsm_user: _,
229 nethsm_key_setup: _,
230 ssh_authorized_key: _,
231 system_user,
232 tag: _,
233 }
234 | UserMapping::SystemNetHsmMetrics {
235 nethsm_users: _,
236 ssh_authorized_key: _,
237 system_user,
238 }
239 | UserMapping::HermeticSystemNetHsmMetrics {
240 nethsm_users: _,
241 system_user,
242 }
243 | UserMapping::SystemOnlyShareDownload {
244 system_user,
245 ssh_authorized_keys: _,
246 }
247 | UserMapping::SystemOnlyShareUpload {
248 system_user,
249 ssh_authorized_keys: _,
250 }
251 | UserMapping::SystemOnlyWireGuardDownload {
252 system_user,
253 ssh_authorized_keys: _,
254 } => Some(system_user),
255 }
256 }
257
258 /// Returns the NetHsm users of the mapping
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use nethsm::UserId;
264 /// use nethsm_config::{AuthorizedKeyEntryList, UserMapping};
265 ///
266 /// # fn main() -> testresult::TestResult {
267 /// let mapping = UserMapping::SystemOnlyShareDownload {
268 /// system_user: "user1".parse()?,
269 /// ssh_authorized_keys: AuthorizedKeyEntryList::new(vec!["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?])?,
270 /// };
271 /// assert!(mapping.get_nethsm_users().is_empty());
272 ///
273 /// let mapping = UserMapping::NetHsmOnlyAdmin("user1".parse()?);
274 /// assert_eq!(mapping.get_nethsm_users(), vec![UserId::new("user1".to_string())?]);
275 /// # Ok(())
276 /// # }
277 /// ```
278 pub fn get_nethsm_users(&self) -> Vec<UserId> {
279 match self {
280 UserMapping::SystemNetHsmBackup {
281 nethsm_user,
282 system_user: _,
283 ssh_authorized_key: _,
284 } => vec![nethsm_user.clone().into()],
285 UserMapping::NetHsmOnlyAdmin(nethsm_user)
286 | UserMapping::SystemNetHsmOperatorSigning {
287 nethsm_user,
288 nethsm_key_setup: _,
289 system_user: _,
290 ssh_authorized_key: _,
291 tag: _,
292 } => vec![nethsm_user.clone()],
293 UserMapping::SystemNetHsmMetrics {
294 nethsm_users,
295 system_user: _,
296 ssh_authorized_key: _,
297 }
298 | UserMapping::HermeticSystemNetHsmMetrics {
299 nethsm_users,
300 system_user: _,
301 } => nethsm_users.get_users(),
302 UserMapping::SystemOnlyShareDownload {
303 system_user: _,
304 ssh_authorized_keys: _,
305 }
306 | UserMapping::SystemOnlyShareUpload {
307 system_user: _,
308 ssh_authorized_keys: _,
309 }
310 | UserMapping::SystemOnlyWireGuardDownload {
311 system_user: _,
312 ssh_authorized_keys: _,
313 } => vec![],
314 }
315 }
316
317 /// Returns the SSH authorized keys of the mapping
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// use nethsm_config::{AuthorizedKeyEntry, AuthorizedKeyEntryList, UserMapping};
323 ///
324 /// # fn main() -> testresult::TestResult {
325 /// let mapping = UserMapping::SystemOnlyShareDownload {
326 /// system_user: "user1".parse()?,
327 /// ssh_authorized_keys: AuthorizedKeyEntryList::new(vec!["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?])?,
328 /// };
329 /// assert_eq!(mapping.get_ssh_authorized_keys(), vec![AuthorizedKeyEntry::new("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".to_string())?]);
330 ///
331 /// let mapping = UserMapping::NetHsmOnlyAdmin("user1".parse()?);
332 /// assert_eq!(mapping.get_ssh_authorized_keys(), vec![]);
333 /// # Ok(())
334 /// # }
335 /// ```
336 pub fn get_ssh_authorized_keys(&self) -> Vec<AuthorizedKeyEntry> {
337 match self {
338 UserMapping::NetHsmOnlyAdmin(_) => vec![],
339 UserMapping::SystemNetHsmBackup {
340 nethsm_user: _,
341 system_user: _,
342 ssh_authorized_key,
343 }
344 | UserMapping::SystemNetHsmOperatorSigning {
345 nethsm_user: _,
346 nethsm_key_setup: _,
347 system_user: _,
348 ssh_authorized_key,
349 tag: _,
350 } => vec![ssh_authorized_key.clone()],
351 UserMapping::SystemNetHsmMetrics {
352 nethsm_users: _,
353 system_user: _,
354 ssh_authorized_key,
355 } => vec![ssh_authorized_key.clone()],
356 UserMapping::HermeticSystemNetHsmMetrics {
357 nethsm_users: _,
358 system_user: _,
359 } => vec![],
360 UserMapping::SystemOnlyShareDownload {
361 system_user: _,
362 ssh_authorized_keys,
363 }
364 | UserMapping::SystemOnlyShareUpload {
365 system_user: _,
366 ssh_authorized_keys,
367 }
368 | UserMapping::SystemOnlyWireGuardDownload {
369 system_user: _,
370 ssh_authorized_keys,
371 } => ssh_authorized_keys.into(),
372 }
373 }
374
375 /// Returns all used [`KeyId`]s of the mapping
376 ///
377 /// # Examples
378 ///
379 /// ```
380 /// use nethsm::{CryptographicKeyContext, KeyId, OpenPgpUserIdList, SigningKeySetup};
381 /// use nethsm_config::{AuthorizedKeyEntryList, UserMapping};
382 ///
383 /// # fn main() -> testresult::TestResult {
384 /// let mapping = UserMapping::SystemNetHsmOperatorSigning {
385 /// nethsm_user: "user1".parse()?,
386 /// nethsm_key_setup: SigningKeySetup::new(
387 /// "key1".parse()?,
388 /// "Curve25519".parse()?,
389 /// vec!["EdDsaSignature".parse()?],
390 /// None,
391 /// "EdDsa".parse()?,
392 /// CryptographicKeyContext::OpenPgp{
393 /// user_ids: OpenPgpUserIdList::new(vec!["John Doe <john@example.org>".parse()?])?,
394 /// version: "v4".parse()?,
395 /// },
396 /// )?,
397 /// system_user: "ssh-user1".parse()?,
398 /// ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?,
399 /// tag: "tag1".to_string(),
400 /// };
401 /// assert_eq!(mapping.get_key_ids(None), vec![KeyId::new("key1".to_string())?]);
402 ///
403 /// let mapping = UserMapping::SystemOnlyShareDownload {
404 /// system_user: "user1".parse()?,
405 /// ssh_authorized_keys: AuthorizedKeyEntryList::new(vec!["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?])?,
406 /// };
407 /// assert_eq!(mapping.get_key_ids(None), vec![]);
408 /// # Ok(())
409 /// # }
410 /// ```
411 pub fn get_key_ids(&self, namespace: Option<&str>) -> Vec<KeyId> {
412 match self {
413 UserMapping::SystemNetHsmOperatorSigning {
414 nethsm_user,
415 nethsm_key_setup,
416 system_user: _,
417 ssh_authorized_key: _,
418 tag: _,
419 } => {
420 if nethsm_user.namespace().as_deref() == namespace {
421 vec![nethsm_key_setup.get_key_id()]
422 } else {
423 vec![]
424 }
425 }
426 UserMapping::SystemNetHsmMetrics {
427 nethsm_users: _,
428 system_user: _,
429 ssh_authorized_key: _,
430 }
431 | UserMapping::NetHsmOnlyAdmin(_)
432 | UserMapping::HermeticSystemNetHsmMetrics {
433 nethsm_users: _,
434 system_user: _,
435 }
436 | UserMapping::SystemNetHsmBackup {
437 nethsm_user: _,
438 system_user: _,
439 ssh_authorized_key: _,
440 }
441 | UserMapping::SystemOnlyShareDownload {
442 system_user: _,
443 ssh_authorized_keys: _,
444 }
445 | UserMapping::SystemOnlyShareUpload {
446 system_user: _,
447 ssh_authorized_keys: _,
448 }
449 | UserMapping::SystemOnlyWireGuardDownload {
450 system_user: _,
451 ssh_authorized_keys: _,
452 } => vec![],
453 }
454 }
455
456 /// Returns tags for keys and users
457 ///
458 /// Tags can be filtered by [namespace] by providing [`Some`] `namespace`.
459 /// Providing [`None`] implies that the context is system-wide.
460 ///
461 /// # Examples
462 ///
463 /// ```
464 /// use nethsm::{CryptographicKeyContext, OpenPgpUserIdList, SigningKeySetup};
465 /// use nethsm_config::{AuthorizedKeyEntryList, UserMapping};
466 ///
467 /// # fn main() -> testresult::TestResult {
468 /// let mapping = UserMapping::SystemOnlyShareDownload {
469 /// system_user: "user1".parse()?,
470 /// ssh_authorized_keys: AuthorizedKeyEntryList::new(vec!["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?])?,
471 /// };
472 /// assert!(mapping.get_tags(None).is_empty());
473 ///
474 /// let mapping = UserMapping::NetHsmOnlyAdmin("user1".parse()?);
475 /// assert!(mapping.get_tags(None).is_empty());
476 ///
477 /// let mapping = UserMapping::SystemNetHsmOperatorSigning{
478 /// nethsm_user: "ns1~user1".parse()?,
479 /// nethsm_key_setup: SigningKeySetup::new(
480 /// "key1".parse()?,
481 /// "Curve25519".parse()?,
482 /// vec!["EdDsaSignature".parse()?],
483 /// None,
484 /// "EdDsa".parse()?,
485 /// CryptographicKeyContext::OpenPgp{
486 /// user_ids: OpenPgpUserIdList::new(vec!["John Doe <john@example.org>".parse()?])?,
487 /// version: "4".parse()?,
488 /// })?,
489 /// system_user: "user1".parse()?,
490 /// ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?,
491 /// tag: "tag1".to_string(),
492 /// };
493 /// assert!(mapping.get_tags(None).is_empty());
494 /// assert_eq!(mapping.get_tags(Some("ns1")), vec!["tag1"]);
495 /// # Ok(())
496 /// # }
497 /// ```
498 /// [namespace]: https://docs.nitrokey.com/nethsm/administration#namespaces
499 pub fn get_tags(&self, namespace: Option<&str>) -> Vec<&str> {
500 match self {
501 UserMapping::SystemNetHsmOperatorSigning {
502 nethsm_user,
503 nethsm_key_setup: _,
504 system_user: _,
505 ssh_authorized_key: _,
506 tag,
507 } => {
508 if nethsm_user.namespace().as_deref() == namespace {
509 vec![tag.as_str()]
510 } else {
511 vec![]
512 }
513 }
514 UserMapping::SystemNetHsmMetrics {
515 nethsm_users: _,
516 system_user: _,
517 ssh_authorized_key: _,
518 }
519 | UserMapping::NetHsmOnlyAdmin(_)
520 | UserMapping::HermeticSystemNetHsmMetrics {
521 nethsm_users: _,
522 system_user: _,
523 }
524 | UserMapping::SystemNetHsmBackup {
525 nethsm_user: _,
526 system_user: _,
527 ssh_authorized_key: _,
528 }
529 | UserMapping::SystemOnlyShareDownload {
530 system_user: _,
531 ssh_authorized_keys: _,
532 }
533 | UserMapping::SystemOnlyShareUpload {
534 system_user: _,
535 ssh_authorized_keys: _,
536 }
537 | UserMapping::SystemOnlyWireGuardDownload {
538 system_user: _,
539 ssh_authorized_keys: _,
540 } => vec![],
541 }
542 }
543
544 /// Returns all [`NetHsm`][`nethsm::NetHsm`] [namespaces] of the mapping
545 ///
546 /// # Examples
547 ///
548 /// ```
549 /// use nethsm::{CryptographicKeyContext, OpenPgpUserIdList, SigningKeySetup};
550 /// use nethsm_config::{AuthorizedKeyEntryList, UserMapping};
551 ///
552 /// # fn main() -> testresult::TestResult {
553 /// let mapping = UserMapping::SystemOnlyShareDownload {
554 /// system_user: "user1".parse()?,
555 /// ssh_authorized_keys: AuthorizedKeyEntryList::new(vec!["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?])?,
556 /// };
557 /// assert!(mapping.get_namespaces().is_empty());
558 ///
559 /// let mapping = UserMapping::NetHsmOnlyAdmin("user1".parse()?);
560 /// assert!(mapping.get_namespaces().is_empty());
561 ///
562 /// let mapping = UserMapping::SystemNetHsmOperatorSigning{
563 /// nethsm_user: "ns1~user1".parse()?,
564 /// nethsm_key_setup: SigningKeySetup::new(
565 /// "key1".parse()?,
566 /// "Curve25519".parse()?,
567 /// vec!["EdDsaSignature".parse()?],
568 /// None,
569 /// "EdDsa".parse()?,
570 /// CryptographicKeyContext::OpenPgp{
571 /// user_ids: OpenPgpUserIdList::new(vec!["John Doe <john@example.org>".parse()?])?,
572 /// version: "4".parse()?,
573 /// })?,
574 /// system_user: "user1".parse()?,
575 /// ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH3NyNfSqtDxdnWwSVzulZi0k7Lyjw3vBEG+U8y6KsuW user@host".parse()?,
576 /// tag: "tag1".to_string(),
577 /// };
578 /// assert_eq!(mapping.get_namespaces(), vec!["ns1".to_string()]);
579 /// # Ok(())
580 /// # }
581 /// ```
582 /// [namespaces]: https://docs.nitrokey.com/nethsm/administration#namespaces
583 pub fn get_namespaces(&self) -> Vec<String> {
584 match self {
585 UserMapping::NetHsmOnlyAdmin(nethsm_user)
586 | UserMapping::SystemNetHsmOperatorSigning {
587 nethsm_user,
588 nethsm_key_setup: _,
589 system_user: _,
590 ssh_authorized_key: _,
591 tag: _,
592 } => {
593 if let Some(namespace) = nethsm_user.namespace() {
594 vec![namespace]
595 } else {
596 vec![]
597 }
598 }
599 UserMapping::HermeticSystemNetHsmMetrics {
600 nethsm_users,
601 system_user: _,
602 }
603 | UserMapping::SystemNetHsmMetrics {
604 nethsm_users,
605 system_user: _,
606 ssh_authorized_key: _,
607 } => nethsm_users
608 .get_users()
609 .iter()
610 .filter_map(|user_id| user_id.namespace())
611 .collect(),
612 UserMapping::SystemOnlyShareDownload {
613 system_user: _,
614 ssh_authorized_keys: _,
615 }
616 | UserMapping::SystemNetHsmBackup {
617 nethsm_user: _,
618 system_user: _,
619 ssh_authorized_key: _,
620 }
621 | UserMapping::SystemOnlyShareUpload {
622 system_user: _,
623 ssh_authorized_keys: _,
624 }
625 | UserMapping::SystemOnlyWireGuardDownload {
626 system_user: _,
627 ssh_authorized_keys: _,
628 } => vec![],
629 }
630 }
631
632 /// Returns whether the mapping has both system and [`NetHsm`] users.
633 ///
634 /// Returns `true` if the `self` has at least one system and one [`NetHsm`] user, and `false`
635 /// otherwise.
636 pub fn has_system_and_nethsm_user(&self) -> bool {
637 match self {
638 UserMapping::SystemNetHsmOperatorSigning {
639 nethsm_user: _,
640 nethsm_key_setup: _,
641 system_user: _,
642 ssh_authorized_key: _,
643 tag: _,
644 }
645 | UserMapping::HermeticSystemNetHsmMetrics {
646 nethsm_users: _,
647 system_user: _,
648 }
649 | UserMapping::SystemNetHsmMetrics {
650 nethsm_users: _,
651 system_user: _,
652 ssh_authorized_key: _,
653 }
654 | UserMapping::SystemNetHsmBackup {
655 nethsm_user: _,
656 system_user: _,
657 ssh_authorized_key: _,
658 } => true,
659 UserMapping::SystemOnlyShareDownload {
660 system_user: _,
661 ssh_authorized_keys: _,
662 }
663 | UserMapping::SystemOnlyShareUpload {
664 system_user: _,
665 ssh_authorized_keys: _,
666 }
667 | UserMapping::SystemOnlyWireGuardDownload {
668 system_user: _,
669 ssh_authorized_keys: _,
670 }
671 | UserMapping::NetHsmOnlyAdmin(_) => false,
672 }
673 }
674}
675
676/// A [`UserMapping`] centric view of a [`HermeticParallelConfig`].
677///
678/// Wraps a single [`UserMapping`], as well as the system-wide [`AdministrativeSecretHandling`],
679/// [`NonAdministrativeSecretHandling`] and [`Connection`]s.
680#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
681pub struct ExtendedUserMapping {
682 admin_secret_handling: AdministrativeSecretHandling,
683 non_admin_secret_handling: NonAdministrativeSecretHandling,
684 connections: HashSet<Connection>,
685 user_mapping: UserMapping,
686}
687
688impl ExtendedUserMapping {
689 /// Creates a new [`ExtendedUserMapping`].
690 pub fn new(
691 admin_secret_handling: AdministrativeSecretHandling,
692 non_admin_secret_handling: NonAdministrativeSecretHandling,
693 connections: HashSet<Connection>,
694 user_mapping: UserMapping,
695 ) -> Self {
696 Self {
697 admin_secret_handling,
698 non_admin_secret_handling,
699 connections,
700 user_mapping,
701 }
702 }
703
704 /// Returns the [`AdministrativeSecretHandling`].
705 pub fn get_admin_secret_handling(&self) -> AdministrativeSecretHandling {
706 self.admin_secret_handling
707 }
708
709 /// Returns the [`Connection`]s.
710 pub fn get_connections(&self) -> HashSet<Connection> {
711 self.connections.clone()
712 }
713
714 /// Returns the [`NonAdministrativeSecretHandling`].
715 pub fn get_non_admin_secret_handling(&self) -> NonAdministrativeSecretHandling {
716 self.non_admin_secret_handling
717 }
718
719 /// Returns the [`UserMapping`].
720 pub fn get_user_mapping(&self) -> &UserMapping {
721 &self.user_mapping
722 }
723}
724
725impl From<HermeticParallelConfig> for Vec<ExtendedUserMapping> {
726 /// Creates a `Vec` of [`ExtendedUserMapping`] from a [`HermeticParallelConfig`].
727 ///
728 /// A [`UserMapping`] can not be aware of credentials if it does not track at least one
729 /// [`SystemUserId`] and one [`UserId`]. Therefore only those [`UserMapping`]s for which
730 /// [`has_system_and_nethsm_user`](UserMapping::has_system_and_nethsm_user) returns `true` are
731 /// returned.
732 fn from(value: HermeticParallelConfig) -> Self {
733 value
734 .iter_user_mappings()
735 .filter_map(|mapping| {
736 if mapping.has_system_and_nethsm_user() {
737 Some(ExtendedUserMapping {
738 admin_secret_handling: value.get_administrative_secret_handling(),
739 non_admin_secret_handling: value.get_non_administrative_secret_handling(),
740 connections: value.iter_connections().cloned().collect(),
741 user_mapping: mapping.clone(),
742 })
743 } else {
744 None
745 }
746 })
747 .collect()
748 }
749}