mirror of
https://github.com/lldap/lldap.git
synced 2026-06-10 05:20:33 +00:00
server: prevent attributes with conflicting types across users/groups (#1426)
Before creating a user attribute, check if a group attribute with the same name exists with a different type (and vice versa). Return an error if the types conflict, as LDAP requires each attribute name to have a single associated type (RFC 4512). Partial fix for #1202 Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
This commit is contained in:
@@ -29,28 +29,80 @@ impl ReadSchemaBackendHandler for SqlBackendHandler {
|
||||
#[async_trait]
|
||||
impl SchemaBackendHandler for SqlBackendHandler {
|
||||
async fn add_user_attribute(&self, request: CreateAttributeRequest) -> Result<()> {
|
||||
let new_attribute = model::user_attribute_schema::ActiveModel {
|
||||
attribute_name: Set(request.name),
|
||||
attribute_type: Set(request.attribute_type),
|
||||
is_list: Set(request.is_list),
|
||||
is_user_visible: Set(request.is_visible),
|
||||
is_user_editable: Set(request.is_editable),
|
||||
is_hardcoded: Set(false),
|
||||
};
|
||||
new_attribute.insert(&self.sql_pool).await?;
|
||||
self.sql_pool
|
||||
.transaction::<_, (), DomainError>(|transaction| {
|
||||
Box::pin(async move {
|
||||
// Check for conflicting group attribute with the same name but different type.
|
||||
// Done inside the transaction to prevent TOCTOU races.
|
||||
let schema =
|
||||
Self::get_schema_with_transaction(transaction).await?;
|
||||
if let Some(group_attr) = schema
|
||||
.group_attributes
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|a| a.name == request.name)
|
||||
{
|
||||
if group_attr.attribute_type != request.attribute_type {
|
||||
return Err(DomainError::InternalError(format!(
|
||||
"A group attribute '{}' already exists with type {:?}, \
|
||||
cannot create a user attribute with type {:?}. \
|
||||
LDAP requires each attribute name to have a single type.",
|
||||
request.name, group_attr.attribute_type, request.attribute_type
|
||||
)));
|
||||
}
|
||||
}
|
||||
let new_attribute = model::user_attribute_schema::ActiveModel {
|
||||
attribute_name: Set(request.name),
|
||||
attribute_type: Set(request.attribute_type),
|
||||
is_list: Set(request.is_list),
|
||||
is_user_visible: Set(request.is_visible),
|
||||
is_user_editable: Set(request.is_editable),
|
||||
is_hardcoded: Set(false),
|
||||
};
|
||||
new_attribute.insert(transaction).await?;
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_group_attribute(&self, request: CreateAttributeRequest) -> Result<()> {
|
||||
let new_attribute = model::group_attribute_schema::ActiveModel {
|
||||
attribute_name: Set(request.name),
|
||||
attribute_type: Set(request.attribute_type),
|
||||
is_list: Set(request.is_list),
|
||||
is_group_visible: Set(request.is_visible),
|
||||
is_group_editable: Set(request.is_editable),
|
||||
is_hardcoded: Set(false),
|
||||
};
|
||||
new_attribute.insert(&self.sql_pool).await?;
|
||||
self.sql_pool
|
||||
.transaction::<_, (), DomainError>(|transaction| {
|
||||
Box::pin(async move {
|
||||
// Check for conflicting user attribute with the same name but different type.
|
||||
// Done inside the transaction to prevent TOCTOU races.
|
||||
let schema =
|
||||
Self::get_schema_with_transaction(transaction).await?;
|
||||
if let Some(user_attr) = schema
|
||||
.user_attributes
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|a| a.name == request.name)
|
||||
{
|
||||
if user_attr.attribute_type != request.attribute_type {
|
||||
return Err(DomainError::InternalError(format!(
|
||||
"A user attribute '{}' already exists with type {:?}, \
|
||||
cannot create a group attribute with type {:?}. \
|
||||
LDAP requires each attribute name to have a single type.",
|
||||
request.name, user_attr.attribute_type, request.attribute_type
|
||||
)));
|
||||
}
|
||||
}
|
||||
let new_attribute = model::group_attribute_schema::ActiveModel {
|
||||
attribute_name: Set(request.name),
|
||||
attribute_type: Set(request.attribute_type),
|
||||
is_list: Set(request.is_list),
|
||||
is_group_visible: Set(request.is_visible),
|
||||
is_group_editable: Set(request.is_editable),
|
||||
is_hardcoded: Set(false),
|
||||
};
|
||||
new_attribute.insert(transaction).await?;
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user