1use std::collections::{BTreeSet, HashSet};
4
5use garde::Validate;
6#[cfg(doc)]
7use nethsm::NetHsm;
8use nethsm::{
9 Connection,
10 FullCredentials,
11 KeyId,
12 NamespaceId,
13 Passphrase,
14 SystemWideUserId,
15 UserId,
16 UserRole,
17};
18use serde::{Deserialize, Serialize};
19use signstar_crypto::{key::SigningKeySetup, traits::UserWithPassphrase};
20
21use crate::{
22 AuthorizedKeyEntry,
23 SystemUserId,
24 config::{
25 BackendDomainFilter,
26 BackendKeyIdFilter,
27 BackendUserIdFilter,
28 BackendUserIdKind,
29 ConfigAuthorizedKeyEntries,
30 ConfigSystemUserIds,
31 MappingAuthorizedKeyEntry,
32 MappingBackendDomain,
33 MappingBackendKeyId,
34 MappingBackendUserIds,
35 MappingBackendUserSecrets,
36 MappingSystemUserId,
37 duplicate_authorized_keys,
38 duplicate_backend_user_ids,
39 duplicate_domains,
40 duplicate_key_ids,
41 duplicate_system_user_ids,
42 },
43};
44
45#[derive(Debug, thiserror::Error)]
47pub enum Error {
48 #[error("The NetHSM user {metrics_user} is both in the Metrics and Operator role!")]
51 MetricsAlsoOperator {
52 metrics_user: SystemWideUserId,
56 },
57
58 #[error("The NetHSM user {user} cannot be found")]
60 UserIdNotFound {
61 user: String,
63 },
64}
65
66#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
68pub enum FilterUserKeys {
69 All,
71
72 Namespaced,
74
75 Namespace(NamespaceId),
77
78 SystemWide,
80
81 Tag(String),
83}
84
85#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
91pub struct NetHsmMetricsUsers {
92 metrics_user: SystemWideUserId,
93 operator_users: Vec<UserId>,
94}
95
96impl NetHsmMetricsUsers {
97 pub fn new(
127 metrics_user: SystemWideUserId,
128 operator_users: Vec<UserId>,
129 ) -> Result<Self, crate::Error> {
130 if operator_users.contains(metrics_user.as_ref()) {
132 return Err(Error::MetricsAlsoOperator { metrics_user }.into());
133 }
134
135 Ok(Self {
136 metrics_user,
137 operator_users,
138 })
139 }
140
141 pub fn get_users(&self) -> Vec<UserId> {
167 [
168 vec![self.metrics_user.clone().into()],
169 self.operator_users.clone(),
170 ]
171 .concat()
172 }
173
174 pub fn get_users_and_roles(&self) -> Vec<(UserId, UserRole)> {
200 [
201 vec![(self.metrics_user.clone().into(), UserRole::Metrics)],
202 self.operator_users
203 .iter()
204 .map(|user| (user.clone(), UserRole::Operator))
205 .collect(),
206 ]
207 .concat()
208 }
209}
210
211#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
213pub struct NetHsmUserData<'a> {
214 pub user: &'a UserId,
216
217 pub role: UserRole,
219
220 pub tag: Option<&'a str>,
222}
223
224#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
226pub enum NetHsmUserKeysFilter {
227 All,
229
230 Namespaced,
232
233 SystemWide,
235}
236
237#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
239pub struct NetHsmUserKeyData<'a> {
240 pub user: &'a UserId,
242
243 pub key_id: &'a KeyId,
245
246 pub key_setup: &'a SigningKeySetup,
248
249 pub tag: &'a str,
251}
252
253#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
255#[serde(rename_all = "snake_case")]
256pub enum NetHsmUserMapping {
257 Admin(UserId),
259
260 Backup {
262 backend_user: SystemWideUserId,
264 ssh_authorized_key: AuthorizedKeyEntry,
266 system_user: SystemUserId,
268 },
269
270 HermeticMetrics {
274 backend_users: NetHsmMetricsUsers,
277 system_user: SystemUserId,
279 },
280
281 Metrics {
285 backend_users: NetHsmMetricsUsers,
288 ssh_authorized_key: AuthorizedKeyEntry,
290 system_user: SystemUserId,
292 },
293
294 Signing {
299 backend_user: UserId,
301 signing_key_id: KeyId,
303 key_setup: SigningKeySetup,
305 ssh_authorized_key: AuthorizedKeyEntry,
307 system_user: SystemUserId,
309 tag: String,
311 },
312}
313
314impl NetHsmUserMapping {
315 pub fn namespaces(&self) -> Vec<&NamespaceId> {
317 match self {
318 Self::Admin(backend_user) | Self::Signing { backend_user, .. } => {
319 if let Some(namespace) = backend_user.namespace() {
320 vec![namespace]
321 } else {
322 Vec::new()
323 }
324 }
325 Self::Backup { .. } => Vec::new(),
326 Self::HermeticMetrics { backend_users, .. } | Self::Metrics { backend_users, .. } => {
327 backend_users
328 .operator_users
329 .iter()
330 .filter_map(|user_id| user_id.namespace())
331 .collect::<Vec<_>>()
332 }
333 }
334 }
335
336 pub fn tag(&self, namespace: Option<&NamespaceId>) -> Option<&str> {
342 match self {
343 Self::Signing {
344 backend_user, tag, ..
345 } => {
346 if namespace == backend_user.namespace() {
347 Some(tag.as_str())
348 } else {
349 None
350 }
351 }
352 Self::Admin(_)
353 | Self::Backup { .. }
354 | Self::HermeticMetrics { .. }
355 | Self::Metrics { .. } => None,
356 }
357 }
358
359 pub fn nethsm_user_ids(&self) -> Vec<UserId> {
361 match self {
362 Self::Admin(user_id) => vec![user_id.clone()],
363 Self::Backup { backend_user, .. } => vec![backend_user.as_ref().clone()],
364 Self::Metrics { backend_users, .. } | Self::HermeticMetrics { backend_users, .. } => {
365 backend_users.get_users()
366 }
367 Self::Signing { backend_user, .. } => vec![backend_user.clone()],
368 }
369 }
370
371 pub fn nethsm_user_data<'a>(&'a self) -> HashSet<NetHsmUserData<'a>> {
373 match self {
374 Self::Admin(user_id) => HashSet::from_iter([NetHsmUserData {
375 user: user_id,
376 role: UserRole::Administrator,
377 tag: None,
378 }]),
379 Self::Backup { backend_user, .. } => HashSet::from_iter([NetHsmUserData {
380 user: backend_user.as_ref(),
381 role: UserRole::Backup,
382 tag: None,
383 }]),
384 Self::Metrics { backend_users, .. } | Self::HermeticMetrics { backend_users, .. } => {
385 let mut users = backend_users
386 .operator_users
387 .iter()
388 .map(|user_id| NetHsmUserData {
389 user: user_id,
390 role: UserRole::Operator,
391 tag: None,
392 })
393 .collect::<Vec<_>>();
394 users.push(NetHsmUserData {
395 user: backend_users.metrics_user.as_ref(),
396 role: UserRole::Metrics,
397 tag: None,
398 });
399 HashSet::from_iter(users)
400 }
401 Self::Signing {
402 backend_user, tag, ..
403 } => HashSet::from_iter([NetHsmUserData {
404 user: backend_user,
405 role: UserRole::Operator,
406 tag: Some(tag.as_ref()),
407 }]),
408 }
409 }
410
411 pub fn nethsm_user_key_data<'a>(
416 &'a self,
417 filter: NetHsmUserKeysFilter,
418 ) -> Option<NetHsmUserKeyData<'a>> {
419 match self {
420 Self::Admin(_)
421 | Self::Backup { .. }
422 | Self::Metrics { .. }
423 | Self::HermeticMetrics { .. } => None,
424 Self::Signing {
425 backend_user,
426 signing_key_id,
427 key_setup,
428 tag,
429 ..
430 } => {
431 if matches!(filter, NetHsmUserKeysFilter::All)
432 || (matches!(filter, NetHsmUserKeysFilter::Namespaced)
433 && backend_user.is_namespaced())
434 || (matches!(filter, NetHsmUserKeysFilter::SystemWide)
435 && !backend_user.is_namespaced())
436 {
437 Some(NetHsmUserKeyData {
438 user: backend_user,
439 key_id: signing_key_id,
440 key_setup,
441 tag,
442 })
443 } else {
444 None
445 }
446 }
447 }
448 }
449}
450
451impl MappingSystemUserId for NetHsmUserMapping {
452 fn system_user_id(&self) -> Option<&SystemUserId> {
453 match self {
454 Self::Admin(_) => None,
455 Self::Backup { system_user, .. }
456 | Self::Metrics { system_user, .. }
457 | Self::HermeticMetrics { system_user, .. }
458 | Self::Signing { system_user, .. } => Some(system_user),
459 }
460 }
461}
462
463impl MappingAuthorizedKeyEntry for NetHsmUserMapping {
464 fn authorized_key_entry(&self) -> Option<&AuthorizedKeyEntry> {
465 match self {
466 Self::Admin(_) | Self::HermeticMetrics { .. } => None,
467 Self::Backup {
468 ssh_authorized_key, ..
469 }
470 | Self::Metrics {
471 ssh_authorized_key, ..
472 }
473 | Self::Signing {
474 ssh_authorized_key, ..
475 } => Some(ssh_authorized_key),
476 }
477 }
478}
479
480impl MappingBackendUserIds for NetHsmUserMapping {
481 fn backend_user_ids(&self, filter: BackendUserIdFilter) -> Vec<String> {
482 match self {
483 Self::Admin(user_id) => {
484 if [BackendUserIdKind::Admin, BackendUserIdKind::Any]
485 .contains(&filter.backend_user_id_kind)
486 {
487 Some(vec![user_id.to_string()])
488 } else {
489 None
490 }
491 }
492 Self::Backup { backend_user, .. } => {
493 if [
494 BackendUserIdKind::Any,
495 BackendUserIdKind::Backup,
496 BackendUserIdKind::NonAdmin,
497 ]
498 .contains(&filter.backend_user_id_kind)
499 {
500 Some(vec![backend_user.to_string()])
501 } else {
502 None
503 }
504 }
505 Self::Metrics { backend_users, .. } | Self::HermeticMetrics { backend_users, .. } => {
506 match filter.backend_user_id_kind {
507 BackendUserIdKind::Admin
508 | BackendUserIdKind::Backup
509 | BackendUserIdKind::Signing => None,
510 BackendUserIdKind::Metrics => {
511 Some(vec![backend_users.metrics_user.to_string()])
512 }
513 BackendUserIdKind::NonAdmin | BackendUserIdKind::Any => Some(
514 backend_users
515 .get_users()
516 .iter()
517 .map(ToString::to_string)
518 .collect(),
519 ),
520 BackendUserIdKind::Observer => Some(
521 backend_users
522 .operator_users
523 .iter()
524 .map(ToString::to_string)
525 .collect(),
526 ),
527 }
528 }
529 Self::Signing { backend_user, .. } => {
530 if [
531 BackendUserIdKind::Any,
532 BackendUserIdKind::NonAdmin,
533 BackendUserIdKind::Signing,
534 ]
535 .contains(&filter.backend_user_id_kind)
536 {
537 Some(vec![backend_user.to_string()])
538 } else {
539 None
540 }
541 }
542 }
543 .unwrap_or_default()
544 }
545
546 fn backend_user_with_passphrase(
547 &self,
548 name: &str,
549 passphrase: Passphrase,
550 ) -> Result<Box<dyn UserWithPassphrase>, crate::Error> {
551 for user in self.nethsm_user_ids() {
552 if user.to_string() == name {
553 return Ok(Box::new(FullCredentials::new(user, passphrase)));
554 }
555 }
556
557 Err(Error::UserIdNotFound {
558 user: name.to_string(),
559 }
560 .into())
561 }
562
563 fn backend_users_with_new_passphrase(
564 &self,
565 filter: BackendUserIdFilter,
566 ) -> Vec<Box<dyn UserWithPassphrase>> {
567 if let Some(backend_user_ids) = match self {
568 Self::Admin(user_id) => {
569 if [BackendUserIdKind::Any, BackendUserIdKind::Admin]
570 .contains(&filter.backend_user_id_kind)
571 {
572 Some(vec![user_id.clone()])
573 } else {
574 None
575 }
576 }
577 Self::Backup { backend_user, .. } => {
578 if [
579 BackendUserIdKind::Any,
580 BackendUserIdKind::Backup,
581 BackendUserIdKind::NonAdmin,
582 ]
583 .contains(&filter.backend_user_id_kind)
584 {
585 Some(vec![UserId::from(backend_user.clone())])
586 } else {
587 None
588 }
589 }
590 Self::Metrics { backend_users, .. } | Self::HermeticMetrics { backend_users, .. } => {
591 match filter.backend_user_id_kind {
592 BackendUserIdKind::Admin
593 | BackendUserIdKind::Backup
594 | BackendUserIdKind::Signing => None,
595 BackendUserIdKind::Metrics => {
596 Some(vec![backend_users.metrics_user.as_ref().clone()])
597 }
598 BackendUserIdKind::NonAdmin | BackendUserIdKind::Any => {
599 Some(backend_users.get_users().to_vec())
600 }
601 BackendUserIdKind::Observer => Some(backend_users.operator_users.to_vec()),
602 }
603 }
604 Self::Signing { backend_user, .. } => {
605 if [
606 BackendUserIdKind::Any,
607 BackendUserIdKind::NonAdmin,
608 BackendUserIdKind::Signing,
609 ]
610 .contains(&filter.backend_user_id_kind)
611 {
612 Some(vec![backend_user.clone()])
613 } else {
614 None
615 }
616 }
617 } {
618 backend_user_ids
619 .into_iter()
620 .map(|backend_user_id| {
621 Box::new(FullCredentials::new(
622 backend_user_id,
623 Passphrase::generate(None),
624 )) as Box<dyn UserWithPassphrase>
625 })
626 .collect()
627 } else {
628 Vec::new()
629 }
630 }
631}
632
633#[derive(Clone, Debug)]
635pub struct NetHsmBackendKeyIdFilter<'a> {
636 pub namespace: Option<&'a NamespaceId>,
637}
638
639impl<'a> BackendKeyIdFilter for NetHsmBackendKeyIdFilter<'a> {}
640
641impl<'a> MappingBackendKeyId<NetHsmBackendKeyIdFilter<'a>> for NetHsmUserMapping {
642 fn backend_key_id(&self, filter: &NetHsmBackendKeyIdFilter<'a>) -> Option<String> {
643 match self {
644 Self::Admin(_)
645 | Self::Backup { .. }
646 | Self::HermeticMetrics { .. }
647 | Self::Metrics { .. } => None,
648 Self::Signing {
649 backend_user,
650 signing_key_id,
651 ..
652 } => {
653 if filter.namespace == backend_user.namespace() {
654 Some(signing_key_id.to_string())
655 } else {
656 None
657 }
658 }
659 }
660 }
661}
662
663impl MappingBackendUserSecrets for NetHsmUserMapping {}
664
665#[derive(Clone, Debug)]
667pub struct NetHsmConfigDomainFilter<'a> {
668 pub namespace: Option<&'a NamespaceId>,
671}
672
673impl<'a> BackendDomainFilter for NetHsmConfigDomainFilter<'a> {}
674
675impl<'a> MappingBackendDomain<NetHsmConfigDomainFilter<'a>> for NetHsmUserMapping {
676 fn backend_domain(&self, filter: Option<&NetHsmConfigDomainFilter>) -> Option<String> {
682 let filter = if let Some(filter) = filter {
683 filter.namespace
684 } else {
685 None
686 };
687
688 self.tag(filter).map(ToString::to_string)
689 }
690}
691
692fn validate_nethsm_config_connections(
709 value: &BTreeSet<Connection>,
710 _context: &(),
711) -> garde::Result {
712 if value.is_empty() {
713 return Err(garde::Error::new("contains no connections"));
714 }
715
716 let urls = value
717 .iter()
718 .map(|connection| connection.url())
719 .collect::<Vec<_>>();
720 let duplicates = {
721 let mut duplicates = HashSet::new();
722
723 for url in urls.iter() {
724 if urls.iter().filter(|list_url| url == *list_url).count() > 1 {
725 duplicates.insert(url);
726 }
727 }
728 let mut duplicates = Vec::from_iter(duplicates);
729 duplicates.sort();
730 duplicates
731 };
732
733 if !duplicates.is_empty() {
734 return Err(garde::Error::new(format!(
735 "contains the duplicate URL{} {}",
736 if duplicates.len() > 1 { "s" } else { "" },
737 duplicates
738 .iter()
739 .map(|url| format!("\"{url}\""))
740 .collect::<Vec<_>>()
741 .join(", ")
742 )));
743 }
744
745 Ok(())
746}
747
748fn validate_nethsm_config_mappings(
781 value: &BTreeSet<NetHsmUserMapping>,
782 _context: &(),
783) -> garde::Result {
784 if value.is_empty() {
785 return Err(garde::Error::new("contains no user mappings"));
786 }
787
788 let duplicate_system_user_ids = duplicate_system_user_ids(value);
790
791 let duplicate_authorized_keys = duplicate_authorized_keys(value);
793
794 let missing_system_wide_admin = {
796 let num_system_admins = value
797 .iter()
798 .filter_map(|mapping| {
799 if let NetHsmUserMapping::Admin(user_id) = mapping
800 && !user_id.is_namespaced()
801 {
802 Some(user_id)
803 } else {
804 None
805 }
806 })
807 .count();
808
809 if num_system_admins == 0 {
810 Some("no system-wide administrator user".to_string())
811 } else {
812 None
813 }
814 };
815
816 let duplicate_backend_user_ids = duplicate_backend_user_ids(value);
818
819 let duplicate_system_wide_key_ids = duplicate_key_ids(
821 value,
822 &NetHsmBackendKeyIdFilter { namespace: None },
823 Some(" system-wide".to_string()),
824 );
825
826 let duplicate_system_wide_tags =
828 duplicate_domains(value, None, Some(" system-wide".to_string()), Some("tag"));
829
830 let all_namespaces = {
832 let mut all_namespaces = Vec::from_iter(
833 value
834 .iter()
835 .flat_map(|mapping| mapping.namespaces())
836 .collect::<HashSet<_>>(),
837 );
838 all_namespaces.sort();
839 all_namespaces
840 };
841
842 let namespaces_without_admin = {
844 let mut all_namespaces: HashSet<&NamespaceId> = HashSet::from_iter(all_namespaces.clone());
845
846 for mapping in value.iter() {
847 if let NetHsmUserMapping::Admin(user_id) = mapping
848 && let Some(namespace) = user_id.namespace()
849 {
850 all_namespaces.remove(namespace);
851 }
852 }
853
854 if all_namespaces.is_empty() {
855 None
856 } else {
857 let mut namespaces_without_admin = all_namespaces
858 .iter()
859 .map(|namespace| format!("\"{namespace}\""))
860 .collect::<Vec<_>>();
861 namespaces_without_admin.sort();
862 Some(format!(
863 "the namespace{} {} without an administrator user",
864 if namespaces_without_admin.len() > 1 {
865 "s"
866 } else {
867 ""
868 },
869 namespaces_without_admin.join(", ")
870 ))
871 }
872 };
873
874 let duplicate_namespaced_key_ids = {
876 let mut all_duplicates = Vec::new();
877
878 for namespace in all_namespaces.iter() {
879 let mut duplicates = duplicate_key_ids(
880 value,
881 &NetHsmBackendKeyIdFilter {
882 namespace: Some(namespace),
883 },
884 Some(format!(" \"{namespace}\" namespaced")),
885 );
886 if let Some(message) = duplicates.take() {
887 all_duplicates.push(message)
888 }
889 }
890
891 if all_duplicates.is_empty() {
892 None
893 } else {
894 Some(all_duplicates.join("\n"))
895 }
896 };
897
898 let duplicate_namespaced_tags = {
900 let mut all_duplicates = Vec::new();
901
902 for namespace in all_namespaces.iter() {
903 let mut duplicates = duplicate_domains(
904 value,
905 Some(&NetHsmConfigDomainFilter {
906 namespace: Some(namespace),
907 }),
908 Some(format!(" \"{namespace}\" namespaced")),
909 Some("tag"),
910 );
911 if let Some(message) = duplicates.take() {
912 all_duplicates.push(message)
913 }
914 }
915
916 if all_duplicates.is_empty() {
917 None
918 } else {
919 Some(all_duplicates.join("\n"))
920 }
921 };
922
923 let messages = [
924 duplicate_system_user_ids,
925 duplicate_authorized_keys,
926 missing_system_wide_admin,
927 duplicate_backend_user_ids,
928 duplicate_system_wide_key_ids,
929 duplicate_system_wide_tags,
930 namespaces_without_admin,
931 duplicate_namespaced_key_ids,
932 duplicate_namespaced_tags,
933 ];
934 let error_messages = {
935 let mut error_messages = Vec::new();
936
937 for message in messages.iter().flatten() {
938 error_messages.push(message.as_str());
939 }
940
941 error_messages
942 };
943
944 match error_messages.len() {
945 0 => Ok(()),
946 1 => Err(garde::Error::new(format!(
947 "contains {}",
948 error_messages.join("\n")
949 ))),
950 _ => Err(garde::Error::new(format!(
951 "contains multiple issues:\n⤷ {}",
952 error_messages.join("\n⤷ ")
953 ))),
954 }
955}
956
957#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
962#[serde(rename_all = "snake_case")]
963pub struct NetHsmConfig {
964 #[garde(custom(validate_nethsm_config_connections))]
965 connections: BTreeSet<Connection>,
966
967 #[garde(custom(validate_nethsm_config_mappings))]
968 mappings: BTreeSet<NetHsmUserMapping>,
969}
970
971impl NetHsmConfig {
972 pub fn new(
975 connections: BTreeSet<Connection>,
976 mappings: BTreeSet<NetHsmUserMapping>,
977 ) -> Result<Self, crate::Error> {
978 let config = Self {
979 connections,
980 mappings,
981 };
982
983 config
984 .validate()
985 .map_err(|source| crate::Error::Validation {
986 context: "validating a NetHSM specific configuration item".to_string(),
987 source,
988 })?;
989
990 Ok(config)
991 }
992
993 pub fn connections(&self) -> &BTreeSet<Connection> {
995 &self.connections
996 }
997
998 pub fn mappings(&self) -> &BTreeSet<NetHsmUserMapping> {
1000 &self.mappings
1001 }
1002}
1003
1004impl ConfigAuthorizedKeyEntries for NetHsmConfig {
1005 fn authorized_key_entries(&self) -> HashSet<&AuthorizedKeyEntry> {
1006 self.mappings
1007 .iter()
1008 .filter_map(|mapping| mapping.authorized_key_entry())
1009 .collect()
1010 }
1011}
1012
1013impl ConfigSystemUserIds for NetHsmConfig {
1014 fn system_user_ids(&self) -> HashSet<&SystemUserId> {
1015 self.mappings
1016 .iter()
1017 .filter_map(|mapping| mapping.system_user_id())
1018 .collect()
1019 }
1020}
1021
1022#[cfg(test)]
1023mod tests {
1024 use std::thread::current;
1025
1026 use insta::{assert_snapshot, with_settings};
1027 use rstest::{fixture, rstest};
1028 use signstar_crypto::{
1029 key::{CryptographicKeyContext, KeyMechanism, KeyType, SignatureType, SigningKeySetup},
1030 openpgp::OpenPgpUserIdList,
1031 };
1032 use testresult::TestResult;
1033
1034 use super::*;
1035
1036 const SNAPSHOT_PATH: &str = "fixtures/nethsm_config/";
1037
1038 #[test]
1039 fn nethsm_metrics_users_succeeds() -> TestResult {
1040 NetHsmMetricsUsers::new(
1041 SystemWideUserId::new("metrics".to_string())?,
1042 vec![
1043 UserId::new("operator".to_string())?,
1044 UserId::new("ns1~operator".to_string())?,
1045 ],
1046 )?;
1047 Ok(())
1048 }
1049
1050 #[test]
1051 fn nethsm_metrics_users_fails() -> TestResult {
1052 if let Ok(user) = NetHsmMetricsUsers::new(
1053 SystemWideUserId::new("metrics".to_string())?,
1054 vec![
1055 UserId::new("metrics".to_string())?,
1056 UserId::new("ns1~operator".to_string())?,
1057 ],
1058 ) {
1059 panic!("Succeeded creating a NetHsmMetricsUsers, but should have failed:\n{user:?}")
1060 }
1061 Ok(())
1062 }
1063
1064 #[rstest]
1065 #[case::admin(NetHsmUserMapping::Admin("admin".parse()?), vec!["admin".parse()?])]
1066 #[case::backup(
1067 NetHsmUserMapping::Backup{
1068 backend_user: "backup".parse()?,
1069 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1070 system_user: "backup-user".parse()?,
1071 },
1072 vec!["backup".parse()?],
1073 )]
1074 #[case::backup(
1075 NetHsmUserMapping::Metrics{
1076 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1077 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1078 system_user: "metrics-user".parse()?,
1079 },
1080 vec!["metrics".parse()?, "keymetrics".parse()?],
1081 )]
1082 #[case::backup(
1083 NetHsmUserMapping::Signing {
1084 backend_user: "signing".parse()?,
1085 signing_key_id: "signing1".parse()?,
1086 key_setup: SigningKeySetup::new(
1087 KeyType::Curve25519,
1088 vec![KeyMechanism::EdDsaSignature],
1089 None,
1090 SignatureType::EdDsa,
1091 CryptographicKeyContext::OpenPgp {
1092 user_ids: OpenPgpUserIdList::new(vec![
1093 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1094 ])?,
1095 version: "v4".parse()?,
1096 },
1097 )?,
1098 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1099 system_user: "signing-user".parse()?,
1100 tag: "signing1".to_string(),
1101 },
1102 vec!["signing".parse()?],
1103 )]
1104 fn nethsm_user_mapping_nethsm_user_ids(
1105 #[case] mapping: NetHsmUserMapping,
1106 #[case] expected: Vec<UserId>,
1107 ) -> TestResult {
1108 assert_eq!(mapping.nethsm_user_ids(), expected,);
1109
1110 Ok(())
1111 }
1112
1113 #[rstest]
1114 #[case::admin(
1115 NetHsmUserMapping::Admin("admin".parse()?),
1116 vec![("admin".parse()?, UserRole::Administrator, None)],
1117 )]
1118 #[case::backup(
1119 NetHsmUserMapping::Backup{
1120 backend_user: "backup".parse()?,
1121 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1122 system_user: "backup-user".parse()?,
1123 },
1124 vec![("backup".parse()?, UserRole::Backup, None)],
1125 )]
1126 #[case::metrics(
1127 NetHsmUserMapping::Metrics{
1128 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1129 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1130 system_user: "metrics-user".parse()?,
1131 },
1132 vec![
1133 ("keymetrics".parse()?, UserRole::Operator, None),
1134 ("metrics".parse()?, UserRole::Metrics, None),
1135 ],
1136 )]
1137 #[case::signing(
1138 NetHsmUserMapping::Signing {
1139 backend_user: "signing".parse()?,
1140 signing_key_id: "signing1".parse()?,
1141 key_setup: SigningKeySetup::new(
1142 KeyType::Curve25519,
1143 vec![KeyMechanism::EdDsaSignature],
1144 None,
1145 SignatureType::EdDsa,
1146 CryptographicKeyContext::OpenPgp {
1147 user_ids: OpenPgpUserIdList::new(vec![
1148 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1149 ])?,
1150 version: "v4".parse()?,
1151 },
1152 )?,
1153 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1154 system_user: "signing-user".parse()?,
1155 tag: "signing1".to_string(),
1156 },
1157 vec![("signing".parse()?, UserRole::Operator, Some("signing1"))],
1158 )]
1159 fn nethsm_user_mapping_nethsm_user_data(
1160 #[case] mapping: NetHsmUserMapping,
1161 #[case] expected: Vec<(UserId, UserRole, Option<&str>)>,
1162 ) -> TestResult {
1163 let expected = expected
1164 .iter()
1165 .map(|(user, role, tag)| NetHsmUserData {
1166 user,
1167 role: *role,
1168 tag: *tag,
1169 })
1170 .collect::<HashSet<_>>();
1171 assert_eq!(mapping.nethsm_user_data(), expected);
1172
1173 Ok(())
1174 }
1175
1176 #[rstest]
1177 #[case::admin_filter_all(
1178 NetHsmUserMapping::Admin("admin".parse()?),
1179 NetHsmUserKeysFilter::All,
1180 None,
1181 )]
1182 #[case::admin_filter_namespace(
1183 NetHsmUserMapping::Admin("admin".parse()?),
1184 NetHsmUserKeysFilter::Namespaced,
1185 None,
1186 )]
1187 #[case::admin_filter_system_wide(
1188 NetHsmUserMapping::Admin("admin".parse()?),
1189 NetHsmUserKeysFilter::SystemWide,
1190 None,
1191 )]
1192 #[case::backup_filter_all(
1193 NetHsmUserMapping::Backup{
1194 backend_user: "backup".parse()?,
1195 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1196 system_user: "backup-user".parse()?,
1197 },
1198 NetHsmUserKeysFilter::All,
1199 None,
1200 )]
1201 #[case::backup_filter_namespaced(
1202 NetHsmUserMapping::Backup{
1203 backend_user: "backup".parse()?,
1204 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1205 system_user: "backup-user".parse()?,
1206 },
1207 NetHsmUserKeysFilter::Namespaced,
1208 None,
1209 )]
1210 #[case::backup_filter_system_wide(
1211 NetHsmUserMapping::Backup{
1212 backend_user: "backup".parse()?,
1213 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1214 system_user: "backup-user".parse()?,
1215 },
1216 NetHsmUserKeysFilter::SystemWide,
1217 None,
1218 )]
1219 #[case::metrics_filter_all(
1220 NetHsmUserMapping::Metrics{
1221 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1222 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1223 system_user: "metrics-user".parse()?,
1224 },
1225 NetHsmUserKeysFilter::All,
1226 None,
1227 )]
1228 #[case::metrics_filter_namespaced(
1229 NetHsmUserMapping::Metrics{
1230 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1231 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1232 system_user: "metrics-user".parse()?,
1233 },
1234 NetHsmUserKeysFilter::Namespaced,
1235 None,
1236 )]
1237 #[case::metrics_filter_system_wide(
1238 NetHsmUserMapping::Metrics{
1239 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1240 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1241 system_user: "metrics-user".parse()?,
1242 },
1243 NetHsmUserKeysFilter::SystemWide,
1244 None,
1245 )]
1246 #[case::signing_system_wide_filter_all(
1247 NetHsmUserMapping::Signing {
1248 backend_user: "signing".parse()?,
1249 signing_key_id: "signing1".parse()?,
1250 key_setup: SigningKeySetup::new(
1251 KeyType::Curve25519,
1252 vec![KeyMechanism::EdDsaSignature],
1253 None,
1254 SignatureType::EdDsa,
1255 CryptographicKeyContext::OpenPgp {
1256 user_ids: OpenPgpUserIdList::new(vec![
1257 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1258 ])?,
1259 version: "v4".parse()?,
1260 },
1261 )?,
1262 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1263 system_user: "signing-user".parse()?,
1264 tag: "signing1".to_string(),
1265 },
1266 NetHsmUserKeysFilter::All,
1267 Some((
1268 "signing".parse()?,
1269 "signing1".parse()?,
1270 SigningKeySetup::new(
1271 KeyType::Curve25519,
1272 vec![KeyMechanism::EdDsaSignature],
1273 None,
1274 SignatureType::EdDsa,
1275 CryptographicKeyContext::OpenPgp {
1276 user_ids: OpenPgpUserIdList::new(vec![
1277 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1278 ])?,
1279 version: "v4".parse()?,
1280 },
1281 )?,
1282 "signing1",
1283 )),
1284 )]
1285 #[case::signing_system_wide_filter_namespaced(
1286 NetHsmUserMapping::Signing {
1287 backend_user: "signing".parse()?,
1288 signing_key_id: "signing1".parse()?,
1289 key_setup: SigningKeySetup::new(
1290 KeyType::Curve25519,
1291 vec![KeyMechanism::EdDsaSignature],
1292 None,
1293 SignatureType::EdDsa,
1294 CryptographicKeyContext::OpenPgp {
1295 user_ids: OpenPgpUserIdList::new(vec![
1296 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1297 ])?,
1298 version: "v4".parse()?,
1299 },
1300 )?,
1301 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1302 system_user: "signing-user".parse()?,
1303 tag: "signing1".to_string(),
1304 },
1305 NetHsmUserKeysFilter::Namespaced,
1306 None,
1307 )]
1308 #[case::signing_system_wide_filter_system_wide(
1309 NetHsmUserMapping::Signing {
1310 backend_user: "signing".parse()?,
1311 signing_key_id: "signing1".parse()?,
1312 key_setup: SigningKeySetup::new(
1313 KeyType::Curve25519,
1314 vec![KeyMechanism::EdDsaSignature],
1315 None,
1316 SignatureType::EdDsa,
1317 CryptographicKeyContext::OpenPgp {
1318 user_ids: OpenPgpUserIdList::new(vec![
1319 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1320 ])?,
1321 version: "v4".parse()?,
1322 },
1323 )?,
1324 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1325 system_user: "signing-user".parse()?,
1326 tag: "signing1".to_string(),
1327 },
1328 NetHsmUserKeysFilter::SystemWide,
1329 Some((
1330 "signing".parse()?,
1331 "signing1".parse()?,
1332 SigningKeySetup::new(
1333 KeyType::Curve25519,
1334 vec![KeyMechanism::EdDsaSignature],
1335 None,
1336 SignatureType::EdDsa,
1337 CryptographicKeyContext::OpenPgp {
1338 user_ids: OpenPgpUserIdList::new(vec![
1339 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1340 ])?,
1341 version: "v4".parse()?,
1342 },
1343 )?,
1344 "signing1",
1345 )),
1346 )]
1347 #[case::signing_namespaced_filter_all(
1348 NetHsmUserMapping::Signing {
1349 backend_user: "ns1~signing".parse()?,
1350 signing_key_id: "signing1".parse()?,
1351 key_setup: SigningKeySetup::new(
1352 KeyType::Curve25519,
1353 vec![KeyMechanism::EdDsaSignature],
1354 None,
1355 SignatureType::EdDsa,
1356 CryptographicKeyContext::OpenPgp {
1357 user_ids: OpenPgpUserIdList::new(vec![
1358 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1359 ])?,
1360 version: "v4".parse()?,
1361 },
1362 )?,
1363 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1364 system_user: "signing-user".parse()?,
1365 tag: "signing1".to_string(),
1366 },
1367 NetHsmUserKeysFilter::All,
1368 Some((
1369 "ns1~signing".parse()?,
1370 "signing1".parse()?,
1371 SigningKeySetup::new(
1372 KeyType::Curve25519,
1373 vec![KeyMechanism::EdDsaSignature],
1374 None,
1375 SignatureType::EdDsa,
1376 CryptographicKeyContext::OpenPgp {
1377 user_ids: OpenPgpUserIdList::new(vec![
1378 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1379 ])?,
1380 version: "v4".parse()?,
1381 },
1382 )?,
1383 "signing1",
1384 )),
1385 )]
1386 #[case::signing_system_wide_filter_namespaced(
1387 NetHsmUserMapping::Signing {
1388 backend_user: "ns1~signing".parse()?,
1389 signing_key_id: "signing1".parse()?,
1390 key_setup: SigningKeySetup::new(
1391 KeyType::Curve25519,
1392 vec![KeyMechanism::EdDsaSignature],
1393 None,
1394 SignatureType::EdDsa,
1395 CryptographicKeyContext::OpenPgp {
1396 user_ids: OpenPgpUserIdList::new(vec![
1397 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1398 ])?,
1399 version: "v4".parse()?,
1400 },
1401 )?,
1402 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1403 system_user: "signing-user".parse()?,
1404 tag: "signing1".to_string(),
1405 },
1406 NetHsmUserKeysFilter::Namespaced,
1407 Some((
1408 "ns1~signing".parse()?,
1409 "signing1".parse()?,
1410 SigningKeySetup::new(
1411 KeyType::Curve25519,
1412 vec![KeyMechanism::EdDsaSignature],
1413 None,
1414 SignatureType::EdDsa,
1415 CryptographicKeyContext::OpenPgp {
1416 user_ids: OpenPgpUserIdList::new(vec![
1417 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1418 ])?,
1419 version: "v4".parse()?,
1420 },
1421 )?,
1422 "signing1",
1423 )),
1424 )]
1425 #[case::signing_system_wide_filter_system_wide(
1426 NetHsmUserMapping::Signing {
1427 backend_user: "ns1~signing".parse()?,
1428 signing_key_id: "signing1".parse()?,
1429 key_setup: SigningKeySetup::new(
1430 KeyType::Curve25519,
1431 vec![KeyMechanism::EdDsaSignature],
1432 None,
1433 SignatureType::EdDsa,
1434 CryptographicKeyContext::OpenPgp {
1435 user_ids: OpenPgpUserIdList::new(vec![
1436 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1437 ])?,
1438 version: "v4".parse()?,
1439 },
1440 )?,
1441 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1442 system_user: "signing-user".parse()?,
1443 tag: "signing1".to_string(),
1444 },
1445 NetHsmUserKeysFilter::SystemWide,
1446 None,
1447 )]
1448 fn nethsm_user_mapping_nethsm_user_key_data(
1449 #[case] mapping: NetHsmUserMapping,
1450 #[case] filter: NetHsmUserKeysFilter,
1451 #[case] expected: Option<(UserId, KeyId, SigningKeySetup, &str)>,
1452 ) -> TestResult {
1453 let expected = expected
1454 .as_ref()
1455 .map(|(user, key_id, key_setup, tag)| NetHsmUserKeyData {
1456 user,
1457 key_id,
1458 key_setup,
1459 tag,
1460 });
1461 assert_eq!(mapping.nethsm_user_key_data(filter), expected);
1462
1463 Ok(())
1464 }
1465
1466 #[rstest]
1467 #[case::admin_filter_admin(
1468 NetHsmUserMapping::Admin("admin".parse()?),
1469 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
1470 vec!["admin"]
1471 )]
1472 #[case::admin_filter_any(
1473 NetHsmUserMapping::Admin("admin".parse()?),
1474 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1475 vec!["admin"]
1476 )]
1477 #[case::backup_filter_any(
1478 NetHsmUserMapping::Backup{
1479 backend_user: "backup".parse()?,
1480 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1481 system_user: "backup-user".parse()?,
1482 },
1483 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1484 vec!["backup"]
1485 )]
1486 #[case::backup_filter_backup(
1487 NetHsmUserMapping::Backup{
1488 backend_user: "backup".parse()?,
1489 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1490 system_user: "backup-user".parse()?,
1491 },
1492 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
1493 vec!["backup"]
1494 )]
1495 #[case::backup_filter_non_admin(
1496 NetHsmUserMapping::Backup{
1497 backend_user: "backup".parse()?,
1498 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1499 system_user: "backup-user".parse()?,
1500 },
1501 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1502 vec!["backup"]
1503 )]
1504 #[case::hermetic_metrics_filter_any(
1505 NetHsmUserMapping::HermeticMetrics {
1506 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1507 system_user: "metrics-user".parse()?,
1508 },
1509 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1510 vec!["metrics", "keymetrics"]
1511 )]
1512 #[case::hermetic_metrics_filter_metrics(
1513 NetHsmUserMapping::HermeticMetrics {
1514 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1515 system_user: "metrics-user".parse()?,
1516 },
1517 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
1518 vec!["metrics"]
1519 )]
1520 #[case::hermetic_metrics_filter_non_admin(
1521 NetHsmUserMapping::HermeticMetrics {
1522 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1523 system_user: "metrics-user".parse()?,
1524 },
1525 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1526 vec!["metrics", "keymetrics"]
1527 )]
1528 #[case::hermetic_metrics_filter_observer(
1529 NetHsmUserMapping::HermeticMetrics {
1530 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1531 system_user: "metrics-user".parse()?,
1532 },
1533 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
1534 vec!["keymetrics"]
1535 )]
1536 #[case::signing_filter_any(
1537 NetHsmUserMapping::Signing {
1538 backend_user: "signing".parse()?,
1539 signing_key_id: "signing1".parse()?,
1540 key_setup: SigningKeySetup::new(
1541 KeyType::Curve25519,
1542 vec![KeyMechanism::EdDsaSignature],
1543 None,
1544 SignatureType::EdDsa,
1545 CryptographicKeyContext::OpenPgp {
1546 user_ids: OpenPgpUserIdList::new(vec![
1547 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1548 ])?,
1549 version: "v4".parse()?,
1550 },
1551 )?,
1552 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1553 system_user: "signing-user".parse()?,
1554 tag: "signing1".to_string(),
1555 },
1556 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1557 vec!["signing"]
1558 )]
1559 #[case::signing_filter_non_admin(
1560 NetHsmUserMapping::Signing {
1561 backend_user: "signing".parse()?,
1562 signing_key_id: "signing1".parse()?,
1563 key_setup: SigningKeySetup::new(
1564 KeyType::Curve25519,
1565 vec![KeyMechanism::EdDsaSignature],
1566 None,
1567 SignatureType::EdDsa,
1568 CryptographicKeyContext::OpenPgp {
1569 user_ids: OpenPgpUserIdList::new(vec![
1570 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1571 ])?,
1572 version: "v4".parse()?,
1573 },
1574 )?,
1575 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1576 system_user: "signing-user".parse()?,
1577 tag: "signing1".to_string(),
1578 },
1579 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1580 vec!["signing"]
1581 )]
1582 #[case::signing_filter_signing(
1583 NetHsmUserMapping::Signing {
1584 backend_user: "signing".parse()?,
1585 signing_key_id: "signing1".parse()?,
1586 key_setup: SigningKeySetup::new(
1587 KeyType::Curve25519,
1588 vec![KeyMechanism::EdDsaSignature],
1589 None,
1590 SignatureType::EdDsa,
1591 CryptographicKeyContext::OpenPgp {
1592 user_ids: OpenPgpUserIdList::new(vec![
1593 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1594 ])?,
1595 version: "v4".parse()?,
1596 },
1597 )?,
1598 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1599 system_user: "signing-user".parse()?,
1600 tag: "signing1".to_string(),
1601 },
1602 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1603 vec!["signing"]
1604 )]
1605 fn nethsm_user_mapping_backend_user_ids_filter_matches(
1606 #[case] mapping: NetHsmUserMapping,
1607 #[case] filter: BackendUserIdFilter,
1608 #[case] expected: Vec<&str>,
1609 ) -> TestResult {
1610 assert_eq!(mapping.backend_user_ids(filter), expected);
1611
1612 Ok(())
1613 }
1614
1615 #[rstest]
1616 #[case::admin_filter_metrics(
1617 NetHsmUserMapping::Admin("admin".parse()?),
1618 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
1619 )]
1620 #[case::admin_filter_non_admin(
1621 NetHsmUserMapping::Admin("admin".parse()?),
1622 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1623 )]
1624 #[case::admin_filter_observer(
1625 NetHsmUserMapping::Admin("admin".parse()?),
1626 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
1627 )]
1628 #[case::admin_filter_signing(
1629 NetHsmUserMapping::Admin("admin".parse()?),
1630 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1631 )]
1632 #[case::backup_filter_admin(
1633 NetHsmUserMapping::Backup{
1634 backend_user: "backup".parse()?,
1635 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1636 system_user: "backup-user".parse()?,
1637 },
1638 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
1639 )]
1640 #[case::backup_filter_metrics(
1641 NetHsmUserMapping::Backup{
1642 backend_user: "backup".parse()?,
1643 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1644 system_user: "backup-user".parse()?,
1645 },
1646 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
1647 )]
1648 #[case::backup_filter_observer(
1649 NetHsmUserMapping::Backup{
1650 backend_user: "backup".parse()?,
1651 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1652 system_user: "backup-user".parse()?,
1653 },
1654 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
1655 )]
1656 #[case::backup_filter_signing(
1657 NetHsmUserMapping::Backup{
1658 backend_user: "backup".parse()?,
1659 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1660 system_user: "backup-user".parse()?,
1661 },
1662 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1663 )]
1664 #[case::hermetic_metrics_filter_admin(
1665 NetHsmUserMapping::HermeticMetrics {
1666 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1667 system_user: "metrics-user".parse()?,
1668 },
1669 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
1670 )]
1671 #[case::hermetic_metrics_filter_backup(
1672 NetHsmUserMapping::HermeticMetrics {
1673 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1674 system_user: "metrics-user".parse()?,
1675 },
1676 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
1677 )]
1678 #[case::hermetic_metrics_filter_signing(
1679 NetHsmUserMapping::HermeticMetrics {
1680 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1681 system_user: "metrics-user".parse()?,
1682 },
1683 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1684 )]
1685 #[case::metrics_filter_admin(
1686 NetHsmUserMapping::Metrics {
1687 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
1688 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1689 system_user: "hermetic-metrics-user".parse()?,
1690 },
1691 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
1692 )]
1693 #[case::metrics_filter_backup(
1694 NetHsmUserMapping::Metrics {
1695 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
1696 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1697 system_user: "hermetic-metrics-user".parse()?,
1698 },
1699 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
1700 )]
1701 #[case::metrics_filter_signing(
1702 NetHsmUserMapping::Metrics {
1703 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
1704 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
1705 system_user: "hermetic-metrics-user".parse()?,
1706 },
1707 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1708 )]
1709 #[case::signing_filter_admin(
1710 NetHsmUserMapping::Signing {
1711 backend_user: "signing".parse()?,
1712 signing_key_id: "signing1".parse()?,
1713 key_setup: SigningKeySetup::new(
1714 KeyType::Curve25519,
1715 vec![KeyMechanism::EdDsaSignature],
1716 None,
1717 SignatureType::EdDsa,
1718 CryptographicKeyContext::OpenPgp {
1719 user_ids: OpenPgpUserIdList::new(vec![
1720 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1721 ])?,
1722 version: "v4".parse()?,
1723 },
1724 )?,
1725 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1726 system_user: "signing-user".parse()?,
1727 tag: "signing1".to_string(),
1728 },
1729 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
1730 )]
1731 #[case::signing_filter_backup(
1732 NetHsmUserMapping::Signing {
1733 backend_user: "signing".parse()?,
1734 signing_key_id: "signing1".parse()?,
1735 key_setup: SigningKeySetup::new(
1736 KeyType::Curve25519,
1737 vec![KeyMechanism::EdDsaSignature],
1738 None,
1739 SignatureType::EdDsa,
1740 CryptographicKeyContext::OpenPgp {
1741 user_ids: OpenPgpUserIdList::new(vec![
1742 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1743 ])?,
1744 version: "v4".parse()?,
1745 },
1746 )?,
1747 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1748 system_user: "signing-user".parse()?,
1749 tag: "signing1".to_string(),
1750 },
1751 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
1752 )]
1753 #[case::signing_filter_metrics(
1754 NetHsmUserMapping::Signing {
1755 backend_user: "signing".parse()?,
1756 signing_key_id: "signing1".parse()?,
1757 key_setup: SigningKeySetup::new(
1758 KeyType::Curve25519,
1759 vec![KeyMechanism::EdDsaSignature],
1760 None,
1761 SignatureType::EdDsa,
1762 CryptographicKeyContext::OpenPgp {
1763 user_ids: OpenPgpUserIdList::new(vec![
1764 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1765 ])?,
1766 version: "v4".parse()?,
1767 },
1768 )?,
1769 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1770 system_user: "signing-user".parse()?,
1771 tag: "signing1".to_string(),
1772 },
1773 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
1774 )]
1775 #[case::signing_filter_observer(
1776 NetHsmUserMapping::Signing {
1777 backend_user: "signing".parse()?,
1778 signing_key_id: "signing1".parse()?,
1779 key_setup: SigningKeySetup::new(
1780 KeyType::Curve25519,
1781 vec![KeyMechanism::EdDsaSignature],
1782 None,
1783 SignatureType::EdDsa,
1784 CryptographicKeyContext::OpenPgp {
1785 user_ids: OpenPgpUserIdList::new(vec![
1786 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1787 ])?,
1788 version: "v4".parse()?,
1789 },
1790 )?,
1791 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1792 system_user: "signing-user".parse()?,
1793 tag: "signing1".to_string(),
1794 },
1795 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
1796 )]
1797 fn nethsm_user_mapping_backend_user_ids_filter_mismatches(
1798 #[case] mapping: NetHsmUserMapping,
1799 #[case] filter: BackendUserIdFilter,
1800 ) -> TestResult {
1801 assert!(mapping.backend_user_ids(filter).is_empty());
1802
1803 Ok(())
1804 }
1805
1806 #[test]
1807 fn nethsm_user_mapping_backend_user_with_passphrase_succeeds() -> TestResult {
1808 let mapping = NetHsmUserMapping::Admin("admin".parse()?);
1809 let passphrase = Passphrase::generate(None);
1810 let creds = mapping.backend_user_with_passphrase("admin", passphrase.clone())?;
1811
1812 assert_eq!(creds.user(), "admin");
1813 assert_eq!(
1814 creds.passphrase().expose_borrowed(),
1815 passphrase.expose_borrowed()
1816 );
1817
1818 Ok(())
1819 }
1820
1821 #[rstest]
1822 #[case::admin_filter_admin(
1823 NetHsmUserMapping::Admin("admin".parse()?),
1824 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
1825 vec!["admin"]
1826 )]
1827 #[case::admin_filter_any(
1828 NetHsmUserMapping::Admin("admin".parse()?),
1829 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1830 vec!["admin"]
1831 )]
1832 #[case::backup_filter_any(
1833 NetHsmUserMapping::Backup{
1834 backend_user: "backup".parse()?,
1835 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1836 system_user: "backup-user".parse()?,
1837 },
1838 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1839 vec!["backup"]
1840 )]
1841 #[case::backup_filter_backup(
1842 NetHsmUserMapping::Backup{
1843 backend_user: "backup".parse()?,
1844 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1845 system_user: "backup-user".parse()?,
1846 },
1847 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
1848 vec!["backup"]
1849 )]
1850 #[case::backup_filter_non_admin(
1851 NetHsmUserMapping::Backup{
1852 backend_user: "backup".parse()?,
1853 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
1854 system_user: "backup-user".parse()?,
1855 },
1856 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1857 vec!["backup"]
1858 )]
1859 #[case::hermetic_metrics_filter_any(
1860 NetHsmUserMapping::HermeticMetrics {
1861 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1862 system_user: "metrics-user".parse()?,
1863 },
1864 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1865 vec!["metrics", "keymetrics"]
1866 )]
1867 #[case::hermetic_metrics_filter_metrics(
1868 NetHsmUserMapping::HermeticMetrics {
1869 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1870 system_user: "metrics-user".parse()?,
1871 },
1872 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
1873 vec!["metrics"]
1874 )]
1875 #[case::hermetic_metrics_filter_non_admin(
1876 NetHsmUserMapping::HermeticMetrics {
1877 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1878 system_user: "metrics-user".parse()?,
1879 },
1880 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1881 vec!["metrics", "keymetrics"]
1882 )]
1883 #[case::hermetic_metrics_filter_observer(
1884 NetHsmUserMapping::HermeticMetrics {
1885 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
1886 system_user: "metrics-user".parse()?,
1887 },
1888 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
1889 vec!["keymetrics"]
1890 )]
1891 #[case::signing_filter_any(
1892 NetHsmUserMapping::Signing {
1893 backend_user: "signing".parse()?,
1894 signing_key_id: "signing1".parse()?,
1895 key_setup: SigningKeySetup::new(
1896 KeyType::Curve25519,
1897 vec![KeyMechanism::EdDsaSignature],
1898 None,
1899 SignatureType::EdDsa,
1900 CryptographicKeyContext::OpenPgp {
1901 user_ids: OpenPgpUserIdList::new(vec![
1902 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1903 ])?,
1904 version: "v4".parse()?,
1905 },
1906 )?,
1907 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1908 system_user: "signing-user".parse()?,
1909 tag: "signing1".to_string(),
1910 },
1911 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Any },
1912 vec!["signing"]
1913 )]
1914 #[case::signing_filter_non_admin(
1915 NetHsmUserMapping::Signing {
1916 backend_user: "signing".parse()?,
1917 signing_key_id: "signing1".parse()?,
1918 key_setup: SigningKeySetup::new(
1919 KeyType::Curve25519,
1920 vec![KeyMechanism::EdDsaSignature],
1921 None,
1922 SignatureType::EdDsa,
1923 CryptographicKeyContext::OpenPgp {
1924 user_ids: OpenPgpUserIdList::new(vec![
1925 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1926 ])?,
1927 version: "v4".parse()?,
1928 },
1929 )?,
1930 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1931 system_user: "signing-user".parse()?,
1932 tag: "signing1".to_string(),
1933 },
1934 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1935 vec!["signing"]
1936 )]
1937 #[case::signing_filter_signing(
1938 NetHsmUserMapping::Signing {
1939 backend_user: "signing".parse()?,
1940 signing_key_id: "signing1".parse()?,
1941 key_setup: SigningKeySetup::new(
1942 KeyType::Curve25519,
1943 vec![KeyMechanism::EdDsaSignature],
1944 None,
1945 SignatureType::EdDsa,
1946 CryptographicKeyContext::OpenPgp {
1947 user_ids: OpenPgpUserIdList::new(vec![
1948 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
1949 ])?,
1950 version: "v4".parse()?,
1951 },
1952 )?,
1953 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
1954 system_user: "signing-user".parse()?,
1955 tag: "signing1".to_string(),
1956 },
1957 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1958 vec!["signing"]
1959 )]
1960
1961 fn nethsm_user_mapping_backend_users_with_new_passphrase_filter_matches(
1962 #[case] mapping: NetHsmUserMapping,
1963 #[case] filter: BackendUserIdFilter,
1964 #[case] expected: Vec<&str>,
1965 ) -> TestResult {
1966 let creds = mapping.backend_users_with_new_passphrase(filter);
1967 let users = creds
1968 .iter()
1969 .map(|creds| creds.user())
1970 .collect::<HashSet<_>>();
1971 let expected = expected
1972 .iter()
1973 .map(ToString::to_string)
1974 .collect::<HashSet<_>>();
1975 assert_eq!(users, expected);
1976
1977 Ok(())
1978 }
1979
1980 #[rstest]
1981 #[case::admin_filter_metrics(
1982 NetHsmUserMapping::Admin("admin".parse()?),
1983 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
1984 )]
1985 #[case::admin_filter_non_admin(
1986 NetHsmUserMapping::Admin("admin".parse()?),
1987 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::NonAdmin },
1988 )]
1989 #[case::admin_filter_observer(
1990 NetHsmUserMapping::Admin("admin".parse()?),
1991 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
1992 )]
1993 #[case::admin_filter_signing(
1994 NetHsmUserMapping::Admin("admin".parse()?),
1995 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
1996 )]
1997 #[case::backup_filter_admin(
1998 NetHsmUserMapping::Backup{
1999 backend_user: "backup".parse()?,
2000 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2001 system_user: "backup-user".parse()?,
2002 },
2003 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
2004 )]
2005 #[case::backup_filter_metrics(
2006 NetHsmUserMapping::Backup{
2007 backend_user: "backup".parse()?,
2008 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2009 system_user: "backup-user".parse()?,
2010 },
2011 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
2012 )]
2013 #[case::backup_filter_observer(
2014 NetHsmUserMapping::Backup{
2015 backend_user: "backup".parse()?,
2016 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2017 system_user: "backup-user".parse()?,
2018 },
2019 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
2020 )]
2021 #[case::backup_filter_signing(
2022 NetHsmUserMapping::Backup{
2023 backend_user: "backup".parse()?,
2024 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2025 system_user: "backup-user".parse()?,
2026 },
2027 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
2028 )]
2029 #[case::hermetic_metrics_filter_admin(
2030 NetHsmUserMapping::HermeticMetrics {
2031 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2032 system_user: "metrics-user".parse()?,
2033 },
2034 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
2035 )]
2036 #[case::hermetic_metrics_filter_backup(
2037 NetHsmUserMapping::HermeticMetrics {
2038 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2039 system_user: "metrics-user".parse()?,
2040 },
2041 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
2042 )]
2043 #[case::hermetic_metrics_filter_signing(
2044 NetHsmUserMapping::HermeticMetrics {
2045 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2046 system_user: "metrics-user".parse()?,
2047 },
2048 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
2049 )]
2050 #[case::metrics_filter_admin(
2051 NetHsmUserMapping::Metrics {
2052 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2053 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2054 system_user: "hermetic-metrics-user".parse()?,
2055 },
2056 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
2057 )]
2058 #[case::metrics_filter_backup(
2059 NetHsmUserMapping::Metrics {
2060 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2061 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2062 system_user: "hermetic-metrics-user".parse()?,
2063 },
2064 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
2065 )]
2066 #[case::metrics_filter_signing(
2067 NetHsmUserMapping::Metrics {
2068 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2069 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2070 system_user: "hermetic-metrics-user".parse()?,
2071 },
2072 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Signing },
2073 )]
2074 #[case::signing_filter_admin(
2075 NetHsmUserMapping::Signing {
2076 backend_user: "signing".parse()?,
2077 signing_key_id: "signing1".parse()?,
2078 key_setup: SigningKeySetup::new(
2079 KeyType::Curve25519,
2080 vec![KeyMechanism::EdDsaSignature],
2081 None,
2082 SignatureType::EdDsa,
2083 CryptographicKeyContext::OpenPgp {
2084 user_ids: OpenPgpUserIdList::new(vec![
2085 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2086 ])?,
2087 version: "v4".parse()?,
2088 },
2089 )?,
2090 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2091 system_user: "signing-user".parse()?,
2092 tag: "signing1".to_string(),
2093 },
2094 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Admin },
2095 )]
2096 #[case::signing_filter_backup(
2097 NetHsmUserMapping::Signing {
2098 backend_user: "signing".parse()?,
2099 signing_key_id: "signing1".parse()?,
2100 key_setup: SigningKeySetup::new(
2101 KeyType::Curve25519,
2102 vec![KeyMechanism::EdDsaSignature],
2103 None,
2104 SignatureType::EdDsa,
2105 CryptographicKeyContext::OpenPgp {
2106 user_ids: OpenPgpUserIdList::new(vec![
2107 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2108 ])?,
2109 version: "v4".parse()?,
2110 },
2111 )?,
2112 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2113 system_user: "signing-user".parse()?,
2114 tag: "signing1".to_string(),
2115 },
2116 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Backup },
2117 )]
2118 #[case::signing_filter_metrics(
2119 NetHsmUserMapping::Signing {
2120 backend_user: "signing".parse()?,
2121 signing_key_id: "signing1".parse()?,
2122 key_setup: SigningKeySetup::new(
2123 KeyType::Curve25519,
2124 vec![KeyMechanism::EdDsaSignature],
2125 None,
2126 SignatureType::EdDsa,
2127 CryptographicKeyContext::OpenPgp {
2128 user_ids: OpenPgpUserIdList::new(vec![
2129 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2130 ])?,
2131 version: "v4".parse()?,
2132 },
2133 )?,
2134 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2135 system_user: "signing-user".parse()?,
2136 tag: "signing1".to_string(),
2137 },
2138 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Metrics },
2139 )]
2140 #[case::signing_filter_observer(
2141 NetHsmUserMapping::Signing {
2142 backend_user: "signing".parse()?,
2143 signing_key_id: "signing1".parse()?,
2144 key_setup: SigningKeySetup::new(
2145 KeyType::Curve25519,
2146 vec![KeyMechanism::EdDsaSignature],
2147 None,
2148 SignatureType::EdDsa,
2149 CryptographicKeyContext::OpenPgp {
2150 user_ids: OpenPgpUserIdList::new(vec![
2151 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2152 ])?,
2153 version: "v4".parse()?,
2154 },
2155 )?,
2156 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2157 system_user: "signing-user".parse()?,
2158 tag: "signing1".to_string(),
2159 },
2160 BackendUserIdFilter{ backend_user_id_kind: BackendUserIdKind::Observer },
2161 )]
2162 fn nethsm_user_mapping_backend_users_with_new_passphrase_filter_mismatches(
2163 #[case] mapping: NetHsmUserMapping,
2164 #[case] filter: BackendUserIdFilter,
2165 ) -> TestResult {
2166 assert!(mapping.backend_users_with_new_passphrase(filter).is_empty());
2167
2168 Ok(())
2169 }
2170
2171 #[test]
2172 fn nethsm_user_mapping_backend_user_with_passphrase_fails() -> TestResult {
2173 let mapping = NetHsmUserMapping::Admin("admin".parse()?);
2174 assert!(
2175 mapping
2176 .backend_user_with_passphrase("2", Passphrase::generate(None))
2177 .is_err()
2178 );
2179
2180 Ok(())
2181 }
2182
2183 #[fixture]
2184 fn nethsm_config_connections() -> TestResult<BTreeSet<Connection>> {
2185 Ok(BTreeSet::from_iter([
2186 Connection::new(
2187 "https://nethsm1.example.org/".parse()?,
2188 nethsm::ConnectionSecurity::Unsafe,
2189 ),
2190 Connection::new(
2191 "https://nethsm2.example.org/".parse()?,
2192 nethsm::ConnectionSecurity::Unsafe,
2193 ),
2194 ]))
2195 }
2196
2197 #[fixture]
2198 fn nethsm_config_mappings() -> TestResult<BTreeSet<NetHsmUserMapping>> {
2199 Ok(BTreeSet::from_iter([
2200 NetHsmUserMapping::Admin("admin".parse()?),
2201 NetHsmUserMapping::Backup{
2202 backend_user: "backup".parse()?,
2203 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2204 system_user: "backup-user".parse()?,
2205 },
2206 NetHsmUserMapping::HermeticMetrics {
2207 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2208 system_user: "metrics-user".parse()?,
2209 },
2210 NetHsmUserMapping::Metrics {
2211 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2212 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2213 system_user: "hermetic-metrics-user".parse()?,
2214 },
2215 NetHsmUserMapping::Signing {
2216 backend_user: "signing".parse()?,
2217 signing_key_id: "signing1".parse()?,
2218 key_setup: SigningKeySetup::new(
2219 KeyType::Curve25519,
2220 vec![KeyMechanism::EdDsaSignature],
2221 None,
2222 SignatureType::EdDsa,
2223 CryptographicKeyContext::OpenPgp {
2224 user_ids: OpenPgpUserIdList::new(vec![
2225 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2226 ])?,
2227 version: "v4".parse()?,
2228 },
2229 )?,
2230 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2231 system_user: "signing-user".parse()?,
2232 tag: "signing1".to_string(),
2233 }
2234 ]))
2235 }
2236
2237 #[fixture]
2238 fn nethsm_config(
2239 nethsm_config_connections: TestResult<BTreeSet<Connection>>,
2240 nethsm_config_mappings: TestResult<BTreeSet<NetHsmUserMapping>>,
2241 ) -> TestResult<NetHsmConfig> {
2242 let nethsm_config_connections = nethsm_config_connections?;
2243 let nethsm_config_mappings = nethsm_config_mappings?;
2244 Ok(NetHsmConfig::new(
2245 nethsm_config_connections,
2246 nethsm_config_mappings,
2247 )?)
2248 }
2249
2250 #[rstest]
2251 fn nethsm_config_connections_matches(
2252 nethsm_config: TestResult<NetHsmConfig>,
2253 nethsm_config_connections: TestResult<BTreeSet<Connection>>,
2254 ) -> TestResult {
2255 let nethsm_config = nethsm_config?;
2256 let nethsm_config_connections = nethsm_config_connections?;
2257 assert_eq!(nethsm_config.connections(), &nethsm_config_connections);
2258
2259 Ok(())
2260 }
2261
2262 #[rstest]
2263 fn nethsm_config_mappings_matches(
2264 nethsm_config: TestResult<NetHsmConfig>,
2265 nethsm_config_mappings: TestResult<BTreeSet<NetHsmUserMapping>>,
2266 ) -> TestResult {
2267 let nethsm_config = nethsm_config?;
2268 let nethsm_config_mappings = nethsm_config_mappings?;
2269 assert_eq!(nethsm_config.mappings(), &nethsm_config_mappings);
2270
2271 Ok(())
2272 }
2273
2274 #[rstest]
2275 fn nethsm_config_authorized_key_entries(
2276 nethsm_config: TestResult<NetHsmConfig>,
2277 nethsm_config_mappings: TestResult<BTreeSet<NetHsmUserMapping>>,
2278 ) -> TestResult {
2279 let nethsm_config = nethsm_config?;
2280 let nethsm_config_mappings = nethsm_config_mappings?;
2281 let expected = nethsm_config_mappings
2282 .iter()
2283 .filter_map(|mapping| mapping.authorized_key_entry())
2284 .collect::<HashSet<_>>();
2285 assert_eq!(nethsm_config.authorized_key_entries(), expected);
2286
2287 Ok(())
2288 }
2289
2290 #[rstest]
2291 fn nethsm_config_system_user_ids(
2292 nethsm_config: TestResult<NetHsmConfig>,
2293 nethsm_config_mappings: TestResult<BTreeSet<NetHsmUserMapping>>,
2294 ) -> TestResult {
2295 let nethsm_config = nethsm_config?;
2296 let nethsm_config_mappings = nethsm_config_mappings?;
2297 let expected = nethsm_config_mappings
2298 .iter()
2299 .filter_map(|mapping| mapping.system_user_id())
2300 .collect::<HashSet<_>>();
2301 assert_eq!(nethsm_config.system_user_ids(), expected);
2302
2303 Ok(())
2304 }
2305
2306 #[rstest]
2307 #[case::no_connection(
2308 "Error message for NetHsmConfig::new with no backend connection",
2309 BTreeSet::new(),
2310 BTreeSet::from_iter([
2311 NetHsmUserMapping::Admin("admin".parse()?),
2312 NetHsmUserMapping::Backup{
2313 backend_user: "backup".parse()?,
2314 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2315 system_user: "backup-user".parse()?,
2316 },
2317 NetHsmUserMapping::HermeticMetrics {
2318 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2319 system_user: "hermetic-metrics-user".parse()?,
2320 },
2321 NetHsmUserMapping::Metrics {
2322 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2323 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2324 system_user: "metrics-user".parse()?,
2325 },
2326 NetHsmUserMapping::Signing {
2327 backend_user: "signing".parse()?,
2328 signing_key_id: "signing1".parse()?,
2329 key_setup: SigningKeySetup::new(
2330 KeyType::Curve25519,
2331 vec![KeyMechanism::EdDsaSignature],
2332 None,
2333 SignatureType::EdDsa,
2334 CryptographicKeyContext::OpenPgp {
2335 user_ids: OpenPgpUserIdList::new(vec![
2336 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2337 ])?,
2338 version: "v4".parse()?,
2339 },
2340 )?,
2341 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2342 system_user: "signing-user".parse()?,
2343 tag: "signing1".to_string(),
2344 }
2345 ]),
2346 )]
2347 #[case::duplicate_connection_url(
2348 "Error message for NetHsmConfig::new with two duplicate connection URLs",
2349 BTreeSet::from_iter([
2350 Connection::new("https://nethsm1.example.org/".parse()?, nethsm::ConnectionSecurity::Unsafe),
2351 Connection::new("https://nethsm1.example.org/".parse()?, nethsm::ConnectionSecurity::Native),
2352 ]),
2353 BTreeSet::from_iter([
2354 NetHsmUserMapping::Admin("admin".parse()?),
2355 NetHsmUserMapping::Backup{
2356 backend_user: "backup".parse()?,
2357 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2358 system_user: "backup-user".parse()?,
2359 },
2360 NetHsmUserMapping::HermeticMetrics {
2361 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2362 system_user: "hermetic-metrics-user".parse()?,
2363 },
2364 NetHsmUserMapping::Metrics {
2365 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2366 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2367 system_user: "metrics-user".parse()?,
2368 },
2369 NetHsmUserMapping::Signing {
2370 backend_user: "signing".parse()?,
2371 signing_key_id: "signing1".parse()?,
2372 key_setup: SigningKeySetup::new(
2373 KeyType::Curve25519,
2374 vec![KeyMechanism::EdDsaSignature],
2375 None,
2376 SignatureType::EdDsa,
2377 CryptographicKeyContext::OpenPgp {
2378 user_ids: OpenPgpUserIdList::new(vec![
2379 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2380 ])?,
2381 version: "v4".parse()?,
2382 },
2383 )?,
2384 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2385 system_user: "signing-user".parse()?,
2386 tag: "signing1".to_string(),
2387 }
2388 ]),
2389 )]
2390 #[case::no_mappings(
2391 "Error message for NetHsmConfig::new with no user mappings",
2392 BTreeSet::from_iter([
2393 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2394 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2395 ]),
2396 BTreeSet::new(),
2397 )]
2398 #[case::duplicate_system_user_ids(
2399 "Error message for NetHsmConfig::new with two duplicate system user IDs",
2400 BTreeSet::from_iter([
2401 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2402 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2403 ]),
2404 BTreeSet::from_iter([
2405 NetHsmUserMapping::Admin("admin".parse()?),
2406 NetHsmUserMapping::Backup{
2407 backend_user: "backup".parse()?,
2408 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2409 system_user: "backup-user".parse()?,
2410 },
2411 NetHsmUserMapping::HermeticMetrics {
2412 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2413 system_user: "hermetic-metrics-user".parse()?,
2414 },
2415 NetHsmUserMapping::Metrics {
2416 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2417 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2418 system_user: "backup-user".parse()?,
2419 },
2420 NetHsmUserMapping::Signing {
2421 backend_user: "signing".parse()?,
2422 signing_key_id: "signing1".parse()?,
2423 key_setup: SigningKeySetup::new(
2424 KeyType::Curve25519,
2425 vec![KeyMechanism::EdDsaSignature],
2426 None,
2427 SignatureType::EdDsa,
2428 CryptographicKeyContext::OpenPgp {
2429 user_ids: OpenPgpUserIdList::new(vec![
2430 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2431 ])?,
2432 version: "v4".parse()?,
2433 },
2434 )?,
2435 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2436 system_user: "signing-user".parse()?,
2437 tag: "signing1".to_string(),
2438 }
2439 ]),
2440 )]
2441 #[case::duplicate_ssh_public_keys(
2442 "Error message for NetHsmConfig::new with two duplicate SSH public keys as authorized keys",
2443 BTreeSet::from_iter([
2444 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2445 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2446 ]),
2447 BTreeSet::from_iter([
2448 NetHsmUserMapping::Admin("admin".parse()?),
2449 NetHsmUserMapping::Backup{
2450 backend_user: "backup".parse()?,
2451 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2452 system_user: "backup-user".parse()?,
2453 },
2454 NetHsmUserMapping::HermeticMetrics {
2455 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2456 system_user: "hermetic-metrics-user".parse()?,
2457 },
2458 NetHsmUserMapping::Metrics {
2459 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2460 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user2@other-host".parse()?,
2461 system_user: "metrics-user".parse()?,
2462 },
2463 NetHsmUserMapping::Signing {
2464 backend_user: "signing".parse()?,
2465 signing_key_id: "signing1".parse()?,
2466 key_setup: SigningKeySetup::new(
2467 KeyType::Curve25519,
2468 vec![KeyMechanism::EdDsaSignature],
2469 None,
2470 SignatureType::EdDsa,
2471 CryptographicKeyContext::OpenPgp {
2472 user_ids: OpenPgpUserIdList::new(vec![
2473 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2474 ])?,
2475 version: "v4".parse()?,
2476 },
2477 )?,
2478 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2479 system_user: "signing-user".parse()?,
2480 tag: "signing1".to_string(),
2481 }
2482 ]),
2483 )]
2484 #[case::missing_system_wide_administrator(
2485 "Error message for NetHsmConfig::new with a system-wide administrator missing",
2486 BTreeSet::from_iter([
2487 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2488 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2489 ]),
2490 BTreeSet::from_iter([
2491 NetHsmUserMapping::Backup{
2492 backend_user: "backup".parse()?,
2493 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2494 system_user: "backup-user".parse()?,
2495 },
2496 NetHsmUserMapping::HermeticMetrics {
2497 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2498 system_user: "hermetic-metrics-user".parse()?,
2499 },
2500 NetHsmUserMapping::Metrics {
2501 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2502 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2503 system_user: "metrics-user".parse()?,
2504 },
2505 NetHsmUserMapping::Signing {
2506 backend_user: "signing".parse()?,
2507 signing_key_id: "signing1".parse()?,
2508 key_setup: SigningKeySetup::new(
2509 KeyType::Curve25519,
2510 vec![KeyMechanism::EdDsaSignature],
2511 None,
2512 SignatureType::EdDsa,
2513 CryptographicKeyContext::OpenPgp {
2514 user_ids: OpenPgpUserIdList::new(vec![
2515 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2516 ])?,
2517 version: "v4".parse()?,
2518 },
2519 )?,
2520 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2521 system_user: "signing-user".parse()?,
2522 tag: "signing1".to_string(),
2523 }
2524 ]),
2525 )]
2526 #[case::duplicate_system_wide_backend_user_ids(
2527 "Error message for NetHsmConfig::new with two duplicate system-wide backend user IDs",
2528 BTreeSet::from_iter([
2529 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2530 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2531 ]),
2532 BTreeSet::from_iter([
2533 NetHsmUserMapping::Admin("admin".parse()?),
2534 NetHsmUserMapping::Admin("backup".parse()?),
2535 NetHsmUserMapping::Backup{
2536 backend_user: "backup".parse()?,
2537 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2538 system_user: "backup-user".parse()?,
2539 },
2540 NetHsmUserMapping::HermeticMetrics {
2541 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2542 system_user: "hermetic-metrics-user".parse()?,
2543 },
2544 NetHsmUserMapping::Metrics {
2545 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2546 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2547 system_user: "metrics-user".parse()?,
2548 },
2549 NetHsmUserMapping::Signing {
2550 backend_user: "signing".parse()?,
2551 signing_key_id: "signing1".parse()?,
2552 key_setup: SigningKeySetup::new(
2553 KeyType::Curve25519,
2554 vec![KeyMechanism::EdDsaSignature],
2555 None,
2556 SignatureType::EdDsa,
2557 CryptographicKeyContext::OpenPgp {
2558 user_ids: OpenPgpUserIdList::new(vec![
2559 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2560 ])?,
2561 version: "v4".parse()?,
2562 },
2563 )?,
2564 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2565 system_user: "signing-user".parse()?,
2566 tag: "signing1".to_string(),
2567 }
2568 ]),
2569 )]
2570 #[case::duplicate_namespaced_backend_user_ids(
2571 "Error message for NetHsmConfig::new with two duplicate namespaced backend user IDs",
2572 BTreeSet::from_iter([
2573 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2574 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2575 ]),
2576 BTreeSet::from_iter([
2577 NetHsmUserMapping::Admin("admin".parse()?),
2578 NetHsmUserMapping::Admin("ns1~admin".parse()?),
2579 NetHsmUserMapping::Signing {
2580 backend_user: "ns1~signing1".parse()?,
2581 signing_key_id: "signing1".parse()?,
2582 key_setup: SigningKeySetup::new(
2583 KeyType::Curve25519,
2584 vec![KeyMechanism::EdDsaSignature],
2585 None,
2586 SignatureType::EdDsa,
2587 CryptographicKeyContext::OpenPgp {
2588 user_ids: OpenPgpUserIdList::new(vec![
2589 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2590 ])?,
2591 version: "v4".parse()?,
2592 },
2593 )?,
2594 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2595 system_user: "ns1-signing-user1".parse()?,
2596 tag: "signing1".to_string(),
2597 },
2598 NetHsmUserMapping::Signing {
2599 backend_user: "ns1~signing1".parse()?,
2600 signing_key_id: "signing2".parse()?,
2601 key_setup: SigningKeySetup::new(
2602 KeyType::Curve25519,
2603 vec![KeyMechanism::EdDsaSignature],
2604 None,
2605 SignatureType::EdDsa,
2606 CryptographicKeyContext::OpenPgp {
2607 user_ids: OpenPgpUserIdList::new(vec![
2608 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2609 ])?,
2610 version: "v4".parse()?,
2611 },
2612 )?,
2613 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2614 system_user: "ns1-signing-user2".parse()?,
2615 tag: "signing2".to_string(),
2616 }
2617 ]),
2618 )]
2619 #[case::duplicate_system_wide_key_ids(
2620 "Error message for NetHsmConfig::new with two duplicate system-wide key IDs",
2621 BTreeSet::from_iter([
2622 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2623 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2624 ]),
2625 BTreeSet::from_iter([
2626 NetHsmUserMapping::Admin("admin".parse()?),
2627 NetHsmUserMapping::Backup{
2628 backend_user: "backup".parse()?,
2629 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2630 system_user: "backup-user".parse()?,
2631 },
2632 NetHsmUserMapping::HermeticMetrics {
2633 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2634 system_user: "hermetic-metrics-user".parse()?,
2635 },
2636 NetHsmUserMapping::Metrics {
2637 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2638 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2639 system_user: "metrics-user".parse()?,
2640 },
2641 NetHsmUserMapping::Signing {
2642 backend_user: "signing1".parse()?,
2643 signing_key_id: "signing1".parse()?,
2644 key_setup: SigningKeySetup::new(
2645 KeyType::Curve25519,
2646 vec![KeyMechanism::EdDsaSignature],
2647 None,
2648 SignatureType::EdDsa,
2649 CryptographicKeyContext::OpenPgp {
2650 user_ids: OpenPgpUserIdList::new(vec![
2651 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2652 ])?,
2653 version: "v4".parse()?,
2654 },
2655 )?,
2656 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2657 system_user: "signing-user".parse()?,
2658 tag: "signing1".to_string(),
2659 },
2660 NetHsmUserMapping::Signing {
2661 backend_user: "signing2".parse()?,
2662 signing_key_id: "signing1".parse()?,
2663 key_setup: SigningKeySetup::new(
2664 KeyType::Curve25519,
2665 vec![KeyMechanism::EdDsaSignature],
2666 None,
2667 SignatureType::EdDsa,
2668 CryptographicKeyContext::OpenPgp {
2669 user_ids: OpenPgpUserIdList::new(vec![
2670 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2671 ])?,
2672 version: "v4".parse()?,
2673 },
2674 )?,
2675 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2676 system_user: "signing-user2".parse()?,
2677 tag: "signing2".to_string(),
2678 }
2679 ]),
2680 )]
2681 #[case::duplicate_system_wide_tags(
2682 "Error message for NetHsmConfig::new with two duplicate system-wide tags",
2683 BTreeSet::from_iter([
2684 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2685 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2686 ]),
2687 BTreeSet::from_iter([
2688 NetHsmUserMapping::Admin("admin".parse()?),
2689 NetHsmUserMapping::Backup{
2690 backend_user: "backup".parse()?,
2691 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh9BTe81DC6A0YZALsq9dWcyl6xjjqlxWPwlExTFgBt user@host".parse()?,
2692 system_user: "backup-user".parse()?,
2693 },
2694 NetHsmUserMapping::HermeticMetrics {
2695 backend_users: NetHsmMetricsUsers::new("hermeticmetrics".parse()?, vec!["hermetickeymetrics".parse()?])?,
2696 system_user: "hermetic-metrics-user".parse()?,
2697 },
2698 NetHsmUserMapping::Metrics {
2699 backend_users: NetHsmMetricsUsers::new("metrics".parse()?, vec!["keymetrics".parse()?])?,
2700 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPkpXKiNhy39A3bZ1u19a5d4sFwYMBkWQyCbzgUfdKBm user@host".parse()?,
2701 system_user: "metrics-user".parse()?,
2702 },
2703 NetHsmUserMapping::Signing {
2704 backend_user: "signing1".parse()?,
2705 signing_key_id: "signing1".parse()?,
2706 key_setup: SigningKeySetup::new(
2707 KeyType::Curve25519,
2708 vec![KeyMechanism::EdDsaSignature],
2709 None,
2710 SignatureType::EdDsa,
2711 CryptographicKeyContext::OpenPgp {
2712 user_ids: OpenPgpUserIdList::new(vec![
2713 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2714 ])?,
2715 version: "v4".parse()?,
2716 },
2717 )?,
2718 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2719 system_user: "signing-user".parse()?,
2720 tag: "signing1".to_string(),
2721 },
2722 NetHsmUserMapping::Signing {
2723 backend_user: "signing2".parse()?,
2724 signing_key_id: "signing2".parse()?,
2725 key_setup: SigningKeySetup::new(
2726 KeyType::Curve25519,
2727 vec![KeyMechanism::EdDsaSignature],
2728 None,
2729 SignatureType::EdDsa,
2730 CryptographicKeyContext::OpenPgp {
2731 user_ids: OpenPgpUserIdList::new(vec![
2732 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2733 ])?,
2734 version: "v4".parse()?,
2735 },
2736 )?,
2737 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2738 system_user: "signing-user2".parse()?,
2739 tag: "signing1".to_string(),
2740 }
2741 ]),
2742 )]
2743 #[case::missing_namespace_administrator(
2744 "Error message for NetHsmConfig::new with a missing namespace administrator",
2745 BTreeSet::from_iter([
2746 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2747 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2748 ]),
2749 BTreeSet::from_iter([
2750 NetHsmUserMapping::Admin("admin".parse()?),
2751 NetHsmUserMapping::Signing {
2752 backend_user: "ns1~signing1".parse()?,
2753 signing_key_id: "signing1".parse()?,
2754 key_setup: SigningKeySetup::new(
2755 KeyType::Curve25519,
2756 vec![KeyMechanism::EdDsaSignature],
2757 None,
2758 SignatureType::EdDsa,
2759 CryptographicKeyContext::OpenPgp {
2760 user_ids: OpenPgpUserIdList::new(vec![
2761 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2762 ])?,
2763 version: "v4".parse()?,
2764 },
2765 )?,
2766 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2767 system_user: "ns1-signing-user".parse()?,
2768 tag: "signing1".to_string(),
2769 },
2770 ]),
2771 )]
2772 #[case::duplicate_namespace_key_ids(
2773 "Error message for NetHsmConfig::new with two duplicate namespaced key IDs",
2774 BTreeSet::from_iter([
2775 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2776 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2777 ]),
2778 BTreeSet::from_iter([
2779 NetHsmUserMapping::Admin("admin".parse()?),
2780 NetHsmUserMapping::Admin("ns1~admin".parse()?),
2781 NetHsmUserMapping::Signing {
2782 backend_user: "ns1~signing1".parse()?,
2783 signing_key_id: "signing1".parse()?,
2784 key_setup: SigningKeySetup::new(
2785 KeyType::Curve25519,
2786 vec![KeyMechanism::EdDsaSignature],
2787 None,
2788 SignatureType::EdDsa,
2789 CryptographicKeyContext::OpenPgp {
2790 user_ids: OpenPgpUserIdList::new(vec![
2791 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2792 ])?,
2793 version: "v4".parse()?,
2794 },
2795 )?,
2796 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2797 system_user: "ns1-signing-user".parse()?,
2798 tag: "signing1".to_string(),
2799 },
2800 NetHsmUserMapping::Signing {
2801 backend_user: "ns1~signing2".parse()?,
2802 signing_key_id: "signing1".parse()?,
2803 key_setup: SigningKeySetup::new(
2804 KeyType::Curve25519,
2805 vec![KeyMechanism::EdDsaSignature],
2806 None,
2807 SignatureType::EdDsa,
2808 CryptographicKeyContext::OpenPgp {
2809 user_ids: OpenPgpUserIdList::new(vec![
2810 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2811 ])?,
2812 version: "v4".parse()?,
2813 },
2814 )?,
2815 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2816 system_user: "ns1-signing-user2".parse()?,
2817 tag: "signing2".to_string(),
2818 }
2819 ]),
2820 )]
2821 #[case::duplicate_namespace_tags(
2822 "Error message for NetHsmConfig::new with two duplicate namespaced tags",
2823 BTreeSet::from_iter([
2824 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2825 Connection::new("https://nethsm2.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2826 ]),
2827 BTreeSet::from_iter([
2828 NetHsmUserMapping::Admin("admin".parse()?),
2829 NetHsmUserMapping::Admin("ns1~admin".parse()?),
2830 NetHsmUserMapping::Signing {
2831 backend_user: "ns1~signing1".parse()?,
2832 signing_key_id: "signing1".parse()?,
2833 key_setup: SigningKeySetup::new(
2834 KeyType::Curve25519,
2835 vec![KeyMechanism::EdDsaSignature],
2836 None,
2837 SignatureType::EdDsa,
2838 CryptographicKeyContext::OpenPgp {
2839 user_ids: OpenPgpUserIdList::new(vec![
2840 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2841 ])?,
2842 version: "v4".parse()?,
2843 },
2844 )?,
2845 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2846 system_user: "ns1-signing-user".parse()?,
2847 tag: "signing1".to_string(),
2848 },
2849 NetHsmUserMapping::Signing {
2850 backend_user: "ns1~signing2".parse()?,
2851 signing_key_id: "signing2".parse()?,
2852 key_setup: SigningKeySetup::new(
2853 KeyType::Curve25519,
2854 vec![KeyMechanism::EdDsaSignature],
2855 None,
2856 SignatureType::EdDsa,
2857 CryptographicKeyContext::OpenPgp {
2858 user_ids: OpenPgpUserIdList::new(vec![
2859 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2860 ])?,
2861 version: "v4".parse()?,
2862 },
2863 )?,
2864 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2865 system_user: "ns1-signing-user2".parse()?,
2866 tag: "signing1".to_string(),
2867 }
2868 ]),
2869 )]
2870 #[case::all_the_issues(
2871 "Error message for NetHsmConfig::new with multiple validation issues (connections and mappings)",
2872 BTreeSet::from_iter([
2873 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Unsafe),
2874 Connection::new("https://nethsm1.example.org/".parse()?,nethsm::ConnectionSecurity::Native),
2875 ]),
2876 BTreeSet::from_iter([
2877 NetHsmUserMapping::Signing {
2878 backend_user: "signing1".parse()?,
2879 signing_key_id: "signing1".parse()?,
2880 key_setup: SigningKeySetup::new(
2881 KeyType::Curve25519,
2882 vec![KeyMechanism::EdDsaSignature],
2883 None,
2884 SignatureType::EdDsa,
2885 CryptographicKeyContext::OpenPgp {
2886 user_ids: OpenPgpUserIdList::new(vec![
2887 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2888 ])?,
2889 version: "v4".parse()?,
2890 },
2891 )?,
2892 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAN54Gd1jMz+yNDjBRwX1SnOtWuUsVF64RJIeYJ8DI7b user@host".parse()?,
2893 system_user: "ns1-signing-user1".parse()?,
2894 tag: "signing1".to_string(),
2895 },
2896 NetHsmUserMapping::Signing {
2897 backend_user: "signing1".parse()?,
2898 signing_key_id: "signing1".parse()?,
2899 key_setup: SigningKeySetup::new(
2900 KeyType::Curve25519,
2901 vec![KeyMechanism::EdDsaSignature],
2902 None,
2903 SignatureType::EdDsa,
2904 CryptographicKeyContext::OpenPgp {
2905 user_ids: OpenPgpUserIdList::new(vec![
2906 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2907 ])?,
2908 version: "v4".parse()?,
2909 },
2910 )?,
2911 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2912 system_user: "ns1-signing-user1".parse()?,
2913 tag: "signing1".to_string(),
2914 },
2915 NetHsmUserMapping::Signing {
2916 backend_user: "ns1~signing1".parse()?,
2917 signing_key_id: "signing1".parse()?,
2918 key_setup: SigningKeySetup::new(
2919 KeyType::Curve25519,
2920 vec![KeyMechanism::EdDsaSignature],
2921 None,
2922 SignatureType::EdDsa,
2923 CryptographicKeyContext::OpenPgp {
2924 user_ids: OpenPgpUserIdList::new(vec![
2925 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2926 ])?,
2927 version: "v4".parse()?,
2928 },
2929 )?,
2930 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh96uFTnvX6P1ebbLxXFvy6sK7qFqlMHDOuJ0TmuXQQ user@host".parse()?,
2931 system_user: "ns1-signing-user1".parse()?,
2932 tag: "signing1".to_string(),
2933 },
2934 NetHsmUserMapping::Signing {
2935 backend_user: "ns1~signing1".parse()?,
2936 signing_key_id: "signing2".parse()?,
2937 key_setup: SigningKeySetup::new(
2938 KeyType::Curve25519,
2939 vec![KeyMechanism::EdDsaSignature],
2940 None,
2941 SignatureType::EdDsa,
2942 CryptographicKeyContext::OpenPgp {
2943 user_ids: OpenPgpUserIdList::new(vec![
2944 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2945 ])?,
2946 version: "v4".parse()?,
2947 },
2948 )?,
2949 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2950 system_user: "ns1-signing-user2".parse()?,
2951 tag: "signing1".to_string(),
2952 },
2953 NetHsmUserMapping::Signing {
2954 backend_user: "ns1~signing2".parse()?,
2955 signing_key_id: "signing2".parse()?,
2956 key_setup: SigningKeySetup::new(
2957 KeyType::Curve25519,
2958 vec![KeyMechanism::EdDsaSignature],
2959 None,
2960 SignatureType::EdDsa,
2961 CryptographicKeyContext::OpenPgp {
2962 user_ids: OpenPgpUserIdList::new(vec![
2963 "Foobar McFooface <foobar@mcfooface.org>".parse()?,
2964 ])?,
2965 version: "v4".parse()?,
2966 },
2967 )?,
2968 ssh_authorized_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPDgwGfIRBAsOUuDEZw/uJQZSwOYr4sg2DAZpcc7MfOj user@host".parse()?,
2969 system_user: "ns1-signing-user1".parse()?,
2970 tag: "signing1".to_string(),
2971 },
2972 ]),
2973 )]
2974 fn nethsm_config_new_fails_validation(
2975 #[case] description: &str,
2976 #[case] connections: BTreeSet<Connection>,
2977 #[case] mappings: BTreeSet<NetHsmUserMapping>,
2978 ) -> TestResult {
2979 let error_msg = match NetHsmConfig::new(connections, mappings) {
2980 Err(crate::Error::Validation { source, .. }) => source.to_string(),
2981 Ok(config) => {
2982 panic!("Expected to fail with Error::Validation, but succeeded instead: {config:?}")
2983 }
2984 Err(error) => panic!(
2985 "Expected to fail with Error::Validation, but failed with a different error instead: {error}"
2986 ),
2987 };
2988
2989 with_settings!({
2990 description => description,
2991 snapshot_path => SNAPSHOT_PATH,
2992 prepend_module_to_snapshot => false,
2993 }, {
2994 assert_snapshot!(current().name().expect("current thread should have a name").to_string().replace("::", "__"), error_msg);
2995 });
2996 Ok(())
2997 }
2998}