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 let val = if newlegalname.is_empty() {
69 vec![]
70 } else {
71 vec![newlegalname.to_string()]
72 };
73 update_entry.attrs.insert(ATTR_LEGALNAME.to_string(), val);
74 }
75 if let Some(mail) = mail {
76 update_entry
77 .attrs
78 .insert(ATTR_MAIL.to_string(), mail.to_vec());
79 }
80
81 self.perform_patch_request(format!("/v1/person/{id}").as_str(), update_entry)
82 .await
83 }
84
85 pub async fn idm_person_account_delete(&self, id: &str) -> Result<(), ClientError> {
86 self.perform_delete_request(format!("/v1/person/{id}").as_str())
87 .await
88 }
89
90 pub async fn idm_person_account_add_attr(
91 &self,
92 id: &str,
93 attr: &str,
94 values: &[&str],
95 ) -> Result<(), ClientError> {
96 let msg: Vec<_> = values.iter().map(|v| (*v).to_string()).collect();
97 self.perform_post_request(format!("/v1/person/{id}/_attr/{attr}").as_str(), msg)
98 .await
99 }
100
101 pub async fn idm_person_account_set_attr(
102 &self,
103 id: &str,
104 attr: &str,
105 values: &[&str],
106 ) -> Result<(), ClientError> {
107 let m: Vec<_> = values.iter().map(|v| (*v).to_string()).collect();
108 self.perform_put_request(format!("/v1/person/{id}/_attr/{attr}").as_str(), m)
109 .await
110 }
111
112 pub async fn idm_person_account_get_attr(
113 &self,
114 id: &str,
115 attr: &str,
116 ) -> Result<Option<Vec<String>>, ClientError> {
117 self.perform_get_request(format!("/v1/person/{id}/_attr/{attr}").as_str())
118 .await
119 }
120
121 pub async fn idm_person_account_purge_attr(
122 &self,
123 id: &str,
124 attr: &str,
125 ) -> Result<(), ClientError> {
126 self.perform_delete_request(format!("/v1/person/{id}/_attr/{attr}").as_str())
127 .await
128 }
129
130 pub async fn idm_person_account_get_credential_status(
131 &self,
132 id: &str,
133 ) -> Result<CredentialStatus, ClientError> {
134 let res: Result<CredentialStatus, ClientError> = self
135 .perform_get_request(format!("/v1/person/{id}/_credential/_status").as_str())
136 .await;
137 res.and_then(|cs| {
138 if cs.creds.is_empty() {
139 Err(ClientError::EmptyResponse)
140 } else {
141 Ok(cs)
142 }
143 })
144 }
145
146 pub async fn idm_person_account_primary_credential_set_password(
148 &self,
149 id: &str,
150 pw: &str,
151 ) -> Result<(), ClientError> {
152 let (session_tok, status) = self.idm_account_credential_update_begin(id).await?;
153 trace!(?status);
154
155 let status = self
156 .idm_account_credential_update_set_password(&session_tok, pw)
157 .await?;
158 trace!(?status);
159
160 self.idm_account_credential_update_commit(&session_tok)
161 .await
162 }
163
164 pub async fn idm_person_account_post_ssh_pubkey(
165 &self,
166 id: &str,
167 tag: &str,
168 pubkey: &str,
169 ) -> Result<(), ClientError> {
170 let sk = (tag.to_string(), pubkey.to_string());
171 self.perform_post_request(format!("/v1/person/{id}/_ssh_pubkeys").as_str(), sk)
172 .await
173 }
174
175 pub async fn idm_person_account_delete_ssh_pubkey(
176 &self,
177 id: &str,
178 tag: &str,
179 ) -> Result<(), ClientError> {
180 self.perform_delete_request(format!("/v1/person/{id}/_ssh_pubkeys/{tag}").as_str())
181 .await
182 }
183
184 pub async fn idm_person_account_unix_extend(
185 &self,
186 id: &str,
187 gidnumber: Option<u32>,
188 shell: Option<&str>,
189 ) -> Result<(), ClientError> {
190 let ux = AccountUnixExtend {
191 shell: shell.map(str::to_string),
192 gidnumber,
193 };
194 self.perform_post_request(format!("/v1/person/{id}/_unix").as_str(), ux)
195 .await
196 }
197
198 pub async fn idm_person_account_unix_cred_put(
199 &self,
200 id: &str,
201 cred: &str,
202 ) -> Result<(), ClientError> {
203 let req = SingleStringRequest {
204 value: cred.to_string(),
205 };
206 self.perform_put_request(
207 ["/v1/person/", id, "/_unix/_credential"].concat().as_str(),
208 req,
209 )
210 .await
211 }
212
213 pub async fn idm_person_account_unix_cred_delete(&self, id: &str) -> Result<(), ClientError> {
214 self.perform_delete_request(["/v1/person/", id, "/_unix/_credential"].concat().as_str())
215 .await
216 }
217
218 pub async fn idm_person_identify_user(
219 &self,
220 id: &str,
221 request: IdentifyUserRequest,
222 ) -> Result<IdentifyUserResponse, ClientError> {
223 self.perform_post_request(
224 ["/v1/person/", id, "/_identify_user"].concat().as_str(),
225 request,
226 )
227 .await
228 }
229
230 pub async fn idm_account_radius_credential_get(
231 &self,
232 id: &str,
233 ) -> Result<Option<String>, ClientError> {
234 self.perform_get_request(format!("/v1/person/{id}/_radius").as_str())
235 .await
236 }
237
238 pub async fn idm_account_radius_credential_regenerate(
239 &self,
240 id: &str,
241 ) -> Result<String, ClientError> {
242 self.perform_post_request(format!("/v1/person/{id}/_radius").as_str(), ())
243 .await
244 }
245
246 pub async fn idm_account_radius_credential_delete(&self, id: &str) -> Result<(), ClientError> {
247 self.perform_delete_request(format!("/v1/person/{id}/_radius").as_str())
248 .await
249 }
250
251 pub async fn idm_account_list_user_auth_token(
252 &self,
253 id: &str,
254 ) -> Result<Vec<UatStatus>, ClientError> {
255 self.perform_get_request(format!("/v1/account/{id}/_user_auth_token").as_str())
256 .await
257 }
258
259 pub async fn idm_account_destroy_user_auth_token(
260 &self,
261 id: &str,
262 token_id: Uuid,
263 ) -> Result<(), ClientError> {
264 self.perform_delete_request(
265 format!(
266 "/v1/account/{}/_user_auth_token/{}",
267 id,
268 &token_id.to_string()
269 )
270 .as_str(),
271 )
272 .await
273 }
274
275 pub async fn idm_person_certificate_list(&self, id: &str) -> Result<Vec<Entry>, ClientError> {
276 self.perform_get_request(format!("/v1/person/{id}/_certificate").as_str())
277 .await
278 }
279
280 pub async fn idm_person_certificate_create(
281 &self,
282 id: &str,
283 pem_data: &str,
284 ) -> Result<(), ClientError> {
285 let mut new_cert = Entry {
286 attrs: BTreeMap::new(),
287 };
288 new_cert
289 .attrs
290 .insert(ATTR_CERTIFICATE.to_string(), vec![pem_data.to_string()]);
291 self.perform_post_request(format!("/v1/person/{id}/_certificate").as_str(), new_cert)
292 .await
293 }
294}