1use crate::prelude::*;
2
3use crate::migration_data;
4use kanidm_proto::internal::{
5 DomainUpgradeCheckItem as ProtoDomainUpgradeCheckItem,
6 DomainUpgradeCheckReport as ProtoDomainUpgradeCheckReport,
7 DomainUpgradeCheckStatus as ProtoDomainUpgradeCheckStatus,
8};
9
10use super::ServerPhase;
11
12impl QueryServer {
13 #[instrument(level = "info", name = "system_initialisation", skip_all)]
14 pub async fn initialise_helper(
15 &self,
16 ts: Duration,
17 domain_target_level: DomainVersion,
18 ) -> Result<(), OperationError> {
19 let mut write_txn = self.write(ts).await?;
22
23 write_txn.upgrade_reindex(SYSTEM_INDEX_VERSION)?;
27
28 write_txn
38 .initialise_schema_core()
39 .and_then(|_| write_txn.reload())?;
40
41 let db_domain_version = match write_txn.internal_search_uuid(UUID_DOMAIN_INFO) {
44 Ok(e) => Ok(e.get_ava_single_uint32(Attribute::Version).unwrap_or(0)),
45 Err(OperationError::NoMatchingEntries) => Ok(0),
46 Err(r) => Err(r),
47 }?;
48
49 debug!(?db_domain_version, "Before setting internal domain info");
50
51 if db_domain_version == 0 {
52 debug_assert!(domain_target_level <= DOMAIN_MAX_LEVEL);
56
57 const { assert!(DOMAIN_MIN_CREATION_LEVEL == DOMAIN_LEVEL_10) };
59
60 match domain_target_level {
64 DOMAIN_LEVEL_10 => write_txn.migrate_domain_9_to_10()?,
65 DOMAIN_LEVEL_11 => write_txn.migrate_domain_10_to_11()?,
66 DOMAIN_LEVEL_12 => write_txn.migrate_domain_11_to_12()?,
67 DOMAIN_LEVEL_13 => write_txn.migrate_domain_12_to_13()?,
68 DOMAIN_LEVEL_14 => write_txn.migrate_domain_13_to_14()?,
69 DOMAIN_LEVEL_15 => write_txn.migrate_domain_14_to_15()?,
70 _ => {
71 error!("Invalid requested domain target level for server bootstrap");
72 debug_assert!(false);
73 return Err(OperationError::MG0009InvalidTargetLevelForBootstrap);
74 }
75 }
76
77 write_txn
78 .internal_apply_domain_migration(domain_target_level)
79 .map(|()| {
80 warn!(
81 "Domain level has been bootstrapped to {}",
82 domain_target_level
83 );
84 })?;
85 }
86
87 write_txn.force_domain_reload();
99
100 write_txn.reload()?;
101
102 write_txn.set_phase(ServerPhase::SchemaReady);
105
106 write_txn.force_schema_reload();
115
116 write_txn.reload()?;
118
119 write_txn.set_phase(ServerPhase::DomainInfoReady);
121
122 let domain_info_version = write_txn.get_domain_version();
129 let domain_patch_level = write_txn.get_domain_patch_level();
130 let domain_development_taint = write_txn.get_domain_development_taint();
131 debug!(
132 ?db_domain_version,
133 ?domain_patch_level,
134 ?domain_development_taint,
135 "After setting internal domain info"
136 );
137
138 let mut reload_required = false;
139
140 if domain_info_version < domain_target_level {
142 if domain_info_version < DOMAIN_MIGRATION_FROM_MIN {
144 error!(
145 "UNABLE TO PROCEED. You are attempting a skip update which is NOT SUPPORTED."
146 );
147 error!(
148 "For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html"
149 );
150 error!(domain_previous_version = ?domain_info_version, domain_target_version = ?domain_target_level, domain_migration_minimum_limit = ?DOMAIN_MIGRATION_FROM_MIN);
151 return Err(OperationError::MG0008SkipUpgradeAttempted);
152 }
153
154 for domain_target_level_step in domain_info_version..domain_target_level {
156 let domain_target_level_step = domain_target_level_step + 1;
160 write_txn
161 .internal_apply_domain_migration(domain_target_level_step)
162 .map(|()| {
163 warn!(
164 "Domain level has been raised to {}",
165 domain_target_level_step
166 );
167 })?;
168 }
169
170 if domain_info_version != 0 {
176 reload_required = true;
177 }
178 } else if domain_info_version > domain_target_level {
179 error!("UNABLE TO PROCEED. You are attempting a downgrade which is NOT SUPPORTED.");
181 error!(
182 "For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html"
183 );
184 error!(domain_previous_version = ?domain_info_version, domain_target_version = ?domain_target_level);
185 return Err(OperationError::MG0010DowngradeNotAllowed);
186 } else if domain_development_taint {
187 write_txn.domain_remigrate(DOMAIN_PREVIOUS_TGT_LEVEL)?;
198
199 reload_required = true;
200 }
201
202 if domain_patch_level < DOMAIN_TGT_PATCH_LEVEL {
205 write_txn
206 .internal_modify_uuid(
207 UUID_DOMAIN_INFO,
208 &ModifyList::new_purge_and_set(
209 Attribute::PatchLevel,
210 Value::new_uint32(DOMAIN_TGT_PATCH_LEVEL),
211 ),
212 )
213 .map(|()| {
214 warn!(
215 "Domain patch level has been raised to {}",
216 domain_patch_level
217 );
218 })?;
219
220 reload_required = true;
221 };
222
223 if reload_required {
227 write_txn.reload()?;
228 }
229
230 let current_devel_flag = option_env!("KANIDM_PRE_RELEASE").is_some();
233 if current_devel_flag {
234 warn!("Domain Development Taint mode is enabled");
235 }
236 if domain_development_taint != current_devel_flag {
237 write_txn.internal_modify_uuid(
238 UUID_DOMAIN_INFO,
239 &ModifyList::new_purge_and_set(
240 Attribute::DomainDevelopmentTaint,
241 Value::Bool(current_devel_flag),
242 ),
243 )?;
244 }
245
246 write_txn.set_phase(ServerPhase::Running);
248
249 write_txn.commit()?;
252
253 debug!("Database version check and migrations success! ☀️ ");
254 Ok(())
255 }
256}
257
258impl QueryServerWriteTransaction<'_> {
259 #[instrument(level = "debug", skip(self))]
262 pub(crate) fn internal_apply_domain_migration(
263 &mut self,
264 to_level: u32,
265 ) -> Result<(), OperationError> {
266 self.internal_modify_uuid(
267 UUID_DOMAIN_INFO,
268 &ModifyList::new_purge_and_set(Attribute::Version, Value::new_uint32(to_level)),
269 )
270 .and_then(|()| self.reload())
271 }
272
273 fn internal_migrate_or_create_batch(
274 &mut self,
275 msg: &str,
276 entries: Vec<EntryInitNew>,
277 ) -> Result<(), OperationError> {
278 #[cfg(test)]
279 eprintln!("MIGRATION BATCH: {}", msg);
280 let r: Result<(), _> = entries
281 .into_iter()
282 .try_for_each(|entry| self.internal_migrate_or_create(entry));
283
284 if let Err(err) = r {
285 error!(?err, msg);
286 debug_assert!(false);
287 }
288
289 Ok(())
290 }
291
292 #[instrument(level = "debug", skip_all)]
293 fn internal_migrate_or_create(
303 &mut self,
304 e: Entry<EntryInit, EntryNew>,
305 ) -> Result<(), OperationError> {
306 self.internal_migrate_or_create_ignore_attrs(
308 e,
309 &[
310 Attribute::CredentialTypeMinimum,
312 ],
313 )
314 }
315
316 #[instrument(level = "debug", skip_all)]
317 fn internal_delete_batch(
318 &mut self,
319 msg: &str,
320 entries: Vec<Uuid>,
321 ) -> Result<(), OperationError> {
322 let filter = entries
323 .into_iter()
324 .map(|uuid| f_eq(Attribute::Uuid, PartialValue::Uuid(uuid)))
325 .collect();
326
327 let filter = filter_all!(f_or(filter));
328
329 let result = self.internal_delete(&filter);
330
331 match result {
332 Ok(_) | Err(OperationError::NoMatchingEntries) => Ok(()),
333 Err(err) => {
334 error!(?err, msg);
335 Err(err)
336 }
337 }
338 }
339
340 #[instrument(level = "trace", skip_all)]
344 fn internal_migrate_or_create_ignore_attrs(
345 &mut self,
346 mut e: Entry<EntryInit, EntryNew>,
347 attrs: &[Attribute],
348 ) -> Result<(), OperationError> {
349 trace!("operating on {:?}", e.get_uuid());
350
351 let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid]) else {
352 return Err(OperationError::FilterGeneration);
353 };
354
355 trace!("search {:?}", filt);
356
357 let results = self.internal_search(filt.clone())?;
358
359 if results.is_empty() {
360 if let Some(members_create_once) = e.pop_ava(Attribute::MemberCreateOnce) {
364 if let Some(members) = e.get_ava_mut(Attribute::Member) {
365 members.merge(&members_create_once).inspect_err(|err| {
367 error!(?err, "Unable to merge member sets, mismatched types?");
368 })?;
369 } else {
370 e.set_ava_set(&Attribute::Member, members_create_once);
372 }
373 };
374
375 self.internal_create(vec![e])
376 } else if results.len() == 1 {
377 e.remove_ava(&Attribute::MemberCreateOnce);
379
380 for attr in attrs.iter() {
382 e.remove_ava(attr);
383 }
384
385 match e.gen_modlist_assert(&self.schema) {
387 Ok(modlist) => {
388 trace!(?modlist);
390 self.internal_modify(&filt, &modlist)
391 }
392 Err(e) => Err(OperationError::SchemaViolation(e)),
393 }
394 } else {
395 admin_error!(
396 "Invalid Result Set - Expected One Entry for {:?} - {:?}",
397 filt,
398 results
399 );
400 Err(OperationError::InvalidDbState)
401 }
402 }
403
404 #[instrument(level = "info", skip_all)]
433 pub(crate) fn migrate_domain_9_to_10(&mut self) -> Result<(), OperationError> {
434 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_9 {
435 error!("Unable to raise domain level from 9 to 10.");
436 return Err(OperationError::MG0004DomainLevelInDevelopment);
437 }
438
439 self.internal_migrate_or_create_batch(
441 "phase 1 - schema attrs",
442 migration_data::dl10::phase_1_schema_attrs(),
443 )?;
444
445 self.internal_migrate_or_create_batch(
446 "phase 2 - schema classes",
447 migration_data::dl10::phase_2_schema_classes(),
448 )?;
449
450 self.reload()?;
452
453 self.reindex(false)?;
456
457 self.set_phase(ServerPhase::SchemaReady);
461
462 self.internal_migrate_or_create_batch(
463 "phase 3 - key provider",
464 migration_data::dl10::phase_3_key_provider(),
465 )?;
466
467 self.reload()?;
469
470 self.internal_migrate_or_create_batch(
471 "phase 4 - system entries",
472 migration_data::dl10::phase_4_system_entries(),
473 )?;
474
475 self.reload()?;
477
478 self.set_phase(ServerPhase::DomainInfoReady);
480
481 self.internal_migrate_or_create_batch(
483 "phase 5 - builtin admin entries",
484 migration_data::dl10::phase_5_builtin_admin_entries()?,
485 )?;
486
487 self.internal_migrate_or_create_batch(
488 "phase 6 - builtin not admin entries",
489 migration_data::dl10::phase_6_builtin_non_admin_entries()?,
490 )?;
491
492 self.internal_migrate_or_create_batch(
493 "phase 7 - builtin access control profiles",
494 migration_data::dl10::phase_7_builtin_access_control_profiles(),
495 )?;
496
497 self.reload()?;
498
499 debug!("START OAUTH2 MIGRATION");
502
503 let all_oauth2_rs_entries = self.internal_search(filter!(f_eq(
505 Attribute::Class,
506 EntryClass::OAuth2ResourceServer.into()
507 )))?;
508
509 if !all_oauth2_rs_entries.is_empty() {
510 let entry_iter = all_oauth2_rs_entries.iter().map(|tgt_entry| {
511 let entry_uuid = tgt_entry.get_uuid();
512 let mut modlist = ModifyList::new_list(vec![
513 Modify::Present(Attribute::Class, EntryClass::KeyObject.to_value()),
514 Modify::Present(Attribute::Class, EntryClass::KeyObjectJwtEs256.to_value()),
515 Modify::Present(Attribute::Class, EntryClass::KeyObjectJweA128GCM.to_value()),
516 Modify::Purged(Attribute::OAuth2RsTokenKey),
518 Modify::Purged(Attribute::Es256PrivateKeyDer),
519 Modify::Purged(Attribute::Rs256PrivateKeyDer),
520 ]);
521
522 trace!(?tgt_entry);
523
524 if let Some(es256_private_der) =
526 tgt_entry.get_ava_single_private_binary(Attribute::Es256PrivateKeyDer)
527 {
528 modlist.push_mod(Modify::Present(
529 Attribute::KeyActionImportJwsEs256,
530 Value::PrivateBinary(es256_private_der.to_vec()),
531 ))
532 } else {
533 warn!("Unable to migrate es256 key");
534 }
535
536 let has_rs256 = tgt_entry
537 .get_ava_single_bool(Attribute::OAuth2JwtLegacyCryptoEnable)
538 .unwrap_or(false);
539
540 if has_rs256 {
543 modlist.push_mod(Modify::Present(
544 Attribute::Class,
545 EntryClass::KeyObjectJwtEs256.to_value(),
546 ));
547
548 if let Some(rs256_private_der) =
549 tgt_entry.get_ava_single_private_binary(Attribute::Rs256PrivateKeyDer)
550 {
551 modlist.push_mod(Modify::Present(
552 Attribute::KeyActionImportJwsRs256,
553 Value::PrivateBinary(rs256_private_der.to_vec()),
554 ))
555 } else {
556 warn!("Unable to migrate rs256 key");
557 }
558 }
559
560 (entry_uuid, modlist)
561 });
562
563 self.internal_batch_modify(entry_iter)?;
564 }
565
566 self.reload()?;
568
569 Ok(())
572 }
573
574 #[instrument(level = "info", skip_all)]
576 pub(crate) fn migrate_domain_10_to_11(&mut self) -> Result<(), OperationError> {
577 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_10 {
578 error!("Unable to raise domain level from 10 to 11.");
579 return Err(OperationError::MG0004DomainLevelInDevelopment);
580 }
581
582 self.internal_migrate_or_create_batch(
584 "phase 1 - schema attrs",
585 migration_data::dl11::phase_1_schema_attrs(),
586 )?;
587
588 self.internal_migrate_or_create_batch(
589 "phase 2 - schema classes",
590 migration_data::dl11::phase_2_schema_classes(),
591 )?;
592
593 self.reload()?;
595
596 self.reindex(false)?;
599
600 self.set_phase(ServerPhase::SchemaReady);
604
605 self.internal_migrate_or_create_batch(
606 "phase 3 - key provider",
607 migration_data::dl11::phase_3_key_provider(),
608 )?;
609
610 self.reload()?;
612
613 self.internal_migrate_or_create_batch(
614 "phase 4 - system entries",
615 migration_data::dl11::phase_4_system_entries(),
616 )?;
617
618 self.reload()?;
620
621 self.set_phase(ServerPhase::DomainInfoReady);
623
624 self.internal_migrate_or_create_batch(
626 "phase 5 - builtin admin entries",
627 migration_data::dl11::phase_5_builtin_admin_entries()?,
628 )?;
629
630 self.internal_migrate_or_create_batch(
631 "phase 6 - builtin not admin entries",
632 migration_data::dl11::phase_6_builtin_non_admin_entries()?,
633 )?;
634
635 self.internal_migrate_or_create_batch(
636 "phase 7 - builtin access control profiles",
637 migration_data::dl11::phase_7_builtin_access_control_profiles(),
638 )?;
639
640 self.reload()?;
641
642 Ok(())
643 }
644
645 #[instrument(level = "info", skip_all)]
647 pub(crate) fn migrate_domain_11_to_12(&mut self) -> Result<(), OperationError> {
648 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_11 {
649 error!("Unable to raise domain level from 11 to 12.");
650 return Err(OperationError::MG0004DomainLevelInDevelopment);
651 }
652
653 self.internal_migrate_or_create_batch(
655 "phase 1 - schema attrs",
656 migration_data::dl12::phase_1_schema_attrs(),
657 )?;
658
659 self.internal_migrate_or_create_batch(
660 "phase 2 - schema classes",
661 migration_data::dl12::phase_2_schema_classes(),
662 )?;
663
664 self.reload()?;
666
667 self.reindex(false)?;
670
671 self.set_phase(ServerPhase::SchemaReady);
675
676 self.internal_migrate_or_create_batch(
677 "phase 3 - key provider",
678 migration_data::dl12::phase_3_key_provider(),
679 )?;
680
681 self.reload()?;
683
684 self.internal_migrate_or_create_batch(
685 "phase 4 - system entries",
686 migration_data::dl12::phase_4_system_entries(),
687 )?;
688
689 self.reload()?;
691
692 self.set_phase(ServerPhase::DomainInfoReady);
694
695 self.internal_migrate_or_create_batch(
697 "phase 5 - builtin admin entries",
698 migration_data::dl12::phase_5_builtin_admin_entries()?,
699 )?;
700
701 self.internal_migrate_or_create_batch(
702 "phase 6 - builtin not admin entries",
703 migration_data::dl12::phase_6_builtin_non_admin_entries()?,
704 )?;
705
706 self.internal_migrate_or_create_batch(
707 "phase 7 - builtin access control profiles",
708 migration_data::dl12::phase_7_builtin_access_control_profiles(),
709 )?;
710
711 self.reload()?;
712
713 let modlist = ModifyList::new_purge(Attribute::IdVerificationEcKey);
715 let filter = filter_all!(f_pres(Attribute::IdVerificationEcKey));
716
717 self.internal_modify(&filter, &modlist)?;
718
719 Ok(())
720 }
721
722 #[instrument(level = "info", skip_all)]
724 pub(crate) fn migrate_domain_12_to_13(&mut self) -> Result<(), OperationError> {
725 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_12 {
726 error!("Unable to raise domain level from 12 to 13.");
727 return Err(OperationError::MG0004DomainLevelInDevelopment);
728 }
729
730 self.internal_migrate_or_create_batch(
732 "phase 1 - schema attrs",
733 migration_data::dl13::phase_1_schema_attrs(),
734 )?;
735
736 self.internal_migrate_or_create_batch(
737 "phase 2 - schema classes",
738 migration_data::dl13::phase_2_schema_classes(),
739 )?;
740
741 self.reload()?;
743
744 self.reindex(false)?;
747
748 self.set_phase(ServerPhase::SchemaReady);
752
753 self.internal_migrate_or_create_batch(
754 "phase 3 - key provider",
755 migration_data::dl13::phase_3_key_provider(),
756 )?;
757
758 self.reload()?;
760
761 self.internal_migrate_or_create_batch(
762 "phase 4 - system entries",
763 migration_data::dl13::phase_4_system_entries(),
764 )?;
765
766 self.reload()?;
768
769 self.set_phase(ServerPhase::DomainInfoReady);
771
772 self.internal_migrate_or_create_batch(
774 "phase 5 - builtin admin entries",
775 migration_data::dl13::phase_5_builtin_admin_entries()?,
776 )?;
777
778 self.internal_migrate_or_create_batch(
779 "phase 6 - builtin not admin entries",
780 migration_data::dl13::phase_6_builtin_non_admin_entries()?,
781 )?;
782
783 self.internal_migrate_or_create_batch(
784 "phase 7 - builtin access control profiles",
785 migration_data::dl13::phase_7_builtin_access_control_profiles(),
786 )?;
787
788 self.internal_delete_batch(
789 "phase 8 - delete UUIDS",
790 migration_data::dl13::phase_8_delete_uuids(),
791 )?;
792
793 self.reload()?;
794
795 Ok(())
796 }
797
798 #[instrument(level = "info", skip_all)]
800 pub(crate) fn migrate_domain_13_to_14(&mut self) -> Result<(), OperationError> {
801 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_13 {
802 error!("Unable to raise domain level from 13 to 14.");
803 return Err(OperationError::MG0004DomainLevelInDevelopment);
804 }
805
806 self.internal_migrate_or_create_batch(
808 &format!("phase 1 - schema attrs target {}", DOMAIN_TGT_LEVEL),
809 migration_data::dl14::phase_1_schema_attrs(),
810 )?;
811
812 self.internal_migrate_or_create_batch(
813 "phase 2 - schema classes",
814 migration_data::dl14::phase_2_schema_classes(),
815 )?;
816
817 self.reload()?;
819
820 self.reindex(false)?;
823
824 self.set_phase(ServerPhase::SchemaReady);
828
829 self.internal_migrate_or_create_batch(
830 "phase 3 - key provider",
831 migration_data::dl14::phase_3_key_provider(),
832 )?;
833
834 self.reload()?;
836
837 self.internal_migrate_or_create_batch(
838 "phase 4 - dl14 system entries",
839 migration_data::dl14::phase_4_system_entries(),
840 )?;
841
842 self.reload()?;
844
845 self.set_phase(ServerPhase::DomainInfoReady);
847
848 self.internal_migrate_or_create_batch(
850 "phase 5 - builtin admin entries",
851 migration_data::dl14::phase_5_builtin_admin_entries()?,
852 )?;
853
854 self.internal_migrate_or_create_batch(
855 "phase 6 - builtin not admin entries",
856 migration_data::dl14::phase_6_builtin_non_admin_entries()?,
857 )?;
858
859 self.internal_migrate_or_create_batch(
860 "phase 7 - builtin access control profiles",
861 migration_data::dl14::phase_7_builtin_access_control_profiles(),
862 )?;
863
864 self.internal_delete_batch(
865 "phase 8 - delete UUIDS",
866 migration_data::dl14::phase_8_delete_uuids(),
867 )?;
868
869 self.reload()?;
870
871 let filter = filter_all!(f_and!([
873 f_eq(Attribute::Class, EntryClass::Person.into()),
874 f_andnot(f_pres(Attribute::PasswordChangedTime)),
875 ]));
876 let modlist = ModifyList::new_purge_and_set(
877 Attribute::PasswordChangedTime,
878 Value::DateTime(time::OffsetDateTime::UNIX_EPOCH),
879 );
880 self.internal_modify(&filter, &modlist)?;
881
882 Ok(())
883 }
884
885 #[instrument(level = "info", skip_all)]
887 pub(crate) fn migrate_domain_14_to_15(&mut self) -> Result<(), OperationError> {
888 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_14 {
889 error!("Unable to raise domain level from 14 to 15.");
890 return Err(OperationError::MG0004DomainLevelInDevelopment);
891 }
892
893 Ok(())
894 }
895
896 #[instrument(level = "info", skip_all)]
897 pub(crate) fn initialise_schema_core(&mut self) -> Result<(), OperationError> {
898 admin_debug!("initialise_schema_core -> start ...");
899 let entries = self.schema.to_entries();
901
902 let r: Result<_, _> = entries.into_iter().try_for_each(|e| {
906 trace!(?e, "init schema entry");
907 self.internal_migrate_or_create(e)
908 });
909 if r.is_ok() {
910 admin_debug!("initialise_schema_core -> Ok!");
911 } else {
912 admin_error!(?r, "initialise_schema_core -> Error");
913 }
914 debug_assert!(r.is_ok());
916 r
917 }
918}
919
920impl QueryServerReadTransaction<'_> {
921 pub fn domain_upgrade_check(
923 &mut self,
924 ) -> Result<ProtoDomainUpgradeCheckReport, OperationError> {
925 let d_info = &self.d_info;
926
927 let name = d_info.d_name.clone();
928 let uuid = d_info.d_uuid;
929 let current_level = d_info.d_vers;
930 let upgrade_level = DOMAIN_TGT_NEXT_LEVEL;
931
932 let mut report_items = Vec::with_capacity(1);
933
934 if current_level <= DOMAIN_LEVEL_7 && upgrade_level >= DOMAIN_LEVEL_8 {
935 let item = self
936 .domain_upgrade_check_7_to_8_security_keys()
937 .map_err(|err| {
938 error!(
939 ?err,
940 "Failed to perform domain upgrade check 7 to 8 - security-keys"
941 );
942 err
943 })?;
944 report_items.push(item);
945
946 let item = self
947 .domain_upgrade_check_7_to_8_oauth2_strict_redirect_uri()
948 .map_err(|err| {
949 error!(
950 ?err,
951 "Failed to perform domain upgrade check 7 to 8 - oauth2-strict-redirect_uri"
952 );
953 err
954 })?;
955 report_items.push(item);
956 }
957
958 Ok(ProtoDomainUpgradeCheckReport {
959 name,
960 uuid,
961 current_level,
962 upgrade_level,
963 report_items,
964 })
965 }
966
967 pub(crate) fn domain_upgrade_check_7_to_8_security_keys(
968 &mut self,
969 ) -> Result<ProtoDomainUpgradeCheckItem, OperationError> {
970 let filter = filter!(f_and!([
971 f_eq(Attribute::Class, EntryClass::Account.into()),
972 f_pres(Attribute::PrimaryCredential),
973 ]));
974
975 let results = self.internal_search(filter)?;
976
977 let affected_entries = results
978 .into_iter()
979 .filter_map(|entry| {
980 if entry
981 .get_ava_single_credential(Attribute::PrimaryCredential)
982 .map(|cred| cred.has_securitykey())
983 .unwrap_or_default()
984 {
985 Some(entry.get_display_id())
986 } else {
987 None
988 }
989 })
990 .collect::<Vec<_>>();
991
992 let status = if affected_entries.is_empty() {
993 ProtoDomainUpgradeCheckStatus::Pass7To8SecurityKeys
994 } else {
995 ProtoDomainUpgradeCheckStatus::Fail7To8SecurityKeys
996 };
997
998 Ok(ProtoDomainUpgradeCheckItem {
999 status,
1000 from_level: DOMAIN_LEVEL_7,
1001 to_level: DOMAIN_LEVEL_8,
1002 affected_entries,
1003 })
1004 }
1005
1006 pub(crate) fn domain_upgrade_check_7_to_8_oauth2_strict_redirect_uri(
1007 &mut self,
1008 ) -> Result<ProtoDomainUpgradeCheckItem, OperationError> {
1009 let filter = filter!(f_and!([
1010 f_eq(Attribute::Class, EntryClass::OAuth2ResourceServer.into()),
1011 f_andnot(f_pres(Attribute::OAuth2StrictRedirectUri)),
1012 ]));
1013
1014 let results = self.internal_search(filter)?;
1015
1016 let affected_entries = results
1017 .into_iter()
1018 .map(|entry| entry.get_display_id())
1019 .collect::<Vec<_>>();
1020
1021 let status = if affected_entries.is_empty() {
1022 ProtoDomainUpgradeCheckStatus::Pass7To8Oauth2StrictRedirectUri
1023 } else {
1024 ProtoDomainUpgradeCheckStatus::Fail7To8Oauth2StrictRedirectUri
1025 };
1026
1027 Ok(ProtoDomainUpgradeCheckItem {
1028 status,
1029 from_level: DOMAIN_LEVEL_7,
1030 to_level: DOMAIN_LEVEL_8,
1031 affected_entries,
1032 })
1033 }
1034}
1035
1036#[cfg(test)]
1037mod tests {
1038 use crate::prelude::*;
1040 use crate::value::CredentialType;
1041 use crate::valueset::ValueSetCredentialType;
1042
1043 #[qs_test]
1044 async fn test_init_idempotent_schema_core(server: &QueryServer) {
1045 {
1046 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1048 assert!(server_txn.initialise_schema_core().is_ok());
1049 }
1050 {
1051 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1052 assert!(server_txn.initialise_schema_core().is_ok());
1053 assert!(server_txn.initialise_schema_core().is_ok());
1054 assert!(server_txn.commit().is_ok());
1055 }
1056 {
1057 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1059 assert!(server_txn.initialise_schema_core().is_ok());
1060 }
1061 {
1062 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1064 assert!(server_txn.initialise_schema_core().is_ok());
1065 assert!(server_txn.commit().is_ok());
1066 }
1067 }
1068
1069 #[qs_test(domain_level=DOMAIN_PREVIOUS_TGT_LEVEL)]
1073 async fn test_migrations_dl_previous_to_dl_target(server: &QueryServer) {
1074 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1075
1076 let db_domain_version = write_txn
1077 .internal_search_uuid(UUID_DOMAIN_INFO)
1078 .expect("unable to access domain entry")
1079 .get_ava_single_uint32(Attribute::Version)
1080 .expect("Attribute Version not present");
1081
1082 assert_eq!(db_domain_version, DOMAIN_PREVIOUS_TGT_LEVEL);
1083
1084 let modlist = ModifyList::new_set(
1089 Attribute::Member,
1090 ValueSetRefer::new(UUID_ANONYMOUS),
1093 );
1094 write_txn
1095 .internal_modify_uuid(UUID_IDM_ADMINS, &modlist)
1096 .expect("Unable to modify CredentialTypeMinimum");
1097
1098 let modlist = ModifyList::new_purge(Attribute::Member);
1101 write_txn
1102 .internal_modify_uuid(UUID_IDM_PEOPLE_SELF_NAME_WRITE, &modlist)
1103 .expect("Unable to remove idm_all_persons from self-write");
1104
1105 let modlist = ModifyList::new_set(
1107 Attribute::CredentialTypeMinimum,
1108 ValueSetCredentialType::new(CredentialType::Any),
1109 );
1110 write_txn
1111 .internal_modify_uuid(UUID_IDM_ALL_PERSONS, &modlist)
1112 .expect("Unable to modify CredentialTypeMinimum");
1113
1114 write_txn.commit().expect("Unable to commit");
1115
1116 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1117
1118 write_txn
1120 .internal_apply_domain_migration(DOMAIN_TGT_LEVEL)
1121 .expect("Unable to set domain level");
1122
1123 let idm_admins_entry = write_txn
1126 .internal_search_uuid(UUID_IDM_ADMINS)
1127 .expect("Unable to retrieve all persons");
1128
1129 let members = idm_admins_entry
1130 .get_ava_refer(Attribute::Member)
1131 .expect("No members present");
1132
1133 assert!(members.contains(&UUID_ANONYMOUS));
1135 assert!(members.contains(&UUID_IDM_ADMIN));
1137
1138 let idm_people_self_name_write_entry = write_txn
1140 .internal_search_uuid(UUID_IDM_PEOPLE_SELF_NAME_WRITE)
1141 .expect("Unable to retrieve all persons");
1142
1143 let members = idm_people_self_name_write_entry.get_ava_refer(Attribute::Member);
1144
1145 assert!(members.is_none());
1147
1148 let all_persons_entry = write_txn
1150 .internal_search_uuid(UUID_IDM_ALL_PERSONS)
1151 .expect("Unable to retrieve all persons");
1152
1153 assert_eq!(
1154 all_persons_entry.get_ava_single_credential_type(Attribute::CredentialTypeMinimum),
1155 Some(CredentialType::Any)
1156 );
1157
1158 write_txn.commit().expect("Unable to commit");
1159 }
1160
1161 #[qs_test(domain_level=DOMAIN_TGT_LEVEL)]
1162 async fn test_migrations_prevent_downgrades(server: &QueryServer) {
1163 let curtime = duration_from_epoch_now();
1164
1165 let mut write_txn = server.write(curtime).await.unwrap();
1166
1167 let db_domain_version = write_txn
1168 .internal_search_uuid(UUID_DOMAIN_INFO)
1169 .expect("unable to access domain entry")
1170 .get_ava_single_uint32(Attribute::Version)
1171 .expect("Attribute Version not present");
1172
1173 assert_eq!(db_domain_version, DOMAIN_TGT_LEVEL);
1174
1175 drop(write_txn);
1176
1177 let err = server
1179 .initialise_helper(curtime, DOMAIN_PREVIOUS_TGT_LEVEL)
1180 .await
1181 .expect_err("Domain level was lowered!!!!");
1182
1183 assert_eq!(err, OperationError::MG0010DowngradeNotAllowed);
1184 }
1185
1186 #[qs_test(domain_level=DOMAIN_MIGRATION_FROM_INVALID)]
1187 async fn test_migrations_prevent_skips(server: &QueryServer) {
1188 let curtime = duration_from_epoch_now();
1189
1190 let mut write_txn = server.write(curtime).await.unwrap();
1191
1192 let db_domain_version = write_txn
1193 .internal_search_uuid(UUID_DOMAIN_INFO)
1194 .expect("unable to access domain entry")
1195 .get_ava_single_uint32(Attribute::Version)
1196 .expect("Attribute Version not present");
1197
1198 assert_eq!(db_domain_version, DOMAIN_MIGRATION_FROM_INVALID);
1199
1200 drop(write_txn);
1201
1202 let err = server
1204 .initialise_helper(curtime, DOMAIN_TGT_LEVEL)
1205 .await
1206 .expect_err("Migration went ahead!!!!");
1207
1208 assert_eq!(err, OperationError::MG0008SkipUpgradeAttempted);
1209 }
1210
1211 #[qs_test(domain_level=DOMAIN_MIGRATION_FROM_MIN)]
1212 async fn test_migrations_skip_valid(server: &QueryServer) {
1213 let curtime = duration_from_epoch_now();
1214 let mut write_txn = server.write(curtime).await.unwrap();
1217
1218 let db_domain_version = write_txn
1219 .internal_search_uuid(UUID_DOMAIN_INFO)
1220 .expect("unable to access domain entry")
1221 .get_ava_single_uint32(Attribute::Version)
1222 .expect("Attribute Version not present");
1223
1224 assert_eq!(db_domain_version, DOMAIN_MIGRATION_FROM_MIN);
1225
1226 drop(write_txn);
1227
1228 server
1230 .initialise_helper(curtime, DOMAIN_TGT_LEVEL)
1231 .await
1232 .expect("Migration failed!!!!")
1233 }
1234
1235 #[qs_test(domain_level=DOMAIN_LEVEL_10)]
1236 async fn test_migrations_dl10_dl11(server: &QueryServer) {
1237 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1238
1239 let db_domain_version = write_txn
1240 .internal_search_uuid(UUID_DOMAIN_INFO)
1241 .expect("unable to access domain entry")
1242 .get_ava_single_uint32(Attribute::Version)
1243 .expect("Attribute Version not present");
1244
1245 assert_eq!(db_domain_version, DOMAIN_LEVEL_10);
1246
1247 write_txn.commit().expect("Unable to commit");
1248
1249 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1256
1257 write_txn
1261 .internal_apply_domain_migration(DOMAIN_LEVEL_11)
1262 .expect("Unable to set domain level to version 11");
1263
1264 write_txn.commit().expect("Unable to commit");
1267 }
1268
1269 #[qs_test(domain_level=DOMAIN_LEVEL_11)]
1270 async fn test_migrations_dl11_dl12(server: &QueryServer) {
1271 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1272
1273 let db_domain_version = write_txn
1274 .internal_search_uuid(UUID_DOMAIN_INFO)
1275 .expect("unable to access domain entry")
1276 .get_ava_single_uint32(Attribute::Version)
1277 .expect("Attribute Version not present");
1278
1279 assert_eq!(db_domain_version, DOMAIN_LEVEL_11);
1280
1281 let tuuid = Uuid::new_v4();
1283 let e1 = entry_init!(
1284 (Attribute::Class, EntryClass::Object.to_value()),
1285 (Attribute::Class, EntryClass::Person.to_value()),
1286 (Attribute::Class, EntryClass::Account.to_value()),
1287 (Attribute::Name, Value::new_iname("testperson1")),
1288 (Attribute::Uuid, Value::Uuid(tuuid)),
1289 (Attribute::Description, Value::new_utf8s("testperson1")),
1290 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
1291 );
1292
1293 write_txn
1294 .internal_create(vec![e1])
1295 .expect("Unable to create user");
1296
1297 let user = write_txn
1298 .internal_search_uuid(tuuid)
1299 .expect("Unable to load user");
1300
1301 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_some());
1303
1304 write_txn.commit().expect("Unable to commit");
1305
1306 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1313
1314 write_txn
1318 .internal_apply_domain_migration(DOMAIN_LEVEL_12)
1319 .expect("Unable to set domain level to version 12");
1320
1321 let user = write_txn
1323 .internal_search_uuid(tuuid)
1324 .expect("Unable to load user");
1325
1326 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_none());
1328
1329 let t2uuid = Uuid::new_v4();
1331 let e2 = entry_init!(
1332 (Attribute::Class, EntryClass::Object.to_value()),
1333 (Attribute::Class, EntryClass::Person.to_value()),
1334 (Attribute::Class, EntryClass::Account.to_value()),
1335 (Attribute::Name, Value::new_iname("testperson2")),
1336 (Attribute::Uuid, Value::Uuid(t2uuid)),
1337 (Attribute::Description, Value::new_utf8s("testperson2")),
1338 (Attribute::DisplayName, Value::new_utf8s("testperson2"))
1339 );
1340
1341 write_txn
1342 .internal_create(vec![e2])
1343 .expect("Unable to create user");
1344
1345 let user = write_txn
1346 .internal_search_uuid(t2uuid)
1347 .expect("Unable to load user");
1348
1349 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_none());
1351
1352 write_txn.commit().expect("Unable to commit");
1353 }
1354
1355 #[qs_test(domain_level=DOMAIN_LEVEL_12)]
1356 async fn test_migrations_dl12_dl13(server: &QueryServer) {
1357 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1358
1359 let db_domain_version = write_txn
1360 .internal_search_uuid(UUID_DOMAIN_INFO)
1361 .expect("unable to access domain entry")
1362 .get_ava_single_uint32(Attribute::Version)
1363 .expect("Attribute Version not present");
1364
1365 assert_eq!(db_domain_version, DOMAIN_LEVEL_12);
1366
1367 write_txn.commit().expect("Unable to commit");
1368
1369 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1376
1377 write_txn
1381 .internal_apply_domain_migration(DOMAIN_LEVEL_13)
1382 .expect("Unable to set domain level to version 13");
1383
1384 write_txn.commit().expect("Unable to commit");
1387 }
1388
1389 #[qs_test(domain_level=DOMAIN_LEVEL_13)]
1390 async fn test_migrations_dl13_dl14(server: &QueryServer) {
1391 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1392
1393 let db_domain_version = write_txn
1394 .internal_search_uuid(UUID_DOMAIN_INFO)
1395 .expect("unable to access domain entry")
1396 .get_ava_single_uint32(Attribute::Version)
1397 .expect("Attribute Version not present");
1398
1399 assert_eq!(db_domain_version, DOMAIN_LEVEL_13);
1400
1401 let tuuid = Uuid::new_v4();
1403 let e1 = entry_init!(
1404 (Attribute::Class, EntryClass::Object.to_value()),
1405 (Attribute::Class, EntryClass::Person.to_value()),
1406 (Attribute::Class, EntryClass::Account.to_value()),
1407 (Attribute::Name, Value::new_iname("testperson1")),
1408 (Attribute::Uuid, Value::Uuid(tuuid)),
1409 (Attribute::Description, Value::new_utf8s("testperson1")),
1410 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
1411 );
1412
1413 write_txn
1414 .internal_create(vec![e1])
1415 .expect("Unable to create test person");
1416
1417 let user = write_txn
1418 .internal_search_uuid(tuuid)
1419 .expect("Unable to load test person");
1420
1421 assert!(user
1423 .get_ava_single_datetime(Attribute::PasswordChangedTime)
1424 .is_none());
1425
1426 write_txn.commit().expect("Unable to commit");
1427
1428 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1435
1436 write_txn
1440 .internal_apply_domain_migration(DOMAIN_LEVEL_14)
1441 .expect("Unable to set domain level to version 14");
1442
1443 let user = write_txn
1446 .internal_search_uuid(tuuid)
1447 .expect("Unable to load test person after migration");
1448
1449 let pwd_changed = user
1450 .get_ava_single_datetime(Attribute::PasswordChangedTime)
1451 .expect("PasswordChangedTime should be set after DL13->DL14 migration");
1452
1453 assert_eq!(pwd_changed, time::OffsetDateTime::UNIX_EPOCH);
1454
1455 write_txn.commit().expect("Unable to commit");
1456 }
1457}