server: read custom attributes from LDAP

This commit is contained in:
Valentin Tolmer
2023-09-15 00:53:24 +02:00
committed by nitnelave
parent 8e1515c27b
commit 39a75b2c35
9 changed files with 289 additions and 161 deletions

View File

@@ -6,13 +6,14 @@ use tracing::{debug, instrument, warn};
use crate::domain::{
handler::{GroupListerBackendHandler, GroupRequestFilter},
ldap::error::LdapError,
schema::{PublicSchema, SchemaGroupAttributeExtractor},
types::{Group, UserId, Uuid},
};
use super::{
error::LdapResult,
utils::{
expand_attribute_wildcards, get_group_id_from_distinguished_name,
expand_attribute_wildcards, get_custom_attribute, get_group_id_from_distinguished_name,
get_user_id_from_distinguished_name, map_group_field, LdapInfo,
},
};
@@ -23,6 +24,7 @@ pub fn get_group_attribute(
attribute: &str,
user_filter: &Option<UserId>,
ignored_group_attributes: &[String],
schema: &PublicSchema,
) -> Option<Vec<Vec<u8>>> {
let attribute = attribute.to_ascii_lowercase();
let attribute_values = match attribute.as_str() {
@@ -46,13 +48,20 @@ pub fn get_group_attribute(
attribute
)
}
_ => {
attr => {
if !ignored_group_attributes.contains(&attribute) {
warn!(
r#"Ignoring unrecognized group attribute: {}\n\
match get_custom_attribute::<SchemaGroupAttributeExtractor>(
&group.attributes,
attr,
schema,
) {
Some(v) => return Some(v),
None => warn!(
r#"Ignoring unrecognized group attribute: {}\n\
To disable this warning, add it to "ignored_group_attributes" in the config."#,
attribute
);
attribute
),
};
}
return None;
}
@@ -83,6 +92,7 @@ fn make_ldap_search_group_result_entry(
attributes: &[String],
user_filter: &Option<UserId>,
ignored_group_attributes: &[String],
schema: &PublicSchema,
) -> LdapSearchResultEntry {
let expanded_attributes = expand_group_attribute_wildcards(attributes);
@@ -97,6 +107,7 @@ fn make_ldap_search_group_result_entry(
a,
user_filter,
ignored_group_attributes,
schema,
)?;
Some(LdapPartialAttribute {
atype: a.to_string(),
@@ -221,6 +232,7 @@ pub fn convert_groups_to_ldap_op<'a>(
attributes: &'a [String],
ldap_info: &'a LdapInfo,
user_filter: &'a Option<UserId>,
schema: &'a PublicSchema,
) -> impl Iterator<Item = LdapOp> + 'a {
groups.into_iter().map(move |g| {
LdapOp::SearchResultEntry(make_ldap_search_group_result_entry(
@@ -229,6 +241,7 @@ pub fn convert_groups_to_ldap_op<'a>(
attributes,
user_filter,
&ldap_info.ignored_group_attributes,
schema,
))
})
}

View File

@@ -5,7 +5,7 @@ use ldap3_proto::{
use tracing::{debug, instrument, warn};
use crate::domain::{
handler::{Schema, UserListerBackendHandler, UserRequestFilter},
handler::{UserListerBackendHandler, UserRequestFilter},
ldap::{
error::{LdapError, LdapResult},
utils::{
@@ -13,6 +13,7 @@ use crate::domain::{
get_user_id_from_distinguished_name, map_user_field, LdapInfo, UserFieldType,
},
},
schema::{PublicSchema, SchemaUserAttributeExtractor},
types::{GroupDetails, User, UserAndGroups, UserColumn, UserId},
};
@@ -22,7 +23,7 @@ pub fn get_user_attribute(
base_dn_str: &str,
groups: Option<&[GroupDetails]>,
ignored_user_attributes: &[String],
schema: &Schema,
schema: &PublicSchema,
) -> Option<Vec<Vec<u8>>> {
let attribute = attribute.to_ascii_lowercase();
let attribute_values = match attribute.as_str() {
@@ -37,13 +38,21 @@ pub fn get_user_attribute(
"uid" | "user_id" | "id" => vec![user.user_id.to_string().into_bytes()],
"entryuuid" | "uuid" => vec![user.uuid.to_string().into_bytes()],
"mail" | "email" => vec![user.email.clone().into_bytes()],
"givenname" | "first_name" | "firstname" => {
get_custom_attribute(&user.attributes, "first_name", schema)?
}
"sn" | "last_name" | "lastname" => {
get_custom_attribute(&user.attributes, "last_name", schema)?
}
"jpegphoto" | "avatar" => get_custom_attribute(&user.attributes, "avatar", schema)?,
"givenname" | "first_name" | "firstname" => get_custom_attribute::<
SchemaUserAttributeExtractor,
>(
&user.attributes, "first_name", schema
)?,
"sn" | "last_name" | "lastname" => get_custom_attribute::<SchemaUserAttributeExtractor>(
&user.attributes,
"last_name",
schema,
)?,
"jpegphoto" | "avatar" => get_custom_attribute::<SchemaUserAttributeExtractor>(
&user.attributes,
"avatar",
schema,
)?,
"memberof" => groups
.into_iter()
.flatten()
@@ -67,13 +76,20 @@ pub fn get_user_attribute(
attribute
)
}
_ => {
attr => {
if !ignored_user_attributes.contains(&attribute) {
warn!(
r#"Ignoring unrecognized group attribute: {}\n\
match get_custom_attribute::<SchemaUserAttributeExtractor>(
&user.attributes,
attr,
schema,
) {
Some(v) => return Some(v),
None => warn!(
r#"Ignoring unrecognized group attribute: {}\n\
To disable this warning, add it to "ignored_user_attributes" in the config."#,
attribute
);
attr
),
};
}
return None;
}
@@ -103,7 +119,7 @@ fn make_ldap_search_user_result_entry(
attributes: &[String],
groups: Option<&[GroupDetails]>,
ignored_user_attributes: &[String],
schema: &Schema,
schema: &PublicSchema,
) -> LdapSearchResultEntry {
let expanded_attributes = expand_user_attribute_wildcards(attributes);
let dn = format!("uid={},ou=people,{}", user.user_id.as_str(), base_dn_str);
@@ -253,7 +269,7 @@ pub fn convert_users_to_ldap_op<'a>(
users: Vec<UserAndGroups>,
attributes: &'a [String],
ldap_info: &'a LdapInfo,
schema: &'a Schema,
schema: &'a PublicSchema,
) -> impl Iterator<Item = LdapOp> + 'a {
users.into_iter().map(move |u| {
LdapOp::SearchResultEntry(make_ldap_search_user_result_entry(

View File

@@ -4,8 +4,9 @@ use ldap3_proto::{proto::LdapSubstringFilter, LdapResultCode};
use tracing::{debug, instrument, warn};
use crate::domain::{
handler::{Schema, SubStringFilter},
handler::SubStringFilter,
ldap::error::{LdapError, LdapResult},
schema::{PublicSchema, SchemaAttributeExtractor},
types::{AttributeType, AttributeValue, JpegPhoto, UserColumn, UserId},
};
@@ -195,10 +196,10 @@ pub struct LdapInfo {
pub ignored_group_attributes: Vec<String>,
}
pub fn get_custom_attribute(
pub fn get_custom_attribute<Extractor: SchemaAttributeExtractor>(
attributes: &[AttributeValue],
attribute_name: &str,
schema: &Schema,
schema: &PublicSchema,
) -> Option<Vec<Vec<u8>>> {
let convert_date = |date| {
chrono::Utc
@@ -206,8 +207,7 @@ pub fn get_custom_attribute(
.to_rfc3339()
.into_bytes()
};
schema
.user_attributes
Extractor::get_attributes(schema)
.get_attribute_type(attribute_name)
.and_then(|attribute_type| {
attributes