mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 12:37:00 +01:00
20231218 ipa sync unix password (#2374)
* Add support for importing the users password as unix password
This commit is contained in:
parent
608e4b579d
commit
5c445a4704
|
@ -26,6 +26,15 @@ ipa_sync_pw = "directory manager password"
|
|||
# The basedn to examine.
|
||||
ipa_sync_base_dn = "dc=ipa,dc=dev,dc=kanidm,dc=com"
|
||||
|
||||
# By default Kanidm seperates the primary account password and credentials from
|
||||
# the unix credential. This allows the unix password to be isolated from the
|
||||
# account password so that compromise of one doesn't compromise the other. However
|
||||
# this can be surprising for new users during a migration. This boolean allows the
|
||||
# user password to be set as the unix password during the migration for consistency
|
||||
# and then after the migration they are "unlinked".
|
||||
#
|
||||
# sync_password_as_unix_password = false
|
||||
|
||||
# The sync tool can alter or exclude entries. These are mapped by their syncuuid
|
||||
# (not their ipa-object-uuid). The syncuuid is derived from nsUniqueId in 389-ds.
|
||||
# This is chosen oven DN because DN's can change with modrdn where nsUniqueId is
|
||||
|
|
|
@ -32,6 +32,15 @@ ldap_sync_base_dn = "dc=ldap,dc=dev,dc=kanidm,dc=com"
|
|||
ldap_filter = "(|(objectclass=person)(objectclass=posixgroup))"
|
||||
# ldap_filter = "(cn=\"my value\")"
|
||||
|
||||
# By default Kanidm seperates the primary account password and credentials from
|
||||
# the unix credential. This allows the unix password to be isolated from the
|
||||
# account password so that compromise of one doesn't compromise the other. However
|
||||
# this can be surprising for new users during a migration. This boolean allows the
|
||||
# user password to be set as the unix password during the migration for consistency
|
||||
# and then after the migration they are "unlinked".
|
||||
#
|
||||
# sync_password_as_unix_password = false
|
||||
|
||||
# The objectclass used to identify persons to import to Kanidm.
|
||||
#
|
||||
# If not set, defaults to "person"
|
||||
|
|
|
@ -172,6 +172,7 @@ pub const ATTR_UID: &str = "uid";
|
|||
pub const ATTR_UIDNUMBER: &str = "uidnumber";
|
||||
pub const ATTR_UNIQUE: &str = "unique";
|
||||
pub const ATTR_UNIX_PASSWORD: &str = "unix_password";
|
||||
pub const ATTR_UNIX_PASSWORD_IMPORT: &str = "unix_password_import";
|
||||
pub const ATTR_USER_AUTH_TOKEN_SESSION: &str = "user_auth_token_session";
|
||||
pub const ATTR_USERID: &str = "userid";
|
||||
pub const ATTR_USERPASSWORD: &str = "userpassword";
|
||||
|
|
|
@ -10,7 +10,8 @@ use scim_proto::*;
|
|||
|
||||
use crate::constants::{
|
||||
ATTR_ACCOUNT_EXPIRE, ATTR_ACCOUNT_VALID_FROM, ATTR_DESCRIPTION, ATTR_DISPLAYNAME,
|
||||
ATTR_GIDNUMBER, ATTR_LOGINSHELL, ATTR_MAIL, ATTR_MEMBER, ATTR_NAME, ATTR_SSH_PUBLICKEY,
|
||||
ATTR_GIDNUMBER, ATTR_LOGINSHELL, ATTR_MAIL, ATTR_MEMBER, ATTR_NAME, ATTR_PASSWORD_IMPORT,
|
||||
ATTR_SSH_PUBLICKEY, ATTR_UNIX_PASSWORD_IMPORT, ATTR_TOTP_IMPORT
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, ToSchema)]
|
||||
|
@ -138,6 +139,7 @@ pub struct ScimSyncPerson {
|
|||
pub display_name: String,
|
||||
pub gidnumber: Option<u32>,
|
||||
pub password_import: Option<String>,
|
||||
pub unix_password_import: Option<String>,
|
||||
pub totp_import: Vec<ScimTotp>,
|
||||
pub login_shell: Option<String>,
|
||||
pub mail: Vec<MultiValueAttr>,
|
||||
|
@ -158,6 +160,7 @@ impl Into<ScimEntry> for ScimSyncPerson {
|
|||
display_name,
|
||||
gidnumber,
|
||||
password_import,
|
||||
unix_password_import,
|
||||
totp_import,
|
||||
login_shell,
|
||||
mail,
|
||||
|
@ -184,8 +187,9 @@ impl Into<ScimEntry> for ScimSyncPerson {
|
|||
set_string!(attrs, ATTR_NAME, user_name);
|
||||
set_string!(attrs, ATTR_DISPLAYNAME, display_name);
|
||||
set_option_u32!(attrs, ATTR_GIDNUMBER, gidnumber);
|
||||
set_option_string!(attrs, "password_import", password_import);
|
||||
set_multi_complex!(attrs, "totp_import", totp_import);
|
||||
set_option_string!(attrs, ATTR_PASSWORD_IMPORT, password_import);
|
||||
set_option_string!(attrs, ATTR_UNIX_PASSWORD_IMPORT, unix_password_import);
|
||||
set_multi_complex!(attrs, ATTR_TOTP_IMPORT, totp_import);
|
||||
set_option_string!(attrs, ATTR_LOGINSHELL, login_shell);
|
||||
set_multi_complex!(attrs, ATTR_MAIL, mail);
|
||||
set_multi_complex!(attrs, ATTR_SSH_PUBLICKEY, ssh_publickey); // with the underscore
|
||||
|
|
|
@ -169,6 +169,7 @@ pub enum Attribute {
|
|||
UidNumber,
|
||||
Unique,
|
||||
UnixPassword,
|
||||
UnixPasswordImport,
|
||||
UserAuthTokenSession,
|
||||
UserId,
|
||||
UserPassword,
|
||||
|
@ -351,6 +352,7 @@ impl TryFrom<String> for Attribute {
|
|||
ATTR_UIDNUMBER => Attribute::UidNumber,
|
||||
ATTR_UNIQUE => Attribute::Unique,
|
||||
ATTR_UNIX_PASSWORD => Attribute::UnixPassword,
|
||||
ATTR_UNIX_PASSWORD_IMPORT => Attribute::UnixPasswordImport,
|
||||
ATTR_USER_AUTH_TOKEN_SESSION => Attribute::UserAuthTokenSession,
|
||||
ATTR_USERID => Attribute::UserId,
|
||||
ATTR_USERPASSWORD => Attribute::UserPassword,
|
||||
|
@ -511,6 +513,7 @@ impl From<Attribute> for &'static str {
|
|||
Attribute::UidNumber => ATTR_UIDNUMBER,
|
||||
Attribute::Unique => ATTR_UNIQUE,
|
||||
Attribute::UnixPassword => ATTR_UNIX_PASSWORD,
|
||||
Attribute::UnixPasswordImport => ATTR_UNIX_PASSWORD_IMPORT,
|
||||
Attribute::UserAuthTokenSession => ATTR_USER_AUTH_TOKEN_SESSION,
|
||||
Attribute::UserId => ATTR_USERID,
|
||||
Attribute::UserPassword => ATTR_USERPASSWORD,
|
||||
|
|
|
@ -268,6 +268,8 @@ pub const UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_ENTRY_MANAGER: Uuid =
|
|||
pub const UUID_SCHEMA_CLASS_ACCESS_CONTROL_TARGET_SCOPE: Uuid =
|
||||
uuid!("00000000-0000-0000-0000-ffff00000155");
|
||||
pub const UUID_SCHEMA_ATTR_ENTRY_MANAGED_BY: Uuid = uuid!("00000000-0000-0000-0000-ffff00000156");
|
||||
pub const UUID_SCHEMA_ATTR_UNIX_PASSWORD_IMPORT: Uuid =
|
||||
uuid!("00000000-0000-0000-0000-ffff00000157");
|
||||
|
||||
// System and domain infos
|
||||
// I'd like to strongly criticise william of the past for making poor choices about these allocations.
|
||||
|
|
|
@ -820,13 +820,11 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
false,
|
||||
ScimAttr::SingleSimple(ScimSimpleAttr::String(value)),
|
||||
) => Ok(vec![Value::new_utf8(value.clone())]),
|
||||
|
||||
(
|
||||
SyntaxType::Utf8StringInsensitive,
|
||||
false,
|
||||
ScimAttr::SingleSimple(ScimSimpleAttr::String(value)),
|
||||
) => Ok(vec![Value::new_iutf8(value)]),
|
||||
|
||||
(
|
||||
SyntaxType::Uint32,
|
||||
false,
|
||||
|
@ -848,7 +846,6 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
})
|
||||
})
|
||||
.map(|value| vec![Value::Uint32(value)]),
|
||||
|
||||
(SyntaxType::ReferenceUuid, true, ScimAttr::MultiComplex(values)) => {
|
||||
// In this case, because it's a reference uuid only, despite the multicomplex structure, it's a list of
|
||||
// "external_id" to external_ids. These *might* also be uuids. So we need to use sync_external_id_to_uuid
|
||||
|
@ -3191,6 +3188,7 @@ mod tests {
|
|||
"value": "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBENubZikrb8hu+HeVRdZ0pp/VAk2qv4JDbuJhvD0yNdWDL2e3cBbERiDeNPkWx58Q4rVnxkbV1fa8E2waRtT91wAAAAEc3NoOg== testuser@fidokey"
|
||||
}
|
||||
],
|
||||
"unix_password_import": "ipaNTHash: iEb36u6PsRetBr3YMLdYbA",
|
||||
"password_import": "ipaNTHash: iEb36u6PsRetBr3YMLdYbA"
|
||||
},
|
||||
{
|
||||
|
@ -3302,6 +3300,7 @@ mod tests {
|
|||
"loginshell": "/bin/sh",
|
||||
"name": "testuser",
|
||||
"password_import": "ipaNTHash: iEb36u6PsRetBr3YMLdYbA",
|
||||
"unix_password_import": "ipaNTHash: iEb36u6PsRetBr3YMLdYbA",
|
||||
"account_valid_from": "2021-11-28T04:57:55Z",
|
||||
"account_expire": "2023-11-28T04:57:55Z"
|
||||
},
|
||||
|
|
|
@ -73,7 +73,7 @@ impl CredImport {
|
|||
let hint = im_pw.split_at(len).0;
|
||||
let id = e.get_display_id();
|
||||
|
||||
error!(%hint, entry_id = %id, "password_import was unable to convert hash format");
|
||||
error!(%hint, entry_id = %id, "{} was unable to convert hash format", Attribute::PasswordImport);
|
||||
|
||||
OperationError::Plugin(PluginError::CredImport(
|
||||
"password_import was unable to convert hash format".to_string(),
|
||||
|
@ -126,6 +126,40 @@ impl CredImport {
|
|||
}
|
||||
}
|
||||
|
||||
// UNIX PASSWORD IMPORT
|
||||
if let Some(vs) = e.pop_ava(Attribute::UnixPasswordImport) {
|
||||
// if there are multiple, fail.
|
||||
let im_pw = vs.to_utf8_single().ok_or_else(|| {
|
||||
OperationError::Plugin(PluginError::CredImport(
|
||||
format!("{} has incorrect value type - should be a single utf8 string", Attribute::UnixPasswordImport),
|
||||
))
|
||||
})?;
|
||||
|
||||
// convert the import_password_string to a password
|
||||
let pw = Password::try_from(im_pw).map_err(|_| {
|
||||
let len = if im_pw.len() > 5 {
|
||||
4
|
||||
} else {
|
||||
im_pw.len() - 1
|
||||
};
|
||||
let hint = im_pw.split_at(len).0;
|
||||
let id = e.get_display_id();
|
||||
|
||||
error!(%hint, entry_id = %id, "{} was unable to convert hash format", Attribute::UnixPasswordImport);
|
||||
|
||||
OperationError::Plugin(PluginError::CredImport(
|
||||
"unix_password_import was unable to convert hash format".to_string(),
|
||||
))
|
||||
})?;
|
||||
|
||||
// Unix pw's aren't like primary, we can just splat them here.
|
||||
let c = Credential::new_from_password(pw);
|
||||
e.set_ava(
|
||||
Attribute::UnixPassword,
|
||||
once(Value::new_credential("primary", c)),
|
||||
);
|
||||
};
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
@ -147,17 +181,29 @@ mod tests {
|
|||
fn test_pre_create_password_import_1() {
|
||||
let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::new();
|
||||
|
||||
let e: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["person", "account"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"],
|
||||
"password_import": ["pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w="]
|
||||
}
|
||||
}"#,
|
||||
let e = entry_init!(
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Name, Value::new_iname("testperson")),
|
||||
(
|
||||
Attribute::Description,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::DisplayName,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::Uuid,
|
||||
Value::Uuid(uuid!("d2b496bd-8493-47b7-8142-f568b5cf47ee"))
|
||||
),
|
||||
(
|
||||
Attribute::PasswordImport,
|
||||
Value::Utf8(
|
||||
"pbkdf2_sha256$36000$xIEozuZVAoYm$uW1b35DUKyhvQAf1mBqMvoBDcqSD06juzyO/nmyV0+w="
|
||||
.into()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
let create = vec![e];
|
||||
|
@ -167,17 +213,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_modify_password_import_1() {
|
||||
// Add another uuid to a type
|
||||
let ea: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["account", "person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"]
|
||||
}
|
||||
}"#,
|
||||
let ea = entry_init!(
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Name, Value::new_iname("testperson")),
|
||||
(
|
||||
Attribute::Description,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::DisplayName,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::Uuid,
|
||||
Value::Uuid(uuid!("d2b496bd-8493-47b7-8142-f568b5cf47ee"))
|
||||
)
|
||||
);
|
||||
|
||||
let preload = vec![ea];
|
||||
|
@ -198,17 +249,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_modify_password_import_2() {
|
||||
// Add another uuid to a type
|
||||
let mut ea: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["account", "person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"]
|
||||
}
|
||||
}"#,
|
||||
let mut ea = entry_init!(
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Name, Value::new_iname("testperson")),
|
||||
(
|
||||
Attribute::Description,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::DisplayName,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::Uuid,
|
||||
Value::Uuid(uuid!("d2b496bd-8493-47b7-8142-f568b5cf47ee"))
|
||||
)
|
||||
);
|
||||
|
||||
let p = CryptoPolicy::minimum();
|
||||
|
@ -236,17 +292,22 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_modify_password_import_3_totp() {
|
||||
// Add another uuid to a type
|
||||
let mut ea: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["account", "person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["d2b496bd-8493-47b7-8142-f568b5cf47ee"]
|
||||
}
|
||||
}"#,
|
||||
let mut ea = entry_init!(
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Name, Value::new_iname("testperson")),
|
||||
(
|
||||
Attribute::Description,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::DisplayName,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::Uuid,
|
||||
Value::Uuid(uuid!("d2b496bd-8493-47b7-8142-f568b5cf47ee"))
|
||||
)
|
||||
);
|
||||
|
||||
let totp = Totp::generate_secure(TOTP_DEFAULT_STEP);
|
||||
|
@ -393,4 +454,50 @@ mod tests {
|
|||
|_| {}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_modify_unix_password_import() {
|
||||
let ea = entry_init!(
|
||||
(Attribute::Class, EntryClass::Account.to_value()),
|
||||
(Attribute::Class, EntryClass::PosixAccount.to_value()),
|
||||
(Attribute::Class, EntryClass::Person.to_value()),
|
||||
(Attribute::Name, Value::new_iname("testperson")),
|
||||
(
|
||||
Attribute::Description,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::DisplayName,
|
||||
Value::Utf8("testperson".to_string())
|
||||
),
|
||||
(
|
||||
Attribute::Uuid,
|
||||
Value::Uuid(uuid!("d2b496bd-8493-47b7-8142-f568b5cf47ee"))
|
||||
)
|
||||
);
|
||||
|
||||
let preload = vec![ea];
|
||||
|
||||
run_modify_test!(
|
||||
Ok(()),
|
||||
preload,
|
||||
filter!(f_eq(Attribute::Name, PartialValue::new_iutf8("testperson"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
Attribute::UnixPasswordImport.into(),
|
||||
Value::from(IMPORT_HASH)
|
||||
)]),
|
||||
None,
|
||||
|_| {},
|
||||
|qs: &mut QueryServerWriteTransaction| {
|
||||
let e = qs
|
||||
.internal_search_uuid(uuid!("d2b496bd-8493-47b7-8142-f568b5cf47ee"))
|
||||
.expect("failed to get entry");
|
||||
let c = e
|
||||
.get_ava_single_credential(Attribute::UnixPassword)
|
||||
.expect("failed to get unix cred.");
|
||||
|
||||
assert!(matches!(&c.type_, CredentialType::Password(_pw)));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1588,6 +1588,24 @@ impl<'a> SchemaWriteTransaction<'a> {
|
|||
},
|
||||
);
|
||||
|
||||
self.attributes.insert(
|
||||
Attribute::UnixPasswordImport.into(),
|
||||
SchemaAttribute {
|
||||
name: Attribute::UnixPasswordImport.into(),
|
||||
uuid: UUID_SCHEMA_ATTR_UNIX_PASSWORD_IMPORT,
|
||||
description: String::from(
|
||||
"An imported unix password hash from an external system.",
|
||||
),
|
||||
multivalue: false,
|
||||
unique: false,
|
||||
phantom: true,
|
||||
sync_allowed: true,
|
||||
replicated: false,
|
||||
index: vec![],
|
||||
syntax: SyntaxType::Utf8String,
|
||||
},
|
||||
);
|
||||
|
||||
self.attributes.insert(
|
||||
Attribute::TotpImport.into(),
|
||||
SchemaAttribute {
|
||||
|
|
|
@ -14,6 +14,8 @@ pub struct Config {
|
|||
pub ipa_sync_pw: String,
|
||||
pub ipa_sync_base_dn: String,
|
||||
|
||||
pub sync_password_as_unix_password: Option<bool>,
|
||||
|
||||
// pub entry: Option<Vec<EntryConfig>>,
|
||||
#[serde(flatten)]
|
||||
pub entry_map: BTreeMap<Uuid, EntryConfig>,
|
||||
|
|
|
@ -456,6 +456,9 @@ async fn run_sync(
|
|||
entries,
|
||||
&sync_config.entry_map,
|
||||
is_initialise,
|
||||
sync_config
|
||||
.sync_password_as_unix_password
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
@ -521,6 +524,7 @@ async fn process_ipa_sync_result(
|
|||
ldap_entries: Vec<LdapSyncReplEntry>,
|
||||
entry_config_map: &BTreeMap<Uuid, EntryConfig>,
|
||||
is_initialise: bool,
|
||||
sync_password_as_unix_password: bool,
|
||||
) -> Result<Vec<ScimEntry>, ()> {
|
||||
// Because of how TOTP works with freeipa it's a soft referral from
|
||||
// the totp toward the user. This means if a TOTP is added or removed
|
||||
|
@ -758,7 +762,7 @@ async fn process_ipa_sync_result(
|
|||
|
||||
let totp = totp_entries.get(&dn).unwrap_or(&empty_slice);
|
||||
|
||||
match ipa_to_scim_entry(e, &e_config, totp) {
|
||||
match ipa_to_scim_entry(e, &e_config, totp, sync_password_as_unix_password) {
|
||||
Ok(Some(e)) => Some(Ok(e)),
|
||||
Ok(None) => None,
|
||||
Err(()) => Some(Err(())),
|
||||
|
@ -767,12 +771,11 @@ async fn process_ipa_sync_result(
|
|||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
// TODO: Allow re-map of uuid -> uuid
|
||||
|
||||
fn ipa_to_scim_entry(
|
||||
sync_entry: LdapSyncReplEntry,
|
||||
entry_config: &EntryConfig,
|
||||
totp: &[LdapSyncReplEntry],
|
||||
sync_password_as_unix_password: bool,
|
||||
) -> Result<Option<ScimEntry>, ()> {
|
||||
debug!("{:#?}", sync_entry);
|
||||
|
||||
|
@ -857,6 +860,12 @@ fn ipa_to_scim_entry(
|
|||
// pw hash formats in 389-ds we don't support!
|
||||
.or_else(|| entry.remove_ava_single(Attribute::UserPassword.as_ref()));
|
||||
|
||||
let unix_password_import = if sync_password_as_unix_password {
|
||||
password_import.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mail: Vec<_> = entry
|
||||
.remove_ava(Attribute::Mail.as_ref())
|
||||
.map(|set| {
|
||||
|
@ -928,6 +937,7 @@ fn ipa_to_scim_entry(
|
|||
display_name,
|
||||
gidnumber,
|
||||
password_import,
|
||||
unix_password_import,
|
||||
totp_import,
|
||||
login_shell,
|
||||
mail,
|
||||
|
|
|
@ -72,6 +72,8 @@ pub struct Config {
|
|||
|
||||
pub ldap_filter: LdapFilter,
|
||||
|
||||
pub sync_password_as_unix_password: Option<bool>,
|
||||
|
||||
#[serde(default = "person_objectclass")]
|
||||
pub person_objectclass: String,
|
||||
#[serde(default = "person_attr_user_name")]
|
||||
|
|
|
@ -553,6 +553,15 @@ fn ldap_to_scim_entry(
|
|||
password_import
|
||||
};
|
||||
|
||||
let unix_password_import = if sync_config
|
||||
.sync_password_as_unix_password
|
||||
.unwrap_or_default()
|
||||
{
|
||||
password_import.clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mail: Vec<_> = entry
|
||||
.remove_ava(&sync_config.person_attr_mail)
|
||||
.map(|set| {
|
||||
|
@ -610,6 +619,7 @@ fn ldap_to_scim_entry(
|
|||
display_name,
|
||||
gidnumber,
|
||||
password_import,
|
||||
unix_password_import,
|
||||
totp_import,
|
||||
login_shell,
|
||||
mail,
|
||||
|
|
Loading…
Reference in a new issue