kanidmd_lib/idm/
identityverification.rs

1use crate::prelude::*;
2use std::time::SystemTime;
3
4use kanidm_proto::internal::IdentifyUserResponse;
5use openssl::ec::EcKey;
6use openssl::pkey::{PKey, Private, Public};
7use openssl::pkey_ctx::PkeyCtx;
8use sketching::admin_error;
9use uuid::Uuid;
10
11use crate::credential::totp::{Totp, TotpAlgo, TotpDigits};
12use crate::server::QueryServerTransaction;
13use crate::{event::SearchEvent, server::identity::Identity};
14
15use crate::idm::server::IdmServerProxyReadTransaction;
16
17static TOTP_STEP: u64 = 30;
18
19#[derive(Debug)]
20pub struct IdentifyUserStartEvent {
21    pub target: Uuid,
22    pub ident: Identity,
23}
24
25impl IdentifyUserStartEvent {
26    pub fn new(target: Uuid, ident: Identity) -> Self {
27        IdentifyUserStartEvent { target, ident }
28    }
29}
30pub struct IdentifyUserDisplayCodeEvent {
31    pub target: Uuid,
32    pub ident: Identity,
33}
34
35impl IdentifyUserDisplayCodeEvent {
36    pub fn new(target: Uuid, ident: Identity) -> Self {
37        IdentifyUserDisplayCodeEvent { target, ident }
38    }
39}
40
41pub struct IdentifyUserSubmitCodeEvent {
42    pub code: u32,
43    pub target: Uuid,
44    pub ident: Identity,
45}
46
47impl IdentifyUserSubmitCodeEvent {
48    pub fn new(target: Uuid, ident: Identity, code: u32) -> Self {
49        IdentifyUserSubmitCodeEvent {
50            target,
51            ident,
52            code,
53        }
54    }
55}
56
57impl IdmServerProxyReadTransaction<'_> {
58    pub fn handle_identify_user_start(
59        &mut self,
60        IdentifyUserStartEvent { target, ident }: &IdentifyUserStartEvent,
61    ) -> Result<IdentifyUserResponse, OperationError> {
62        if let Some(early_response) = self.check_for_early_return_conditions(ident, target)? {
63            return Ok(early_response);
64        }
65        let response = if ident.get_uuid() < Some(*target) {
66            IdentifyUserResponse::WaitForCode
67        } else {
68            let totp_secret = self.get_self_totp_secret(target, ident)?;
69            let totp = self.compute_totp(totp_secret)?;
70            IdentifyUserResponse::ProvideCode {
71                step: TOTP_STEP as u32,
72                totp,
73            }
74        };
75        Ok(response)
76    }
77
78    pub fn handle_identify_user_display_code(
79        &mut self,
80        IdentifyUserDisplayCodeEvent { target, ident }: &IdentifyUserDisplayCodeEvent,
81    ) -> Result<IdentifyUserResponse, OperationError> {
82        if let Some(early_response) = self.check_for_early_return_conditions(ident, target)? {
83            return Ok(early_response);
84        }
85
86        let totp_secret = self.get_self_totp_secret(target, ident)?;
87        let totp = self.compute_totp(totp_secret)?;
88        Ok(IdentifyUserResponse::ProvideCode {
89            step: TOTP_STEP as u32,
90            totp,
91        })
92    }
93
94    pub fn handle_identify_user_submit_code(
95        &mut self,
96        IdentifyUserSubmitCodeEvent {
97            target,
98            ident,
99            code,
100        }: &IdentifyUserSubmitCodeEvent,
101    ) -> Result<IdentifyUserResponse, OperationError> {
102        if let Some(early_response) = self.check_for_early_return_conditions(ident, target)? {
103            return Ok(early_response);
104        }
105
106        let totp_secret = self.get_other_user_totp_secret(target, ident)?;
107        let other_user_totp = self.compute_totp(totp_secret)?;
108        if other_user_totp != *code {
109            return Ok(IdentifyUserResponse::CodeFailure);
110        }
111        // if we are the first it means now it's time to go for ProvideCode, otherwise we just confirm that the code is correct
112        // (we know this for a fact as we have already checked that the code is correct)
113        let res = if ident.get_uuid() < Some(*target) {
114            let shared_secret = self.get_self_totp_secret(target, ident)?;
115            let totp = self.compute_totp(shared_secret)?;
116            IdentifyUserResponse::ProvideCode {
117                step: TOTP_STEP as u32,
118                totp,
119            }
120        } else {
121            IdentifyUserResponse::Success
122        };
123        Ok(res)
124    }
125
126    // End of public functions
127
128    fn check_for_early_return_conditions(
129        &mut self,
130        ident: &Identity,
131        target: &Uuid,
132    ) -> Result<Option<IdentifyUserResponse>, OperationError> {
133        // here we check that the identify user feature is available before we do anything else
134        if !self.check_if_identify_feature_available(ident)? {
135            return Ok(Some(IdentifyUserResponse::IdentityVerificationUnavailable));
136        };
137
138        if !self.is_valid_user_uuid(ident, target)? {
139            return Ok(Some(IdentifyUserResponse::InvalidUserId));
140        };
141        // here we check if the user provided their own uuid, if they did we just respond with IdentityVerificationAvailable.
142        if ident.get_uuid().eq(&Some(*target)) {
143            return Ok(Some(IdentifyUserResponse::IdentityVerificationAvailable));
144        };
145        Ok(None)
146    }
147
148    fn check_if_identify_feature_available(
149        &mut self,
150        ident: &Identity,
151    ) -> Result<bool, OperationError> {
152        let search = match SearchEvent::from_whoami_request(ident.clone(), &self.qs_read) {
153            Ok(s) => s,
154            Err(e) => {
155                admin_error!("Failed to generate whoami search event: {:?}", e);
156                return Err(e);
157            }
158        };
159        self.qs_read
160            .search(&search)
161            .and_then(|mut entries| entries.pop().ok_or(OperationError::NoMatchingEntries))
162            .map(
163                |entry| match entry.get_ava_single_eckey_private(Attribute::IdVerificationEcKey) {
164                    Some(key) => key.check_key().is_ok(),
165                    None => false,
166                },
167            )
168    }
169
170    fn is_valid_user_uuid(
171        &mut self,
172        ident: &Identity,
173        target: &Uuid,
174    ) -> Result<bool, OperationError> {
175        let search =
176            match SearchEvent::from_target_uuid_request(ident.clone(), *target, &self.qs_read) {
177                Ok(s) => s,
178                Err(e) => {
179                    admin_error!("Failed to retrieve user with the given UUID: {:?}", e);
180                    return Err(e);
181                }
182            };
183
184        let user_entry = self
185            .qs_read
186            .search(&search)
187            .and_then(|mut entries| entries.pop().ok_or(OperationError::NoMatchingEntries))?;
188
189        match user_entry.get_ava_single_eckey_public(Attribute::IdVerificationEcKey) {
190            Some(key) => Ok(key.check_key().is_ok()),
191            None => Ok(false),
192        }
193    }
194
195    fn get_user_own_key(&mut self, ident: &Identity) -> Result<EcKey<Private>, OperationError> {
196        let search = match SearchEvent::from_whoami_request(ident.clone(), &self.qs_read) {
197            Ok(s) => s,
198            Err(e) => {
199                admin_error!(
200                    "Failed to retrieve user with the given UUID: {}. \n{:?}",
201                    ident.get_uuid().unwrap_or_default(),
202                    e
203                );
204                return Err(e);
205            }
206        };
207
208        self.qs_read
209            .search(&search)
210            .and_then(|mut entries| entries.pop().ok_or(OperationError::NoMatchingEntries))
211            .and_then(|entry| {
212                match entry.get_ava_single_eckey_private(Attribute::IdVerificationEcKey) {
213                    Some(key) => Ok(key.clone()),
214                    None => Err(OperationError::InvalidAccountState(format!(
215                        "{}'s private key is missing!",
216                        ident.get_uuid().unwrap_or_default()
217                    ))),
218                }
219            })
220    }
221
222    fn get_other_user_public_key(
223        &mut self,
224        target: &Uuid,
225        ident: &Identity,
226    ) -> Result<EcKey<Public>, OperationError> {
227        let search =
228            match SearchEvent::from_target_uuid_request(ident.clone(), *target, &self.qs_read) {
229                Ok(s) => s,
230                Err(e) => {
231                    admin_error!(
232                        "Failed to retrieve user with the given UUID: {}. \n{:?}",
233                        ident.get_uuid().unwrap_or_default(),
234                        e
235                    );
236                    return Err(e);
237                }
238            };
239        self.qs_read
240            .search(&search)
241            .and_then(|mut entries| entries.pop().ok_or(OperationError::NoMatchingEntries))
242            .and_then(|entry| {
243                match entry.get_ava_single_eckey_public(Attribute::IdVerificationEcKey) {
244                    Some(key) => Ok(key.clone()),
245                    None => Err(OperationError::InvalidAccountState(format!(
246                        "{target}'s public key is missing!",
247                    ))),
248                }
249            })
250    }
251
252    fn compute_totp(&mut self, totp_secret: Vec<u8>) -> Result<u32, OperationError> {
253        let totp = Totp::new(totp_secret, TOTP_STEP, TotpAlgo::Sha256, TotpDigits::Six);
254        let current_time = SystemTime::now();
255        totp.do_totp(&current_time)
256            .map_err(|_| OperationError::CryptographyError)
257    }
258
259    fn get_self_totp_secret(
260        &mut self,
261        target: &Uuid,
262        ident: &Identity,
263    ) -> Result<Vec<u8>, OperationError> {
264        let self_private = self.get_user_own_key(ident)?;
265        let other_user_public_key = self.get_other_user_public_key(target, ident)?;
266        let mut shared_key = self.derive_shared_key(self_private, other_user_public_key)?;
267        let Some(self_uuid) = ident.get_uuid() else {
268            return Err(OperationError::NotAuthenticated);
269        };
270        shared_key.extend_from_slice(self_uuid.as_bytes());
271        Ok(shared_key)
272    }
273
274    fn get_other_user_totp_secret(
275        &mut self,
276        target: &Uuid,
277        ident: &Identity,
278    ) -> Result<Vec<u8>, OperationError> {
279        let self_private = self.get_user_own_key(ident)?;
280        let other_user_public_key = self.get_other_user_public_key(target, ident)?;
281        let mut shared_key = self.derive_shared_key(self_private, other_user_public_key)?;
282        shared_key.extend_from_slice(target.as_bytes());
283        Ok(shared_key)
284    }
285
286    fn derive_shared_key(
287        &self,
288        private: EcKey<Private>,
289        public: EcKey<Public>,
290    ) -> Result<Vec<u8>, OperationError> {
291        let cryptography_error = |_| OperationError::CryptographyError;
292        let pkey_private = PKey::from_ec_key(private).map_err(cryptography_error)?;
293        let pkey_public = PKey::from_ec_key(public).map_err(cryptography_error)?;
294
295        let mut private_key_ctx: PkeyCtx<Private> =
296            PkeyCtx::new(&pkey_private).map_err(cryptography_error)?;
297        private_key_ctx.derive_init().map_err(cryptography_error)?;
298        private_key_ctx
299            .derive_set_peer(&pkey_public)
300            .map_err(cryptography_error)?;
301        let keylen = private_key_ctx.derive(None).map_err(cryptography_error)?;
302        let mut tmp_vec = vec![0; keylen];
303        let buffer = tmp_vec.as_mut_slice();
304        private_key_ctx
305            .derive(Some(buffer))
306            .map_err(cryptography_error)?;
307        Ok(buffer.to_vec())
308    }
309}
310
311#[cfg(test)]
312mod test {
313    use kanidm_proto::internal::IdentifyUserResponse;
314
315    use crate::idm::identityverification::{
316        IdentifyUserDisplayCodeEvent, IdentifyUserStartEvent, IdentifyUserSubmitCodeEvent,
317    };
318    use crate::prelude::*;
319
320    #[idm_test]
321    async fn test_identity_verification_unavailable(
322        idms: &IdmServer,
323        _idms_delayed: &IdmServerDelayed,
324    ) {
325        let ct = duration_from_epoch_now();
326        let mut idms_prox_write = idms.proxy_write(ct).await.unwrap();
327
328        let self_uuid = Uuid::new_v4();
329        let valid_user_uuid = Uuid::new_v4();
330
331        let e1 = create_invalid_user_account(self_uuid);
332
333        let e2 = create_valid_user_account(valid_user_uuid);
334
335        let ce = CreateEvent::new_internal(vec![e1, e2]);
336        assert!(idms_prox_write.qs_write.create(&ce).is_ok());
337        assert!(idms_prox_write.commit().is_ok());
338
339        let mut idms_prox_read = idms.proxy_read().await.unwrap();
340
341        let ident = idms_prox_read
342            .qs_read
343            .internal_search_uuid(self_uuid)
344            .map(Identity::from_impersonate_entry_readonly)
345            .expect("Failed to impersonate identity");
346
347        let res = idms_prox_read
348            .handle_identify_user_start(&IdentifyUserStartEvent::new(self_uuid, ident.clone()));
349
350        assert!(matches!(
351            res,
352            Ok(IdentifyUserResponse::IdentityVerificationUnavailable)
353        ));
354
355        let res = idms_prox_read.handle_identify_user_start(&IdentifyUserStartEvent::new(
356            valid_user_uuid,
357            ident.clone(),
358        ));
359
360        assert!(matches!(
361            res,
362            Ok(IdentifyUserResponse::IdentityVerificationUnavailable)
363        ));
364
365        let res = idms_prox_read.handle_identify_user_display_code(
366            &IdentifyUserDisplayCodeEvent::new(valid_user_uuid, ident.clone()),
367        );
368
369        assert!(matches!(
370            res,
371            Ok(IdentifyUserResponse::IdentityVerificationUnavailable)
372        ));
373        let res = idms_prox_read.handle_identify_user_submit_code(
374            &IdentifyUserSubmitCodeEvent::new(valid_user_uuid, ident, 123456),
375        );
376
377        assert!(matches!(
378            res,
379            Ok(IdentifyUserResponse::IdentityVerificationUnavailable)
380        ));
381    }
382
383    #[idm_test]
384    async fn test_invalid_user_id(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
385        let ct = duration_from_epoch_now();
386        let mut idms_prox_write = idms.proxy_write(ct).await.unwrap();
387
388        let invalid_user_uuid = Uuid::new_v4();
389        let valid_user_a_uuid = Uuid::new_v4();
390        let valid_user_b_uuid = Uuid::new_v4();
391
392        let e1 = create_invalid_user_account(invalid_user_uuid);
393
394        let e2 = create_valid_user_account(valid_user_a_uuid);
395
396        let e3 = create_valid_user_account(valid_user_b_uuid);
397
398        let ce = CreateEvent::new_internal(vec![e1, e2, e3]);
399
400        assert!(idms_prox_write.qs_write.create(&ce).is_ok());
401        assert!(idms_prox_write.commit().is_ok());
402
403        let mut idms_prox_read = idms.proxy_read().await.unwrap();
404
405        let ident = idms_prox_read
406            .qs_read
407            .internal_search_uuid(valid_user_a_uuid)
408            .map(Identity::from_impersonate_entry_readonly)
409            .expect("Failed to impersonate identity");
410
411        let res = idms_prox_read.handle_identify_user_start(&IdentifyUserStartEvent::new(
412            invalid_user_uuid,
413            ident.clone(),
414        ));
415
416        assert!(matches!(res, Ok(IdentifyUserResponse::InvalidUserId)));
417
418        let res = idms_prox_read.handle_identify_user_start(&IdentifyUserStartEvent::new(
419            invalid_user_uuid,
420            ident.clone(),
421        ));
422
423        assert!(matches!(res, Ok(IdentifyUserResponse::InvalidUserId)));
424
425        let res = idms_prox_read.handle_identify_user_display_code(
426            &IdentifyUserDisplayCodeEvent::new(invalid_user_uuid, ident.clone()),
427        );
428
429        assert!(matches!(res, Ok(IdentifyUserResponse::InvalidUserId)));
430        let res = idms_prox_read.handle_identify_user_submit_code(
431            &IdentifyUserSubmitCodeEvent::new(invalid_user_uuid, ident, 123456),
432        );
433
434        assert!(matches!(res, Ok(IdentifyUserResponse::InvalidUserId)));
435    }
436
437    #[idm_test]
438    async fn test_start_event(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
439        let ct = duration_from_epoch_now();
440        let mut idms_prox_write = idms.proxy_write(ct).await.unwrap();
441
442        let valid_user_a_uuid = Uuid::new_v4();
443
444        let e = create_valid_user_account(valid_user_a_uuid);
445        let ce = CreateEvent::new_internal(vec![e]);
446        assert!(idms_prox_write.qs_write.create(&ce).is_ok());
447        assert!(idms_prox_write.commit().is_ok());
448
449        let mut idms_prox_read = idms.proxy_read().await.unwrap();
450
451        let ident = idms_prox_read
452            .qs_read
453            .internal_search_uuid(valid_user_a_uuid)
454            .map(Identity::from_impersonate_entry_readonly)
455            .expect("Failed to impersonate identity");
456
457        let res = idms_prox_read.handle_identify_user_start(&IdentifyUserStartEvent::new(
458            valid_user_a_uuid,
459            ident.clone(),
460        ));
461
462        assert!(matches!(
463            res,
464            Ok(IdentifyUserResponse::IdentityVerificationAvailable)
465        ));
466    }
467
468    #[idm_test] // actually this is somewhat a duplicate of `test_full_identification_flow` inside the testkit, with the exception that this
469                //tests ONLY the totp code correctness and not the flow correctness. To test the correctness it obviously needs to also
470                // enforce some flow checks, but this is not the primary scope of this test
471    async fn test_code_correctness(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
472        let ct = duration_from_epoch_now();
473        let mut idms_prox_write = idms.proxy_write(ct).await.unwrap();
474        let user_a_uuid = Uuid::new_v4();
475        let user_b_uuid = Uuid::new_v4();
476        let e1 = create_valid_user_account(user_a_uuid);
477        let e2 = create_valid_user_account(user_b_uuid);
478        let ce = CreateEvent::new_internal(vec![e1, e2]);
479
480        assert!(idms_prox_write.qs_write.create(&ce).is_ok());
481        assert!(idms_prox_write.commit().is_ok());
482
483        let mut idms_prox_read = idms.proxy_read().await.unwrap();
484
485        let ident_a = idms_prox_read
486            .qs_read
487            .internal_search_uuid(user_a_uuid)
488            .map(Identity::from_impersonate_entry_readonly)
489            .expect("Failed to impersonate identity");
490
491        let ident_b = idms_prox_read
492            .qs_read
493            .internal_search_uuid(user_b_uuid)
494            .map(Identity::from_impersonate_entry_readonly)
495            .expect("Failed to impersonate identity");
496
497        let (lower_user, lower_user_uuid, higher_user, higher_user_uuid) =
498            if user_a_uuid < user_b_uuid {
499                (ident_a, user_a_uuid, ident_b, user_b_uuid)
500            } else {
501                (ident_b, user_b_uuid, ident_a, user_a_uuid)
502            };
503
504        // First the user with the lowest uuid receives the uuid from the other user
505
506        let res_higher_user = idms_prox_read.handle_identify_user_start(
507            &IdentifyUserStartEvent::new(lower_user_uuid, higher_user.clone()),
508        );
509
510        let Ok(IdentifyUserResponse::ProvideCode { totp, .. }) = res_higher_user else {
511            panic!();
512        };
513
514        let res_lower_user_wrong = idms_prox_read.handle_identify_user_submit_code(
515            &IdentifyUserSubmitCodeEvent::new(higher_user_uuid, lower_user.clone(), totp + 1),
516        );
517
518        assert!(matches!(
519            res_lower_user_wrong,
520            Ok(IdentifyUserResponse::CodeFailure)
521        ));
522
523        let res_lower_user_correct = idms_prox_read.handle_identify_user_submit_code(
524            &IdentifyUserSubmitCodeEvent::new(higher_user_uuid, lower_user.clone(), totp),
525        );
526
527        assert!(matches!(
528            res_lower_user_correct,
529            Ok(IdentifyUserResponse::ProvideCode { .. })
530        ));
531
532        // now we need to get the code from the lower_user and submit it to the higher_user
533
534        let Ok(IdentifyUserResponse::ProvideCode { totp, .. }) = res_lower_user_correct else {
535            panic!("Invalid");
536        };
537
538        let res_higher_user_2_wrong = idms_prox_read.handle_identify_user_submit_code(
539            &IdentifyUserSubmitCodeEvent::new(lower_user_uuid, higher_user.clone(), totp + 1),
540        );
541
542        assert!(matches!(
543            res_higher_user_2_wrong,
544            Ok(IdentifyUserResponse::CodeFailure)
545        ));
546
547        let res_higher_user_2_correct = idms_prox_read.handle_identify_user_submit_code(
548            &IdentifyUserSubmitCodeEvent::new(lower_user_uuid, higher_user.clone(), totp),
549        );
550
551        assert!(matches!(
552            res_higher_user_2_correct,
553            Ok(IdentifyUserResponse::Success)
554        ));
555    }
556
557    #[idm_test]
558
559    async fn test_totps_differ(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
560        let ct = duration_from_epoch_now();
561        let mut idms_prox_write = idms.proxy_write(ct).await.unwrap();
562        let user_a_uuid = Uuid::new_v4();
563        let user_b_uuid = Uuid::new_v4();
564        let e1 = create_valid_user_account(user_a_uuid);
565        let e2 = create_valid_user_account(user_b_uuid);
566        let ce = CreateEvent::new_internal(vec![e1, e2]);
567
568        assert!(idms_prox_write.qs_write.create(&ce).is_ok());
569        assert!(idms_prox_write.commit().is_ok());
570
571        let mut idms_prox_read = idms.proxy_read().await.unwrap();
572
573        let ident_a = idms_prox_read
574            .qs_read
575            .internal_search_uuid(user_a_uuid)
576            .map(Identity::from_impersonate_entry_readonly)
577            .expect("Failed to impersonate identity");
578
579        let ident_b = idms_prox_read
580            .qs_read
581            .internal_search_uuid(user_b_uuid)
582            .map(Identity::from_impersonate_entry_readonly)
583            .expect("Failed to impersonate identity");
584
585        let (lower_user, lower_user_uuid, higher_user, higher_user_uuid) =
586            if user_a_uuid < user_b_uuid {
587                (ident_a, user_a_uuid, ident_b, user_b_uuid)
588            } else {
589                (ident_b, user_b_uuid, ident_a, user_a_uuid)
590            };
591
592        // First twe retrieve the higher user code
593
594        let res_higher_user = idms_prox_read.handle_identify_user_start(
595            &IdentifyUserStartEvent::new(lower_user_uuid, higher_user.clone()),
596        );
597
598        let Ok(IdentifyUserResponse::ProvideCode {
599            totp: higher_user_totp,
600            ..
601        }) = res_higher_user
602        else {
603            panic!();
604        };
605
606        // then we get the lower user code
607
608        let res_lower_user_correct =
609            idms_prox_read.handle_identify_user_submit_code(&IdentifyUserSubmitCodeEvent::new(
610                higher_user_uuid,
611                lower_user.clone(),
612                higher_user_totp,
613            ));
614
615        if let Ok(IdentifyUserResponse::ProvideCode {
616            totp: lower_user_totp,
617            ..
618        }) = res_lower_user_correct
619        {
620            assert_ne!(higher_user_totp, lower_user_totp);
621        } else {
622            debug_assert!(false);
623        }
624    }
625
626    fn create_valid_user_account(uuid: Uuid) -> EntryInitNew {
627        let mut name = String::from("valid_user");
628        name.push_str(&uuid.to_string());
629        // if anyone from the future will see this test failing because of a schema violation
630        // and wonders to this line of code I'm sorry to have wasted your time
631        name.truncate(14);
632        entry_init!(
633            (Attribute::Class, EntryClass::Object.to_value()),
634            (Attribute::Class, EntryClass::Account.to_value()),
635            (Attribute::Class, EntryClass::Person.to_value()),
636            (Attribute::Name, Value::new_iname(&name)),
637            (Attribute::Uuid, Value::Uuid(uuid)),
638            (Attribute::Description, Value::new_utf8s("some valid user")),
639            (Attribute::DisplayName, Value::new_utf8s("Some valid user"))
640        )
641    }
642
643    fn create_invalid_user_account(uuid: Uuid) -> EntryInitNew {
644        entry_init!(
645            (Attribute::Class, EntryClass::Object.to_value()),
646            (Attribute::Class, EntryClass::Account.to_value()),
647            (Attribute::Class, EntryClass::ServiceAccount.to_value()),
648            (Attribute::Name, Value::new_iname("invalid_user")),
649            (Attribute::Uuid, Value::Uuid(uuid)),
650            (Attribute::Description, Value::new_utf8s("invalid_user")),
651            (Attribute::DisplayName, Value::new_utf8s("Invalid user"))
652        )
653    }
654}