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 if domain_target_level < DOMAIN_LEVEL_1_11 {
38 write_txn
40 .initialise_schema_core()
41 .and_then(|_| write_txn.reload())?;
42 }
43
44 let db_domain_version = match write_txn.internal_search_uuid(UUID_DOMAIN_INFO) {
47 Ok(e) => Ok(e.get_ava_single_uint32(Attribute::Version).unwrap_or(0)),
48 Err(OperationError::NoMatchingEntries) => Ok(0),
49 Err(r) => Err(r),
50 }?;
51
52 debug!(?db_domain_version, "Before setting internal domain info");
53
54 if db_domain_version == DOMAIN_LEVEL_0 {
55 debug_assert!(domain_target_level <= DOMAIN_MAX_LEVEL);
59
60 const { assert!(DOMAIN_MIN_CREATION_LEVEL == DOMAIN_LEVEL_10) };
62
63 match domain_target_level {
67 DOMAIN_LEVEL_10 => write_txn.migrate_domain_9_to_10()?,
68 DOMAIN_LEVEL_11 => write_txn.migrate_domain_10_to_11()?,
69 DOMAIN_LEVEL_12 => write_txn.migrate_domain_11_to_12()?,
70 DOMAIN_LEVEL_13 => write_txn.migrate_domain_12_to_13()?,
71 DOMAIN_LEVEL_14 => write_txn.migrate_domain_13_to_14()?,
72 DOMAIN_LEVEL_1_11 => write_txn.migrate_domain_1_10_to_1_11()?,
73 DOMAIN_LEVEL_1_12 => write_txn.migrate_domain_1_11_to_1_12()?,
74 _ => {
75 error!("Invalid requested domain target level for server bootstrap");
76 debug_assert!(false);
77 return Err(OperationError::MG0009InvalidTargetLevelForBootstrap);
78 }
79 }
80
81 write_txn
82 .internal_apply_domain_migration(domain_target_level)
83 .map(|()| {
84 warn!(
85 "Domain level has been bootstrapped to {}",
86 domain_target_level
87 );
88 })?;
89 }
90
91 write_txn.force_domain_reload();
103
104 write_txn.reload()?;
105
106 assert!(write_txn.get_domain_version() > DOMAIN_LEVEL_0);
107
108 write_txn.set_phase(ServerPhase::SchemaReady);
111
112 write_txn.force_schema_reload();
121
122 write_txn.reload()?;
124
125 write_txn.set_phase(ServerPhase::DomainInfoReady);
127
128 let domain_info_version = write_txn.get_domain_version();
135 let domain_patch_level = write_txn.get_domain_patch_level();
136 let domain_development_taint = write_txn.get_domain_development_taint();
137 debug!(
138 ?db_domain_version,
139 ?domain_patch_level,
140 ?domain_development_taint,
141 "After setting internal domain info"
142 );
143
144 let mut reload_required = false;
145
146 if domain_info_version < domain_target_level {
148 if domain_info_version < DOMAIN_MIGRATION_FROM_MIN {
150 error!(
151 "UNABLE TO PROCEED. You are attempting a skip update which is NOT SUPPORTED."
152 );
153 error!(
154 "For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html"
155 );
156 error!(domain_previous_version = ?domain_info_version, domain_target_version = ?domain_target_level, domain_migration_minimum_limit = ?DOMAIN_MIGRATION_FROM_MIN);
157 return Err(OperationError::MG0008SkipUpgradeAttempted);
158 }
159
160 for domain_target_level_step in domain_info_version..domain_target_level {
162 let domain_target_level_step = domain_target_level_step + 1;
166 write_txn
167 .internal_apply_domain_migration(domain_target_level_step)
168 .map(|()| {
169 warn!(
170 "Domain level has been raised to {}",
171 domain_target_level_step
172 );
173 })?;
174 }
175
176 if domain_info_version != DOMAIN_LEVEL_0 {
182 reload_required = true;
183 }
184 } else if domain_info_version > domain_target_level {
185 error!("UNABLE TO PROCEED. You are attempting a downgrade which is NOT SUPPORTED.");
187 error!(
188 "For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html"
189 );
190 error!(domain_previous_version = ?domain_info_version, domain_target_version = ?domain_target_level);
191 return Err(OperationError::MG0010DowngradeNotAllowed);
192 } else if domain_development_taint {
193 write_txn.domain_remigrate(DOMAIN_PREVIOUS_TGT_LEVEL)?;
204
205 reload_required = true;
206 }
207
208 if domain_patch_level < DOMAIN_TGT_PATCH_LEVEL {
211 write_txn
212 .internal_modify_uuid(
213 UUID_DOMAIN_INFO,
214 &ModifyList::new_purge_and_set(
215 Attribute::PatchLevel,
216 Value::new_uint32(DOMAIN_TGT_PATCH_LEVEL),
217 ),
218 )
219 .map(|()| {
220 warn!(
221 "Domain patch level has been raised to {}",
222 domain_patch_level
223 );
224 })?;
225
226 reload_required = true;
227 };
228
229 if reload_required {
233 write_txn.reload()?;
234 }
235
236 let current_devel_flag = option_env!("KANIDM_PRE_RELEASE").is_some();
239 if current_devel_flag {
240 warn!("Domain Development Taint mode is enabled");
241 }
242 if domain_development_taint != current_devel_flag {
243 write_txn.internal_modify_uuid(
244 UUID_DOMAIN_INFO,
245 &ModifyList::new_purge_and_set(
246 Attribute::DomainDevelopmentTaint,
247 Value::Bool(current_devel_flag),
248 ),
249 )?;
250 }
251
252 write_txn.set_phase(ServerPhase::Running);
254
255 write_txn.commit()?;
258
259 debug!("Database version check and migrations success! ☀️ ");
260 Ok(())
261 }
262}
263
264impl QueryServerWriteTransaction<'_> {
265 #[instrument(level = "debug", skip(self))]
268 pub(crate) fn internal_apply_domain_migration(
269 &mut self,
270 to_level: u32,
271 ) -> Result<(), OperationError> {
272 self.internal_modify_uuid(
273 UUID_DOMAIN_INFO,
274 &ModifyList::new_purge_and_set(Attribute::Version, Value::new_uint32(to_level)),
275 )
276 .and_then(|()| self.reload())
277 }
278
279 fn internal_migrate_or_create_batch(
280 &mut self,
281 msg: &str,
282 entries: Vec<EntryInitNew>,
283 ) -> Result<(), OperationError> {
284 #[cfg(test)]
285 eprintln!("MIGRATION BATCH: {}", msg);
286 let r: Result<(), _> = entries
287 .into_iter()
288 .try_for_each(|entry| self.internal_migrate_or_create(entry));
289
290 if let Err(err) = r {
291 error!(?err, msg);
292 debug_assert!(false);
293 }
294
295 Ok(())
296 }
297
298 #[instrument(level = "debug", skip_all)]
299 fn internal_migrate_or_create(
309 &mut self,
310 e: Entry<EntryInit, EntryNew>,
311 ) -> Result<(), OperationError> {
312 self.internal_migrate_or_create_ignore_attrs(
314 e,
315 &[
316 Attribute::CredentialTypeMinimum,
318 ],
319 )
320 }
321
322 #[instrument(level = "debug", skip_all)]
323 fn internal_delete_batch(
324 &mut self,
325 msg: &str,
326 entries: Vec<Uuid>,
327 ) -> Result<(), OperationError> {
328 let filter = entries
329 .into_iter()
330 .map(|uuid| f_eq(Attribute::Uuid, PartialValue::Uuid(uuid)))
331 .collect();
332
333 let filter = filter!(f_or(filter));
335
336 let result = self.internal_delete(&filter);
337
338 match result {
339 Ok(_) | Err(OperationError::NoMatchingEntries) => Ok(()),
340 Err(err) => {
341 error!(?err, msg);
342 Err(err)
343 }
344 }
345 }
346
347 #[instrument(level = "trace", skip_all)]
351 fn internal_migrate_or_create_ignore_attrs(
352 &mut self,
353 mut e: Entry<EntryInit, EntryNew>,
354 attrs: &[Attribute],
355 ) -> Result<(), OperationError> {
356 trace!("operating on {:?}", e.get_uuid());
357
358 let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid]) else {
359 return Err(OperationError::FilterGeneration);
360 };
361
362 trace!("search {:?}", filt);
363
364 let results = self.internal_search(filt.clone())?;
365
366 if results.is_empty() {
367 if let Some(members_create_once) = e.pop_ava(Attribute::MemberCreateOnce) {
371 if let Some(members) = e.get_ava_mut(Attribute::Member) {
372 members.merge(&members_create_once).inspect_err(|err| {
374 error!(?err, "Unable to merge member sets, mismatched types?");
375 })?;
376 } else {
377 e.set_ava_set(&Attribute::Member, members_create_once);
379 }
380 };
381
382 self.internal_create(vec![e])
383 } else if results.len() == 1 {
384 e.remove_ava(&Attribute::MemberCreateOnce);
386
387 for attr in attrs.iter() {
389 e.remove_ava(attr);
390 }
391
392 match e.gen_modlist_assert(&self.schema) {
394 Ok(modlist) => {
395 trace!(?modlist);
397 self.internal_modify(&filt, &modlist)
398 }
399 Err(e) => Err(OperationError::SchemaViolation(e)),
400 }
401 } else {
402 admin_error!(
403 "Invalid Result Set - Expected One Entry for {:?} - {:?}",
404 filt,
405 results
406 );
407 Err(OperationError::InvalidDbState)
408 }
409 }
410
411 #[instrument(level = "info", skip_all)]
440 pub(crate) fn migrate_domain_9_to_10(&mut self) -> Result<(), OperationError> {
441 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_9 {
442 error!("Unable to raise domain level from 9 to 10.");
443 return Err(OperationError::MG0004DomainLevelInDevelopment);
444 }
445
446 self.internal_migrate_or_create_batch(
448 "phase 1 - schema attrs",
449 migration_data::dl10::phase_1_schema_attrs(),
450 )?;
451
452 self.internal_migrate_or_create_batch(
453 "phase 2 - schema classes",
454 migration_data::dl10::phase_2_schema_classes(),
455 )?;
456
457 self.reload()?;
459
460 self.reindex(false)?;
463
464 self.set_phase(ServerPhase::SchemaReady);
468
469 self.internal_migrate_or_create_batch(
470 "phase 3 - key provider",
471 migration_data::dl10::phase_3_key_provider(),
472 )?;
473
474 self.reload()?;
476
477 self.internal_migrate_or_create_batch(
478 "phase 4 - system entries",
479 migration_data::dl10::phase_4_system_entries(),
480 )?;
481
482 self.reload()?;
484
485 self.set_phase(ServerPhase::DomainInfoReady);
487
488 self.internal_migrate_or_create_batch(
490 "phase 5 - builtin admin entries",
491 migration_data::dl10::phase_5_builtin_admin_entries()?,
492 )?;
493
494 self.internal_migrate_or_create_batch(
495 "phase 6 - builtin not admin entries",
496 migration_data::dl10::phase_6_builtin_non_admin_entries()?,
497 )?;
498
499 self.internal_migrate_or_create_batch(
500 "phase 7 - builtin access control profiles",
501 migration_data::dl10::phase_7_builtin_access_control_profiles(),
502 )?;
503
504 self.reload()?;
505
506 debug!("START OAUTH2 MIGRATION");
509
510 let all_oauth2_rs_entries = self.internal_search(filter!(f_eq(
512 Attribute::Class,
513 EntryClass::OAuth2ResourceServer.into()
514 )))?;
515
516 if !all_oauth2_rs_entries.is_empty() {
517 let entry_iter = all_oauth2_rs_entries.iter().map(|tgt_entry| {
518 let entry_uuid = tgt_entry.get_uuid();
519 let mut modlist = ModifyList::new_list(vec![
520 Modify::Present(Attribute::Class, EntryClass::KeyObject.to_value()),
521 Modify::Present(Attribute::Class, EntryClass::KeyObjectJwtEs256.to_value()),
522 Modify::Present(Attribute::Class, EntryClass::KeyObjectJweA128GCM.to_value()),
523 Modify::Purged(Attribute::OAuth2RsTokenKey),
525 Modify::Purged(Attribute::Es256PrivateKeyDer),
526 Modify::Purged(Attribute::Rs256PrivateKeyDer),
527 ]);
528
529 trace!(?tgt_entry);
530
531 if let Some(es256_private_der) =
533 tgt_entry.get_ava_single_private_binary(Attribute::Es256PrivateKeyDer)
534 {
535 modlist.push_mod(Modify::Present(
536 Attribute::KeyActionImportJwsEs256,
537 Value::PrivateBinary(es256_private_der.to_vec()),
538 ))
539 } else {
540 warn!("Unable to migrate es256 key");
541 }
542
543 let has_rs256 = tgt_entry
544 .get_ava_single_bool(Attribute::OAuth2JwtLegacyCryptoEnable)
545 .unwrap_or(false);
546
547 if has_rs256 {
550 modlist.push_mod(Modify::Present(
551 Attribute::Class,
552 EntryClass::KeyObjectJwtEs256.to_value(),
553 ));
554
555 if let Some(rs256_private_der) =
556 tgt_entry.get_ava_single_private_binary(Attribute::Rs256PrivateKeyDer)
557 {
558 modlist.push_mod(Modify::Present(
559 Attribute::KeyActionImportJwsRs256,
560 Value::PrivateBinary(rs256_private_der.to_vec()),
561 ))
562 } else {
563 warn!("Unable to migrate rs256 key");
564 }
565 }
566
567 (entry_uuid, modlist)
568 });
569
570 self.internal_batch_modify(entry_iter)?;
571 }
572
573 self.reload()?;
575
576 Ok(())
579 }
580
581 #[instrument(level = "info", skip_all)]
583 pub(crate) fn migrate_domain_10_to_11(&mut self) -> Result<(), OperationError> {
584 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_10 {
585 error!("Unable to raise domain level from 10 to 11.");
586 return Err(OperationError::MG0004DomainLevelInDevelopment);
587 }
588
589 self.internal_migrate_or_create_batch(
591 "phase 1 - schema attrs",
592 migration_data::dl11::phase_1_schema_attrs(),
593 )?;
594
595 self.internal_migrate_or_create_batch(
596 "phase 2 - schema classes",
597 migration_data::dl11::phase_2_schema_classes(),
598 )?;
599
600 self.reload()?;
602
603 self.reindex(false)?;
606
607 self.set_phase(ServerPhase::SchemaReady);
611
612 self.internal_migrate_or_create_batch(
613 "phase 3 - key provider",
614 migration_data::dl11::phase_3_key_provider(),
615 )?;
616
617 self.reload()?;
619
620 self.internal_migrate_or_create_batch(
621 "phase 4 - system entries",
622 migration_data::dl11::phase_4_system_entries(),
623 )?;
624
625 self.reload()?;
627
628 self.set_phase(ServerPhase::DomainInfoReady);
630
631 self.internal_migrate_or_create_batch(
633 "phase 5 - builtin admin entries",
634 migration_data::dl11::phase_5_builtin_admin_entries()?,
635 )?;
636
637 self.internal_migrate_or_create_batch(
638 "phase 6 - builtin not admin entries",
639 migration_data::dl11::phase_6_builtin_non_admin_entries()?,
640 )?;
641
642 self.internal_migrate_or_create_batch(
643 "phase 7 - builtin access control profiles",
644 migration_data::dl11::phase_7_builtin_access_control_profiles(),
645 )?;
646
647 self.reload()?;
648
649 Ok(())
650 }
651
652 #[instrument(level = "info", skip_all)]
654 pub(crate) fn migrate_domain_11_to_12(&mut self) -> Result<(), OperationError> {
655 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_11 {
656 error!("Unable to raise domain level from 11 to 12.");
657 return Err(OperationError::MG0004DomainLevelInDevelopment);
658 }
659
660 self.internal_migrate_or_create_batch(
662 "phase 1 - schema attrs",
663 migration_data::dl12::phase_1_schema_attrs(),
664 )?;
665
666 self.internal_migrate_or_create_batch(
667 "phase 2 - schema classes",
668 migration_data::dl12::phase_2_schema_classes(),
669 )?;
670
671 self.reload()?;
673
674 self.reindex(false)?;
677
678 self.set_phase(ServerPhase::SchemaReady);
682
683 self.internal_migrate_or_create_batch(
684 "phase 3 - key provider",
685 migration_data::dl12::phase_3_key_provider(),
686 )?;
687
688 self.reload()?;
690
691 self.internal_migrate_or_create_batch(
692 "phase 4 - system entries",
693 migration_data::dl12::phase_4_system_entries(),
694 )?;
695
696 self.reload()?;
698
699 self.set_phase(ServerPhase::DomainInfoReady);
701
702 self.internal_migrate_or_create_batch(
704 "phase 5 - builtin admin entries",
705 migration_data::dl12::phase_5_builtin_admin_entries()?,
706 )?;
707
708 self.internal_migrate_or_create_batch(
709 "phase 6 - builtin not admin entries",
710 migration_data::dl12::phase_6_builtin_non_admin_entries()?,
711 )?;
712
713 self.internal_migrate_or_create_batch(
714 "phase 7 - builtin access control profiles",
715 migration_data::dl12::phase_7_builtin_access_control_profiles(),
716 )?;
717
718 self.reload()?;
719
720 let modlist = ModifyList::new_purge(Attribute::IdVerificationEcKey);
722 let filter = filter_all!(f_pres(Attribute::IdVerificationEcKey));
723
724 self.internal_modify(&filter, &modlist)?;
725
726 Ok(())
727 }
728
729 #[instrument(level = "info", skip_all)]
731 pub(crate) fn migrate_domain_12_to_13(&mut self) -> Result<(), OperationError> {
732 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_12 {
733 error!("Unable to raise domain level from 12 to 13.");
734 return Err(OperationError::MG0004DomainLevelInDevelopment);
735 }
736
737 self.internal_migrate_or_create_batch(
739 "phase 1 - schema attrs",
740 migration_data::dl13::phase_1_schema_attrs(),
741 )?;
742
743 self.internal_migrate_or_create_batch(
744 "phase 2 - schema classes",
745 migration_data::dl13::phase_2_schema_classes(),
746 )?;
747
748 self.reload()?;
750
751 self.reindex(false)?;
754
755 self.set_phase(ServerPhase::SchemaReady);
759
760 self.internal_migrate_or_create_batch(
761 "phase 3 - key provider",
762 migration_data::dl13::phase_3_key_provider(),
763 )?;
764
765 self.reload()?;
767
768 self.internal_migrate_or_create_batch(
769 "phase 4 - system entries",
770 migration_data::dl13::phase_4_system_entries(),
771 )?;
772
773 self.reload()?;
775
776 self.set_phase(ServerPhase::DomainInfoReady);
778
779 self.internal_migrate_or_create_batch(
781 "phase 5 - builtin admin entries",
782 migration_data::dl13::phase_5_builtin_admin_entries()?,
783 )?;
784
785 self.internal_migrate_or_create_batch(
786 "phase 6 - builtin not admin entries",
787 migration_data::dl13::phase_6_builtin_non_admin_entries()?,
788 )?;
789
790 self.internal_migrate_or_create_batch(
791 "phase 7 - builtin access control profiles",
792 migration_data::dl13::phase_7_builtin_access_control_profiles(),
793 )?;
794
795 self.internal_delete_batch(
796 "phase 8 - delete UUIDS",
797 migration_data::dl13::phase_8_delete_uuids(),
798 )?;
799
800 self.reload()?;
801
802 Ok(())
803 }
804
805 #[instrument(level = "info", skip_all)]
807 pub(crate) fn migrate_domain_13_to_14(&mut self) -> Result<(), OperationError> {
808 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_13 {
809 error!("Unable to raise domain level from 13 to 14.");
810 return Err(OperationError::MG0004DomainLevelInDevelopment);
811 }
812
813 self.internal_migrate_or_create_batch(
815 &format!("phase 1 - schema attrs target {}", DOMAIN_TGT_LEVEL),
816 migration_data::dl14::phase_1_schema_attrs(),
817 )?;
818
819 self.internal_migrate_or_create_batch(
820 "phase 2 - schema classes",
821 migration_data::dl14::phase_2_schema_classes(),
822 )?;
823
824 self.reload()?;
826
827 self.reindex(false)?;
830
831 self.set_phase(ServerPhase::SchemaReady);
835
836 self.internal_migrate_or_create_batch(
837 "phase 3 - key provider",
838 migration_data::dl14::phase_3_key_provider(),
839 )?;
840
841 self.reload()?;
843
844 self.internal_migrate_or_create_batch(
845 "phase 4 - dl14 system entries",
846 migration_data::dl14::phase_4_system_entries(),
847 )?;
848
849 self.reload()?;
851
852 self.set_phase(ServerPhase::DomainInfoReady);
854
855 self.internal_migrate_or_create_batch(
857 "phase 5 - builtin admin entries",
858 migration_data::dl14::phase_5_builtin_admin_entries()?,
859 )?;
860
861 self.internal_migrate_or_create_batch(
862 "phase 6 - builtin not admin entries",
863 migration_data::dl14::phase_6_builtin_non_admin_entries()?,
864 )?;
865
866 self.internal_migrate_or_create_batch(
867 "phase 7 - builtin access control profiles",
868 migration_data::dl14::phase_7_builtin_access_control_profiles(),
869 )?;
870
871 self.internal_delete_batch(
872 "phase 8 - delete UUIDS",
873 migration_data::dl14::phase_8_delete_uuids(),
874 )?;
875
876 self.reload()?;
877
878 let filter = filter_all!(f_and!([
880 f_eq(Attribute::Class, EntryClass::Person.into()),
881 f_andnot(f_pres(Attribute::PasswordChangedTime)),
882 ]));
883 let modlist = ModifyList::new_purge_and_set(
884 Attribute::PasswordChangedTime,
885 Value::DateTime(time::OffsetDateTime::UNIX_EPOCH),
886 );
887 self.internal_modify(&filter, &modlist)?;
888
889 Ok(())
890 }
891
892 pub(crate) fn migrate_schema_1_11(&mut self) -> Result<(), OperationError> {
893 self.schema.extend_in_memory(
894 migration_data::dl15::phase_1_schema_attrs(),
895 migration_data::dl15::phase_2_schema_classes(),
896 )
897 }
898
899 #[instrument(level = "info", skip_all)]
901 pub(crate) fn migrate_domain_1_10_to_1_11(&mut self) -> Result<(), OperationError> {
902 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_14 {
903 error!(
904 "Unable to raise domain level from {} to {}.",
905 DOMAIN_LEVEL_14, DOMAIN_LEVEL_1_11
906 );
907 return Err(OperationError::MG0004DomainLevelInDevelopment);
908 }
909
910 self.migrate_schema_1_11()?;
912
913 self.reload()?;
915
916 self.reindex(false)?;
919
920 let filter = filter!(f_and(vec![
923 f_eq(Attribute::Class, EntryClass::ClassType.into()),
924 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
925 ]));
926
927 self.internal_delete_if_exists(&filter)?;
928
929 self.set_phase(ServerPhase::SchemaReady);
933
934 self.internal_migrate_or_create_batch(
935 "phase 3 - key provider",
936 migration_data::dl15::phase_3_key_provider(),
937 )?;
938
939 self.reload()?;
941
942 self.internal_migrate_or_create_batch(
943 "phase 4 - dl15 system entries",
944 migration_data::dl15::phase_4_system_entries(),
945 )?;
946
947 self.reload()?;
949
950 self.set_phase(ServerPhase::DomainInfoReady);
952
953 self.internal_migrate_or_create_batch(
955 "phase 5 - builtin admin entries",
956 migration_data::dl15::phase_5_builtin_admin_entries()?,
957 )?;
958
959 self.internal_migrate_or_create_batch(
960 "phase 6 - builtin not admin entries",
961 migration_data::dl15::phase_6_builtin_non_admin_entries()?,
962 )?;
963
964 self.internal_migrate_or_create_batch(
965 "phase 7 - builtin access control profiles",
966 migration_data::dl15::phase_7_builtin_access_control_profiles(),
967 )?;
968
969 self.internal_delete_batch(
970 "phase 8 - delete UUIDS",
971 migration_data::dl15::phase_8_delete_uuids(),
972 )?;
973
974 self.reload()?;
975
976 let filter = filter_all!(f_and!([
978 f_eq(Attribute::Class, EntryClass::Person.into()),
979 f_andnot(f_pres(Attribute::PasswordChangedTime)),
980 ]));
981 let modlist = ModifyList::new_purge_and_set(
982 Attribute::PasswordChangedTime,
983 Value::DateTime(time::OffsetDateTime::UNIX_EPOCH),
984 );
985 self.internal_modify(&filter, &modlist)?;
986
987 Ok(())
988 }
989
990 #[instrument(level = "info", skip_all)]
992 pub(crate) fn migrate_domain_1_11_to_1_12(&mut self) -> Result<(), OperationError> {
993 if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_1_11 {
994 error!("Unable to raise domain level from 15 to 16.");
995 return Err(OperationError::MG0004DomainLevelInDevelopment);
996 }
997
998 Ok(())
999 }
1000
1001 #[instrument(level = "info", skip_all)]
1002 pub(crate) fn initialise_schema_core(&mut self) -> Result<(), OperationError> {
1003 debug!("initialise_schema_core -> start ...");
1004 let entries = self.schema.to_entries();
1006
1007 let r: Result<_, _> = entries.into_iter().try_for_each(|e| {
1011 trace!(?e, "init schema entry");
1012 self.internal_migrate_or_create(e)
1013 });
1014 if r.is_ok() {
1015 debug!("initialise_schema_core -> Ok!");
1016 } else {
1017 error!(?r, "initialise_schema_core -> Error");
1018 }
1019 debug_assert!(r.is_ok());
1021 r
1022 }
1023}
1024
1025impl QueryServerReadTransaction<'_> {
1026 pub fn domain_upgrade_check(
1028 &mut self,
1029 ) -> Result<ProtoDomainUpgradeCheckReport, OperationError> {
1030 let d_info = &self.d_info;
1031
1032 let name = d_info.d_name.clone();
1033 let uuid = d_info.d_uuid;
1034 let current_level = d_info.d_vers;
1035 let upgrade_level = DOMAIN_TGT_NEXT_LEVEL;
1036
1037 let mut report_items = Vec::with_capacity(1);
1038
1039 if current_level <= DOMAIN_LEVEL_7 && upgrade_level >= DOMAIN_LEVEL_8 {
1040 let item = self
1041 .domain_upgrade_check_7_to_8_security_keys()
1042 .map_err(|err| {
1043 error!(
1044 ?err,
1045 "Failed to perform domain upgrade check 7 to 8 - security-keys"
1046 );
1047 err
1048 })?;
1049 report_items.push(item);
1050
1051 let item = self
1052 .domain_upgrade_check_7_to_8_oauth2_strict_redirect_uri()
1053 .map_err(|err| {
1054 error!(
1055 ?err,
1056 "Failed to perform domain upgrade check 7 to 8 - oauth2-strict-redirect_uri"
1057 );
1058 err
1059 })?;
1060 report_items.push(item);
1061 }
1062
1063 Ok(ProtoDomainUpgradeCheckReport {
1064 name,
1065 uuid,
1066 current_level,
1067 upgrade_level,
1068 report_items,
1069 })
1070 }
1071
1072 pub(crate) fn domain_upgrade_check_7_to_8_security_keys(
1073 &mut self,
1074 ) -> Result<ProtoDomainUpgradeCheckItem, OperationError> {
1075 let filter = filter!(f_and!([
1076 f_eq(Attribute::Class, EntryClass::Account.into()),
1077 f_pres(Attribute::PrimaryCredential),
1078 ]));
1079
1080 let results = self.internal_search(filter)?;
1081
1082 let affected_entries = results
1083 .into_iter()
1084 .filter_map(|entry| {
1085 if entry
1086 .get_ava_single_credential(Attribute::PrimaryCredential)
1087 .map(|cred| cred.has_securitykey())
1088 .unwrap_or_default()
1089 {
1090 Some(entry.get_display_id())
1091 } else {
1092 None
1093 }
1094 })
1095 .collect::<Vec<_>>();
1096
1097 let status = if affected_entries.is_empty() {
1098 ProtoDomainUpgradeCheckStatus::Pass7To8SecurityKeys
1099 } else {
1100 ProtoDomainUpgradeCheckStatus::Fail7To8SecurityKeys
1101 };
1102
1103 Ok(ProtoDomainUpgradeCheckItem {
1104 status,
1105 from_level: DOMAIN_LEVEL_7,
1106 to_level: DOMAIN_LEVEL_8,
1107 affected_entries,
1108 })
1109 }
1110
1111 pub(crate) fn domain_upgrade_check_7_to_8_oauth2_strict_redirect_uri(
1112 &mut self,
1113 ) -> Result<ProtoDomainUpgradeCheckItem, OperationError> {
1114 let filter = filter!(f_and!([
1115 f_eq(Attribute::Class, EntryClass::OAuth2ResourceServer.into()),
1116 f_andnot(f_pres(Attribute::OAuth2StrictRedirectUri)),
1117 ]));
1118
1119 let results = self.internal_search(filter)?;
1120
1121 let affected_entries = results
1122 .into_iter()
1123 .map(|entry| entry.get_display_id())
1124 .collect::<Vec<_>>();
1125
1126 let status = if affected_entries.is_empty() {
1127 ProtoDomainUpgradeCheckStatus::Pass7To8Oauth2StrictRedirectUri
1128 } else {
1129 ProtoDomainUpgradeCheckStatus::Fail7To8Oauth2StrictRedirectUri
1130 };
1131
1132 Ok(ProtoDomainUpgradeCheckItem {
1133 status,
1134 from_level: DOMAIN_LEVEL_7,
1135 to_level: DOMAIN_LEVEL_8,
1136 affected_entries,
1137 })
1138 }
1139}
1140
1141#[cfg(test)]
1142mod tests {
1143 use crate::prelude::*;
1145 use crate::value::CredentialType;
1146 use crate::valueset::ValueSetCredentialType;
1147
1148 #[qs_test]
1149 async fn test_init_idempotent_schema_core(server: &QueryServer) {
1150 {
1151 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1153 assert!(server_txn.initialise_schema_core().is_ok());
1154 }
1155 {
1156 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1157 assert!(server_txn.initialise_schema_core().is_ok());
1158 assert!(server_txn.initialise_schema_core().is_ok());
1159 assert!(server_txn.commit().is_ok());
1160 }
1161 {
1162 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1164 assert!(server_txn.initialise_schema_core().is_ok());
1165 }
1166 {
1167 let mut server_txn = server.write(duration_from_epoch_now()).await.unwrap();
1169 assert!(server_txn.initialise_schema_core().is_ok());
1170 assert!(server_txn.commit().is_ok());
1171 }
1172 }
1173
1174 #[qs_test(domain_level=DOMAIN_PREVIOUS_TGT_LEVEL)]
1178 async fn test_migrations_dl_previous_to_dl_target(server: &QueryServer) {
1179 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1180
1181 let db_domain_version = write_txn
1182 .internal_search_uuid(UUID_DOMAIN_INFO)
1183 .expect("unable to access domain entry")
1184 .get_ava_single_uint32(Attribute::Version)
1185 .expect("Attribute Version not present");
1186
1187 assert_eq!(db_domain_version, DOMAIN_PREVIOUS_TGT_LEVEL);
1188
1189 let modlist = ModifyList::new_set(
1194 Attribute::Member,
1195 ValueSetRefer::new(UUID_ANONYMOUS),
1198 );
1199 write_txn
1200 .internal_modify_uuid(UUID_IDM_ADMINS, &modlist)
1201 .expect("Unable to modify CredentialTypeMinimum");
1202
1203 let modlist = ModifyList::new_purge(Attribute::Member);
1206 write_txn
1207 .internal_modify_uuid(UUID_IDM_PEOPLE_SELF_NAME_WRITE, &modlist)
1208 .expect("Unable to remove idm_all_persons from self-write");
1209
1210 let modlist = ModifyList::new_set(
1212 Attribute::CredentialTypeMinimum,
1213 ValueSetCredentialType::new(CredentialType::Any),
1214 );
1215 write_txn
1216 .internal_modify_uuid(UUID_IDM_ALL_PERSONS, &modlist)
1217 .expect("Unable to modify CredentialTypeMinimum");
1218
1219 write_txn.commit().expect("Unable to commit");
1220
1221 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1222
1223 write_txn
1225 .internal_apply_domain_migration(DOMAIN_TGT_LEVEL)
1226 .expect("Unable to set domain level");
1227
1228 let idm_admins_entry = write_txn
1231 .internal_search_uuid(UUID_IDM_ADMINS)
1232 .expect("Unable to retrieve all persons");
1233
1234 let members = idm_admins_entry
1235 .get_ava_refer(Attribute::Member)
1236 .expect("No members present");
1237
1238 assert!(members.contains(&UUID_ANONYMOUS));
1240 assert!(members.contains(&UUID_IDM_ADMIN));
1242
1243 let idm_people_self_name_write_entry = write_txn
1245 .internal_search_uuid(UUID_IDM_PEOPLE_SELF_NAME_WRITE)
1246 .expect("Unable to retrieve all persons");
1247
1248 let members = idm_people_self_name_write_entry.get_ava_refer(Attribute::Member);
1249
1250 assert!(members.is_none());
1252
1253 let all_persons_entry = write_txn
1255 .internal_search_uuid(UUID_IDM_ALL_PERSONS)
1256 .expect("Unable to retrieve all persons");
1257
1258 assert_eq!(
1259 all_persons_entry.get_ava_single_credential_type(Attribute::CredentialTypeMinimum),
1260 Some(CredentialType::Any)
1261 );
1262
1263 write_txn.commit().expect("Unable to commit");
1264 }
1265
1266 #[qs_test(domain_level=DOMAIN_TGT_LEVEL)]
1267 async fn test_migrations_prevent_downgrades(server: &QueryServer) {
1268 let curtime = duration_from_epoch_now();
1269
1270 let mut write_txn = server.write(curtime).await.unwrap();
1271
1272 let db_domain_version = write_txn
1273 .internal_search_uuid(UUID_DOMAIN_INFO)
1274 .expect("unable to access domain entry")
1275 .get_ava_single_uint32(Attribute::Version)
1276 .expect("Attribute Version not present");
1277
1278 assert_eq!(db_domain_version, DOMAIN_TGT_LEVEL);
1279
1280 drop(write_txn);
1281
1282 let err = server
1284 .initialise_helper(curtime, DOMAIN_PREVIOUS_TGT_LEVEL)
1285 .await
1286 .expect_err("Domain level was lowered!!!!");
1287
1288 assert_eq!(err, OperationError::MG0010DowngradeNotAllowed);
1289 }
1290
1291 #[qs_test(domain_level=DOMAIN_MIGRATION_FROM_INVALID)]
1292 async fn test_migrations_prevent_skips(server: &QueryServer) {
1293 let curtime = duration_from_epoch_now();
1294
1295 let mut write_txn = server.write(curtime).await.unwrap();
1296
1297 let db_domain_version = write_txn
1298 .internal_search_uuid(UUID_DOMAIN_INFO)
1299 .expect("unable to access domain entry")
1300 .get_ava_single_uint32(Attribute::Version)
1301 .expect("Attribute Version not present");
1302
1303 assert_eq!(db_domain_version, DOMAIN_MIGRATION_FROM_INVALID);
1304
1305 drop(write_txn);
1306
1307 let err = server
1309 .initialise_helper(curtime, DOMAIN_TGT_LEVEL)
1310 .await
1311 .expect_err("Migration went ahead!!!!");
1312
1313 assert_eq!(err, OperationError::MG0008SkipUpgradeAttempted);
1314 }
1315
1316 #[qs_test(domain_level=DOMAIN_MIGRATION_FROM_MIN)]
1317 async fn test_migrations_skip_valid(server: &QueryServer) {
1318 let curtime = duration_from_epoch_now();
1319 let mut write_txn = server.write(curtime).await.unwrap();
1322
1323 let db_domain_version = write_txn
1324 .internal_search_uuid(UUID_DOMAIN_INFO)
1325 .expect("unable to access domain entry")
1326 .get_ava_single_uint32(Attribute::Version)
1327 .expect("Attribute Version not present");
1328
1329 assert_eq!(db_domain_version, DOMAIN_MIGRATION_FROM_MIN);
1330
1331 drop(write_txn);
1332
1333 server
1335 .initialise_helper(curtime, DOMAIN_TGT_LEVEL)
1336 .await
1337 .expect("Migration failed!!!!")
1338 }
1339
1340 #[qs_test(domain_level=DOMAIN_LEVEL_10)]
1341 async fn test_migrations_dl10_dl11(server: &QueryServer) {
1342 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1343
1344 let db_domain_version = write_txn
1345 .internal_search_uuid(UUID_DOMAIN_INFO)
1346 .expect("unable to access domain entry")
1347 .get_ava_single_uint32(Attribute::Version)
1348 .expect("Attribute Version not present");
1349
1350 assert_eq!(db_domain_version, DOMAIN_LEVEL_10);
1351
1352 write_txn.commit().expect("Unable to commit");
1353
1354 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1361
1362 write_txn
1366 .internal_apply_domain_migration(DOMAIN_LEVEL_11)
1367 .expect("Unable to set domain level to version 11");
1368
1369 write_txn.commit().expect("Unable to commit");
1372 }
1373
1374 #[qs_test(domain_level=DOMAIN_LEVEL_11)]
1375 async fn test_migrations_dl11_dl12(server: &QueryServer) {
1376 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1377
1378 let db_domain_version = write_txn
1379 .internal_search_uuid(UUID_DOMAIN_INFO)
1380 .expect("unable to access domain entry")
1381 .get_ava_single_uint32(Attribute::Version)
1382 .expect("Attribute Version not present");
1383
1384 assert_eq!(db_domain_version, DOMAIN_LEVEL_11);
1385
1386 let tuuid = Uuid::new_v4();
1388 let e1 = entry_init!(
1389 (Attribute::Class, EntryClass::Object.to_value()),
1390 (Attribute::Class, EntryClass::Person.to_value()),
1391 (Attribute::Class, EntryClass::Account.to_value()),
1392 (Attribute::Name, Value::new_iname("testperson1")),
1393 (Attribute::Uuid, Value::Uuid(tuuid)),
1394 (Attribute::Description, Value::new_utf8s("testperson1")),
1395 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
1396 );
1397
1398 write_txn
1399 .internal_create(vec![e1])
1400 .expect("Unable to create user");
1401
1402 let user = write_txn
1403 .internal_search_uuid(tuuid)
1404 .expect("Unable to load user");
1405
1406 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_some());
1408
1409 write_txn.commit().expect("Unable to commit");
1410
1411 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1418
1419 write_txn
1423 .internal_apply_domain_migration(DOMAIN_LEVEL_12)
1424 .expect("Unable to set domain level to version 12");
1425
1426 let user = write_txn
1428 .internal_search_uuid(tuuid)
1429 .expect("Unable to load user");
1430
1431 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_none());
1433
1434 let t2uuid = Uuid::new_v4();
1436 let e2 = entry_init!(
1437 (Attribute::Class, EntryClass::Object.to_value()),
1438 (Attribute::Class, EntryClass::Person.to_value()),
1439 (Attribute::Class, EntryClass::Account.to_value()),
1440 (Attribute::Name, Value::new_iname("testperson2")),
1441 (Attribute::Uuid, Value::Uuid(t2uuid)),
1442 (Attribute::Description, Value::new_utf8s("testperson2")),
1443 (Attribute::DisplayName, Value::new_utf8s("testperson2"))
1444 );
1445
1446 write_txn
1447 .internal_create(vec![e2])
1448 .expect("Unable to create user");
1449
1450 let user = write_txn
1451 .internal_search_uuid(t2uuid)
1452 .expect("Unable to load user");
1453
1454 assert!(user.get_ava_set(Attribute::IdVerificationEcKey).is_none());
1456
1457 write_txn.commit().expect("Unable to commit");
1458 }
1459
1460 #[qs_test(domain_level=DOMAIN_LEVEL_12)]
1461 async fn test_migrations_dl12_dl13(server: &QueryServer) {
1462 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1463
1464 let db_domain_version = write_txn
1465 .internal_search_uuid(UUID_DOMAIN_INFO)
1466 .expect("unable to access domain entry")
1467 .get_ava_single_uint32(Attribute::Version)
1468 .expect("Attribute Version not present");
1469
1470 assert_eq!(db_domain_version, DOMAIN_LEVEL_12);
1471
1472 write_txn.commit().expect("Unable to commit");
1473
1474 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1481
1482 write_txn
1486 .internal_apply_domain_migration(DOMAIN_LEVEL_13)
1487 .expect("Unable to set domain level to version 13");
1488
1489 write_txn.commit().expect("Unable to commit");
1492 }
1493
1494 #[qs_test(domain_level=DOMAIN_LEVEL_13)]
1495 async fn test_migrations_dl13_dl14(server: &QueryServer) {
1496 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1497
1498 let db_domain_version = write_txn
1499 .internal_search_uuid(UUID_DOMAIN_INFO)
1500 .expect("unable to access domain entry")
1501 .get_ava_single_uint32(Attribute::Version)
1502 .expect("Attribute Version not present");
1503
1504 assert_eq!(db_domain_version, DOMAIN_LEVEL_13);
1505
1506 let tuuid = Uuid::new_v4();
1508 let e1 = entry_init!(
1509 (Attribute::Class, EntryClass::Object.to_value()),
1510 (Attribute::Class, EntryClass::Person.to_value()),
1511 (Attribute::Class, EntryClass::Account.to_value()),
1512 (Attribute::Name, Value::new_iname("testperson1")),
1513 (Attribute::Uuid, Value::Uuid(tuuid)),
1514 (Attribute::Description, Value::new_utf8s("testperson1")),
1515 (Attribute::DisplayName, Value::new_utf8s("testperson1"))
1516 );
1517
1518 write_txn
1519 .internal_create(vec![e1])
1520 .expect("Unable to create test person");
1521
1522 let user = write_txn
1523 .internal_search_uuid(tuuid)
1524 .expect("Unable to load test person");
1525
1526 assert!(user
1528 .get_ava_single_datetime(Attribute::PasswordChangedTime)
1529 .is_none());
1530
1531 write_txn.commit().expect("Unable to commit");
1532
1533 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1540
1541 write_txn
1545 .internal_apply_domain_migration(DOMAIN_LEVEL_14)
1546 .expect("Unable to set domain level to version 14");
1547
1548 let user = write_txn
1551 .internal_search_uuid(tuuid)
1552 .expect("Unable to load test person after migration");
1553
1554 let pwd_changed = user
1555 .get_ava_single_datetime(Attribute::PasswordChangedTime)
1556 .expect("PasswordChangedTime should be set after DL13->DL14 migration");
1557
1558 assert_eq!(pwd_changed, time::OffsetDateTime::UNIX_EPOCH);
1559
1560 write_txn.commit().expect("Unable to commit");
1561 }
1562
1563 #[qs_test(domain_level=DOMAIN_LEVEL_14)]
1564 async fn test_migrations_dl14_dl1_11(server: &QueryServer) {
1565 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1566
1567 let db_domain_version = write_txn
1568 .internal_search_uuid(UUID_DOMAIN_INFO)
1569 .expect("unable to access domain entry")
1570 .get_ava_single_uint32(Attribute::Version)
1571 .expect("Attribute Version not present");
1572
1573 assert_eq!(db_domain_version, DOMAIN_LEVEL_14);
1574
1575 write_txn.commit().expect("Unable to commit");
1576
1577 let mut write_txn = server.write(duration_from_epoch_now()).await.unwrap();
1584
1585 write_txn
1589 .internal_apply_domain_migration(DOMAIN_LEVEL_1_11)
1590 .expect("Unable to set domain level to version 1_11");
1591
1592 let filter = filter!(f_and(vec![
1597 f_eq(Attribute::Class, EntryClass::ClassType.into()),
1598 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
1599 ]));
1600
1601 let entries_remain = write_txn.internal_exists(&filter).unwrap();
1602 assert!(!entries_remain);
1603
1604 write_txn.commit().expect("Unable to commit");
1605 }
1606}