server: Add support for custom LDAP object classes for users and groups

This commit is contained in:
Valentin Tolmer
2024-02-05 22:20:08 +01:00
committed by nitnelave
parent fa9743be6a
commit 646fe32645
15 changed files with 323 additions and 29 deletions

View File

@@ -7,7 +7,7 @@ use crate::{
ldap::utils::{map_user_field, UserFieldType},
model::UserColumn,
schema::PublicSchema,
types::{AttributeType, GroupDetails, GroupId, JpegPhoto, UserId},
types::{AttributeType, GroupDetails, GroupId, JpegPhoto, LdapObjectClass, UserId},
},
infra::{
access_control::{ReadonlyBackendHandler, UserReadableBackendHandler},
@@ -523,26 +523,32 @@ impl<Handler: BackendHandler> From<DomainAttributeSchema> for AttributeSchema<Ha
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct AttributeList<Handler: BackendHandler> {
schema: DomainAttributeList,
attributes: DomainAttributeList,
extra_classes: Vec<LdapObjectClass>,
_phantom: std::marker::PhantomData<Box<Handler>>,
}
#[graphql_object(context = Context<Handler>)]
impl<Handler: BackendHandler> AttributeList<Handler> {
fn attributes(&self) -> Vec<AttributeSchema<Handler>> {
self.schema
self.attributes
.attributes
.clone()
.into_iter()
.map(Into::into)
.collect()
}
fn extra_ldap_object_classes(&self) -> Vec<String> {
self.extra_classes.iter().map(|c| c.to_string()).collect()
}
}
impl<Handler: BackendHandler> From<DomainAttributeList> for AttributeList<Handler> {
fn from(value: DomainAttributeList) -> Self {
impl<Handler: BackendHandler> AttributeList<Handler> {
fn new(attributes: DomainAttributeList, extra_classes: Vec<LdapObjectClass>) -> Self {
Self {
schema: value,
attributes,
extra_classes,
_phantom: std::marker::PhantomData,
}
}
@@ -557,10 +563,16 @@ pub struct Schema<Handler: BackendHandler> {
#[graphql_object(context = Context<Handler>)]
impl<Handler: BackendHandler> Schema<Handler> {
fn user_schema(&self) -> AttributeList<Handler> {
self.schema.get_schema().user_attributes.clone().into()
AttributeList::<Handler>::new(
self.schema.get_schema().user_attributes.clone(),
self.schema.get_schema().extra_user_object_classes.clone(),
)
}
fn group_schema(&self) -> AttributeList<Handler> {
self.schema.get_schema().group_attributes.clone().into()
AttributeList::<Handler>::new(
self.schema.get_schema().group_attributes.clone(),
self.schema.get_schema().extra_group_object_classes.clone(),
)
}
}
@@ -670,7 +682,7 @@ mod tests {
use crate::{
domain::{
handler::AttributeList,
types::{AttributeName, AttributeType, Serialized},
types::{AttributeName, AttributeType, LdapObjectClass, Serialized},
},
infra::{
access_control::{Permission, ValidationResults},
@@ -755,6 +767,11 @@ mod tests {
is_hardcoded: false,
}],
},
extra_user_object_classes: vec![
LdapObjectClass::from("customUserClass"),
LdapObjectClass::from("myUserClass"),
],
extra_group_object_classes: vec![LdapObjectClass::from("customGroupClass")],
})
});
mock.expect_get_user_details()
@@ -946,6 +963,7 @@ mod tests {
isEditable
isHardcoded
}
extraLdapObjectClasses
}
groupSchema {
attributes {
@@ -956,6 +974,7 @@ mod tests {
isEditable
isHardcoded
}
extraLdapObjectClasses
}
}
}"#;
@@ -1040,7 +1059,8 @@ mod tests {
"isEditable": false,
"isHardcoded": true,
},
]
],
"extraLdapObjectClasses": ["customUserClass"],
},
"groupSchema": {
"attributes": [
@@ -1076,7 +1096,8 @@ mod tests {
"isEditable": false,
"isHardcoded": true,
},
]
],
"extraLdapObjectClasses": [],
}
}
}),
@@ -1093,6 +1114,7 @@ mod tests {
attributes {
name
}
extraLdapObjectClasses
}
}
}"#;
@@ -1114,6 +1136,8 @@ mod tests {
group_attributes: AttributeList {
attributes: Vec::new(),
},
extra_user_object_classes: vec![LdapObjectClass::from("customUserClass")],
extra_group_object_classes: Vec::new(),
})
});
@@ -1139,7 +1163,8 @@ mod tests {
{"name": "mail"},
{"name": "user_id"},
{"name": "uuid"},
]
],
"extraLdapObjectClasses": ["customUserClass"],
}
}
} ),

View File

@@ -1290,7 +1290,8 @@ mod tests {
b"inetOrgPerson".to_vec(),
b"posixAccount".to_vec(),
b"mailAccount".to_vec(),
b"person".to_vec()
b"person".to_vec(),
b"customUserClass".to_vec(),
]
},
LdapPartialAttribute {
@@ -1332,7 +1333,8 @@ mod tests {
b"inetOrgPerson".to_vec(),
b"posixAccount".to_vec(),
b"mailAccount".to_vec(),
b"person".to_vec()
b"person".to_vec(),
b"customUserClass".to_vec(),
]
},
LdapPartialAttribute {
@@ -1919,7 +1921,8 @@ mod tests {
b"inetOrgPerson".to_vec(),
b"posixAccount".to_vec(),
b"mailAccount".to_vec(),
b"person".to_vec()
b"person".to_vec(),
b"customUserClass".to_vec(),
]
},]
}),
@@ -1983,7 +1986,8 @@ mod tests {
b"inetOrgPerson".to_vec(),
b"posixAccount".to_vec(),
b"mailAccount".to_vec(),
b"person".to_vec()
b"person".to_vec(),
b"customUserClass".to_vec(),
]
},
LdapPartialAttribute {
@@ -2068,6 +2072,7 @@ mod tests {
b"posixAccount".to_vec(),
b"mailAccount".to_vec(),
b"person".to_vec(),
b"customUserClass".to_vec(),
],
},
LdapPartialAttribute {
@@ -2849,6 +2854,11 @@ mod tests {
is_hardcoded: false,
}],
},
extra_user_object_classes: vec![
LdapObjectClass::from("customUserClass"),
LdapObjectClass::from("myUserClass"),
],
extra_group_object_classes: vec![LdapObjectClass::from("customGroupClass")],
})
});
let mut ldap_handler = setup_bound_readonly_handler(mock).await;

View File

@@ -47,6 +47,10 @@ mockall::mock! {
async fn add_group_attribute(&self, request: CreateAttributeRequest) -> Result<()>;
async fn delete_user_attribute(&self, name: &AttributeName) -> Result<()>;
async fn delete_group_attribute(&self, name: &AttributeName) -> Result<()>;
async fn add_user_object_class(&self, request: &LdapObjectClass) -> Result<()>;
async fn add_group_object_class(&self, request: &LdapObjectClass) -> Result<()>;
async fn delete_user_object_class(&self, name: &LdapObjectClass) -> Result<()>;
async fn delete_group_object_class(&self, name: &LdapObjectClass) -> Result<()>;
}
#[async_trait]
impl BackendHandler for TestBackendHandler {}
@@ -102,6 +106,8 @@ pub fn setup_default_schema(mock: &mut MockTestBackendHandler) {
group_attributes: AttributeList {
attributes: Vec::new(),
},
extra_user_object_classes: vec![LdapObjectClass::from("customUserClass")],
extra_group_object_classes: Vec::new(),
})
});
}