server: make attributes names, group names and emails case insensitive
In addition, group names and emails keep their casing
This commit is contained in:
committed by
nitnelave
parent
71d37b9e5e
commit
272c84c574
@@ -12,7 +12,7 @@ use crate::domain::{
|
||||
UpdateUserRequest, UserBackendHandler, UserListerBackendHandler, UserRequestFilter,
|
||||
},
|
||||
schema::PublicSchema,
|
||||
types::{Group, GroupDetails, GroupId, User, UserAndGroups, UserId},
|
||||
types::{AttributeName, Group, GroupDetails, GroupId, GroupName, User, UserAndGroups, UserId},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
@@ -110,8 +110,8 @@ pub trait AdminBackendHandler:
|
||||
async fn delete_group(&self, group_id: GroupId) -> Result<()>;
|
||||
async fn add_user_attribute(&self, request: CreateAttributeRequest) -> Result<()>;
|
||||
async fn add_group_attribute(&self, request: CreateAttributeRequest) -> Result<()>;
|
||||
async fn delete_user_attribute(&self, name: &str) -> Result<()>;
|
||||
async fn delete_group_attribute(&self, name: &str) -> Result<()>;
|
||||
async fn delete_user_attribute(&self, name: &AttributeName) -> Result<()>;
|
||||
async fn delete_group_attribute(&self, name: &AttributeName) -> Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -181,10 +181,10 @@ impl<Handler: BackendHandler> AdminBackendHandler for Handler {
|
||||
async fn add_group_attribute(&self, request: CreateAttributeRequest) -> Result<()> {
|
||||
<Handler as SchemaBackendHandler>::add_group_attribute(self, request).await
|
||||
}
|
||||
async fn delete_user_attribute(&self, name: &str) -> Result<()> {
|
||||
async fn delete_user_attribute(&self, name: &AttributeName) -> Result<()> {
|
||||
<Handler as SchemaBackendHandler>::delete_user_attribute(self, name).await
|
||||
}
|
||||
async fn delete_group_attribute(&self, name: &str) -> Result<()> {
|
||||
async fn delete_group_attribute(&self, name: &AttributeName) -> Result<()> {
|
||||
<Handler as SchemaBackendHandler>::delete_group_attribute(self, name).await
|
||||
}
|
||||
}
|
||||
@@ -264,19 +264,23 @@ impl<Handler: BackendHandler> AccessControlledBackendHandler<Handler> {
|
||||
Ok(self.get_permissions_from_groups(user_id, user_groups.iter().map(|g| &g.display_name)))
|
||||
}
|
||||
|
||||
pub fn get_permissions_from_groups<'a, Groups: Iterator<Item = &'a String> + Clone + 'a>(
|
||||
pub fn get_permissions_from_groups<Groups, T>(
|
||||
&self,
|
||||
user_id: UserId,
|
||||
groups: Groups,
|
||||
) -> ValidationResults {
|
||||
let is_in_group = |name| groups.clone().any(|g| g == name);
|
||||
) -> ValidationResults
|
||||
where
|
||||
Groups: Iterator<Item = T> + Clone,
|
||||
T: AsRef<GroupName>,
|
||||
{
|
||||
let is_in_group = |name: GroupName| groups.clone().any(|g| *g.as_ref() == name);
|
||||
ValidationResults {
|
||||
user: user_id,
|
||||
permission: if is_in_group("lldap_admin") {
|
||||
permission: if is_in_group("lldap_admin".into()) {
|
||||
Permission::Admin
|
||||
} else if is_in_group("lldap_password_manager") {
|
||||
} else if is_in_group("lldap_password_manager".into()) {
|
||||
Permission::PasswordManager
|
||||
} else if is_in_group("lldap_strict_readonly") {
|
||||
} else if is_in_group("lldap_strict_readonly".into()) {
|
||||
Permission::Readonly
|
||||
} else {
|
||||
Permission::Regular
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{
|
||||
error::DomainError,
|
||||
handler::{BackendHandler, BindRequest, LoginHandler, UserRequestFilter},
|
||||
opaque_handler::OpaqueHandler,
|
||||
types::{GroupDetails, UserColumn, UserId},
|
||||
types::{GroupDetails, GroupName, UserColumn, UserId},
|
||||
},
|
||||
infra::{
|
||||
access_control::{ReadonlyBackendHandler, UserReadableBackendHandler, ValidationResults},
|
||||
@@ -58,7 +58,10 @@ async fn create_jwt<Handler: TcpBackendHandler>(
|
||||
exp: Utc::now() + chrono::Duration::days(1),
|
||||
iat: Utc::now(),
|
||||
user: user.to_string(),
|
||||
groups: groups.into_iter().map(|g| g.display_name).collect(),
|
||||
groups: groups
|
||||
.into_iter()
|
||||
.map(|g| g.display_name.into_string())
|
||||
.collect(),
|
||||
};
|
||||
let expiry = claims.exp.naive_utc();
|
||||
let header = jwt::Header {
|
||||
@@ -187,7 +190,7 @@ where
|
||||
user.display_name
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| user.user_id.as_str()),
|
||||
&user.email,
|
||||
user.email.as_str(),
|
||||
&token,
|
||||
&data.server_url,
|
||||
&data.mail_options,
|
||||
@@ -503,7 +506,7 @@ where
|
||||
.get_user_groups(&user_id)
|
||||
.await?
|
||||
.iter()
|
||||
.any(|g| g.display_name == "lldap_admin");
|
||||
.any(|g| g.display_name == "lldap_admin".into());
|
||||
if !validation_result.can_change_password(&user_id, user_is_admin) {
|
||||
return Err(TcpError::UnauthorizedError(
|
||||
"Not authorized to change the user's password".to_string(),
|
||||
@@ -633,7 +636,11 @@ pub(crate) fn check_if_token_is_valid<Backend: BackendHandler>(
|
||||
}
|
||||
Ok(state.backend_handler.get_permissions_from_groups(
|
||||
UserId::new(&token.claims().user),
|
||||
token.claims().groups.iter(),
|
||||
token
|
||||
.claims()
|
||||
.groups
|
||||
.iter()
|
||||
.map(|s| GroupName::from(s.as_str())),
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
domain::types::UserId,
|
||||
domain::types::{AttributeName, UserId},
|
||||
infra::cli::{GeneralConfigOpts, LdapsOpts, RunOpts, SmtpEncryption, SmtpOpts, TestEmailOpts},
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
@@ -86,9 +86,9 @@ pub struct Configuration {
|
||||
#[builder(default = r#"String::from("sqlite://users.db?mode=rwc")"#)]
|
||||
pub database_url: String,
|
||||
#[builder(default)]
|
||||
pub ignored_user_attributes: Vec<String>,
|
||||
pub ignored_user_attributes: Vec<AttributeName>,
|
||||
#[builder(default)]
|
||||
pub ignored_group_attributes: Vec<String>,
|
||||
pub ignored_group_attributes: Vec<AttributeName>,
|
||||
#[builder(default = "false")]
|
||||
pub verbose: bool,
|
||||
#[builder(default = r#"String::from("server_key")"#)]
|
||||
|
||||
@@ -5,8 +5,8 @@ use crate::{
|
||||
CreateUserRequest, UpdateGroupRequest, UpdateUserRequest,
|
||||
},
|
||||
types::{
|
||||
AttributeType, AttributeValue as DomainAttributeValue, GroupId, JpegPhoto, Serialized,
|
||||
UserId,
|
||||
AttributeName, AttributeType, AttributeValue as DomainAttributeValue, GroupId,
|
||||
JpegPhoto, Serialized, UserId,
|
||||
},
|
||||
},
|
||||
infra::{
|
||||
@@ -149,7 +149,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
handler
|
||||
.create_user(CreateUserRequest {
|
||||
user_id: user_id.clone(),
|
||||
email: user.email,
|
||||
email: user.email.into(),
|
||||
display_name: user.display_name,
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
@@ -225,12 +225,17 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
handler
|
||||
.update_user(UpdateUserRequest {
|
||||
user_id,
|
||||
email: user.email,
|
||||
email: user.email.map(Into::into),
|
||||
display_name: user.display_name,
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
avatar,
|
||||
delete_attributes: user.remove_attributes.unwrap_or_default(),
|
||||
delete_attributes: user
|
||||
.remove_attributes
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
insert_attributes,
|
||||
})
|
||||
.instrument(span)
|
||||
@@ -263,8 +268,13 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
handler
|
||||
.update_group(UpdateGroupRequest {
|
||||
group_id: GroupId(group.id),
|
||||
display_name: group.display_name,
|
||||
delete_attributes: group.remove_attributes.unwrap_or_default(),
|
||||
display_name: group.display_name.map(Into::into),
|
||||
delete_attributes: group
|
||||
.remove_attributes
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect(),
|
||||
insert_attributes,
|
||||
})
|
||||
.instrument(span)
|
||||
@@ -377,7 +387,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
))?;
|
||||
handler
|
||||
.add_user_attribute(CreateAttributeRequest {
|
||||
name,
|
||||
name: name.into(),
|
||||
attribute_type,
|
||||
is_list,
|
||||
is_visible,
|
||||
@@ -408,7 +418,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
))?;
|
||||
handler
|
||||
.add_group_attribute(CreateAttributeRequest {
|
||||
name,
|
||||
name: name.into(),
|
||||
attribute_type,
|
||||
is_list,
|
||||
is_visible,
|
||||
@@ -424,6 +434,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
name: String,
|
||||
) -> FieldResult<Success> {
|
||||
let span = debug_span!("[GraphQL mutation] delete_user_attribute");
|
||||
let name = AttributeName::from(name);
|
||||
span.in_scope(|| {
|
||||
debug!(?name);
|
||||
});
|
||||
@@ -438,9 +449,9 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
.get_schema()
|
||||
.user_attributes
|
||||
.get_attribute_schema(&name)
|
||||
.ok_or_else(|| anyhow!("Attribute {} is not defined in the schema", name))?;
|
||||
.ok_or_else(|| anyhow!("Attribute {} is not defined in the schema", &name))?;
|
||||
if attribute_schema.is_hardcoded {
|
||||
return Err(anyhow!("Permission denied: Attribute {} cannot be deleted", name).into());
|
||||
return Err(anyhow!("Permission denied: Attribute {} cannot be deleted", &name).into());
|
||||
}
|
||||
handler
|
||||
.delete_user_attribute(&name)
|
||||
@@ -454,6 +465,7 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
name: String,
|
||||
) -> FieldResult<Success> {
|
||||
let span = debug_span!("[GraphQL mutation] delete_group_attribute");
|
||||
let name = AttributeName::from(name);
|
||||
span.in_scope(|| {
|
||||
debug!(?name);
|
||||
});
|
||||
@@ -468,9 +480,9 @@ impl<Handler: BackendHandler> Mutation<Handler> {
|
||||
.get_schema()
|
||||
.group_attributes
|
||||
.get_attribute_schema(&name)
|
||||
.ok_or_else(|| anyhow!("Attribute {} is not defined in the schema", name))?;
|
||||
.ok_or_else(|| anyhow!("Attribute {} is not defined in the schema", &name))?;
|
||||
if attribute_schema.is_hardcoded {
|
||||
return Err(anyhow!("Permission denied: Attribute {} cannot be deleted", name).into());
|
||||
return Err(anyhow!("Permission denied: Attribute {} cannot be deleted", &name).into());
|
||||
}
|
||||
handler
|
||||
.delete_group_attribute(&name)
|
||||
@@ -496,7 +508,7 @@ async fn create_group_with_details<Handler: BackendHandler>(
|
||||
.map(|attr| deserialize_attribute(&schema.get_schema().group_attributes, attr, true))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let request = CreateGroupRequest {
|
||||
display_name: request.display_name,
|
||||
display_name: request.display_name.into(),
|
||||
attributes,
|
||||
};
|
||||
let group_id = handler.create_group(request).await?;
|
||||
@@ -512,8 +524,9 @@ fn deserialize_attribute(
|
||||
attribute: AttributeValue,
|
||||
is_admin: bool,
|
||||
) -> FieldResult<DomainAttributeValue> {
|
||||
let attribute_name = AttributeName::from(attribute.name.as_str());
|
||||
let attribute_schema = attribute_schema
|
||||
.get_attribute_schema(&attribute.name)
|
||||
.get_attribute_schema(&attribute_name)
|
||||
.ok_or_else(|| anyhow!("Attribute {} is not defined in the schema", attribute.name))?;
|
||||
if !is_admin && !attribute_schema.is_editable {
|
||||
return Err(anyhow!(
|
||||
@@ -571,7 +584,7 @@ fn deserialize_attribute(
|
||||
),
|
||||
};
|
||||
Ok(DomainAttributeValue {
|
||||
name: attribute.name,
|
||||
name: attribute_name,
|
||||
value: deserialized_values,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ use crate::{
|
||||
PublicSchema, SchemaAttributeExtractor, SchemaGroupAttributeExtractor,
|
||||
SchemaUserAttributeExtractor,
|
||||
},
|
||||
types::{AttributeType, GroupDetails, GroupId, JpegPhoto, UserColumn, UserId},
|
||||
types::{
|
||||
AttributeName, AttributeType, GroupDetails, GroupId, JpegPhoto, UserColumn, UserId,
|
||||
},
|
||||
},
|
||||
infra::{
|
||||
access_control::{ReadonlyBackendHandler, UserReadableBackendHandler},
|
||||
@@ -50,7 +52,7 @@ impl TryInto<DomainRequestFilter> for RequestFilter {
|
||||
self.member_of_id,
|
||||
) {
|
||||
(Some(eq), None, None, None, None, None) => {
|
||||
match map_user_field(&eq.field.to_ascii_lowercase()) {
|
||||
match map_user_field(&eq.field.as_str().into()) {
|
||||
UserFieldType::NoMatch => Err(format!("Unknown request filter: {}", &eq.field)),
|
||||
UserFieldType::PrimaryField(UserColumn::UserId) => {
|
||||
Ok(DomainRequestFilter::UserId(UserId::new(&eq.value)))
|
||||
@@ -59,7 +61,7 @@ impl TryInto<DomainRequestFilter> for RequestFilter {
|
||||
Ok(DomainRequestFilter::Equality(column, eq.value))
|
||||
}
|
||||
UserFieldType::Attribute(column) => Ok(DomainRequestFilter::AttributeEquality(
|
||||
column.to_owned(),
|
||||
AttributeName::from(column),
|
||||
eq.value,
|
||||
)),
|
||||
}
|
||||
@@ -77,7 +79,9 @@ impl TryInto<DomainRequestFilter> for RequestFilter {
|
||||
(None, None, None, Some(not), None, None) => {
|
||||
Ok(DomainRequestFilter::Not(Box::new((*not).try_into()?)))
|
||||
}
|
||||
(None, None, None, None, Some(group), None) => Ok(DomainRequestFilter::MemberOf(group)),
|
||||
(None, None, None, None, Some(group), None) => {
|
||||
Ok(DomainRequestFilter::MemberOf(group.into()))
|
||||
}
|
||||
(None, None, None, None, None, Some(group_id)) => {
|
||||
Ok(DomainRequestFilter::MemberOfId(GroupId(group_id)))
|
||||
}
|
||||
@@ -228,7 +232,7 @@ impl<Handler: BackendHandler> User<Handler> {
|
||||
}
|
||||
|
||||
fn email(&self) -> &str {
|
||||
&self.user.email
|
||||
self.user.email.as_str()
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
@@ -239,7 +243,7 @@ impl<Handler: BackendHandler> User<Handler> {
|
||||
self.user
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|a| a.name == "first_name")
|
||||
.find(|a| a.name.as_str() == "first_name")
|
||||
.map(|a| a.value.unwrap())
|
||||
.unwrap_or("")
|
||||
}
|
||||
@@ -248,7 +252,7 @@ impl<Handler: BackendHandler> User<Handler> {
|
||||
self.user
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|a| a.name == "last_name")
|
||||
.find(|a| a.name.as_str() == "last_name")
|
||||
.map(|a| a.value.unwrap())
|
||||
.unwrap_or("")
|
||||
}
|
||||
@@ -257,7 +261,7 @@ impl<Handler: BackendHandler> User<Handler> {
|
||||
self.user
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|a| a.name == "avatar")
|
||||
.find(|a| a.name.as_str() == "avatar")
|
||||
.map(|a| String::from(&a.value.unwrap::<JpegPhoto>()))
|
||||
}
|
||||
|
||||
@@ -384,7 +388,7 @@ impl<Handler: BackendHandler> From<GroupDetails> for Group<Handler> {
|
||||
fn from(group_details: GroupDetails) -> Self {
|
||||
Self {
|
||||
group_id: group_details.group_id.0,
|
||||
display_name: group_details.display_name,
|
||||
display_name: group_details.display_name.to_string(),
|
||||
creation_date: group_details.creation_date,
|
||||
uuid: group_details.uuid.into_string(),
|
||||
attributes: group_details.attributes,
|
||||
@@ -398,7 +402,7 @@ impl<Handler: BackendHandler> From<DomainGroup> for Group<Handler> {
|
||||
fn from(group: DomainGroup) -> Self {
|
||||
Self {
|
||||
group_id: group.id.0,
|
||||
display_name: group.display_name,
|
||||
display_name: group.display_name.to_string(),
|
||||
creation_date: group.creation_date,
|
||||
uuid: group.uuid.into_string(),
|
||||
attributes: group.attributes,
|
||||
@@ -417,7 +421,7 @@ pub struct AttributeSchema<Handler: BackendHandler> {
|
||||
#[graphql_object(context = Context<Handler>)]
|
||||
impl<Handler: BackendHandler> AttributeSchema<Handler> {
|
||||
fn name(&self) -> String {
|
||||
self.schema.name.clone()
|
||||
self.schema.name.to_string()
|
||||
}
|
||||
fn attribute_type(&self) -> AttributeType {
|
||||
self.schema.attribute_type
|
||||
@@ -509,7 +513,7 @@ impl<Handler: BackendHandler, Extractor: SchemaAttributeExtractor>
|
||||
AttributeValue<Handler, Extractor>
|
||||
{
|
||||
fn name(&self) -> &str {
|
||||
&self.attribute.name
|
||||
self.attribute.name.as_str()
|
||||
}
|
||||
async fn value(&self, context: &Context<Handler>) -> FieldResult<Vec<String>> {
|
||||
let handler = context
|
||||
@@ -648,7 +652,7 @@ mod tests {
|
||||
user_attributes: DomainAttributeList {
|
||||
attributes: vec![
|
||||
DomainAttributeSchema {
|
||||
name: "first_name".to_owned(),
|
||||
name: "first_name".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
@@ -656,7 +660,7 @@ mod tests {
|
||||
is_hardcoded: true,
|
||||
},
|
||||
DomainAttributeSchema {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
@@ -667,7 +671,7 @@ mod tests {
|
||||
},
|
||||
group_attributes: DomainAttributeList {
|
||||
attributes: vec![DomainAttributeSchema {
|
||||
name: "club_name".to_owned(),
|
||||
name: "club_name".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
@@ -682,16 +686,16 @@ mod tests {
|
||||
.return_once(|_| {
|
||||
Ok(DomainUser {
|
||||
user_id: UserId::new("bob"),
|
||||
email: "bob@bobbers.on".to_string(),
|
||||
email: "bob@bobbers.on".into(),
|
||||
creation_date: chrono::Utc.timestamp_millis_opt(42).unwrap().naive_utc(),
|
||||
uuid: crate::uuid!("b1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: vec![
|
||||
DomainAttributeValue {
|
||||
name: "first_name".to_owned(),
|
||||
name: "first_name".into(),
|
||||
value: Serialized::from("Bob"),
|
||||
},
|
||||
DomainAttributeValue {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
value: Serialized::from("Bobberson"),
|
||||
},
|
||||
],
|
||||
@@ -701,17 +705,17 @@ mod tests {
|
||||
let mut groups = HashSet::new();
|
||||
groups.insert(GroupDetails {
|
||||
group_id: GroupId(3),
|
||||
display_name: "Bobbersons".to_string(),
|
||||
display_name: "Bobbersons".into(),
|
||||
creation_date: chrono::Utc.timestamp_nanos(42).naive_utc(),
|
||||
uuid: crate::uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: vec![DomainAttributeValue {
|
||||
name: "club_name".to_owned(),
|
||||
name: "club_name".into(),
|
||||
value: Serialized::from("Gang of Four"),
|
||||
}],
|
||||
});
|
||||
groups.insert(GroupDetails {
|
||||
group_id: GroupId(7),
|
||||
display_name: "Jefferees".to_string(),
|
||||
display_name: "Jefferees".into(),
|
||||
creation_date: chrono::Utc.timestamp_nanos(12).naive_utc(),
|
||||
uuid: crate::uuid!("b1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
@@ -800,7 +804,7 @@ mod tests {
|
||||
"robert@bobbers.on".to_owned(),
|
||||
),
|
||||
DomainRequestFilter::AttributeEquality(
|
||||
"first_name".to_owned(),
|
||||
AttributeName::from("first_name"),
|
||||
"robert".to_owned(),
|
||||
),
|
||||
]))),
|
||||
@@ -811,7 +815,7 @@ mod tests {
|
||||
DomainUserAndGroups {
|
||||
user: DomainUser {
|
||||
user_id: UserId::new("bob"),
|
||||
email: "bob@bobbers.on".to_owned(),
|
||||
email: "bob@bobbers.on".into(),
|
||||
..Default::default()
|
||||
},
|
||||
groups: None,
|
||||
@@ -819,7 +823,7 @@ mod tests {
|
||||
DomainUserAndGroups {
|
||||
user: DomainUser {
|
||||
user_id: UserId::new("robert"),
|
||||
email: "robert@bobbers.on".to_owned(),
|
||||
email: "robert@bobbers.on".into(),
|
||||
..Default::default()
|
||||
},
|
||||
groups: None,
|
||||
@@ -1022,7 +1026,7 @@ mod tests {
|
||||
Ok(crate::domain::handler::Schema {
|
||||
user_attributes: AttributeList {
|
||||
attributes: vec![crate::domain::handler::AttributeSchema {
|
||||
name: "invisible".to_owned(),
|
||||
name: "invisible".into(),
|
||||
attribute_type: AttributeType::JpegPhoto,
|
||||
is_list: false,
|
||||
is_visible: false,
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::{
|
||||
},
|
||||
opaque_handler::OpaqueHandler,
|
||||
schema::PublicSchema,
|
||||
types::{Group, JpegPhoto, UserAndGroups, UserId},
|
||||
types::{AttributeName, Email, Group, JpegPhoto, UserAndGroups, UserId},
|
||||
},
|
||||
infra::access_control::{
|
||||
AccessControlledBackendHandler, AdminBackendHandler, UserAndGroupListerBackendHandler,
|
||||
@@ -233,8 +233,8 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
pub fn new(
|
||||
backend_handler: AccessControlledBackendHandler<Backend>,
|
||||
mut ldap_base_dn: String,
|
||||
ignored_user_attributes: Vec<String>,
|
||||
ignored_group_attributes: Vec<String>,
|
||||
ignored_user_attributes: Vec<AttributeName>,
|
||||
ignored_group_attributes: Vec<AttributeName>,
|
||||
) -> Self {
|
||||
ldap_base_dn.make_ascii_lowercase();
|
||||
Self {
|
||||
@@ -354,7 +354,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
),
|
||||
})?
|
||||
.iter()
|
||||
.any(|g| g.display_name == "lldap_admin");
|
||||
.any(|g| g.display_name == "lldap_admin".into());
|
||||
if !credentials.can_change_password(&uid, user_is_admin) {
|
||||
Err(LdapError {
|
||||
code: LdapResultCode::InsufficentAccessRights,
|
||||
@@ -479,7 +479,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
message: format!("Internal error while requesting user's groups: {:#?}", e),
|
||||
})?
|
||||
.iter()
|
||||
.any(|g| g.display_name == "lldap_admin");
|
||||
.any(|g| g.display_name == "lldap_admin".into());
|
||||
for change in &request.changes {
|
||||
self.handle_modify_change(&uid, &credentials, user_is_admin, change)
|
||||
.await?
|
||||
@@ -695,10 +695,12 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
backend_handler
|
||||
.create_user(CreateUserRequest {
|
||||
user_id,
|
||||
email: get_attribute("mail")
|
||||
.or_else(|| get_attribute("email"))
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
email: Email::from(
|
||||
get_attribute("mail")
|
||||
.or_else(|| get_attribute("email"))
|
||||
.transpose()?
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
display_name: get_attribute("cn").transpose()?,
|
||||
first_name: get_attribute("givenname").transpose()?,
|
||||
last_name: get_attribute("sn").transpose()?,
|
||||
@@ -857,7 +859,7 @@ mod tests {
|
||||
let mut set = HashSet::new();
|
||||
set.insert(GroupDetails {
|
||||
group_id: GroupId(42),
|
||||
display_name: group,
|
||||
display_name: group.into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
@@ -944,7 +946,7 @@ mod tests {
|
||||
let mut set = HashSet::new();
|
||||
set.insert(GroupDetails {
|
||||
group_id: GroupId(42),
|
||||
display_name: "lldap_admin".to_string(),
|
||||
display_name: "lldap_admin".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
@@ -1031,7 +1033,7 @@ mod tests {
|
||||
},
|
||||
groups: Some(vec![GroupDetails {
|
||||
group_id: GroupId(42),
|
||||
display_name: "rockstars".to_string(),
|
||||
display_name: "rockstars".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
@@ -1179,16 +1181,16 @@ mod tests {
|
||||
UserAndGroups {
|
||||
user: User {
|
||||
user_id: UserId::new("bob_1"),
|
||||
email: "bob@bobmail.bob".to_string(),
|
||||
email: "bob@bobmail.bob".into(),
|
||||
display_name: Some("Bôb Böbberson".to_string()),
|
||||
uuid: uuid!("698e1d5f-7a40-3151-8745-b9b8a37839da"),
|
||||
attributes: vec![
|
||||
AttributeValue {
|
||||
name: "first_name".to_owned(),
|
||||
name: "first_name".into(),
|
||||
value: Serialized::from("Bôb"),
|
||||
},
|
||||
AttributeValue {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
value: Serialized::from("Böbberson"),
|
||||
},
|
||||
],
|
||||
@@ -1199,19 +1201,19 @@ mod tests {
|
||||
UserAndGroups {
|
||||
user: User {
|
||||
user_id: UserId::new("jim"),
|
||||
email: "jim@cricket.jim".to_string(),
|
||||
email: "jim@cricket.jim".into(),
|
||||
display_name: Some("Jimminy Cricket".to_string()),
|
||||
attributes: vec![
|
||||
AttributeValue {
|
||||
name: "avatar".to_owned(),
|
||||
name: "avatar".into(),
|
||||
value: Serialized::from(&JpegPhoto::for_tests()),
|
||||
},
|
||||
AttributeValue {
|
||||
name: "first_name".to_owned(),
|
||||
name: "first_name".into(),
|
||||
value: Serialized::from("Jim"),
|
||||
},
|
||||
AttributeValue {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
value: Serialized::from("Cricket"),
|
||||
},
|
||||
],
|
||||
@@ -1347,7 +1349,7 @@ mod tests {
|
||||
Ok(vec![
|
||||
Group {
|
||||
id: GroupId(1),
|
||||
display_name: "group_1".to_string(),
|
||||
display_name: "group_1".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("bob"), UserId::new("john")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
@@ -1355,7 +1357,7 @@ mod tests {
|
||||
},
|
||||
Group {
|
||||
id: GroupId(3),
|
||||
display_name: "BestGroup".to_string(),
|
||||
display_name: "BestGroup".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("john")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
@@ -1426,9 +1428,9 @@ mod tests {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
mock.expect_list_groups()
|
||||
.with(eq(Some(GroupRequestFilter::And(vec![
|
||||
GroupRequestFilter::DisplayName("group_1".to_string()),
|
||||
GroupRequestFilter::DisplayName("group_1".into()),
|
||||
GroupRequestFilter::Member(UserId::new("bob")),
|
||||
GroupRequestFilter::DisplayName("rockstars".to_string()),
|
||||
GroupRequestFilter::DisplayName("rockstars".into()),
|
||||
false.into(),
|
||||
GroupRequestFilter::Uuid(uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc")),
|
||||
true.into(),
|
||||
@@ -1446,7 +1448,7 @@ mod tests {
|
||||
.times(1)
|
||||
.return_once(|_| {
|
||||
Ok(vec![Group {
|
||||
display_name: "group_1".to_string(),
|
||||
display_name: "group_1".into(),
|
||||
id: GroupId(1),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![],
|
||||
@@ -1511,13 +1513,13 @@ mod tests {
|
||||
mock.expect_list_groups()
|
||||
.with(eq(Some(GroupRequestFilter::Or(vec![
|
||||
GroupRequestFilter::Not(Box::new(GroupRequestFilter::DisplayName(
|
||||
"group_2".to_string(),
|
||||
"group_2".into(),
|
||||
))),
|
||||
]))))
|
||||
.times(1)
|
||||
.return_once(|_| {
|
||||
Ok(vec![Group {
|
||||
display_name: "group_1".to_string(),
|
||||
display_name: "group_1".into(),
|
||||
id: GroupId(1),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![],
|
||||
@@ -1554,7 +1556,7 @@ mod tests {
|
||||
mock.expect_list_groups()
|
||||
.with(eq(Some(GroupRequestFilter::And(vec![
|
||||
true.into(),
|
||||
GroupRequestFilter::DisplayName("rockstars".to_string()),
|
||||
GroupRequestFilter::DisplayName("rockstars".into()),
|
||||
]))))
|
||||
.times(1)
|
||||
.return_once(|_| Ok(vec![]));
|
||||
@@ -1598,7 +1600,7 @@ mod tests {
|
||||
mock.expect_list_groups()
|
||||
.with(eq(Some(GroupRequestFilter::Or(vec![
|
||||
GroupRequestFilter::Not(Box::new(GroupRequestFilter::DisplayName(
|
||||
"group_2".to_string(),
|
||||
"group_2".into(),
|
||||
))),
|
||||
]))))
|
||||
.times(1)
|
||||
@@ -1661,7 +1663,7 @@ mod tests {
|
||||
true.into(),
|
||||
false.into(),
|
||||
UserRequestFilter::AttributeEquality(
|
||||
"first_name".to_owned(),
|
||||
AttributeName::from("first_name"),
|
||||
"firstname".to_owned(),
|
||||
),
|
||||
false.into(),
|
||||
@@ -1765,7 +1767,7 @@ mod tests {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
mock.expect_list_users()
|
||||
.with(
|
||||
eq(Some(UserRequestFilter::MemberOf("group_1".to_string()))),
|
||||
eq(Some(UserRequestFilter::MemberOf("group_1".into()))),
|
||||
eq(false),
|
||||
)
|
||||
.times(1)
|
||||
@@ -1865,15 +1867,15 @@ mod tests {
|
||||
Ok(vec![UserAndGroups {
|
||||
user: User {
|
||||
user_id: UserId::new("bob_1"),
|
||||
email: "bob@bobmail.bob".to_string(),
|
||||
email: "bob@bobmail.bob".into(),
|
||||
display_name: Some("Bôb Böbberson".to_string()),
|
||||
attributes: vec![
|
||||
AttributeValue {
|
||||
name: "first_name".to_owned(),
|
||||
name: "first_name".into(),
|
||||
value: Serialized::from("Bôb"),
|
||||
},
|
||||
AttributeValue {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
value: Serialized::from("Böbberson"),
|
||||
},
|
||||
],
|
||||
@@ -1888,7 +1890,7 @@ mod tests {
|
||||
.return_once(|_| {
|
||||
Ok(vec![Group {
|
||||
id: GroupId(1),
|
||||
display_name: "group_1".to_string(),
|
||||
display_name: "group_1".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("bob"), UserId::new("john")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
@@ -1948,15 +1950,15 @@ mod tests {
|
||||
Ok(vec![UserAndGroups {
|
||||
user: User {
|
||||
user_id: UserId::new("bob_1"),
|
||||
email: "bob@bobmail.bob".to_string(),
|
||||
email: "bob@bobmail.bob".into(),
|
||||
display_name: Some("Bôb Böbberson".to_string()),
|
||||
attributes: vec![
|
||||
AttributeValue {
|
||||
name: "avatar".to_owned(),
|
||||
name: "avatar".into(),
|
||||
value: Serialized::from(&JpegPhoto::for_tests()),
|
||||
},
|
||||
AttributeValue {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
value: Serialized::from("Böbberson"),
|
||||
},
|
||||
],
|
||||
@@ -1971,7 +1973,7 @@ mod tests {
|
||||
.returning(|_| {
|
||||
Ok(vec![Group {
|
||||
id: GroupId(1),
|
||||
display_name: "group_1".to_string(),
|
||||
display_name: "group_1".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("bob"), UserId::new("john")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
@@ -2354,7 +2356,7 @@ mod tests {
|
||||
let mut groups = HashSet::new();
|
||||
groups.insert(GroupDetails {
|
||||
group_id: GroupId(0),
|
||||
display_name: "lldap_admin".to_string(),
|
||||
display_name: "lldap_admin".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
@@ -2434,7 +2436,7 @@ mod tests {
|
||||
mock.expect_create_user()
|
||||
.with(eq(CreateUserRequest {
|
||||
user_id: UserId::new("bob"),
|
||||
email: "".to_owned(),
|
||||
email: "".into(),
|
||||
display_name: Some("Bob".to_string()),
|
||||
..Default::default()
|
||||
}))
|
||||
@@ -2476,7 +2478,7 @@ mod tests {
|
||||
mock.expect_create_user()
|
||||
.with(eq(CreateUserRequest {
|
||||
user_id: UserId::new("bob"),
|
||||
email: "".to_owned(),
|
||||
email: "".into(),
|
||||
display_name: Some("Bob".to_string()),
|
||||
..Default::default()
|
||||
}))
|
||||
@@ -2533,7 +2535,7 @@ mod tests {
|
||||
Ok(vec![UserAndGroups {
|
||||
user: User {
|
||||
user_id: UserId::new("bob"),
|
||||
email: "bob@bobmail.bob".to_string(),
|
||||
email: "bob@bobmail.bob".into(),
|
||||
..Default::default()
|
||||
},
|
||||
groups: None,
|
||||
@@ -2578,10 +2580,10 @@ mod tests {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
mock.expect_list_users().returning(|_, _| Ok(vec![]));
|
||||
mock.expect_list_groups().returning(|f| {
|
||||
assert_eq!(f, Some(GroupRequestFilter::DisplayName("group".to_owned())));
|
||||
assert_eq!(f, Some(GroupRequestFilter::DisplayName("group".into())));
|
||||
Ok(vec![Group {
|
||||
id: GroupId(1),
|
||||
display_name: "group".to_string(),
|
||||
display_name: "group".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("bob")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
@@ -2642,7 +2644,7 @@ mod tests {
|
||||
Ok(vec![UserAndGroups {
|
||||
user: User {
|
||||
user_id: UserId::new("bob"),
|
||||
email: "bob@bobmail.bob".to_string(),
|
||||
email: "bob@bobmail.bob".into(),
|
||||
..Default::default()
|
||||
},
|
||||
groups: None,
|
||||
@@ -2672,10 +2674,10 @@ mod tests {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
mock.expect_list_users().returning(|_, _| Ok(vec![]));
|
||||
mock.expect_list_groups().returning(|f| {
|
||||
assert_eq!(f, Some(GroupRequestFilter::DisplayName("group".to_owned())));
|
||||
assert_eq!(f, Some(GroupRequestFilter::DisplayName("group".into())));
|
||||
Ok(vec![Group {
|
||||
id: GroupId(1),
|
||||
display_name: "group".to_string(),
|
||||
display_name: "group".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("bob")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
@@ -2736,7 +2738,7 @@ mod tests {
|
||||
user: User {
|
||||
user_id: UserId::new("test"),
|
||||
attributes: vec![AttributeValue {
|
||||
name: "nickname".to_owned(),
|
||||
name: "nickname".into(),
|
||||
value: Serialized::from("Bob the Builder"),
|
||||
}],
|
||||
..Default::default()
|
||||
@@ -2747,12 +2749,12 @@ mod tests {
|
||||
mock.expect_list_groups().times(1).return_once(|_| {
|
||||
Ok(vec![Group {
|
||||
id: GroupId(1),
|
||||
display_name: "group".to_string(),
|
||||
display_name: "group".into(),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
users: vec![UserId::new("bob")],
|
||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||
attributes: vec![AttributeValue {
|
||||
name: "club_name".to_owned(),
|
||||
name: "club_name".into(),
|
||||
value: Serialized::from("Breakfast Club"),
|
||||
}],
|
||||
}])
|
||||
@@ -2761,7 +2763,7 @@ mod tests {
|
||||
Ok(crate::domain::handler::Schema {
|
||||
user_attributes: AttributeList {
|
||||
attributes: vec![AttributeSchema {
|
||||
name: "nickname".to_owned(),
|
||||
name: "nickname".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
@@ -2771,7 +2773,7 @@ mod tests {
|
||||
},
|
||||
group_attributes: AttributeList {
|
||||
attributes: vec![AttributeSchema {
|
||||
name: "club_name".to_owned(),
|
||||
name: "club_name".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::{
|
||||
domain::{
|
||||
handler::{BackendHandler, LoginHandler},
|
||||
opaque_handler::OpaqueHandler,
|
||||
types::AttributeName,
|
||||
},
|
||||
infra::{
|
||||
access_control::AccessControlledBackendHandler,
|
||||
@@ -72,8 +73,8 @@ async fn handle_ldap_stream<Stream, Backend>(
|
||||
stream: Stream,
|
||||
backend_handler: Backend,
|
||||
ldap_base_dn: String,
|
||||
ignored_user_attributes: Vec<String>,
|
||||
ignored_group_attributes: Vec<String>,
|
||||
ignored_user_attributes: Vec<AttributeName>,
|
||||
ignored_group_attributes: Vec<AttributeName>,
|
||||
) -> Result<Stream>
|
||||
where
|
||||
Backend: BackendHandler + LoginHandler + OpaqueHandler + 'static,
|
||||
|
||||
@@ -45,8 +45,8 @@ mockall::mock! {
|
||||
impl SchemaBackendHandler for TestBackendHandler {
|
||||
async fn add_user_attribute(&self, request: CreateAttributeRequest) -> Result<()>;
|
||||
async fn add_group_attribute(&self, request: CreateAttributeRequest) -> Result<()>;
|
||||
async fn delete_user_attribute(&self, name: &str) -> Result<()>;
|
||||
async fn delete_group_attribute(&self, name: &str) -> Result<()>;
|
||||
async fn delete_user_attribute(&self, name: &AttributeName) -> Result<()>;
|
||||
async fn delete_group_attribute(&self, name: &AttributeName) -> Result<()>;
|
||||
}
|
||||
#[async_trait]
|
||||
impl BackendHandler for TestBackendHandler {}
|
||||
@@ -74,7 +74,7 @@ pub fn setup_default_schema(mock: &mut MockTestBackendHandler) {
|
||||
user_attributes: AttributeList {
|
||||
attributes: vec![
|
||||
AttributeSchema {
|
||||
name: "avatar".to_owned(),
|
||||
name: "avatar".into(),
|
||||
attribute_type: AttributeType::JpegPhoto,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
@@ -82,7 +82,7 @@ pub fn setup_default_schema(mock: &mut MockTestBackendHandler) {
|
||||
is_hardcoded: true,
|
||||
},
|
||||
AttributeSchema {
|
||||
name: "first_name".to_owned(),
|
||||
name: "first_name".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
@@ -90,7 +90,7 @@ pub fn setup_default_schema(mock: &mut MockTestBackendHandler) {
|
||||
is_hardcoded: true,
|
||||
},
|
||||
AttributeSchema {
|
||||
name: "last_name".to_owned(),
|
||||
name: "last_name".into(),
|
||||
attribute_type: AttributeType::String,
|
||||
is_list: false,
|
||||
is_visible: true,
|
||||
|
||||
Reference in New Issue
Block a user