diff --git a/examples/kanidm-ipa-sync b/examples/kanidm-ipa-sync index d0a94620b..e555efc50 100644 --- a/examples/kanidm-ipa-sync +++ b/examples/kanidm-ipa-sync @@ -23,7 +23,7 @@ ipa_ca = "/path/to/kanidm-ipa-ca.pem" # The DN of an account with content sync rights. By default cn=Directory Manager has # this access. ipa_sync_dn = "cn=Directory Manager" -ipa_sync_pw = "pi9aix6balaqu8Maerah" +ipa_sync_pw = "directory manager password" # The basedn to examine. ipa_sync_base_dn = "dc=ipa,dc=dev,dc=kanidm,dc=com" diff --git a/iam_migrations/freeipa/00config-mod.ldif b/iam_migrations/freeipa/00config-mod.ldif index 51f93ebaa..1995b0d55 100644 --- a/iam_migrations/freeipa/00config-mod.ldif +++ b/iam_migrations/freeipa/00config-mod.ldif @@ -1,4 +1,4 @@ dn: cn=Retro Changelog Plugin,cn=plugins,cn=config changetype: modify -add: nsslapd-include-suffix +replace: nsslapd-include-suffix nsslapd-include-suffix: dc=ipa,dc=dev,dc=kanidm,dc=com diff --git a/kanidm_book/src/sync/freeipa.md b/kanidm_book/src/sync/freeipa.md index 96882ae79..887c9c6e7 100644 --- a/kanidm_book/src/sync/freeipa.md +++ b/kanidm_book/src/sync/freeipa.md @@ -27,18 +27,44 @@ This example is located in [examples/kanidm-ipa-sync](https://github.com/kanidm/ In addition to this, you must make some configuration changes to FreeIPA to enable synchronisation. -You must modify the retro changelog plugin to include the full scope of the database suffix. +You can find the name of your 389 Directory Server instance with: + + dsconf --list + +Using this you can show the current status of the retro changelog plugin to see if you need +to change it's configuration. + + dsconf plugin retro-changelog show + dsconf slapd-DEV-KANIDM-COM plugin retro-changelog show + +You must modify the retro changelog plugin to include the full scope of the database suffix so that +the sync tool can view the changes to the database. Currently dsconf can not modify the include-suffix +so you must do this manually. + +You need to change the `nsslapd-include-suffix` to match your FreeIPA baseDN here. You can +access the basedn with: + + ldapsearch -H ldaps:// -x -b '' -s base namingContexts + # namingContexts: dc=ipa,dc=dev,dc=kanidm,dc=com + +You should ignore `cn=changelog` and `o=ipaca` as these are system internal namingContexts. You +can then create an ldapmodify like the following. ``` {{#rustdoc_include ../../../iam_migrations/freeipa/00config-mod.ldif}} ``` -You must then restart your FreeIPA server. +And apply it with: + + ldapmodify -f change.ldif -H ldaps:// -x -D 'cn=Directory Manager' -W + # Enter LDAP Password: + +You must then reboot your FreeIPA server. ## Running the Sync Tool Manually You can perform a dry run with the sync tool manually to check your configurations are -correct. +correct and that the tool can synchronise from FreeIPA. kanidm-ipa-sync [-c /path/to/kanidm/config] -i /path/to/kanidm-ipa-sync -n kanidm-ipa-sync -i /etc/kanidm/ipa-sync -n diff --git a/kanidm_proto/src/v1.rs b/kanidm_proto/src/v1.rs index 91e724ba8..156b9091c 100644 --- a/kanidm_proto/src/v1.rs +++ b/kanidm_proto/src/v1.rs @@ -327,12 +327,14 @@ impl fmt::Display for AuthType { pub enum UiHint { ExperimentalFeatures = 0, PosixAccount = 1, + CredentialUpdate = 2, } impl fmt::Display for UiHint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { UiHint::PosixAccount => write!(f, "PosixAccount"), + UiHint::CredentialUpdate => write!(f, "CredentialUpdate"), UiHint::ExperimentalFeatures => write!(f, "ExperimentalFeatures"), } } @@ -343,6 +345,7 @@ impl FromStr for UiHint { fn from_str(s: &str) -> Result { match s { + "CredentialUpdate" => Ok(UiHint::CredentialUpdate), "PosixAccount" => Ok(UiHint::PosixAccount), "ExperimentalFeatures" => Ok(UiHint::ExperimentalFeatures), _ => Err(()), diff --git a/kanidmd/lib/src/idm/account.rs b/kanidmd/lib/src/idm/account.rs index ed9bdc17f..9698e03d1 100644 --- a/kanidmd/lib/src/idm/account.rs +++ b/kanidmd/lib/src/idm/account.rs @@ -99,6 +99,10 @@ macro_rules! try_from_entry { .copied() .collect(); + if !$value.attribute_equality("class", &PVCLASS_SYNC_OBJECT) { + ui_hints.insert(UiHint::CredentialUpdate); + } + if $value.attribute_equality("class", &PVCLASS_POSIXACCOUNT) { ui_hints.insert(UiHint::PosixAccount); } @@ -722,7 +726,8 @@ mod tests { .expect("Unable to create uat"); // Check the ui hints are as expected. - assert!(uat.ui_hints.is_empty()); + assert!(uat.ui_hints.len() == 1); + assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate)); // Modify the user to be a posix account, ensure they get the hint. let me_posix = unsafe { @@ -748,8 +753,9 @@ mod tests { .to_userauthtoken(session_id, ct, AuthType::Passkey, None) .expect("Unable to create uat"); - assert!(uat.ui_hints.len() == 1); + assert!(uat.ui_hints.len() == 2); assert!(uat.ui_hints.contains(&UiHint::PosixAccount)); + assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate)); // Add a group with a ui hint, and then check they get the hint. let e = entry_init!( @@ -772,9 +778,10 @@ mod tests { .to_userauthtoken(session_id, ct, AuthType::Passkey, None) .expect("Unable to create uat"); - assert!(uat.ui_hints.len() == 2); + assert!(uat.ui_hints.len() == 3); assert!(uat.ui_hints.contains(&UiHint::PosixAccount)); assert!(uat.ui_hints.contains(&UiHint::ExperimentalFeatures)); + assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate)); assert!(idms_prox_write.commit().is_ok()); }) diff --git a/kanidmd_web_ui/pkg/kanidmd_web_ui.js b/kanidmd_web_ui/pkg/kanidmd_web_ui.js index 627e6131b..80bfbb47c 100644 --- a/kanidmd_web_ui/pkg/kanidmd_web_ui.js +++ b/kanidmd_web_ui/pkg/kanidmd_web_ui.js @@ -233,7 +233,7 @@ function addBorrowedObject(obj) { } function __wbg_adapter_48(arg0, arg1, arg2) { try { - wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h871c42aaca1d3703(arg0, arg1, addBorrowedObject(arg2)); + wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hdb7f5bd2101eb559(arg0, arg1, addBorrowedObject(arg2)); } finally { heap[stack_pointer++] = undefined; } @@ -261,11 +261,11 @@ function makeClosure(arg0, arg1, dtor, f) { return real; } function __wbg_adapter_51(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h6073fca8e152ad8e(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd6c53cf713a6c0ff(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_54(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h501c623b6f23b8ff(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3b581d83a45c2264(arg0, arg1, addHeapObject(arg2)); } /** @@ -345,6 +345,10 @@ async function load(module, imports) { function getImports() { const imports = {}; imports.wbg = {}; + imports.wbg.__wbindgen_is_undefined = function(arg0) { + const ret = getObject(arg0) === undefined; + return ret; + }; imports.wbg.__wbindgen_number_get = function(arg0, arg1) { const obj = getObject(arg1); const ret = typeof(obj) === 'number' ? obj : undefined; @@ -386,10 +390,6 @@ function getImports() { imports.wbg.__wbindgen_object_drop_ref = function(arg0) { takeObject(arg0); }; - imports.wbg.__wbindgen_is_undefined = function(arg0) { - const ret = getObject(arg0) === undefined; - return ret; - }; imports.wbg.__wbindgen_in = function(arg0, arg1) { const ret = getObject(arg0) in getObject(arg1); return ret; @@ -542,6 +542,29 @@ function getImports() { imports.wbg.__wbg_log_4b5638ad60bdc54a = function(arg0) { console.log(getObject(arg0)); }; + imports.wbg.__wbg_getItem_845e475f85f593e4 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); + var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }, arguments) }; + imports.wbg.__wbg_removeItem_9da69ede4eea3326 = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2)); + }, arguments) }; + imports.wbg.__wbg_setItem_9c469d634d0c321c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }, arguments) }; + imports.wbg.__wbg_instanceof_HtmlFormElement_1c489ff7e99e43d3 = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof HTMLFormElement; + } catch { + result = false; + } + const ret = result; + return ret; + }; imports.wbg.__wbg_value_ccb32485ee1b3928 = function(arg0, arg1) { const ret = getObject(arg1).value; const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); @@ -566,39 +589,6 @@ function getImports() { imports.wbg.__wbg_set_992c1d31586b2957 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).set(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); }, arguments) }; - imports.wbg.__wbg_instanceof_HtmlFormElement_1c489ff7e99e43d3 = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof HTMLFormElement; - } catch { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_getItem_845e475f85f593e4 = function() { return handleError(function (arg0, arg1, arg2, arg3) { - const ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); - var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len0 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len0; - getInt32Memory0()[arg0 / 4 + 0] = ptr0; - }, arguments) }; - imports.wbg.__wbg_removeItem_9da69ede4eea3326 = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2)); - }, arguments) }; - imports.wbg.__wbg_setItem_9c469d634d0c321c = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); - }, arguments) }; - imports.wbg.__wbg_new_ca4d3a3eca340210 = function() { return handleError(function () { - const ret = new URLSearchParams(); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_add_89a4f3b0846cf0aa = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).add(getStringFromWasm0(arg1, arg2)); - }, arguments) }; - imports.wbg.__wbg_remove_1a26eb5d822902ed = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).remove(getStringFromWasm0(arg1, arg2)); - }, arguments) }; imports.wbg.__wbg_pathname_78a642e573bf8169 = function(arg0, arg1) { const ret = getObject(arg1).pathname; const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); @@ -620,6 +610,10 @@ function getImports() { const ret = new URL(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); }, arguments) }; + imports.wbg.__wbg_new_ca4d3a3eca340210 = function() { return handleError(function () { + const ret = new URLSearchParams(); + return addHeapObject(ret); + }, arguments) }; imports.wbg.__wbg_instanceof_HtmlInputElement_970e4026de0fccff = function(arg0) { let result; try { @@ -643,13 +637,11 @@ function getImports() { imports.wbg.__wbg_setvalue_e5b519cca37d82a7 = function(arg0, arg1, arg2) { getObject(arg0).value = getStringFromWasm0(arg1, arg2); }; - imports.wbg.__wbg_create_53c6ddb068a22172 = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).create(getObject(arg1)); - return addHeapObject(ret); + imports.wbg.__wbg_add_89a4f3b0846cf0aa = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).add(getStringFromWasm0(arg1, arg2)); }, arguments) }; - imports.wbg.__wbg_get_da97585bbb5a63bb = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).get(getObject(arg1)); - return addHeapObject(ret); + imports.wbg.__wbg_remove_1a26eb5d822902ed = function() { return handleError(function (arg0, arg1, arg2) { + getObject(arg0).remove(getStringFromWasm0(arg1, arg2)); }, arguments) }; imports.wbg.__wbg_href_90ff36b5040e3b76 = function(arg0, arg1) { const ret = getObject(arg1).href; @@ -720,10 +712,14 @@ function getImports() { imports.wbg.__wbg_focus_adfe4cc61e2c09bc = function() { return handleError(function (arg0) { getObject(arg0).focus(); }, arguments) }; - imports.wbg.__wbg_credentials_eab5c0bffc3e9cc5 = function(arg0) { - const ret = getObject(arg0).credentials; + imports.wbg.__wbg_create_53c6ddb068a22172 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).create(getObject(arg1)); return addHeapObject(ret); - }; + }, arguments) }; + imports.wbg.__wbg_get_da97585bbb5a63bb = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).get(getObject(arg1)); + return addHeapObject(ret); + }, arguments) }; imports.wbg.__wbg_getClientExtensionResults_0381c2792f96b9fa = function(arg0) { const ret = getObject(arg0).getClientExtensionResults(); return addHeapObject(ret); @@ -757,6 +753,10 @@ function getImports() { const ret = getObject(arg0).get(getStringFromWasm0(arg1, arg2)); return addHeapObject(ret); }; + imports.wbg.__wbg_credentials_eab5c0bffc3e9cc5 = function(arg0) { + const ret = getObject(arg0).credentials; + return addHeapObject(ret); + }; imports.wbg.__wbg_addEventListener_1fc744729ac6dc27 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); }, arguments) }; @@ -786,6 +786,20 @@ function getImports() { const ret = getObject(arg0).removeChild(getObject(arg1)); return addHeapObject(ret); }, arguments) }; + imports.wbg.__wbg_instanceof_WorkerGlobalScope_16bb97a4549a3f21 = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof WorkerGlobalScope; + } catch { + result = false; + } + const ret = result; + return ret; + }; + imports.wbg.__wbg_fetch_749a56934f95c96c = function(arg0, arg1) { + const ret = getObject(arg0).fetch(getObject(arg1)); + return addHeapObject(ret); + }; imports.wbg.__wbg_pushState_38917fb88b4add30 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5) { getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5)); }, arguments) }; @@ -1016,10 +1030,6 @@ function getImports() { const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); return ret; }, arguments) }; - imports.wbg.__wbg_stringify_d6471d300ded9b68 = function() { return handleError(function (arg0) { - const ret = JSON.stringify(getObject(arg0)); - return addHeapObject(ret); - }, arguments) }; imports.wbg.__wbindgen_bigint_get_as_i64 = function(arg0, arg1) { const v = getObject(arg1); const ret = typeof(v) === 'bigint' ? v : undefined; @@ -1040,16 +1050,16 @@ function getImports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper4814 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1014, __wbg_adapter_48); + imports.wbg.__wbindgen_closure_wrapper4824 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1020, __wbg_adapter_48); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper5000 = function(arg0, arg1, arg2) { - const ret = makeClosure(arg0, arg1, 1041, __wbg_adapter_51); + imports.wbg.__wbindgen_closure_wrapper5009 = function(arg0, arg1, arg2) { + const ret = makeClosure(arg0, arg1, 1044, __wbg_adapter_51); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper5658 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 1290, __wbg_adapter_54); + imports.wbg.__wbindgen_closure_wrapper5669 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 1294, __wbg_adapter_54); return addHeapObject(ret); }; diff --git a/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm b/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm index e8c11804c..de1dcbb0d 100644 Binary files a/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm and b/kanidmd_web_ui/pkg/kanidmd_web_ui_bg.wasm differ diff --git a/kanidmd_web_ui/src/views/mod.rs b/kanidmd_web_ui/src/views/mod.rs index 9f6765ca5..b9ad04aec 100644 --- a/kanidmd_web_ui/src/views/mod.rs +++ b/kanidmd_web_ui/src/views/mod.rs @@ -237,6 +237,7 @@ impl ViewsApp { let current_user_uat = uat.clone(); let ui_hint_experimental = uat.ui_hints.contains(&UiHint::ExperimentalFeatures); + let credential_update = uat.ui_hints.contains(&UiHint::CredentialUpdate); // WARN set dash-body against body here? html! { @@ -269,12 +270,14 @@ impl ViewsApp { } -
  • - classes="nav-link" to={ViewRoute::Security}> - - { "Security" } - > -
  • + if credential_update { +
  • + classes="nav-link" to={ViewRoute::Security}> + + { "Security" } + > +
  • + } if ui_hint_experimental {
  • @@ -292,10 +295,10 @@ impl ViewsApp { >{"Sign out"}
  • -
    - - -
    + //
    + // + // + //