mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Restrict posix passwords on ldap bind with config
Signed-off-by: NavinShrinivas <karupal2002@gmail.com>
This commit is contained in:
parent
e02328ae8b
commit
12ea1c8702
|
@ -66,6 +66,7 @@ pub const ATTR_DN: &str = "dn";
|
|||
pub const ATTR_DOMAIN_DISPLAY_NAME: &str = "domain_display_name";
|
||||
pub const ATTR_DOMAIN_LDAP_BASEDN: &str = "domain_ldap_basedn";
|
||||
pub const ATTR_DOMAIN_NAME: &str = "domain_name";
|
||||
pub const ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND : &str = "domain_ldap_allow_unix_pw_bind";
|
||||
pub const ATTR_DOMAIN_SSID: &str = "domain_ssid";
|
||||
pub const ATTR_DOMAIN_TOKEN_KEY: &str = "domain_token_key";
|
||||
pub const ATTR_DOMAIN_UUID: &str = "domain_uuid";
|
||||
|
|
|
@ -71,6 +71,7 @@ pub enum Attribute {
|
|||
DomainDisplayName,
|
||||
DomainLdapBasedn,
|
||||
DomainName,
|
||||
DomainLdapAllowUnixPwBind,
|
||||
DomainSsid,
|
||||
DomainTokenKey,
|
||||
DomainUuid,
|
||||
|
@ -247,6 +248,7 @@ impl TryFrom<String> for Attribute {
|
|||
ATTR_DOMAIN_DISPLAY_NAME => Attribute::DomainDisplayName,
|
||||
ATTR_DOMAIN_LDAP_BASEDN => Attribute::DomainLdapBasedn,
|
||||
ATTR_DOMAIN_NAME => Attribute::DomainName,
|
||||
ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND => Attribute::DomainLdapAllowUnixPwBind,
|
||||
ATTR_DOMAIN_SSID => Attribute::DomainSsid,
|
||||
ATTR_DOMAIN_TOKEN_KEY => Attribute::DomainTokenKey,
|
||||
ATTR_DOMAIN_UUID => Attribute::DomainUuid,
|
||||
|
@ -397,6 +399,7 @@ impl From<Attribute> for &'static str {
|
|||
Attribute::Dn => ATTR_DN,
|
||||
Attribute::Domain => ATTR_DOMAIN,
|
||||
Attribute::DomainDisplayName => ATTR_DOMAIN_DISPLAY_NAME,
|
||||
Attribute::DomainLdapAllowUnixPwBind => ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND,
|
||||
Attribute::DomainLdapBasedn => ATTR_DOMAIN_LDAP_BASEDN,
|
||||
Attribute::DomainName => ATTR_DOMAIN_NAME,
|
||||
Attribute::DomainSsid => ATTR_DOMAIN_SSID,
|
||||
|
|
|
@ -111,6 +111,15 @@ pub static ref SCHEMA_ATTR_DOMAIN_NAME: SchemaAttribute = SchemaAttribute {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
pub static ref SCHEMA_ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND: SchemaAttribute = SchemaAttribute {
|
||||
uuid: UUID_SCHEMA_ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND,
|
||||
name: Attribute::DomainLdapAllowUnixPwBind.into(),
|
||||
description: "Configuration to allow binds to LDAP objects using UNIX passwords.".to_string(),
|
||||
unique: false,
|
||||
syntax: SyntaxType::Boolean,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
pub static ref SCHEMA_ATTR_DOMAIN_LDAP_BASEDN: SchemaAttribute = SchemaAttribute {
|
||||
uuid: UUID_SCHEMA_ATTR_DOMAIN_LDAP_BASEDN,
|
||||
name: Attribute::DomainLdapBasedn.into(),
|
||||
|
@ -708,7 +717,7 @@ pub static ref SCHEMA_CLASS_DOMAIN_INFO: SchemaClass = SchemaClass {
|
|||
name: EntryClass::DomainInfo.into(),
|
||||
description: "Local domain information and partial configuration.to_string().".to_string(),
|
||||
|
||||
systemmay: vec![Attribute::DomainSsid.into(), Attribute::DomainLdapBasedn.into()],
|
||||
systemmay: vec![Attribute::DomainSsid.into(), Attribute::DomainLdapBasedn.into(),Attribute::DomainLdapAllowUnixPwBind.into()],
|
||||
systemmust: vec![
|
||||
Attribute::Name.into(),
|
||||
Attribute::DomainUuid.into(),
|
||||
|
|
|
@ -243,6 +243,9 @@ pub const UUID_SCHEMA_ATTR_IMAGE: Uuid = uuid!("00000000-0000-0000-0000-ffff0000
|
|||
pub const UUID_SCHEMA_ATTR_DENIED_NAME: Uuid = uuid!("00000000-0000-0000-0000-ffff00000144");
|
||||
|
||||
// Leave 145 for ldap unix pw bind
|
||||
pub const UUID_SCHEMA_ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND: Uuid =
|
||||
uuid!("00000000-0000-0000-0000-ffff00000145");
|
||||
|
||||
pub const UUID_SCHEMA_CLASS_ACCOUNT_POLICY: Uuid = uuid!("00000000-0000-0000-0000-ffff00000146");
|
||||
|
||||
// System and domain infos
|
||||
|
|
|
@ -450,7 +450,7 @@ impl LdapServer {
|
|||
idm_auth.auth_ldap(&lae, ct).await.and_then(|r| {
|
||||
idm_auth.commit().map(|_| {
|
||||
if r.is_some() {
|
||||
security_info!(%dn, "✅ LDAP Bind success");
|
||||
security_info!(%dn, "✅ LDAP Bind (password) success");
|
||||
} else {
|
||||
security_info!(%dn, "❌ LDAP Bind failure");
|
||||
};
|
||||
|
@ -643,13 +643,51 @@ mod tests {
|
|||
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
|
||||
|
||||
assert!(idms_prox_write.set_unix_account_password(&pce).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok()); // Committing all configs
|
||||
|
||||
// default UNIX_PW bind (default is set to true)
|
||||
// Hence allows all unix binds
|
||||
let admin_t = ldaps
|
||||
.do_bind(idms, "admin", TEST_PASSWORD)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(admin_t.effective_session == LdapSession::UnixBind(UUID_ADMIN));
|
||||
let admin_t = ldaps
|
||||
.do_bind(idms, "admin@example.com", TEST_PASSWORD)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(admin_t.effective_session == LdapSession::UnixBind(UUID_ADMIN));
|
||||
|
||||
// Setting UNIX_PW_BIND flag to false:
|
||||
// Hence all of the below authentication will fail (asserts are still satisfied)
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
let disallow_unix_pw_flag = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_purge_and_set(Attribute::DomainLdapAllowUnixPwBind, Value::Bool(false)),
|
||||
);
|
||||
assert!(idms_prox_write
|
||||
.qs_write
|
||||
.modify(&disallow_unix_pw_flag)
|
||||
.is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
let anon_t = ldaps.do_bind(idms, "", "").await.unwrap().unwrap();
|
||||
assert!(anon_t.effective_session == LdapSession::UnixBind(UUID_ANONYMOUS));
|
||||
assert!(
|
||||
ldaps.do_bind(idms, "", "test").await.unwrap_err() == OperationError::NotAuthenticated
|
||||
);
|
||||
let admin_t = ldaps.do_bind(idms, "admin", TEST_PASSWORD).await.unwrap();
|
||||
assert!(admin_t.is_none() == true);
|
||||
|
||||
// Setting UNIX_PW_BIND flag to true :
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
let allow_unix_pw_flag = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(Attribute::Uuid, PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_purge_and_set(Attribute::DomainLdapAllowUnixPwBind, Value::Bool(true)),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&allow_unix_pw_flag).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
// Now test the admin and various DN's
|
||||
let admin_t = ldaps
|
||||
|
|
|
@ -1325,6 +1325,10 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
effective_session: LdapSession::UnixBind(UUID_ANONYMOUS),
|
||||
}))
|
||||
} else {
|
||||
if !self.qs_read.d_info.d_ldap_allow_unix_pw_bind {
|
||||
security_info!("Bind not allowed through Unix passwords.");
|
||||
return Ok(None);
|
||||
}
|
||||
let account =
|
||||
UnixUserAccount::try_from_entry_ro(account_entry.as_ref(), &mut self.qs_read)?;
|
||||
|
||||
|
|
|
@ -565,6 +565,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
SCHEMA_ATTR_DOMAIN_DISPLAY_NAME.clone().into(),
|
||||
SCHEMA_ATTR_DOMAIN_LDAP_BASEDN.clone().into(),
|
||||
SCHEMA_ATTR_DOMAIN_NAME.clone().into(),
|
||||
SCHEMA_ATTR_DOMAIN_LDAP_ALLOW_UNIX_PW_BIND.clone().into(),
|
||||
SCHEMA_ATTR_DOMAIN_SSID.clone().into(),
|
||||
SCHEMA_ATTR_DOMAIN_TOKEN_KEY.clone().into(),
|
||||
SCHEMA_ATTR_DOMAIN_UUID.clone().into(),
|
||||
|
|
|
@ -65,6 +65,7 @@ pub struct DomainInfo {
|
|||
pub(crate) d_name: String,
|
||||
pub(crate) d_display: String,
|
||||
pub(crate) d_vers: DomainVersion,
|
||||
pub(crate) d_ldap_allow_unix_pw_bind: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
|
@ -813,7 +814,13 @@ pub trait QueryServerTransaction<'a> {
|
|||
e
|
||||
})
|
||||
}
|
||||
|
||||
fn get_domain_ldap_allow_unix_pw_bind(&mut self) -> Result<bool, OperationError> {
|
||||
self.internal_search_uuid(UUID_DOMAIN_INFO).map(|entry| {
|
||||
entry
|
||||
.get_ava_single_bool(Attribute::DomainLdapAllowUnixPwBind)
|
||||
.unwrap_or(true)
|
||||
})
|
||||
}
|
||||
fn get_domain_cookie_key(&mut self) -> Result<[u8; 64], OperationError> {
|
||||
self.internal_search_uuid(UUID_DOMAIN_INFO)
|
||||
.and_then(|e| {
|
||||
|
@ -1130,6 +1137,7 @@ impl QueryServer {
|
|||
// we set the domain_display_name to the configuration file's domain_name
|
||||
// here because the database is not started, so we cannot pull it from there.
|
||||
d_display: domain_name,
|
||||
d_ldap_allow_unix_pw_bind: false,
|
||||
}));
|
||||
|
||||
// These default to empty, but they'll be populated shortly.
|
||||
|
@ -1563,8 +1571,16 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
pub(crate) fn reload_domain_info(&mut self) -> Result<(), OperationError> {
|
||||
let domain_name = self.get_db_domain_name()?;
|
||||
let display_name = self.get_db_domain_display_name()?;
|
||||
let domain_ldap_allow_unix_pw_bind = match self.get_domain_ldap_allow_unix_pw_bind() {
|
||||
Ok(v) => v,
|
||||
_ => {
|
||||
admin_warn!("Defaulting ldap_allow_unix_pw_bind to true");
|
||||
true
|
||||
}
|
||||
};
|
||||
let domain_uuid = self.be_txn.get_db_d_uuid()?;
|
||||
let mut_d_info = self.d_info.get_mut();
|
||||
mut_d_info.d_ldap_allow_unix_pw_bind = domain_ldap_allow_unix_pw_bind;
|
||||
if mut_d_info.d_uuid != domain_uuid {
|
||||
admin_warn!(
|
||||
"Using domain uuid from the database {} - was {} in memory",
|
||||
|
|
Loading…
Reference in a new issue