handle wildcards being given as ldap attribute params

fix wildcard expansion

address some pr comments

Move ldap attribute expansion lists to constants

As per: https://github.com/nitnelave/lldap/pull/164#discussion_r867348971

lldap *+ expansion: remove unneccesary cloning

https://github.com/nitnelave/lldap/pull/164#discussion_r867349805

ldap attribute wildcard handling: remove duplicated wildcards

https://github.com/nitnelave/lldap/pull/164#issuecomment-1120211031

ldap wildcard expansion: refactor

ldap attribute handlers: handle '+' by ignoring, '*' and unmatched by warning and ignoring

attribute wildcard expansion: refactor, don't remove '+'
This commit is contained in:
Matthew Strasiotto 2022-05-07 14:48:53 +10:00 committed by nitnelave
parent 875c59758b
commit e5c80b9f17

View File

@ -6,6 +6,7 @@ use crate::domain::{
opaque_handler::OpaqueHandler, opaque_handler::OpaqueHandler,
}; };
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use itertools::Itertools;
use ldap3_server::proto::{ use ldap3_server::proto::{
LdapBindCred, LdapBindRequest, LdapBindResponse, LdapExtendedRequest, LdapExtendedResponse, LdapBindCred, LdapBindRequest, LdapBindResponse, LdapExtendedRequest, LdapExtendedResponse,
LdapFilter, LdapOp, LdapPartialAttribute, LdapPasswordModifyRequest, LdapResult, LdapFilter, LdapOp, LdapPartialAttribute, LdapPasswordModifyRequest, LdapResult,
@ -116,19 +117,60 @@ fn get_user_attribute(user: &User, attribute: &str, dn: &str) -> Result<Option<V
"cn" | "displayname" => vec![user.display_name.clone()], "cn" | "displayname" => vec![user.display_name.clone()],
"createtimestamp" | "modifytimestamp" => vec![user.creation_date.to_rfc3339()], "createtimestamp" | "modifytimestamp" => vec![user.creation_date.to_rfc3339()],
"1.1" => return Ok(None), "1.1" => return Ok(None),
_ => bail!("Unsupported user attribute: {}", attribute), // We ignore the operational attribute wildcard
"+" => return Ok(None),
"*" => {
warn!(
"Matched {}, * should have been expanded into attribute list and * removed",
attribute
);
return Ok(None);
}
_ => {
warn!("Ignoring unrecognized group attribute: {}", attribute);
return Ok(None);
}
})) }))
} }
fn expand_attribute_wildcards(attributes: &[String], all_attribute_keys: &[&str]) -> Vec<String> {
let mut attributes_out = attributes.to_owned();
if attributes_out.iter().any(|x| x == "*") || attributes_out.is_empty() {
debug!(r#"Expanding * / empty attrs:"#);
// Remove occurrences of '*'
attributes_out.retain(|x| x != "*");
// Splice in all non-operational attributes
attributes_out.extend(all_attribute_keys.iter().map(|s| s.to_string()));
}
debug!(r#"Expanded: "{:?}""#, &attributes_out);
// Deduplicate, preserving order
attributes_out.into_iter().unique().collect_vec()
}
const ALL_USER_ATTRIBUTE_KEYS: &[&str] = &[
"objectclass",
"dn",
"uid",
"mail",
"givenname",
"sn",
"cn",
"createtimestamp",
];
fn make_ldap_search_user_result_entry( fn make_ldap_search_user_result_entry(
user: User, user: User,
base_dn_str: &str, base_dn_str: &str,
attributes: &[String], attributes: &[String],
) -> Result<LdapSearchResultEntry> { ) -> Result<LdapSearchResultEntry> {
let dn = format!("uid={},ou=people,{}", user.user_id.as_str(), base_dn_str); let dn = format!("uid={},ou=people,{}", user.user_id.as_str(), base_dn_str);
let expanded_attributes = expand_attribute_wildcards(attributes, ALL_USER_ATTRIBUTE_KEYS);
Ok(LdapSearchResultEntry { Ok(LdapSearchResultEntry {
dn: dn.clone(), dn: dn.clone(),
attributes: attributes attributes: expanded_attributes
.iter() .iter()
.filter_map(|a| { .filter_map(|a| {
let values = match get_user_attribute(&user, a, &dn) { let values = match get_user_attribute(&user, a, &dn) {
@ -164,19 +206,36 @@ fn get_group_attribute(
.map(|u| format!("uid={},ou=people,{}", u, base_dn_str)) .map(|u| format!("uid={},ou=people,{}", u, base_dn_str))
.collect(), .collect(),
"1.1" => return Ok(None), "1.1" => return Ok(None),
_ => bail!("Unsupported group attribute: {}", attribute), // We ignore the operational attribute wildcard
"+" => return Ok(None),
"*" => {
warn!(
"Matched {}, * should have been expanded into attribute list and * removed",
attribute
);
return Ok(None);
}
_ => {
warn!("Ignoring unrecognized group attribute: {}", attribute);
return Ok(None);
}
})) }))
} }
const ALL_GROUP_ATTRIBUTE_KEYS: &[&str] =
&["objectclass", "dn", "uid", "cn", "member", "uniquemember"];
fn make_ldap_search_group_result_entry( fn make_ldap_search_group_result_entry(
group: Group, group: Group,
base_dn_str: &str, base_dn_str: &str,
attributes: &[String], attributes: &[String],
user_filter: &Option<&UserId>, user_filter: &Option<&UserId>,
) -> Result<LdapSearchResultEntry> { ) -> Result<LdapSearchResultEntry> {
let expanded_attributes = expand_attribute_wildcards(attributes, ALL_GROUP_ATTRIBUTE_KEYS);
Ok(LdapSearchResultEntry { Ok(LdapSearchResultEntry {
dn: format!("cn={},ou=groups,{}", group.display_name, base_dn_str), dn: format!("cn={},ou=groups,{}", group.display_name, base_dn_str),
attributes: attributes attributes: expanded_attributes
.iter() .iter()
.filter_map(|a| { .filter_map(|a| {
let values = match get_group_attribute(&group, base_dn_str, a, user_filter) { let values = match get_group_attribute(&group, base_dn_str, a, user_filter) {