1use std::collections::BTreeMap;
2
3use kanidm_proto::constants::*;
4use kanidm_proto::internal::{CredentialStatus, IdentifyUserRequest, IdentifyUserResponse};
5use kanidm_proto::v1::{AccountUnixExtend, Entry, SingleStringRequest, UatStatus};
6use uuid::Uuid;
7
8use crate::{ClientError, KanidmClient};
9
10impl KanidmClient {
11 pub async fn idm_person_account_list(&self) -> Result<Vec<Entry>, ClientError> {
12 self.perform_get_request("/v1/person").await
13 }
14
15 pub async fn idm_person_account_get(&self, id: &str) -> Result<Option<Entry>, ClientError> {
16 self.perform_get_request(format!("/v1/person/{}", id).as_str())
17 .await
18 }
19
20 pub async fn idm_person_search(&self, id: &str) -> Result<Vec<Entry>, ClientError> {
21 self.perform_get_request(format!("/v1/person/_search/{}", id).as_str())
22 .await
23 }
24
25 pub async fn idm_person_account_create(
26 &self,
27 name: &str,
28 displayname: &str,
29 ) -> Result<(), ClientError> {
30 let mut new_acct = Entry {
31 attrs: BTreeMap::new(),
32 };
33 new_acct
34 .attrs
35 .insert(ATTR_NAME.to_string(), vec![name.to_string()]);
36 new_acct
37 .attrs
38 .insert(ATTR_DISPLAYNAME.to_string(), vec![displayname.to_string()]);
39 self.perform_post_request("/v1/person", new_acct).await
40 }
41
42 pub async fn idm_person_account_update(
43 &self,
44 id: &str,
45 newname: Option<&str>,
46 displayname: Option<&str>,
47 legalname: Option<&str>,
48 mail: Option<&[String]>,
49 ) -> Result<(), ClientError> {
50 let mut update_entry = Entry {
51 attrs: BTreeMap::new(),
52 };
53
54 if let Some(newname) = newname {
55 update_entry
56 .attrs
57 .insert(ATTR_NAME.to_string(), vec![newname.to_string()]);
58 }
59 if let Some(newdisplayname) = displayname {
60 update_entry.attrs.insert(
61 ATTR_DISPLAYNAME.to_string(),
62 vec![newdisplayname.to_string()],
63 );
64 }
65 if let Some(newlegalname) = legalname {
66 update_entry
67 .attrs
68 .insert(ATTR_LEGALNAME.to_string(), vec![newlegalname.to_string()]);
69 }
70 if let Some(mail) = mail {
71 update_entry
72 .attrs
73 .insert(ATTR_MAIL.to_string(), mail.to_vec());
74 }
75
76 self.perform_patch_request(format!("/v1/person/{}", id).as_str(), update_entry)
77 .await
78 }
79
80 pub async fn idm_person_account_delete(&self, id: &str) -> Result<(), ClientError> {
81 self.perform_delete_request(format!("/v1/person/{}", id).as_str())
82 .await
83 }
84
85 pub async fn idm_person_account_add_attr(
86 &self,
87 id: &str,
88 attr: &str,
89 values: &[&str],
90 ) -> Result<(), ClientError> {
91 let msg: Vec<_> = values.iter().map(|v| (*v).to_string()).collect();
92 self.perform_post_request(format!("/v1/person/{}/_attr/{}", id, attr).as_str(), msg)
93 .await
94 }
95
96 pub async fn idm_person_account_set_attr(
97 &self,
98 id: &str,
99 attr: &str,
100 values: &[&str],
101 ) -> Result<(), ClientError> {
102 let m: Vec<_> = values.iter().map(|v| (*v).to_string()).collect();
103 self.perform_put_request(format!("/v1/person/{}/_attr/{}", id, attr).as_str(), m)
104 .await
105 }
106
107 pub async fn idm_person_account_get_attr(
108 &self,
109 id: &str,
110 attr: &str,
111 ) -> Result<Option<Vec<String>>, ClientError> {
112 self.perform_get_request(format!("/v1/person/{}/_attr/{}", id, attr).as_str())
113 .await
114 }
115
116 pub async fn idm_person_account_purge_attr(
117 &self,
118 id: &str,
119 attr: &str,
120 ) -> Result<(), ClientError> {
121 self.perform_delete_request(format!("/v1/person/{}/_attr/{}", id, attr).as_str())
122 .await
123 }
124
125 pub async fn idm_person_account_get_credential_status(
126 &self,
127 id: &str,
128 ) -> Result<CredentialStatus, ClientError> {
129 let res: Result<CredentialStatus, ClientError> = self
130 .perform_get_request(format!("/v1/person/{}/_credential/_status", id).as_str())
131 .await;
132 res.and_then(|cs| {
133 if cs.creds.is_empty() {
134 Err(ClientError::EmptyResponse)
135 } else {
136 Ok(cs)
137 }
138 })
139 }
140
141 pub async fn idm_person_account_primary_credential_set_password(
143 &self,
144 id: &str,
145 pw: &str,
146 ) -> Result<(), ClientError> {
147 let (session_tok, status) = self.idm_account_credential_update_begin(id).await?;
148 trace!(?status);
149
150 let status = self
151 .idm_account_credential_update_set_password(&session_tok, pw)
152 .await?;
153 trace!(?status);
154
155 self.idm_account_credential_update_commit(&session_tok)
156 .await
157 }
158
159 pub async fn idm_person_account_post_ssh_pubkey(
160 &self,
161 id: &str,
162 tag: &str,
163 pubkey: &str,
164 ) -> Result<(), ClientError> {
165 let sk = (tag.to_string(), pubkey.to_string());
166 self.perform_post_request(format!("/v1/person/{}/_ssh_pubkeys", id).as_str(), sk)
167 .await
168 }
169
170 pub async fn idm_person_account_delete_ssh_pubkey(
171 &self,
172 id: &str,
173 tag: &str,
174 ) -> Result<(), ClientError> {
175 self.perform_delete_request(format!("/v1/person/{}/_ssh_pubkeys/{}", id, tag).as_str())
176 .await
177 }
178
179 pub async fn idm_person_account_unix_extend(
180 &self,
181 id: &str,
182 gidnumber: Option<u32>,
183 shell: Option<&str>,
184 ) -> Result<(), ClientError> {
185 let ux = AccountUnixExtend {
186 shell: shell.map(str::to_string),
187 gidnumber,
188 };
189 self.perform_post_request(format!("/v1/person/{}/_unix", id).as_str(), ux)
190 .await
191 }
192
193 pub async fn idm_person_account_unix_cred_put(
194 &self,
195 id: &str,
196 cred: &str,
197 ) -> Result<(), ClientError> {
198 let req = SingleStringRequest {
199 value: cred.to_string(),
200 };
201 self.perform_put_request(
202 ["/v1/person/", id, "/_unix/_credential"].concat().as_str(),
203 req,
204 )
205 .await
206 }
207
208 pub async fn idm_person_account_unix_cred_delete(&self, id: &str) -> Result<(), ClientError> {
209 self.perform_delete_request(["/v1/person/", id, "/_unix/_credential"].concat().as_str())
210 .await
211 }
212
213 pub async fn idm_person_identify_user(
214 &self,
215 id: &str,
216 request: IdentifyUserRequest,
217 ) -> Result<IdentifyUserResponse, ClientError> {
218 self.perform_post_request(
219 ["/v1/person/", id, "/_identify_user"].concat().as_str(),
220 request,
221 )
222 .await
223 }
224
225 pub async fn idm_account_radius_credential_get(
226 &self,
227 id: &str,
228 ) -> Result<Option<String>, ClientError> {
229 self.perform_get_request(format!("/v1/person/{}/_radius", id).as_str())
230 .await
231 }
232
233 pub async fn idm_account_radius_credential_regenerate(
234 &self,
235 id: &str,
236 ) -> Result<String, ClientError> {
237 self.perform_post_request(format!("/v1/person/{}/_radius", id).as_str(), ())
238 .await
239 }
240
241 pub async fn idm_account_radius_credential_delete(&self, id: &str) -> Result<(), ClientError> {
242 self.perform_delete_request(format!("/v1/person/{}/_radius", id).as_str())
243 .await
244 }
245
246 pub async fn idm_account_list_user_auth_token(
247 &self,
248 id: &str,
249 ) -> Result<Vec<UatStatus>, ClientError> {
250 self.perform_get_request(format!("/v1/account/{}/_user_auth_token", id).as_str())
251 .await
252 }
253
254 pub async fn idm_account_destroy_user_auth_token(
255 &self,
256 id: &str,
257 token_id: Uuid,
258 ) -> Result<(), ClientError> {
259 self.perform_delete_request(
260 format!(
261 "/v1/account/{}/_user_auth_token/{}",
262 id,
263 &token_id.to_string()
264 )
265 .as_str(),
266 )
267 .await
268 }
269
270 pub async fn idm_person_certificate_list(&self, id: &str) -> Result<Vec<Entry>, ClientError> {
271 self.perform_get_request(format!("/v1/person/{}/_certificate", id).as_str())
272 .await
273 }
274
275 pub async fn idm_person_certificate_create(
276 &self,
277 id: &str,
278 pem_data: &str,
279 ) -> Result<(), ClientError> {
280 let mut new_cert = Entry {
281 attrs: BTreeMap::new(),
282 };
283 new_cert
284 .attrs
285 .insert(ATTR_CERTIFICATE.to_string(), vec![pem_data.to_string()]);
286 self.perform_post_request(format!("/v1/person/{}/_certificate", id).as_str(), new_cert)
287 .await
288 }
289}