kanidm_client/
person.rs

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    // This helper calls through the credential update session wrappers to
142    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}