scratchstack_aws_principal/
root_user.rs1use {
2 crate::PrincipalError,
3 scratchstack_arn::{
4 utils::{validate_account_id, validate_partition},
5 Arn,
6 },
7 std::fmt::{Display, Formatter, Result as FmtResult},
8};
9
10#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
14pub struct RootUser {
15 partition: String,
17
18 account_id: String,
20}
21
22impl RootUser {
23 pub fn new(partition: &str, account_id: &str) -> Result<Self, PrincipalError> {
36 validate_partition(partition)?;
37 validate_account_id(account_id)?;
38
39 Ok(Self {
40 partition: partition.into(),
41 account_id: account_id.into(),
42 })
43 }
44
45 #[inline]
47 pub fn partition(&self) -> &str {
48 &self.partition
49 }
50
51 #[inline]
53 pub fn account_id(&self) -> &str {
54 &self.account_id
55 }
56}
57
58impl From<&RootUser> for Arn {
59 fn from(root_user: &RootUser) -> Self {
60 Arn::new(&root_user.partition, "iam", "", &root_user.account_id, "root").unwrap()
61 }
62}
63
64impl Display for RootUser {
65 fn fmt(&self, f: &mut Formatter) -> FmtResult {
66 write!(f, "{}", self.account_id)
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use {
73 super::RootUser,
74 crate::{PrincipalIdentity, PrincipalSource},
75 scratchstack_arn::Arn,
76 std::{
77 collections::hash_map::DefaultHasher,
78 hash::{Hash, Hasher},
79 },
80 };
81
82 #[test]
83 fn check_components() {
84 let root_user = RootUser::new("aws", "123456789012").unwrap();
85 assert_eq!(root_user.partition(), "aws");
86 assert_eq!(root_user.account_id(), "123456789012");
87
88 let p = PrincipalIdentity::from(root_user);
89 let source = p.source();
90 assert_eq!(source, PrincipalSource::Aws);
91 assert_eq!(source.to_string(), "AWS");
92 }
93
94 #[test]
95 fn check_derived() {
96 let r1a = RootUser::new("aws", "123456789012").unwrap();
97 let r1b = RootUser::new("aws", "123456789012").unwrap();
98 let r2 = RootUser::new("aws", "123456789099").unwrap();
99 let r3 = RootUser::new("awt", "123456789099").unwrap();
100
101 let mut h1a = DefaultHasher::new();
103 let mut h1b = DefaultHasher::new();
104 r1a.hash(&mut h1a);
105 r1b.hash(&mut h1b);
106 assert_eq!(h1a.finish(), h1b.finish());
107
108 assert!(r1a <= r1b);
109 assert!(r1a < r2);
110 assert!(r2 > r1a);
111 assert!(r2 < r3);
112 assert!(r3 > r2);
113 assert!(r1a < r3);
114
115 assert!(r1a.clone().min(r2.clone()) == r1a);
116 assert!(r2.clone().max(r1a.clone()) == r2);
117
118 let _ = format!("{r1a:?}");
120 }
121
122 #[test]
123 fn check_valid_root_users() {
124 let r1a = RootUser::new("aws", "123456789012").unwrap();
125 let r1b = RootUser::new("aws", "123456789012").unwrap();
126 let r2 = RootUser::new("aws", "123456789099").unwrap();
127
128 assert_eq!(r1a, r1b);
129 assert_ne!(r1a, r2);
130 assert_eq!(r1a, r1a.clone());
131
132 assert_eq!(r1a.to_string(), "123456789012");
133 assert_eq!(r2.to_string(), "123456789099");
134
135 let arn1a: Arn = (&r1a).into();
136
137 assert_eq!(arn1a.partition(), "aws");
138 assert_eq!(arn1a.service(), "iam");
139 assert_eq!(arn1a.region(), "");
140 assert_eq!(arn1a.account_id(), "123456789012");
141 assert_eq!(arn1a.resource(), "root");
142 }
143
144 #[test]
145 fn check_invalid_root_users() {
146 assert_eq!(RootUser::new("", "123456789012",).unwrap_err().to_string(), r#"Invalid partition: """#);
147 assert_eq!(RootUser::new("aws", "",).unwrap_err().to_string(), r#"Invalid account id: """#);
148 }
149}
150