Update to 1.4.0-dev (#2943)

This commit is contained in:
Firstyear 2024-08-01 00:02:11 +10:00 committed by GitHub
parent a365312076
commit 329750981e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 181 additions and 1221 deletions

50
Cargo.lock generated
View file

@ -1213,7 +1213,7 @@ dependencies = [
[[package]]
name = "daemon"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"clap",
"clap_complete",
@ -3188,7 +3188,7 @@ dependencies = [
[[package]]
name = "kanidm-ipa-sync"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"chrono",
"clap",
@ -3212,7 +3212,7 @@ dependencies = [
[[package]]
name = "kanidm-ldap-sync"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"base64urlsafedata 0.5.0",
"chrono",
@ -3238,7 +3238,7 @@ dependencies = [
[[package]]
name = "kanidm_build_profiles"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"base64 0.22.1",
"gix",
@ -3248,7 +3248,7 @@ dependencies = [
[[package]]
name = "kanidm_client"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"compact_jwt 0.4.2",
"http 1.1.0",
@ -3269,7 +3269,7 @@ dependencies = [
[[package]]
name = "kanidm_lib_crypto"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"argon2",
"base64 0.22.1",
@ -3290,7 +3290,7 @@ dependencies = [
[[package]]
name = "kanidm_lib_file_permissions"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"kanidm_utils_users",
"whoami",
@ -3298,7 +3298,7 @@ dependencies = [
[[package]]
name = "kanidm_proto"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"base32",
"base64urlsafedata 0.5.0",
@ -3318,7 +3318,7 @@ dependencies = [
[[package]]
name = "kanidm_tools"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"anyhow",
"async-recursion",
@ -3351,7 +3351,7 @@ dependencies = [
[[package]]
name = "kanidm_unix_common"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"bytes",
"csv",
@ -3367,7 +3367,7 @@ dependencies = [
[[package]]
name = "kanidm_unix_int"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"async-trait",
"bytes",
@ -3407,14 +3407,14 @@ dependencies = [
[[package]]
name = "kanidm_utils_users"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"libc",
]
[[package]]
name = "kanidmd_core"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"askama",
"async-trait",
@ -3471,7 +3471,7 @@ dependencies = [
[[package]]
name = "kanidmd_lib"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"base64 0.22.1",
"base64urlsafedata 0.5.0",
@ -3532,7 +3532,7 @@ dependencies = [
[[package]]
name = "kanidmd_lib_macros"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"proc-macro2",
"quote",
@ -3541,7 +3541,7 @@ dependencies = [
[[package]]
name = "kanidmd_testkit"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"assert_cmd",
"compact_jwt 0.4.2",
@ -3579,7 +3579,7 @@ dependencies = [
[[package]]
name = "kanidmd_web_ui_admin"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"enum-iterator",
"gloo",
@ -3601,7 +3601,7 @@ dependencies = [
[[package]]
name = "kanidmd_web_ui_login_flows"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"gloo",
"gloo-utils 0.2.0",
@ -3622,7 +3622,7 @@ dependencies = [
[[package]]
name = "kanidmd_web_ui_shared"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"gloo",
"js-sys",
@ -3641,7 +3641,7 @@ dependencies = [
[[package]]
name = "kanidmd_web_ui_user"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"enum-iterator",
"gloo",
@ -4097,7 +4097,7 @@ dependencies = [
[[package]]
name = "nss_kanidm"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"kanidm_unix_common",
"lazy_static",
@ -4470,7 +4470,7 @@ dependencies = [
[[package]]
name = "orca"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"async-trait",
"chrono",
@ -4513,7 +4513,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "pam_kanidm"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"kanidm_unix_common",
"libc",
@ -5367,7 +5367,7 @@ dependencies = [
[[package]]
name = "scim_proto"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"base64urlsafedata 0.5.0",
"peg",
@ -5647,7 +5647,7 @@ dependencies = [
[[package]]
name = "sketching"
version = "1.3.0-dev"
version = "1.4.0-dev"
dependencies = [
"gethostname",
"num_enum",

View file

@ -1,5 +1,5 @@
[workspace.package]
version = "1.3.0-dev"
version = "1.4.0-dev"
authors = [
"William Brown <william@blackhats.net.au>",
"James Hodgkinson <james@terminaloutcomes.com>",
@ -124,20 +124,20 @@ codegen-units = 256
# kanidm-hsm-crypto = { path = "../hsm-crypto" }
[workspace.dependencies]
kanidmd_core = { path = "./server/core", version = "=1.3.0-dev" }
kanidmd_lib = { path = "./server/lib", version = "=1.3.0-dev" }
kanidmd_lib_macros = { path = "./server/lib-macros", version = "=1.3.0-dev" }
kanidmd_testkit = { path = "./server/testkit", version = "=1.3.0-dev" }
kanidm_build_profiles = { path = "./libs/profiles", version = "=1.3.0-dev" }
kanidm_client = { path = "./libs/client", version = "=1.3.0-dev" }
kanidmd_core = { path = "./server/core", version = "=1.4.0-dev" }
kanidmd_lib = { path = "./server/lib", version = "=1.4.0-dev" }
kanidmd_lib_macros = { path = "./server/lib-macros", version = "=1.4.0-dev" }
kanidmd_testkit = { path = "./server/testkit", version = "=1.4.0-dev" }
kanidm_build_profiles = { path = "./libs/profiles", version = "=1.4.0-dev" }
kanidm_client = { path = "./libs/client", version = "=1.4.0-dev" }
kanidm-hsm-crypto = "^0.2.0"
kanidm_lib_crypto = { path = "./libs/crypto", version = "=1.3.0-dev" }
kanidm_lib_file_permissions = { path = "./libs/file_permissions", version = "=1.3.0-dev" }
kanidm_proto = { path = "./proto", version = "=1.3.0-dev" }
kanidm_unix_common = { path = "./unix_integration/common", version = "=1.3.0-dev" }
kanidm_utils_users = { path = "./libs/users", version = "=1.3.0-dev" }
scim_proto = { path = "./libs/scim_proto", version = "=1.3.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.3.0-dev" }
kanidm_lib_crypto = { path = "./libs/crypto", version = "=1.4.0-dev" }
kanidm_lib_file_permissions = { path = "./libs/file_permissions", version = "=1.4.0-dev" }
kanidm_proto = { path = "./proto", version = "=1.4.0-dev" }
kanidm_unix_common = { path = "./unix_integration/common", version = "=1.4.0-dev" }
kanidm_utils_users = { path = "./libs/users", version = "=1.4.0-dev" }
scim_proto = { path = "./libs/scim_proto", version = "=1.4.0-dev" }
sketching = { path = "./libs/sketching", version = "=1.4.0-dev" }
anyhow = { version = "1.0.86" }
argon2 = { version = "0.5.3", features = ["alloc"] }

View file

@ -153,6 +153,7 @@ pub enum OperationError {
MG0005GidConstraintsNotMet,
MG0006SKConstraintsNotMet,
MG0007Oauth2StrictConstraintsNotMet,
MG0008SkipUpgradeAttempted,
//
KP0001KeyProviderNotLoaded,
KP0002KeyProviderInvalidClass,
@ -306,6 +307,7 @@ impl OperationError {
Self::MG0005GidConstraintsNotMet => None,
Self::MG0006SKConstraintsNotMet => Some("Migration Constraints Not Met - Security Keys should not be present."),
Self::MG0007Oauth2StrictConstraintsNotMet => Some("Migration Constraints Not Met - All OAuth2 clients must have strict-redirect-uri mode enabled."),
Self::MG0008SkipUpgradeAttempted => Some("Skip Upgrade Attempted."),
Self::KP0001KeyProviderNotLoaded => None,
Self::KP0002KeyProviderInvalidClass => None,
Self::KP0003KeyProviderInvalidType => None,

View file

@ -491,53 +491,6 @@ lazy_static! {
};
}
lazy_static! {
pub static ref IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_V1: BuiltinAcp = BuiltinAcp {
classes: vec![
EntryClass::Object,
EntryClass::AccessControlProfile,
EntryClass::AccessControlModify,
EntryClass::AccessControlSearch
],
name: "idm_acp_group_account_policy_manage_",
uuid: UUID_IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE,
description: "Builtin IDM Control for management of account policy on groups",
receiver: BuiltinAcpReceiver::Group(vec![UUID_IDM_ACCOUNT_POLICY_ADMINS]),
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
match_class_filter!(EntryClass::Group),
ProtoFilter::AndNot(Box::new(FILTER_HP_OR_RECYCLED_OR_TOMBSTONE.clone())),
])),
search_attrs: vec![
Attribute::Class,
Attribute::Name,
Attribute::Uuid,
Attribute::AuthSessionExpiry,
Attribute::AuthPasswordMinimumLength,
Attribute::CredentialTypeMinimum,
Attribute::PrivilegeExpiry,
Attribute::WebauthnAttestationCaList,
],
modify_removed_attrs: vec![
Attribute::Class,
Attribute::AuthSessionExpiry,
Attribute::AuthPasswordMinimumLength,
Attribute::CredentialTypeMinimum,
Attribute::PrivilegeExpiry,
Attribute::WebauthnAttestationCaList,
],
modify_present_attrs: vec![
Attribute::Class,
Attribute::AuthSessionExpiry,
Attribute::AuthPasswordMinimumLength,
Attribute::CredentialTypeMinimum,
Attribute::PrivilegeExpiry,
Attribute::WebauthnAttestationCaList,
],
modify_classes: vec![EntryClass::AccountPolicy,],
..Default::default()
};
}
lazy_static! {
pub static ref IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_DL6: BuiltinAcp = BuiltinAcp {
classes: vec![
@ -591,96 +544,6 @@ lazy_static! {
};
}
lazy_static! {
pub static ref IDM_ACP_OAUTH2_MANAGE_V1: BuiltinAcp = BuiltinAcp {
classes: vec![
EntryClass::Object,
EntryClass::AccessControlProfile,
EntryClass::AccessControlCreate,
EntryClass::AccessControlDelete,
EntryClass::AccessControlModify,
EntryClass::AccessControlSearch
],
name: "idm_acp_hp_oauth2_manage_priv",
uuid: UUID_IDM_ACP_OAUTH2_MANAGE_V1,
description: "Builtin IDM Control for managing oauth2 resource server integrations.",
receiver: BuiltinAcpReceiver::Group(vec![UUID_IDM_OAUTH2_ADMINS]),
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
match_class_filter!(EntryClass::OAuth2ResourceServer),
FILTER_ANDNOT_TOMBSTONE_OR_RECYCLED.clone(),
])),
search_attrs: vec![
Attribute::Class,
Attribute::Description,
Attribute::DisplayName,
Attribute::OAuth2RsName,
Attribute::OAuth2RsOrigin,
Attribute::OAuth2RsOriginLanding,
Attribute::OAuth2RsScopeMap,
Attribute::OAuth2RsSupScopeMap,
Attribute::OAuth2RsBasicSecret,
Attribute::OAuth2RsTokenKey,
Attribute::Es256PrivateKeyDer,
Attribute::OAuth2AllowInsecureClientDisablePkce,
Attribute::Rs256PrivateKeyDer,
Attribute::OAuth2JwtLegacyCryptoEnable,
Attribute::OAuth2PreferShortUsername,
Attribute::Image,
],
modify_removed_attrs: vec![
Attribute::Description,
Attribute::DisplayName,
Attribute::OAuth2RsName,
Attribute::OAuth2RsOrigin,
Attribute::OAuth2RsOriginLanding,
Attribute::OAuth2RsScopeMap,
Attribute::OAuth2RsSupScopeMap,
Attribute::OAuth2RsBasicSecret,
Attribute::OAuth2RsTokenKey,
Attribute::Es256PrivateKeyDer,
Attribute::OAuth2AllowInsecureClientDisablePkce,
Attribute::Rs256PrivateKeyDer,
Attribute::OAuth2JwtLegacyCryptoEnable,
Attribute::OAuth2PreferShortUsername,
Attribute::Image,
],
modify_present_attrs: vec![
Attribute::Description,
Attribute::DisplayName,
Attribute::OAuth2RsName,
Attribute::OAuth2RsOrigin,
Attribute::OAuth2RsOriginLanding,
Attribute::OAuth2RsSupScopeMap,
Attribute::OAuth2RsScopeMap,
Attribute::OAuth2AllowInsecureClientDisablePkce,
Attribute::OAuth2JwtLegacyCryptoEnable,
Attribute::OAuth2PreferShortUsername,
Attribute::Image,
],
create_attrs: vec![
Attribute::Class,
Attribute::Description,
Attribute::DisplayName,
Attribute::OAuth2RsName,
Attribute::OAuth2RsOrigin,
Attribute::OAuth2RsOriginLanding,
Attribute::OAuth2RsSupScopeMap,
Attribute::OAuth2RsScopeMap,
Attribute::OAuth2AllowInsecureClientDisablePkce,
Attribute::OAuth2JwtLegacyCryptoEnable,
Attribute::OAuth2PreferShortUsername,
Attribute::Image,
],
create_classes: vec![
EntryClass::Object,
EntryClass::OAuth2ResourceServer,
EntryClass::OAuth2ResourceServerBasic,
EntryClass::OAuth2ResourceServerPublic,
],
..Default::default()
};
}
lazy_static! {
pub static ref IDM_ACP_OAUTH2_MANAGE_DL4: BuiltinAcp = BuiltinAcp {
classes: vec![
@ -858,6 +721,7 @@ lazy_static! {
Attribute::Class,
Attribute::Description,
Attribute::Name,
Attribute::DisplayName,
Attribute::OAuth2RsName,
Attribute::OAuth2RsOrigin,
Attribute::OAuth2RsOriginLanding,
@ -963,6 +827,7 @@ lazy_static! {
Attribute::Class,
Attribute::Description,
Attribute::Name,
Attribute::DisplayName,
Attribute::OAuth2RsName,
Attribute::OAuth2RsOrigin,
Attribute::OAuth2RsOriginLanding,
@ -987,59 +852,6 @@ lazy_static! {
};
}
lazy_static! {
pub static ref IDM_ACP_DOMAIN_ADMIN_V1: BuiltinAcp = BuiltinAcp {
classes: vec![
EntryClass::Object,
EntryClass::AccessControlProfile,
EntryClass::AccessControlModify,
EntryClass::AccessControlSearch
],
name: "idm_acp_domain_admin",
uuid: UUID_IDM_ACP_DOMAIN_ADMIN_V1,
description: "Builtin IDM Control for granting domain info administration locally",
receiver: BuiltinAcpReceiver::Group(vec![UUID_DOMAIN_ADMINS]),
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
ProtoFilter::Eq(
Attribute::Uuid.to_string(),
STR_UUID_DOMAIN_INFO.to_string()
),
FILTER_ANDNOT_TOMBSTONE_OR_RECYCLED.clone()
])),
search_attrs: vec![
Attribute::Class,
Attribute::Name,
Attribute::Uuid,
Attribute::DomainDisplayName,
Attribute::DomainName,
Attribute::DomainLdapBasedn,
Attribute::DomainSsid,
Attribute::DomainUuid,
Attribute::Es256PrivateKeyDer,
Attribute::FernetPrivateKeyStr,
Attribute::CookiePrivateKey,
Attribute::LdapAllowUnixPwBind,
Attribute::Version,
],
modify_removed_attrs: vec![
Attribute::DomainDisplayName,
Attribute::DomainSsid,
Attribute::DomainLdapBasedn,
Attribute::Es256PrivateKeyDer,
Attribute::CookiePrivateKey,
Attribute::FernetPrivateKeyStr,
Attribute::LdapAllowUnixPwBind,
],
modify_present_attrs: vec![
Attribute::DomainDisplayName,
Attribute::DomainLdapBasedn,
Attribute::DomainSsid,
Attribute::LdapAllowUnixPwBind,
],
..Default::default()
};
}
lazy_static! {
pub static ref IDM_ACP_DOMAIN_ADMIN_DL6: BuiltinAcp = BuiltinAcp {
classes: vec![
@ -1479,26 +1291,6 @@ lazy_static! {
};
}
lazy_static! {
pub static ref IDM_ACP_ACCOUNT_MAIL_READ_V1: BuiltinAcp = BuiltinAcp {
classes: vec![
EntryClass::Object,
EntryClass::AccessControlProfile,
EntryClass::AccessControlSearch
],
name: "idm_acp_account_mail_read",
uuid: UUID_IDM_ACP_ACCOUNT_MAIL_READ_V1,
description: "Builtin IDM Control for reading account mail attributes.",
receiver: BuiltinAcpReceiver::Group(vec![UUID_IDM_ACCOUNT_MAIL_READ]),
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
match_class_filter!(EntryClass::Account),
FILTER_ANDNOT_TOMBSTONE_OR_RECYCLED.clone(),
])),
search_attrs: vec![Attribute::Mail],
..Default::default()
};
}
lazy_static! {
pub static ref IDM_ACP_ACCOUNT_MAIL_READ_DL6: BuiltinAcp = BuiltinAcp {
classes: vec![
@ -1610,61 +1402,6 @@ lazy_static! {
};
}
lazy_static! {
pub static ref IDM_ACP_GROUP_MANAGE_V1: BuiltinAcp = BuiltinAcp{
classes: vec![
EntryClass::Object,
EntryClass::AccessControlProfile,
EntryClass::AccessControlCreate,
EntryClass::AccessControlDelete,
EntryClass::AccessControlModify,
EntryClass::AccessControlSearch
],
name: "idm_acp_group_manage",
uuid: UUID_IDM_ACP_GROUP_MANAGE_V1,
description: "Builtin IDM Control for creating and deleting groups in the directory",
receiver: BuiltinAcpReceiver::Group ( vec![UUID_IDM_GROUP_ADMINS] ),
// group which is not in HP, Recycled, Tombstone
target: BuiltinAcpTarget::Filter( ProtoFilter::And(vec![
match_class_filter!(EntryClass::Group),
FILTER_ANDNOT_HP_OR_RECYCLED_OR_TOMBSTONE.clone(),
])),
search_attrs: vec![
Attribute::Class,
Attribute::Name,
Attribute::Uuid,
Attribute::Spn,
Attribute::Uuid,
Attribute::Description,
Attribute::Member,
Attribute::DynMember,
Attribute::EntryManagedBy,
],
create_attrs: vec![
Attribute::Class,
Attribute::Name,
Attribute::Description,
Attribute::Member,
Attribute::EntryManagedBy,
],
create_classes: vec![
EntryClass::Object,
EntryClass::Group,
],
modify_present_attrs: vec![
Attribute::Name,
Attribute::Description,
Attribute::Member,
],
modify_removed_attrs: vec![
Attribute::Name,
Attribute::Description,
Attribute::Member,
],
..Default::default()
};
}
lazy_static! {
pub static ref IDM_ACP_GROUP_MANAGE_DL6: BuiltinAcp = BuiltinAcp{
classes: vec![
@ -1862,39 +1599,6 @@ lazy_static! {
};
}
// Person Account Create
lazy_static! {
pub static ref IDM_ACP_PEOPLE_CREATE_V1: BuiltinAcp = BuiltinAcp {
classes: vec![
EntryClass::Object,
EntryClass::AccessControlProfile,
EntryClass::AccessControlCreate,
],
name: "idm_acp_people_create",
uuid: UUID_IDM_ACP_PEOPLE_CREATE_V1,
description: "Builtin IDM Control for creating new persons.",
receiver: BuiltinAcpReceiver::Group(vec![
UUID_IDM_PEOPLE_ADMINS,
UUID_IDM_PEOPLE_ON_BOARDING
]),
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
match_class_filter!(EntryClass::Person).clone(),
match_class_filter!(EntryClass::Account).clone(),
FILTER_ANDNOT_TOMBSTONE_OR_RECYCLED.clone(),
])),
create_attrs: vec![
Attribute::Class,
Attribute::Name,
Attribute::DisplayName,
Attribute::Mail,
Attribute::AccountExpire,
Attribute::AccountValidFrom,
],
create_classes: vec![EntryClass::Object, EntryClass::Account, EntryClass::Person,],
..Default::default()
};
}
lazy_static! {
pub static ref IDM_ACP_PEOPLE_CREATE_DL6: BuiltinAcp = BuiltinAcp {
classes: vec![

View file

@ -800,18 +800,6 @@ lazy_static! {
(Attribute::Version, Value::Uint32(20))
);
pub static ref E_DOMAIN_INFO_V1: EntryInitNew = entry_init!(
(Attribute::Class, EntryClass::Object.to_value()),
(Attribute::Class, EntryClass::DomainInfo.to_value()),
(Attribute::Class, EntryClass::System.to_value()),
(Attribute::Name, Value::new_iname("domain_local")),
(Attribute::Uuid, Value::Uuid(UUID_DOMAIN_INFO)),
(
Attribute::Description,
Value::new_utf8s("This local domain's info and metadata object.")
)
);
pub static ref E_DOMAIN_INFO_DL6: EntryInitNew = entry_init!(
(Attribute::Class, EntryClass::Object.to_value()),
(Attribute::Class, EntryClass::DomainInfo.to_value()),
@ -916,17 +904,6 @@ lazy_static! {
};
}
lazy_static! {
pub static ref BUILTIN_ACCOUNT_ANONYMOUS_V1: BuiltinAccount = BuiltinAccount {
account_type: AccountType::ServiceAccount,
entry_managed_by: None,
name: "anonymous",
uuid: UUID_ANONYMOUS,
description: "Anonymous access account.",
displayname: "Anonymous",
};
}
lazy_static! {
pub static ref BUILTIN_ACCOUNT_ANONYMOUS_DL6: BuiltinAccount = BuiltinAccount {
account_type: AccountType::ServiceAccount,
@ -940,9 +917,9 @@ lazy_static! {
pub fn builtin_accounts() -> Vec<&'static BuiltinAccount> {
vec![
&BUILTIN_ACCOUNT_ANONYMOUS_V1,
&BUILTIN_ACCOUNT_ADMIN,
&BUILTIN_ACCOUNT_IDM_ADMIN,
&BUILTIN_ACCOUNT_ANONYMOUS_DL6,
]
}
@ -981,7 +958,6 @@ lazy_static! {
/// Build a list of internal admin entries
pub fn idm_builtin_admin_entries() -> Result<Vec<EntryInitNew>, OperationError> {
let mut res: Vec<EntryInitNew> = vec![
BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into(),
BUILTIN_ACCOUNT_ADMIN.clone().into(),
BUILTIN_ACCOUNT_IDM_ADMIN.clone().into(),
];
@ -989,5 +965,9 @@ pub fn idm_builtin_admin_entries() -> Result<Vec<EntryInitNew>, OperationError>
let g: EntryInitNew = group.clone().try_into()?;
res.push(g);
}
// We need to push anonymous *after* groups due to entry-managed-by
res.push(BUILTIN_ACCOUNT_ANONYMOUS_DL6.clone().into());
Ok(res)
}

View file

@ -52,15 +52,6 @@ pub type DomainVersion = u32;
/// previously.
pub const DOMAIN_LEVEL_0: DomainVersion = 0;
/// Deprcated as of 1.2.0
pub const DOMAIN_LEVEL_1: DomainVersion = 1;
/// Deprcated as of 1.2.0
pub const DOMAIN_LEVEL_2: DomainVersion = 2;
/// Deprcated as of 1.2.0
pub const DOMAIN_LEVEL_3: DomainVersion = 3;
/// Deprcated as of 1.2.0
pub const DOMAIN_LEVEL_4: DomainVersion = 4;
/// Deprcated as of 1.3.0
pub const DOMAIN_LEVEL_5: DomainVersion = 5;
@ -77,22 +68,26 @@ pub const DOMAIN_LEVEL_7: DomainVersion = 7;
/// Deprcated as of 1.6.0
pub const DOMAIN_LEVEL_8: DomainVersion = 8;
/// Domain Level introduced with 1.5.0.
/// Deprcated as of 1.7.0
pub const DOMAIN_LEVEL_9: DomainVersion = 9;
// The minimum level that we can re-migrate from.
// This should be DOMAIN_TGT_LEVEL minus 2
pub const DOMAIN_MIN_REMIGRATION_LEVEL: DomainVersion = DOMAIN_LEVEL_5;
// The minimum supported domain functional level
pub const DOMAIN_MIN_REMIGRATION_LEVEL: DomainVersion = DOMAIN_LEVEL_6;
// The minimum supported domain functional level (for replication)
pub const DOMAIN_MIN_LEVEL: DomainVersion = DOMAIN_TGT_LEVEL;
// The previous releases domain functional level
pub const DOMAIN_PREVIOUS_TGT_LEVEL: DomainVersion = DOMAIN_LEVEL_6;
pub const DOMAIN_PREVIOUS_TGT_LEVEL: DomainVersion = DOMAIN_LEVEL_7;
// The target supported domain functional level. During development this is
// the NEXT level that users will upgrade too.
pub const DOMAIN_TGT_LEVEL: DomainVersion = DOMAIN_LEVEL_7;
pub const DOMAIN_TGT_LEVEL: DomainVersion = DOMAIN_LEVEL_8;
// The current patch level if any out of band fixes are required.
pub const DOMAIN_TGT_PATCH_LEVEL: u32 = PATCH_LEVEL_1;
// The target domain functional level for the SUBSEQUENT release/dev cycle.
pub const DOMAIN_TGT_NEXT_LEVEL: DomainVersion = DOMAIN_LEVEL_8;
pub const DOMAIN_TGT_NEXT_LEVEL: DomainVersion = DOMAIN_LEVEL_9;
// The maximum supported domain functional level
pub const DOMAIN_MAX_LEVEL: DomainVersion = DOMAIN_LEVEL_8;
pub const DOMAIN_MAX_LEVEL: DomainVersion = DOMAIN_LEVEL_9;
// On test builds define to 60 seconds
#[cfg(test)]

View file

@ -839,23 +839,6 @@ pub static ref SCHEMA_CLASS_ORGPERSON: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_GROUP: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_GROUP,
name: EntryClass::Group.into(),
description: "Object representation of a group".to_string(),
sync_allowed: true,
systemmay: vec![
Attribute::Member.into(),
Attribute::GrantUiHint.into(),
Attribute::Description.into()
],
systemmust: vec![
Attribute::Name.into(),
Attribute::Spn.into()],
..Default::default()
};
pub static ref SCHEMA_CLASS_GROUP_DL6: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_GROUP,
name: EntryClass::Group.into(),
@ -885,22 +868,6 @@ pub static ref SCHEMA_CLASS_DYNGROUP: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_ACCOUNT_POLICY: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_ACCOUNT_POLICY,
name: EntryClass::AccountPolicy.into(),
description: "Policies applied to accounts that are members of a group".to_string(),
systemmay: vec![
Attribute::AuthSessionExpiry.into(),
Attribute::PrivilegeExpiry.into(),
Attribute::AuthPasswordMinimumLength.into(),
Attribute::CredentialTypeMinimum.into(),
Attribute::WebauthnAttestationCaList.into(),
],
systemsupplements: vec![Attribute::Group.into()],
..Default::default()
};
pub static ref SCHEMA_CLASS_ACCOUNT_POLICY_DL6: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_ACCOUNT_POLICY,
name: EntryClass::AccountPolicy.into(),
@ -977,43 +944,6 @@ pub static ref SCHEMA_CLASS_ACCOUNT_DL5: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_SERVICE_ACCOUNT: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_SERVICE_ACCOUNT,
name: EntryClass::ServiceAccount.into(),
description: "Object representation of service account".to_string(),
sync_allowed: true,
systemmay: vec![
Attribute::Mail.into(),
Attribute::PrimaryCredential.into(),
Attribute::JwsEs256PrivateKey.into(),
Attribute::ApiTokenSession.into(),
],
systemexcludes: vec![EntryClass::Person.into()],
..Default::default()
};
pub static ref SCHEMA_CLASS_SERVICE_ACCOUNT_DL5: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_SERVICE_ACCOUNT,
name: EntryClass::ServiceAccount.into(),
description: "Object representation of service account".to_string(),
sync_allowed: true,
systemmay: vec![
Attribute::SshPublicKey.into(),
Attribute::UserAuthTokenSession.into(),
Attribute::OAuth2Session.into(),
Attribute::Description.into(),
Attribute::Mail.into(),
Attribute::PrimaryCredential.into(),
Attribute::JwsEs256PrivateKey.into(),
Attribute::ApiTokenSession.into(),
],
systemexcludes: vec![EntryClass::Person.into()],
..Default::default()
};
pub static ref SCHEMA_CLASS_SERVICE_ACCOUNT_DL6: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_SERVICE_ACCOUNT,
name: EntryClass::ServiceAccount.into(),
@ -1058,22 +988,6 @@ pub static ref SCHEMA_CLASS_SERVICE_ACCOUNT_DL7: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_SYNC_ACCOUNT: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_SYNC_ACCOUNT,
name: EntryClass::SyncAccount.into(),
description: "Object representation of sync account".to_string(),
systemmust: vec![Attribute::Name.into(), Attribute::JwsEs256PrivateKey.into()],
systemmay: vec![
Attribute::SyncTokenSession.into(),
Attribute::SyncCookie.into(),
Attribute::SyncCredentialPortal.into(),
Attribute::SyncYieldAuthority.into(),
],
systemexcludes: vec![EntryClass::Account.into()],
..Default::default()
};
pub static ref SCHEMA_CLASS_SYNC_ACCOUNT_DL6: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_SYNC_ACCOUNT,
name: EntryClass::SyncAccount.into(),
@ -1107,29 +1021,6 @@ pub static ref SCHEMA_CLASS_SYNC_ACCOUNT_DL7: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_DOMAIN_INFO: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_DOMAIN_INFO,
name: EntryClass::DomainInfo.into(),
description: "Local domain information and partial configuration".to_string(),
systemmay: vec![
Attribute::DomainSsid.into(),
Attribute::DomainLdapBasedn.into(),
Attribute::LdapAllowUnixPwBind.into()
],
systemmust: vec![
Attribute::Name.into(),
Attribute::DomainUuid.into(),
Attribute::DomainName.into(),
Attribute::DomainDisplayName.into(),
Attribute::FernetPrivateKeyStr.into(),
Attribute::Es256PrivateKeyDer.into(),
Attribute::PrivateCookieKey.into(),
Attribute::Version.into(),
],
..Default::default()
};
pub static ref SCHEMA_CLASS_DOMAIN_INFO_DL6: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_DOMAIN_INFO,
name: EntryClass::DomainInfo.into(),
@ -1213,31 +1104,6 @@ pub static ref SCHEMA_CLASS_SYSTEM_CONFIG: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_OAUTH2_RS: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_OAUTH2_RS,
name: EntryClass::OAuth2ResourceServer.into(),
description: "The class representing a configured Oauth2 Resource Server".to_string(),
systemmay: vec![
Attribute::Description.into(),
Attribute::OAuth2RsScopeMap.into(),
Attribute::OAuth2RsSupScopeMap.into(),
Attribute::Rs256PrivateKeyDer.into(),
Attribute::OAuth2JwtLegacyCryptoEnable.into(),
Attribute::OAuth2PreferShortUsername.into(),
Attribute::OAuth2RsOriginLanding.into(),
Attribute::Image.into(),
],
systemmust: vec![
Attribute::OAuth2RsName.into(),
Attribute::DisplayName.into(),
Attribute::OAuth2RsOrigin.into(),
Attribute::OAuth2RsTokenKey.into(),
Attribute::Es256PrivateKeyDer.into(),
],
..Default::default()
};
pub static ref SCHEMA_CLASS_OAUTH2_RS_DL4: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_OAUTH2_RS,
name: EntryClass::OAuth2ResourceServer.into(),
@ -1315,17 +1181,6 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_DL7: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_OAUTH2_RS_BASIC: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_OAUTH2_RS_BASIC,
name: EntryClass::OAuth2ResourceServerBasic.into(),
description: "The class representing a configured Oauth2 Resource Server authenticated with http basic authentication".to_string(),
systemmay: vec![ Attribute::OAuth2AllowInsecureClientDisablePkce.into()],
systemmust: vec![ Attribute::OAuth2RsBasicSecret.into()],
systemexcludes: vec![ EntryClass::OAuth2ResourceServerPublic.into()],
..Default::default()
};
pub static ref SCHEMA_CLASS_OAUTH2_RS_BASIC_DL5: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_OAUTH2_RS_BASIC,
name: EntryClass::OAuth2ResourceServerBasic.into(),
@ -1339,15 +1194,6 @@ pub static ref SCHEMA_CLASS_OAUTH2_RS_BASIC_DL5: SchemaClass = SchemaClass {
..Default::default()
};
pub static ref SCHEMA_CLASS_OAUTH2_RS_PUBLIC: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_OAUTH2_RS_PUBLIC,
name: EntryClass::OAuth2ResourceServerPublic.into(),
description: "The class representing a configured Oauth2 Resource Server with public clients and pkce verification".to_string(),
systemexcludes: vec![EntryClass::OAuth2ResourceServerBasic.into()],
..Default::default()
};
// Introduced in DomainLevel4
pub static ref SCHEMA_CLASS_OAUTH2_RS_PUBLIC_DL4: SchemaClass = SchemaClass {
uuid: UUID_SCHEMA_CLASS_OAUTH2_RS_PUBLIC,

View file

@ -970,7 +970,7 @@ mod tests {
#[test]
fn test_idm_account_from_anonymous() {
let account: Account = BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into();
let account: Account = BUILTIN_ACCOUNT_ANONYMOUS_DL6.clone().into();
debug!("{:?}", account);
// I think that's it? we may want to check anonymous mech ...
}

View file

@ -1732,7 +1732,7 @@ mod tests {
let webauthn = create_webauthn();
let anon_account: Account = BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into();
let anon_account: Account = BUILTIN_ACCOUNT_ANONYMOUS_DL6.clone().into();
let asd = AuthSessionData {
account: anon_account,

View file

@ -1521,8 +1521,6 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
mod tests {
use crate::idm::server::{IdmServerProxyWriteTransaction, IdmServerTransaction};
use crate::prelude::*;
use crate::server::keys::KeyProvidersTransaction;
use crate::value::KeyStatus;
use compact_jwt::traits::JwsVerifiable;
use compact_jwt::{Jws, JwsCompact, JwsEs256Signer, JwsSigner};
use kanidm_proto::internal::ApiTokenPurpose;
@ -1730,117 +1728,6 @@ mod tests {
assert!(matches!(fail, Err(OperationError::NotAuthenticated)));
}
#[idm_test(domain_level=DOMAIN_LEVEL_5)]
async fn test_idm_scim_sync_token_dl5_dl6_token(
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed,
) {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let mut idms_prox_write = idms.proxy_write(ct).await;
assert_eq!(
idms_prox_write.qs_write.get_domain_version(),
DOMAIN_LEVEL_5
);
let sync_uuid = Uuid::new_v4();
let e1 = entry_init!(
(Attribute::Class, EntryClass::Object.to_value()),
(Attribute::Class, EntryClass::SyncAccount.to_value()),
(Attribute::Name, Value::new_iname("test_scim_sync")),
(Attribute::Uuid, Value::Uuid(sync_uuid)),
(
Attribute::Description,
Value::new_utf8s("A test sync agreement")
)
);
idms_prox_write
.qs_write
.internal_create(vec![e1])
.expect("Failed to create sync account");
let gte = GenerateScimSyncTokenEvent::new_internal(sync_uuid, "Sync Connector");
let old_sync_token = idms_prox_write
.scim_sync_generate_token(&gte, ct)
.expect("failed to generate new scim sync token");
assert!(idms_prox_write.commit().is_ok());
// Now trigger 5 -> 6
let mut idms_prox_write = idms.proxy_write(ct).await;
idms_prox_write
.qs_write
.internal_apply_domain_migration(DOMAIN_LEVEL_6)
.expect("Unable to set domain level to version 6");
assert!(idms_prox_write.commit().is_ok());
// Check existing token still validates.
let mut idms_prox_write = idms.proxy_write(ct).await;
let _ident = idms_prox_write
.validate_sync_client_auth_info_to_ident(old_sync_token.clone().into(), ct)
.expect("Failed to process old sync token to ident");
// Delete the old session else we get a schema violation
let modlist = ModifyList::new_purge(Attribute::SyncTokenSession.into());
idms_prox_write
.qs_write
.internal_modify_uuid(sync_uuid, &modlist)
.expect("Unable to delete previous sync token session");
let gte = GenerateScimSyncTokenEvent::new_internal(sync_uuid, "Sync Connector");
let new_sync_token = idms_prox_write
.scim_sync_generate_token(&gte, ct)
.expect("failed to generate new scim sync token");
assert_ne!(old_sync_token.kid(), new_sync_token.kid());
let _ident = idms_prox_write
.validate_sync_client_auth_info_to_ident(new_sync_token.into(), ct)
.expect("Failed to process new sync token to ident");
// The former key is now on the domain object.
let key_object = idms_prox_write
.qs_write
.get_key_providers()
.get_key_object(UUID_DOMAIN_INFO)
.expect("Unable to retrieve key object by uuid");
// Assert the former key is now in the domain key object, and now is "retained".
let former_kid = old_sync_token.kid().unwrap().to_string();
let status = key_object
.kid_status(&former_kid)
.expect("Failed to access kid status");
assert_eq!(status, Some(KeyStatus::Retained));
assert!(idms_prox_write.commit().is_ok());
// Now trigger 6 -> 7
let mut idms_prox_write = idms.proxy_write(ct).await;
idms_prox_write
.qs_write
.internal_apply_domain_migration(DOMAIN_LEVEL_7)
.expect("Unable to set domain level to version 7");
assert!(idms_prox_write.commit().is_ok());
// The key on the service account is removed.
let mut idms_prox_write = idms.proxy_write(ct).await;
let sync_entry = idms_prox_write
.qs_write
.internal_search_uuid(sync_uuid)
.expect("Unable to access service account");
assert!(!sync_entry.attribute_pres(Attribute::JwsEs256PrivateKey));
assert!(idms_prox_write.commit().is_ok());
}
fn test_scim_sync_apply_setup_ident(
idms_prox_write: &mut IdmServerProxyWriteTransaction,
ct: Duration,

View file

@ -423,15 +423,12 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
mod tests {
use std::time::Duration;
use compact_jwt::traits::JwsVerifiable;
use compact_jwt::{dangernoverify::JwsDangerReleaseWithoutVerify, JwsVerifier};
use kanidm_proto::internal::ApiToken;
use super::{DestroyApiTokenEvent, GenerateApiTokenEvent};
use crate::idm::server::IdmServerTransaction;
use crate::prelude::*;
use crate::server::keys::KeyProvidersTransaction;
use crate::value::KeyStatus;
const TEST_CURRENT_TIME: u64 = 6000;
@ -520,112 +517,4 @@ mod tests {
assert!(idms_prox_write.commit().is_ok());
}
#[idm_test(domain_level=DOMAIN_LEVEL_5)]
async fn test_idm_service_account_dl5_dl6_api_token(
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed,
) {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let exp = Duration::from_secs(TEST_CURRENT_TIME + 6000);
let mut idms_prox_write = idms.proxy_write(ct).await;
assert_eq!(
idms_prox_write.qs_write.get_domain_version(),
DOMAIN_LEVEL_5
);
let testaccount_uuid = Uuid::new_v4();
let e1 = entry_init!(
(Attribute::Class, EntryClass::Object.to_value()),
(Attribute::Class, EntryClass::Account.to_value()),
(Attribute::Class, EntryClass::ServiceAccount.to_value()),
(Attribute::Name, Value::new_iname("test_account_only")),
(Attribute::Uuid, Value::Uuid(testaccount_uuid)),
(Attribute::Description, Value::new_utf8s("testaccount")),
(Attribute::DisplayName, Value::new_utf8s("testaccount"))
);
idms_prox_write
.qs_write
.internal_create(vec![e1])
.expect("Failed to create service account");
let gte = GenerateApiTokenEvent::new_internal(testaccount_uuid, "TestToken", Some(exp));
let api_token = idms_prox_write
.service_account_generate_api_token(&gte, ct)
.expect("failed to generate new api token");
trace!(?api_token);
assert!(idms_prox_write.commit().is_ok());
// Now trigger 5 -> 6
let mut idms_prox_write = idms.proxy_write(ct).await;
idms_prox_write
.qs_write
.internal_apply_domain_migration(DOMAIN_LEVEL_6)
.expect("Unable to set domain level to version 6");
assert!(idms_prox_write.commit().is_ok());
// Now check our api token still validates.
let mut idms_prox_write = idms.proxy_write(ct).await;
// Check a new token is domain key signed.
let gte = GenerateApiTokenEvent::new_internal(testaccount_uuid, "TestToken", Some(exp));
let new_api_token = idms_prox_write
.service_account_generate_api_token(&gte, ct)
.expect("failed to generate new api token");
assert_ne!(api_token.kid(), new_api_token.kid());
// Check that both tokens verify and work.
let _ident = idms_prox_write
.validate_client_auth_info_to_ident(api_token.clone().into(), ct)
.expect("Unable to verify old api token.");
let _ident = idms_prox_write
.validate_client_auth_info_to_ident(new_api_token.clone().into(), ct)
.expect("Unable to verify new api token.");
// The former key is now on the domain object.
let key_object = idms_prox_write
.qs_write
.get_key_providers()
.get_key_object(UUID_DOMAIN_INFO)
.expect("Unable to retrieve key object by uuid");
// Assert the former key is now in the domain key object, and now is "retained".
let former_kid = api_token.kid().unwrap().to_string();
let status = key_object
.kid_status(&former_kid)
.expect("Failed to access kid status");
assert_eq!(status, Some(KeyStatus::Retained));
assert!(idms_prox_write.commit().is_ok());
// Now trigger 6 -> 7
let mut idms_prox_write = idms.proxy_write(ct).await;
idms_prox_write
.qs_write
.internal_apply_domain_migration(DOMAIN_LEVEL_7)
.expect("Unable to set domain level to version 7");
assert!(idms_prox_write.commit().is_ok());
// The key on the service account is removed.
let mut idms_prox_write = idms.proxy_write(ct).await;
let service_entry = idms_prox_write
.qs_write
.internal_search_uuid(testaccount_uuid)
.expect("Unable to access service account");
assert!(!service_entry.attribute_pres(Attribute::JwsEs256PrivateKey));
assert!(idms_prox_write.commit().is_ok());
}
}

View file

@ -3099,7 +3099,7 @@ mod tests {
#[test]
fn test_access_delete_protect_system_ranges() {
let ev1: EntryInitNew = BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into();
let ev1: EntryInitNew = BUILTIN_ACCOUNT_ANONYMOUS_DL6.clone().into();
let ev1 = ev1.into_sealed_committed();
let r_set = vec![Arc::new(ev1)];

View file

@ -292,6 +292,7 @@ impl<'a> KeyProvidersWriteTransaction<'a> {
}
}
/*
#[cfg(test)]
mod tests {
use super::{KeyProvider, KeyProvidersTransaction};
@ -299,85 +300,5 @@ mod tests {
use crate::value::KeyStatus;
use compact_jwt::{JwsEs256Signer, JwsSigner};
#[qs_test(domain_level=DOMAIN_LEVEL_5)]
async fn test_key_provider_internal_migration(server: &QueryServer) {
let mut write_txn = server.write(duration_from_epoch_now()).await;
// Read the initial state of the domain object, including it's
// private key.
let domain_object_initial = write_txn
.internal_search_uuid(UUID_DOMAIN_INFO)
.expect("unable to access domain object");
let initial_private_es256_key = domain_object_initial
.get_ava_single_private_binary(Attribute::Es256PrivateKeyDer)
.map(|s| s.to_vec())
.expect("No private key found");
let initial_jwt_signer =
JwsEs256Signer::from_es256_der(&initial_private_es256_key).unwrap();
let former_kid = initial_jwt_signer.get_legacy_kid().to_string();
// Set the version to 6.
write_txn
.internal_apply_domain_migration(DOMAIN_LEVEL_6)
.expect("Unable to set domain level to version 6");
// The internal key provider is created from dl 5 to 6
let key_provider_object = write_txn
.internal_search_uuid(UUID_KEY_PROVIDER_INTERNAL)
.expect("Unable to find key provider entry.");
assert!(key_provider_object.attribute_equality(
Attribute::Name,
&PartialValue::new_iname("key_provider_internal")
));
// Check that is loaded in the qs.
let key_provider = write_txn
.get_key_providers()
.get_uuid(UUID_KEY_PROVIDER_INTERNAL)
.expect("Unable to access key provider object.");
// Because there is only one variant today ...
#[allow(irrefutable_let_patterns)]
let KeyProvider::Internal(key_provider_internal) = key_provider
else {
unreachable!()
};
// Run the providers internal test
assert!(key_provider_internal.test().is_ok());
// Now at this point, the domain object should now be a key object, and have it's
// keys migrated.
let key_object = write_txn
.get_key_providers()
.get_key_object(UUID_DOMAIN_INFO)
.expect("Unable to retrieve key object by uuid");
// Assert the former key is now in the domain key object, and now is "retained".
let status = key_object
.kid_status(&former_kid)
.expect("Failed to access kid status");
assert_eq!(status, Some(KeyStatus::Retained));
// Now from DL6 -> 7 the keys are actually removed.
write_txn
.internal_apply_domain_migration(DOMAIN_LEVEL_7)
.expect("Unable to set domain level to version 7");
let domain_object_migrated = write_txn
.internal_search_uuid(UUID_DOMAIN_INFO)
.expect("unable to access domain object");
assert!(!domain_object_migrated.attribute_pres(Attribute::Es256PrivateKeyDer));
assert!(!domain_object_migrated.attribute_pres(Attribute::FernetPrivateKeyStr));
assert!(!domain_object_migrated.attribute_pres(Attribute::PrivateCookieKey));
write_txn.commit().expect("Failed to commit");
}
}
*/

View file

@ -1,4 +1,3 @@
use crate::value::CredentialType;
use std::time::Duration;
use crate::prelude::*;
@ -80,13 +79,13 @@ impl QueryServer {
// are created in the next phase of migrations.
write_txn.set_phase(ServerPhase::SchemaReady);
// Init idm will now set the system config version and minimum domain
// level if none was present
write_txn.initialise_domain_info()?;
// No domain info was present, so neither was the rest of the IDM. We need to bootstrap
// the base entries here.
if db_domain_version == 0 {
// Init idm will now set the system config version and minimum domain
// level if none was present
write_txn.initialise_domain_info()?;
// In this path because we create the dyn groups they are immediately added to the
// dyngroup cache and begin to operate.
write_txn.initialise_idm()?;
@ -294,273 +293,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
}
}
#[instrument(level = "info", skip_all)]
/// This migration will
/// * Trigger a "once off" mfa account policy rule on all persons.
pub(crate) fn migrate_domain_2_to_3(&mut self) -> Result<(), OperationError> {
let idm_all_persons = match self.internal_search_uuid(UUID_IDM_ALL_PERSONS) {
Ok(entry) => entry,
Err(OperationError::NoMatchingEntries) => return Ok(()),
Err(e) => return Err(e),
};
let credential_policy =
idm_all_persons.get_ava_single_credential_type(Attribute::CredentialTypeMinimum);
if credential_policy.is_some() {
debug!("Credential policy already present, not applying change.");
return Ok(());
}
self.internal_modify_uuid(
UUID_IDM_ALL_PERSONS,
&ModifyList::new_purge_and_set(
Attribute::CredentialTypeMinimum,
CredentialType::Mfa.into(),
),
)
.map(|()| {
info!("Upgraded default account policy to enforce MFA");
})
}
#[instrument(level = "info", skip_all)]
/// Migrations for Oauth to support multiple origins, and custom claims.
pub(crate) fn migrate_domain_3_to_4(&mut self) -> Result<(), OperationError> {
let idm_schema_attrs = [
SCHEMA_ATTR_OAUTH2_RS_CLAIM_MAP_DL4.clone().into(),
SCHEMA_ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT_DL4
.clone()
.into(),
];
idm_schema_attrs
.into_iter()
.try_for_each(|entry| self.internal_migrate_or_create(entry))
.map_err(|err| {
error!(?err, "migrate_domain_3_to_4 -> Error");
err
})?;
let idm_schema_classes = [
SCHEMA_CLASS_OAUTH2_RS_DL4.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_PUBLIC_DL4.clone().into(),
IDM_ACP_OAUTH2_MANAGE_DL4.clone().into(),
];
idm_schema_classes
.into_iter()
.try_for_each(|entry| self.internal_migrate_or_create(entry))
.map_err(|err| {
error!(?err, "migrate_domain_3_to_4 -> Error");
err
})
}
#[instrument(level = "info", skip_all)]
/// Migrations for Oauth to move rs name from a dedicated type to name
/// and to allow oauth2 sessions on resource servers for client credentials
/// grants. Accounts, persons and service accounts have some attributes
/// relocated to allow oauth2 rs to become accounts.
pub(crate) fn migrate_domain_4_to_5(&mut self) -> Result<(), OperationError> {
let idm_schema_classes = [
SCHEMA_CLASS_PERSON_DL5.clone().into(),
SCHEMA_CLASS_ACCOUNT_DL5.clone().into(),
SCHEMA_CLASS_SERVICE_ACCOUNT_DL5.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_DL5.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_BASIC_DL5.clone().into(),
IDM_ACP_OAUTH2_MANAGE_DL5.clone().into(),
];
idm_schema_classes
.into_iter()
.try_for_each(|entry| self.internal_migrate_or_create(entry))
.map_err(|err| {
error!(?err, "migrate_domain_4_to_5 -> Error");
err
})?;
// Reload mid txn so that the next modification works.
self.force_schema_reload();
self.reload()?;
// Now we remove attributes from service accounts that have been unable to be set
// via a user interface for more than a year.
let filter = filter!(f_and!([
f_eq(Attribute::Class, EntryClass::Account.into()),
f_eq(Attribute::Class, EntryClass::ServiceAccount.into()),
]));
let modlist = ModifyList::new_list(vec![
Modify::Purged(Attribute::PassKeys.into()),
Modify::Purged(Attribute::AttestedPasskeys.into()),
Modify::Purged(Attribute::CredentialUpdateIntentToken.into()),
Modify::Purged(Attribute::RadiusSecret.into()),
]);
self.internal_modify(&filter, &modlist)?;
// Now move all oauth2 rs name.
let filter = filter!(f_and!([
f_eq(Attribute::Class, EntryClass::OAuth2ResourceServer.into()),
f_pres(Attribute::OAuth2RsName),
]));
let pre_candidates = self.internal_search(filter).map_err(|err| {
admin_error!(?err, "migrate_domain_4_to_5 internal search failure");
err
})?;
let modset: Vec<_> = pre_candidates
.into_iter()
.filter_map(|ent| {
ent.get_ava_single_iname(Attribute::OAuth2RsName)
.map(|rs_name| {
let modlist = vec![
Modify::Present(Attribute::Class.into(), EntryClass::Account.into()),
Modify::Present(Attribute::Name.into(), Value::new_iname(rs_name)),
m_purge(Attribute::OAuth2RsName),
];
(ent.get_uuid(), ModifyList::new_list(modlist))
})
})
.collect();
// If there is nothing, we don't need to do anything.
if modset.is_empty() {
admin_info!("migrate_domain_4_to_5 no entries to migrate, complete");
return Ok(());
}
// Apply the batch mod.
self.internal_batch_modify(modset.into_iter())
}
/// Migration domain level 5 to 6 - support query limits in account policy.
#[instrument(level = "info", skip_all)]
pub(crate) fn migrate_domain_5_to_6(&mut self) -> Result<(), OperationError> {
let idm_schema_classes = [
SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS_DL6.clone().into(),
SCHEMA_ATTR_LIMIT_SEARCH_MAX_FILTER_TEST_DL6.clone().into(),
SCHEMA_ATTR_KEY_INTERNAL_DATA_DL6.clone().into(),
SCHEMA_ATTR_KEY_PROVIDER_DL6.clone().into(),
SCHEMA_ATTR_KEY_ACTION_ROTATE_DL6.clone().into(),
SCHEMA_ATTR_KEY_ACTION_REVOKE_DL6.clone().into(),
SCHEMA_ATTR_KEY_ACTION_IMPORT_JWS_ES256_DL6.clone().into(),
SCHEMA_CLASS_ACCOUNT_POLICY_DL6.clone().into(),
SCHEMA_CLASS_DOMAIN_INFO_DL6.clone().into(),
SCHEMA_CLASS_SERVICE_ACCOUNT_DL6.clone().into(),
SCHEMA_CLASS_SYNC_ACCOUNT_DL6.clone().into(),
SCHEMA_CLASS_GROUP_DL6.clone().into(),
SCHEMA_CLASS_KEY_PROVIDER_DL6.clone().into(),
SCHEMA_CLASS_KEY_PROVIDER_INTERNAL_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_JWT_ES256_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_JWE_A128GCM_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_INTERNAL_DL6.clone().into(),
];
idm_schema_classes
.into_iter()
.try_for_each(|entry| self.internal_migrate_or_create(entry))
.map_err(|err| {
error!(?err, "migrate_domain_5_to_6 -> Error");
err
})?;
self.reload()?;
let idm_data = [
// Update access controls.
IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_DL6.clone().into(),
IDM_ACP_PEOPLE_CREATE_DL6.clone().into(),
IDM_ACP_GROUP_MANAGE_DL6.clone().into(),
IDM_ACP_ACCOUNT_MAIL_READ_DL6.clone().into(),
// Update anonymous with the correct entry manager,
BUILTIN_ACCOUNT_ANONYMOUS_DL6.clone().into(),
// Add the internal key provider.
E_KEY_PROVIDER_INTERNAL_DL6.clone(),
];
idm_data
.into_iter()
.try_for_each(|entry| self.internal_migrate_or_create(entry))
.map_err(|err| {
error!(?err, "migrate_domain_5_to_6 -> Error");
err
})?;
// all existing built-in objects get a builtin class
let filter = f_lt(
Attribute::Uuid,
PartialValue::Uuid(DYNAMIC_RANGE_MINIMUM_UUID),
);
let modlist = modlist!([m_pres(Attribute::Class, &EntryClass::Builtin.into())]);
self.internal_modify(&filter!(filter), &modlist)?;
// Reload such that the new default key provider is loaded.
self.reload()?;
// Update the domain entry to contain its key object, which can now be generated.
let idm_data = [
IDM_ACP_DOMAIN_ADMIN_DL6.clone().into(),
E_DOMAIN_INFO_DL6.clone(),
];
idm_data
.into_iter()
.try_for_each(|entry| self.internal_migrate_or_create(entry))
.map_err(|err| {
error!(?err, "migrate_domain_5_to_6 -> Error");
err
})?;
// At this point we reload to show the new key objects on the domain.
self.reload()?;
// Migrate the domain key to a retained key on the key object.
let domain_es256_private_key = self.get_domain_es256_private_key().map_err(|err| {
error!(?err, "migrate_domain_5_to_6 -> Error");
err
})?;
// Migrate all service/scim account keys to the domain key for verification.
let filter = filter!(f_or!([
f_eq(Attribute::Class, EntryClass::ServiceAccount.into()),
f_eq(Attribute::Class, EntryClass::SyncAccount.into())
]));
let entry_keys_to_migrate = self.internal_search(filter)?;
let mut modlist = Vec::with_capacity(1 + entry_keys_to_migrate.len());
modlist.push(Modify::Present(
Attribute::KeyActionImportJwsEs256.into(),
Value::PrivateBinary(domain_es256_private_key),
));
for entry in entry_keys_to_migrate {
// In these entries, the keys are in JwsEs256PrivateKey.
if let Some(jws_signer) =
entry.get_ava_single_jws_key_es256(Attribute::JwsEs256PrivateKey)
{
let es256_private_key = jws_signer.private_key_to_der().map_err(|err| {
error!(?err, uuid = ?entry.get_display_id(), "unable to convert signer to der");
OperationError::InvalidValueState
})?;
modlist.push(Modify::Present(
Attribute::KeyActionImportJwsEs256.into(),
Value::PrivateBinary(es256_private_key),
));
}
}
let modlist = ModifyList::new_list(modlist);
self.internal_modify_uuid(UUID_DOMAIN_INFO, &modlist)?;
Ok(())
}
/// Migration domain level 6 to 7
#[instrument(level = "info", skip_all)]
pub(crate) fn migrate_domain_6_to_7(&mut self) -> Result<(), OperationError> {
@ -859,6 +591,19 @@ impl<'a> QueryServerWriteTransaction<'a> {
Ok(())
}
/// Migration domain level 8 to 9
#[instrument(level = "info", skip_all)]
pub(crate) fn migrate_domain_8_to_9(&mut self) -> Result<(), OperationError> {
if !cfg!(test) && DOMAIN_TGT_LEVEL < DOMAIN_LEVEL_9 {
error!("Unable to raise domain level from 8 to 9.");
return Err(OperationError::MG0004DomainLevelInDevelopment);
}
// =========== Apply changes ==============
Ok(())
}
#[instrument(level = "info", skip_all)]
pub fn initialise_schema_core(&mut self) -> Result<(), OperationError> {
admin_debug!("initialise_schema_core -> start ...");
@ -966,6 +711,20 @@ impl<'a> QueryServerWriteTransaction<'a> {
SCHEMA_ATTR_DENIED_NAME.clone().into(),
SCHEMA_ATTR_CREDENTIAL_TYPE_MINIMUM.clone().into(),
SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST.clone().into(),
// DL4
SCHEMA_ATTR_OAUTH2_RS_CLAIM_MAP_DL4.clone().into(),
SCHEMA_ATTR_OAUTH2_ALLOW_LOCALHOST_REDIRECT_DL4
.clone()
.into(),
// DL5
// DL6
SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS_DL6.clone().into(),
SCHEMA_ATTR_LIMIT_SEARCH_MAX_FILTER_TEST_DL6.clone().into(),
SCHEMA_ATTR_KEY_INTERNAL_DATA_DL6.clone().into(),
SCHEMA_ATTR_KEY_PROVIDER_DL6.clone().into(),
SCHEMA_ATTR_KEY_ACTION_ROTATE_DL6.clone().into(),
SCHEMA_ATTR_KEY_ACTION_REVOKE_DL6.clone().into(),
SCHEMA_ATTR_KEY_ACTION_IMPORT_JWS_ES256_DL6.clone().into(),
];
let r = idm_schema
@ -984,21 +743,30 @@ impl<'a> QueryServerWriteTransaction<'a> {
//
// DO NOT MODIFY THIS DEFINITION
let idm_schema_classes_dl1: Vec<EntryInitNew> = vec![
SCHEMA_CLASS_ACCOUNT.clone().into(),
SCHEMA_CLASS_ACCOUNT_POLICY.clone().into(),
SCHEMA_CLASS_DOMAIN_INFO.clone().into(),
SCHEMA_CLASS_DYNGROUP.clone().into(),
SCHEMA_CLASS_GROUP.clone().into(),
SCHEMA_CLASS_OAUTH2_RS.clone().into(),
SCHEMA_CLASS_ORGPERSON.clone().into(),
SCHEMA_CLASS_PERSON.clone().into(),
SCHEMA_CLASS_POSIXACCOUNT.clone().into(),
SCHEMA_CLASS_POSIXGROUP.clone().into(),
SCHEMA_CLASS_SERVICE_ACCOUNT.clone().into(),
SCHEMA_CLASS_SYNC_ACCOUNT.clone().into(),
SCHEMA_CLASS_SYSTEM_CONFIG.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_BASIC.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_PUBLIC.clone().into(),
// DL4
SCHEMA_CLASS_OAUTH2_RS_PUBLIC_DL4.clone().into(),
// DL5
SCHEMA_CLASS_PERSON_DL5.clone().into(),
SCHEMA_CLASS_ACCOUNT_DL5.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_DL5.clone().into(),
SCHEMA_CLASS_OAUTH2_RS_BASIC_DL5.clone().into(),
// DL6
SCHEMA_CLASS_ACCOUNT_POLICY_DL6.clone().into(),
SCHEMA_CLASS_DOMAIN_INFO_DL6.clone().into(),
SCHEMA_CLASS_SERVICE_ACCOUNT_DL6.clone().into(),
SCHEMA_CLASS_SYNC_ACCOUNT_DL6.clone().into(),
SCHEMA_CLASS_GROUP_DL6.clone().into(),
SCHEMA_CLASS_KEY_PROVIDER_DL6.clone().into(),
SCHEMA_CLASS_KEY_PROVIDER_INTERNAL_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_JWT_ES256_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_JWE_A128GCM_DL6.clone().into(),
SCHEMA_CLASS_KEY_OBJECT_INTERNAL_DL6.clone().into(),
];
let r: Result<(), _> = idm_schema_classes_dl1
@ -1018,18 +786,24 @@ impl<'a> QueryServerWriteTransaction<'a> {
#[instrument(level = "info", skip_all)]
/// This function is idempotent, runs all the startup functionality and checks
pub fn initialise_domain_info(&mut self) -> Result<(), OperationError> {
// First, check the system_info object. This stores some server information
// and details. It's a pretty const thing. Also check anonymous, important to many
// concepts.
let res = self
.internal_migrate_or_create(E_SYSTEM_INFO_V1.clone())
.and_then(|_| self.internal_migrate_or_create(E_DOMAIN_INFO_V1.clone()))
.and_then(|_| self.internal_migrate_or_create(E_SYSTEM_CONFIG_V1.clone()));
if res.is_err() {
admin_error!("initialise_domain_info -> result {:?}", res);
}
debug_assert!(res.is_ok());
res
// Configure the default key provider. This needs to exist *before* the
// domain info!
self.internal_migrate_or_create(E_KEY_PROVIDER_INTERNAL_DL6.clone())
.and_then(|_| self.reload())
.map_err(|err| {
error!(?err, "initialise_domain_info::E_KEY_PROVIDER_INTERNAL_DL6");
debug_assert!(false);
err
})?;
self.internal_migrate_or_create(E_SYSTEM_INFO_V1.clone())
.and_then(|_| self.internal_migrate_or_create(E_DOMAIN_INFO_DL6.clone()))
.and_then(|_| self.internal_migrate_or_create(E_SYSTEM_CONFIG_V1.clone()))
.map_err(|err| {
error!(?err, "initialise_domain_info");
debug_assert!(false);
err
})
}
#[instrument(level = "info", skip_all)]
@ -1048,9 +822,9 @@ impl<'a> QueryServerWriteTransaction<'a> {
// Each item individually logs it's result
.try_for_each(|ent| self.internal_migrate_or_create(ent));
if res.is_ok() {
admin_debug!("initialise_idm p1 -> result Ok!");
debug!("initialise_idm p1 -> result Ok!");
} else {
admin_error!(?res, "initialise_idm p1 -> result");
error!(?res, "initialise_idm p1 -> result");
}
debug_assert!(res.is_ok());
res?;
@ -1059,9 +833,9 @@ impl<'a> QueryServerWriteTransaction<'a> {
.into_iter()
.try_for_each(|e| self.internal_migrate_or_create(e.clone().try_into()?));
if res.is_ok() {
admin_debug!("initialise_idm p2 -> result Ok!");
debug!("initialise_idm p2 -> result Ok!");
} else {
admin_error!(?res, "initialise_idm p2 -> result");
error!(?res, "initialise_idm p2 -> result");
}
debug_assert!(res.is_ok());
res?;
@ -1079,9 +853,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
IDM_ACP_ACP_MANAGE_V1.clone(),
IDM_ACP_GROUP_ENTRY_MANAGED_BY_MODIFY_V1.clone(),
IDM_ACP_GROUP_ENTRY_MANAGER_V1.clone(),
IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_V1.clone(),
IDM_ACP_OAUTH2_MANAGE_V1.clone(),
IDM_ACP_DOMAIN_ADMIN_V1.clone(),
IDM_ACP_SYNC_ACCOUNT_MANAGE_V1.clone(),
IDM_ACP_RADIUS_SERVERS_V1.clone(),
IDM_ACP_RADIUS_SECRET_MANAGE_V1.clone(),
@ -1091,16 +862,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
IDM_ACP_ACCOUNT_SELF_WRITE_V1.clone(),
IDM_ACP_SELF_NAME_WRITE_V1.clone(),
IDM_ACP_ALL_ACCOUNTS_POSIX_READ_V1.clone(),
IDM_ACP_ACCOUNT_MAIL_READ_V1.clone(),
IDM_ACP_SYSTEM_CONFIG_ACCOUNT_POLICY_MANAGE_V1.clone(),
IDM_ACP_GROUP_UNIX_MANAGE_V1.clone(),
IDM_ACP_HP_GROUP_UNIX_MANAGE_V1.clone(),
IDM_ACP_GROUP_READ_V1.clone(),
IDM_ACP_GROUP_MANAGE_V1.clone(),
IDM_ACP_ACCOUNT_UNIX_EXTEND_V1.clone(),
IDM_ACP_PEOPLE_PII_READ_V1.clone(),
IDM_ACP_PEOPLE_PII_MANAGE_V1.clone(),
IDM_ACP_PEOPLE_CREATE_V1.clone(),
IDM_ACP_PEOPLE_READ_V1.clone(),
IDM_ACP_PEOPLE_MANAGE_V1.clone(),
IDM_ACP_PEOPLE_DELETE_V1.clone(),
@ -1112,6 +880,15 @@ impl<'a> QueryServerWriteTransaction<'a> {
IDM_ACP_SERVICE_ACCOUNT_ENTRY_MANAGED_BY_MODIFY_V1.clone(),
IDM_ACP_HP_SERVICE_ACCOUNT_ENTRY_MANAGED_BY_MODIFY_V1.clone(),
IDM_ACP_SERVICE_ACCOUNT_MANAGE_V1.clone(),
// DL4
// DL5
IDM_ACP_OAUTH2_MANAGE_DL5.clone().into(),
// DL6
IDM_ACP_GROUP_ACCOUNT_POLICY_MANAGE_DL6.clone().into(),
IDM_ACP_PEOPLE_CREATE_DL6.clone().into(),
IDM_ACP_GROUP_MANAGE_DL6.clone().into(),
IDM_ACP_ACCOUNT_MAIL_READ_DL6.clone().into(),
IDM_ACP_DOMAIN_ADMIN_DL6.clone(),
];
let res: Result<(), _> = idm_entries
@ -1375,46 +1152,6 @@ mod tests {
}
}
#[qs_test(domain_level=DOMAIN_LEVEL_5)]
async fn test_migrations_dl5_dl6(server: &QueryServer) {
// Assert our instance was setup to version 5
let mut write_txn = server.write(duration_from_epoch_now()).await;
let db_domain_version = write_txn
.internal_search_uuid(UUID_DOMAIN_INFO)
.expect("unable to access domain entry")
.get_ava_single_uint32(Attribute::Version)
.expect("Attribute Version not present");
assert_eq!(db_domain_version, DOMAIN_LEVEL_5);
// Entry doesn't exist yet.
let _entry_not_found = write_txn
.internal_search_uuid(UUID_SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS)
.expect_err("unable to newly migrated schema entry");
// Set the version to 6.
write_txn
.internal_modify_uuid(
UUID_DOMAIN_INFO,
&ModifyList::new_purge_and_set(
Attribute::Version,
Value::new_uint32(DOMAIN_LEVEL_6),
),
)
.expect("Unable to set domain level to version 6");
// Re-load - this applies the migrations.
write_txn.reload().expect("Unable to reload transaction");
// It now exists as the migrations were run.
let _entry = write_txn
.internal_search_uuid(UUID_SCHEMA_ATTR_LIMIT_SEARCH_MAX_RESULTS)
.expect("unable to newly migrated schema entry");
write_txn.commit().expect("Unable to commit");
}
#[qs_test(domain_level=DOMAIN_LEVEL_6)]
async fn test_migrations_dl6_dl7(server: &QueryServer) {
// Assert our instance was setup to version 6
@ -1460,18 +1197,9 @@ mod tests {
// Set the version to 7.
write_txn
.internal_modify_uuid(
UUID_DOMAIN_INFO,
&ModifyList::new_purge_and_set(
Attribute::Version,
Value::new_uint32(DOMAIN_LEVEL_7),
),
)
.internal_apply_domain_migration(DOMAIN_LEVEL_7)
.expect("Unable to set domain level to version 7");
// Re-load - this applies the migrations.
write_txn.reload().expect("Unable to reload transaction");
// post migration verification.
let domain_entry = write_txn
.internal_search_uuid(UUID_DOMAIN_INFO)
@ -1582,20 +1310,14 @@ mod tests {
// Set the version to 8.
write_txn
.internal_modify_uuid(
UUID_DOMAIN_INFO,
&ModifyList::new_purge_and_set(
Attribute::Version,
Value::new_uint32(DOMAIN_LEVEL_8),
),
)
.internal_apply_domain_migration(DOMAIN_LEVEL_8)
.expect("Unable to set domain level to version 8");
// Re-load - this applies the migrations.
write_txn.reload().expect("Unable to reload transaction");
// post migration verification.
write_txn.commit().expect("Unable to commit");
}
#[qs_test(domain_level=DOMAIN_LEVEL_8)]
async fn test_migrations_dl8_dl9(_server: &QueryServer) {}
}

View file

@ -1890,20 +1890,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
debug!(domain_previous_version = ?previous_version, domain_target_version = ?domain_info_version);
debug!(domain_previous_patch_level = ?previous_patch_level, domain_target_patch_level = ?domain_info_patch_level);
if previous_version <= DOMAIN_LEVEL_2 && domain_info_version >= DOMAIN_LEVEL_3 {
self.migrate_domain_2_to_3()?;
}
if previous_version <= DOMAIN_LEVEL_3 && domain_info_version >= DOMAIN_LEVEL_4 {
self.migrate_domain_3_to_4()?;
}
if previous_version <= DOMAIN_LEVEL_4 && domain_info_version >= DOMAIN_LEVEL_5 {
self.migrate_domain_4_to_5()?;
}
if previous_version <= DOMAIN_LEVEL_5 && domain_info_version >= DOMAIN_LEVEL_6 {
self.migrate_domain_5_to_6()?;
// We have to check for DL0 since that's the initialisation level.
if previous_version <= DOMAIN_LEVEL_5 && previous_version != DOMAIN_LEVEL_0 {
error!("UNABLE TO PROCEED. You are attempting a Skip update which is NOT SUPPORTED. You must upgrade one-version of Kanidm at a time.");
error!("For more see: https://kanidm.github.io/kanidm/stable/support.html#upgrade-policy and https://kanidm.github.io/kanidm/stable/server_updates.html");
error!(domain_previous_version = ?previous_version, domain_target_version = ?domain_info_version);
error!(domain_previous_patch_level = ?previous_patch_level, domain_target_patch_level = ?domain_info_patch_level);
return Err(OperationError::MG0008SkipUpgradeAttempted);
}
if previous_version <= DOMAIN_LEVEL_6 && domain_info_version >= DOMAIN_LEVEL_7 {
@ -1920,6 +1913,10 @@ impl<'a> QueryServerWriteTransaction<'a> {
self.migrate_domain_7_to_8()?;
}
if previous_version <= DOMAIN_LEVEL_8 && domain_info_version >= DOMAIN_LEVEL_9 {
self.migrate_domain_8_to_9()?;
}
// This is here to catch when we increase domain levels but didn't create the migration
// hooks. If this fails it probably means you need to add another migration hook
// in the above.

View file

@ -48,6 +48,7 @@ const TEST_INTEGRATION_RS_ID: &str = "test_integration";
const TEST_INTEGRATION_RS_GROUP_ALL: &str = "idm_all_accounts";
const TEST_INTEGRATION_RS_DISPLAY: &str = "Test Integration";
const TEST_INTEGRATION_RS_URL: &str = "https://demo.example.com";
const TEST_INTEGRATION_REDIRECT_URL: &str = "https://demo.example.com/oauth2/flow";
#[kanidmd_testkit::test]
async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
@ -66,6 +67,14 @@ async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
.await
.expect("Failed to create oauth2 config");
rsclient
.idm_oauth2_client_add_origin(
TEST_INTEGRATION_RS_ID,
&Url::parse(TEST_INTEGRATION_REDIRECT_URL).expect("Invalid URL"),
)
.await
.expect("Failed to update oauth2 config");
// Extend the admin account with extended details for openid claims.
rsclient
.idm_person_account_create("oauth_test", "oauth_test")
@ -236,7 +245,7 @@ async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
("state", "YWJjZGVm"),
("code_challenge", pkce_code_challenge.as_str()),
("code_challenge_method", "S256"),
("redirect_uri", "https://demo.example.com/oauth2/flow"),
("redirect_uri", TEST_INTEGRATION_REDIRECT_URL),
("scope", "email read openid"),
])
.send()
@ -303,7 +312,7 @@ async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
let form_req: AccessTokenRequest = GrantTypeReq::AuthorizationCode {
code: code.to_string(),
redirect_uri: Url::parse("https://demo.example.com/oauth2/flow").expect("Invalid URL"),
redirect_uri: Url::parse(TEST_INTEGRATION_REDIRECT_URL).expect("Invalid URL"),
code_verifier: Some(pkce_code_verifier.secret().clone()),
}
.into();
@ -496,6 +505,14 @@ async fn test_oauth2_openid_public_flow(rsclient: KanidmClient) {
.await
.expect("Failed to create oauth2 config");
rsclient
.idm_oauth2_client_add_origin(
TEST_INTEGRATION_RS_ID,
&Url::parse(TEST_INTEGRATION_REDIRECT_URL).expect("Invalid URL"),
)
.await
.expect("Failed to update oauth2 config");
// Extend the admin account with extended details for openid claims.
rsclient
.idm_person_account_create("oauth_test", "oauth_test")
@ -616,7 +633,7 @@ async fn test_oauth2_openid_public_flow(rsclient: KanidmClient) {
("state", "YWJjZGVm"),
("code_challenge", pkce_code_challenge.as_str()),
("code_challenge_method", "S256"),
("redirect_uri", "https://demo.example.com/oauth2/flow"),
("redirect_uri", TEST_INTEGRATION_REDIRECT_URL),
("scope", "email read openid"),
])
.send()
@ -683,7 +700,7 @@ async fn test_oauth2_openid_public_flow(rsclient: KanidmClient) {
let form_req = AccessTokenRequest {
grant_type: GrantTypeReq::AuthorizationCode {
code: code.to_string(),
redirect_uri: Url::parse("https://demo.example.com/oauth2/flow").expect("Invalid URL"),
redirect_uri: Url::parse(TEST_INTEGRATION_REDIRECT_URL).expect("Invalid URL"),
code_verifier: Some(pkce_code_verifier.secret().clone()),
},
client_id: Some("test_integration".to_string()),