mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
ldap: lowercase all DN, fields, values
This commit is contained in:
parent
7e62cc6eda
commit
1d8582f937
@ -39,6 +39,7 @@ where
|
||||
}
|
||||
|
||||
fn parse_distinguished_name(dn: &str) -> Result<Vec<(String, String)>> {
|
||||
assert!(dn == dn.to_ascii_lowercase());
|
||||
dn.split(',')
|
||||
.map(|s| make_dn_pair(s.split('=').map(str::trim).map(String::from)))
|
||||
.collect()
|
||||
@ -102,7 +103,7 @@ fn get_user_id_from_distinguished_name(
|
||||
}
|
||||
|
||||
fn get_user_attribute(user: &User, attribute: &str, dn: &str) -> Result<Option<Vec<String>>> {
|
||||
Ok(Some(match attribute.to_lowercase().as_str() {
|
||||
Ok(Some(match attribute.to_ascii_lowercase().as_str() {
|
||||
"objectclass" => vec![
|
||||
"inetOrgPerson".to_string(),
|
||||
"posixAccount".to_string(),
|
||||
@ -191,7 +192,7 @@ fn get_group_attribute(
|
||||
attribute: &str,
|
||||
user_filter: &Option<&UserId>,
|
||||
) -> Result<Option<Vec<String>>> {
|
||||
Ok(Some(match attribute.to_lowercase().as_str() {
|
||||
Ok(Some(match attribute.to_ascii_lowercase().as_str() {
|
||||
"objectclass" => vec!["groupOfUniqueNames".to_string()],
|
||||
"dn" | "distinguishedname" => vec![format!(
|
||||
"cn={},ou=groups,{}",
|
||||
@ -250,6 +251,14 @@ fn make_ldap_search_group_result_entry(
|
||||
}
|
||||
|
||||
fn is_subtree(subtree: &[(String, String)], base_tree: &[(String, String)]) -> bool {
|
||||
for (k, v) in subtree {
|
||||
assert!(k == &k.to_ascii_lowercase());
|
||||
assert!(v == &v.to_ascii_lowercase());
|
||||
}
|
||||
for (k, v) in base_tree {
|
||||
assert!(k == &k.to_ascii_lowercase());
|
||||
assert!(v == &v.to_ascii_lowercase());
|
||||
}
|
||||
if subtree.len() < base_tree.len() {
|
||||
return false;
|
||||
}
|
||||
@ -263,22 +272,20 @@ fn is_subtree(subtree: &[(String, String)], base_tree: &[(String, String)]) -> b
|
||||
}
|
||||
|
||||
fn map_field(field: &str) -> Result<String> {
|
||||
assert!(field == field.to_ascii_lowercase());
|
||||
Ok(if field == "uid" {
|
||||
"user_id".to_string()
|
||||
} else if field == "mail" {
|
||||
"email".to_string()
|
||||
} else if field == "cn" || field.to_lowercase() == "displayname" {
|
||||
} else if field == "cn" || field == "displayname" {
|
||||
"display_name".to_string()
|
||||
} else if field.to_lowercase() == "givenname" {
|
||||
} else if field == "givenname" {
|
||||
"first_name".to_string()
|
||||
} else if field == "sn" {
|
||||
"last_name".to_string()
|
||||
} else if field == "avatar" {
|
||||
"avatar".to_string()
|
||||
} else if field.to_lowercase() == "creationdate"
|
||||
|| field.to_lowercase() == "createtimestamp"
|
||||
|| field.to_lowercase() == "modifytimestamp"
|
||||
{
|
||||
} else if field == "creationdate" || field == "createtimestamp" || field == "modifytimestamp" {
|
||||
"creation_date".to_string()
|
||||
} else {
|
||||
bail!("Unknown field: {}", field);
|
||||
@ -357,7 +364,8 @@ pub struct LdapHandler<Backend: BackendHandler + LoginHandler + OpaqueHandler> {
|
||||
}
|
||||
|
||||
impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend> {
|
||||
pub fn new(backend_handler: Backend, ldap_base_dn: String) -> Self {
|
||||
pub fn new(backend_handler: Backend, mut ldap_base_dn: String) -> Self {
|
||||
ldap_base_dn.make_ascii_lowercase();
|
||||
Self {
|
||||
user_info: None,
|
||||
backend_handler,
|
||||
@ -374,7 +382,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
pub async fn do_bind(&mut self, request: &LdapBindRequest) -> (LdapResultCode, String) {
|
||||
debug!(r#"Received bind request for "{}""#, &request.dn);
|
||||
let user_id = match get_user_id_from_distinguished_name(
|
||||
&request.dn,
|
||||
&request.dn.to_ascii_lowercase(),
|
||||
&self.base_dn,
|
||||
&self.base_dn_str,
|
||||
) {
|
||||
@ -514,7 +522,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
return vec![root_dse_response(&self.base_dn_str), make_search_success()];
|
||||
}
|
||||
debug!("Received search request: {:?}", &request);
|
||||
let dn_parts = match parse_distinguished_name(&request.base) {
|
||||
let dn_parts = match parse_distinguished_name(&request.base.to_ascii_lowercase()) {
|
||||
Ok(dn) => dn,
|
||||
Err(_) => {
|
||||
return vec![make_search_error(
|
||||
@ -685,15 +693,17 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
fn convert_group_filter(&self, filter: &LdapFilter) -> Result<GroupRequestFilter> {
|
||||
match filter {
|
||||
LdapFilter::Equality(field, value) => {
|
||||
if field == "member" || field.to_lowercase() == "uniquemember" {
|
||||
let field = &field.to_ascii_lowercase();
|
||||
let value = &value.to_ascii_lowercase();
|
||||
if field == "member" || field == "uniquemember" {
|
||||
let user_name = get_user_id_from_distinguished_name(
|
||||
value,
|
||||
&self.base_dn,
|
||||
&self.base_dn_str,
|
||||
)?;
|
||||
Ok(GroupRequestFilter::Member(user_name))
|
||||
} else if field.to_lowercase() == "objectclass" {
|
||||
if value == "groupOfUniqueNames" || value == "groupOfNames" {
|
||||
} else if field == "objectclass" {
|
||||
if value == "groupofuniquenames" || value == "groupofnames" {
|
||||
Ok(GroupRequestFilter::And(vec![]))
|
||||
} else {
|
||||
Ok(GroupRequestFilter::Not(Box::new(GroupRequestFilter::And(
|
||||
@ -725,7 +735,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
self.convert_group_filter(&*filter)?,
|
||||
))),
|
||||
LdapFilter::Present(field) => {
|
||||
if ALL_GROUP_ATTRIBUTE_KEYS.contains(&field.to_lowercase().as_str()) {
|
||||
if ALL_GROUP_ATTRIBUTE_KEYS.contains(&field.to_ascii_lowercase().as_str()) {
|
||||
Ok(GroupRequestFilter::And(vec![]))
|
||||
} else {
|
||||
Ok(GroupRequestFilter::Not(Box::new(GroupRequestFilter::And(
|
||||
@ -755,14 +765,15 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
self.convert_user_filter(&*filter)?,
|
||||
))),
|
||||
LdapFilter::Equality(field, value) => {
|
||||
if field.to_lowercase() == "memberof" {
|
||||
let field = &field.to_ascii_lowercase();
|
||||
if field == "memberof" {
|
||||
let group_name = get_group_id_from_distinguished_name(
|
||||
value,
|
||||
&value.to_ascii_lowercase(),
|
||||
&self.base_dn,
|
||||
&self.base_dn_str,
|
||||
)?;
|
||||
Ok(UserRequestFilter::MemberOf(group_name))
|
||||
} else if field.to_lowercase() == "objectclass" {
|
||||
} else if field == "objectclass" {
|
||||
if value == "person"
|
||||
|| value == "inetOrgPerson"
|
||||
|| value == "posixAccount"
|
||||
@ -784,8 +795,9 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
}
|
||||
}
|
||||
LdapFilter::Present(field) => {
|
||||
let field = &field.to_ascii_lowercase();
|
||||
// Check that it's a field we support.
|
||||
if field.to_lowercase() == "objectclass" || map_field(field).is_ok() {
|
||||
if field == "objectclass" || map_field(field).is_ok() {
|
||||
Ok(UserRequestFilter::And(vec![]))
|
||||
} else {
|
||||
Ok(UserRequestFilter::Not(Box::new(UserRequestFilter::And(
|
||||
@ -872,7 +884,7 @@ mod tests {
|
||||
filter: LdapFilter,
|
||||
attrs: Vec<S>,
|
||||
) -> LdapSearchRequest {
|
||||
make_search_request::<S>("ou=people,dc=example,dc=com", filter, attrs)
|
||||
make_search_request::<S>("ou=people,Dc=example,dc=com", filter, attrs)
|
||||
}
|
||||
|
||||
async fn setup_bound_handler(
|
||||
@ -891,9 +903,9 @@ mod tests {
|
||||
set.insert(GroupIdAndName(GroupId(42), "lldap_admin".to_string()));
|
||||
Ok(set)
|
||||
});
|
||||
let mut ldap_handler = LdapHandler::new(mock, "dc=example,dc=com".to_string());
|
||||
let mut ldap_handler = LdapHandler::new(mock, "dc=Example,dc=com".to_string());
|
||||
let request = LdapBindRequest {
|
||||
dn: "uid=test,ou=people,dc=example,dc=com".to_string(),
|
||||
dn: "uid=test,ou=people,dc=example,dc=coM".to_string(),
|
||||
cred: LdapBindCred::Simple("pass".to_string()),
|
||||
};
|
||||
assert_eq!(
|
||||
@ -916,7 +928,7 @@ mod tests {
|
||||
mock.expect_get_user_groups()
|
||||
.with(eq(UserId::new("bob")))
|
||||
.return_once(|_| Ok(HashSet::new()));
|
||||
let mut ldap_handler = LdapHandler::new(mock, "dc=example,dc=com".to_string());
|
||||
let mut ldap_handler = LdapHandler::new(mock, "dc=eXample,dc=com".to_string());
|
||||
|
||||
let request = LdapOp::BindRequest(LdapBindRequest {
|
||||
dn: "uid=bob,ou=people,dc=example,dc=com".to_string(),
|
||||
@ -1240,14 +1252,14 @@ mod tests {
|
||||
},
|
||||
Group {
|
||||
id: GroupId(3),
|
||||
display_name: "bestgroup".to_string(),
|
||||
display_name: "BestGroup".to_string(),
|
||||
users: vec![UserId::new("john")],
|
||||
},
|
||||
])
|
||||
});
|
||||
let mut ldap_handler = setup_bound_handler(mock).await;
|
||||
let request = make_search_request(
|
||||
"ou=groups,dc=example,dc=com",
|
||||
"ou=groups,dc=example,dc=cOm",
|
||||
LdapFilter::And(vec![]),
|
||||
vec!["objectClass", "dn", "cn", "uniqueMember"],
|
||||
);
|
||||
@ -1279,7 +1291,7 @@ mod tests {
|
||||
],
|
||||
}),
|
||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||
dn: "cn=bestgroup,ou=groups,dc=example,dc=com".to_string(),
|
||||
dn: "cn=BestGroup,ou=groups,dc=example,dc=com".to_string(),
|
||||
attributes: vec![
|
||||
LdapPartialAttribute {
|
||||
atype: "objectClass".to_string(),
|
||||
@ -1287,11 +1299,11 @@ mod tests {
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "dn".to_string(),
|
||||
vals: vec!["cn=bestgroup,ou=groups,dc=example,dc=com".to_string()]
|
||||
vals: vec!["cn=BestGroup,ou=groups,dc=example,dc=com".to_string()]
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "cn".to_string(),
|
||||
vals: vec!["bestgroup".to_string()]
|
||||
vals: vec!["BestGroup".to_string()]
|
||||
},
|
||||
LdapPartialAttribute {
|
||||
atype: "uniqueMember".to_string(),
|
||||
@ -1331,17 +1343,17 @@ mod tests {
|
||||
let request = make_search_request(
|
||||
"ou=groups,dc=example,dc=com",
|
||||
LdapFilter::And(vec![
|
||||
LdapFilter::Equality("cn".to_string(), "group_1".to_string()),
|
||||
LdapFilter::Equality("cN".to_string(), "Group_1".to_string()),
|
||||
LdapFilter::Equality(
|
||||
"uniqueMember".to_string(),
|
||||
"uid=bob,ou=people,dc=example,dc=com".to_string(),
|
||||
"uid=bob,ou=peopLe,Dc=eXample,dc=com".to_string(),
|
||||
),
|
||||
LdapFilter::Equality("objectclass".to_string(), "groupOfUniqueNames".to_string()),
|
||||
LdapFilter::Equality("obJEctclass".to_string(), "groupOfUniqueNames".to_string()),
|
||||
LdapFilter::Equality("objectclass".to_string(), "groupOfNames".to_string()),
|
||||
LdapFilter::Present("objectclass".to_string()),
|
||||
LdapFilter::Present("dn".to_string()),
|
||||
LdapFilter::Not(Box::new(LdapFilter::Present(
|
||||
"random_attribute".to_string(),
|
||||
"random_attribUte".to_string(),
|
||||
))),
|
||||
]),
|
||||
vec!["1.1"],
|
||||
|
Loading…
Reference in New Issue
Block a user