mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
server: Add support for SubString ldap filter
This commit is contained in:
parent
21e51c3d38
commit
81036943c2
@ -14,13 +14,46 @@ pub struct BindRequest {
|
|||||||
pub password: String,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct SubStringFilter {
|
||||||
|
pub initial: Option<String>,
|
||||||
|
pub any: Vec<String>,
|
||||||
|
pub final_: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubStringFilter {
|
||||||
|
pub fn to_sql_filter(&self) -> String {
|
||||||
|
let mut filter = String::with_capacity(
|
||||||
|
self.initial.as_ref().map(String::len).unwrap_or_default()
|
||||||
|
+ 1
|
||||||
|
+ self.any.iter().map(String::len).sum::<usize>()
|
||||||
|
+ self.any.len()
|
||||||
|
+ self.final_.as_ref().map(String::len).unwrap_or_default(),
|
||||||
|
);
|
||||||
|
if let Some(f) = &self.initial {
|
||||||
|
filter.push_str(&f.to_ascii_lowercase());
|
||||||
|
}
|
||||||
|
filter.push('%');
|
||||||
|
for part in self.any.iter() {
|
||||||
|
filter.push_str(&part.to_ascii_lowercase());
|
||||||
|
filter.push('%');
|
||||||
|
}
|
||||||
|
if let Some(f) = &self.final_ {
|
||||||
|
filter.push_str(&f.to_ascii_lowercase());
|
||||||
|
}
|
||||||
|
filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)]
|
||||||
pub enum UserRequestFilter {
|
pub enum UserRequestFilter {
|
||||||
And(Vec<UserRequestFilter>),
|
And(Vec<UserRequestFilter>),
|
||||||
Or(Vec<UserRequestFilter>),
|
Or(Vec<UserRequestFilter>),
|
||||||
Not(Box<UserRequestFilter>),
|
Not(Box<UserRequestFilter>),
|
||||||
UserId(UserId),
|
UserId(UserId),
|
||||||
|
UserIdSubString(SubStringFilter),
|
||||||
Equality(UserColumn, String),
|
Equality(UserColumn, String),
|
||||||
|
SubString(UserColumn, SubStringFilter),
|
||||||
// Check if a user belongs to a group identified by name.
|
// Check if a user belongs to a group identified by name.
|
||||||
MemberOf(String),
|
MemberOf(String),
|
||||||
// Same, by id.
|
// Same, by id.
|
||||||
@ -43,6 +76,7 @@ pub enum GroupRequestFilter {
|
|||||||
Or(Vec<GroupRequestFilter>),
|
Or(Vec<GroupRequestFilter>),
|
||||||
Not(Box<GroupRequestFilter>),
|
Not(Box<GroupRequestFilter>),
|
||||||
DisplayName(String),
|
DisplayName(String),
|
||||||
|
DisplayNameSubString(SubStringFilter),
|
||||||
Uuid(Uuid),
|
Uuid(Uuid),
|
||||||
GroupId(GroupId),
|
GroupId(GroupId),
|
||||||
// Check if the group contains a user identified by uid.
|
// Check if the group contains a user identified by uid.
|
||||||
|
@ -178,6 +178,21 @@ fn convert_group_filter(
|
|||||||
|| map_group_field(field).is_some(),
|
|| map_group_field(field).is_some(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
LdapFilter::Substring(field, substring_filter) => {
|
||||||
|
let field = &field.to_ascii_lowercase();
|
||||||
|
match map_group_field(field.as_str()) {
|
||||||
|
Some(GroupColumn::DisplayName) => Ok(GroupRequestFilter::DisplayNameSubString(
|
||||||
|
substring_filter.clone().into(),
|
||||||
|
)),
|
||||||
|
_ => Err(LdapError {
|
||||||
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
|
message: format!(
|
||||||
|
"Unsupported group attribute for substring filter: {:?}",
|
||||||
|
field
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(LdapError {
|
_ => Err(LdapError {
|
||||||
code: LdapResultCode::UnwillingToPerform,
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
message: format!("Unsupported group filter: {:?}", filter),
|
message: format!("Unsupported group filter: {:?}", filter),
|
||||||
|
@ -185,6 +185,28 @@ fn convert_user_filter(ldap_info: &LdapInfo, filter: &LdapFilter) -> LdapResult<
|
|||||||
|| map_user_field(field).is_some(),
|
|| map_user_field(field).is_some(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
LdapFilter::Substring(field, substring_filter) => {
|
||||||
|
let field = &field.to_ascii_lowercase();
|
||||||
|
match map_user_field(field.as_str()) {
|
||||||
|
Some(UserColumn::UserId) => Ok(UserRequestFilter::UserIdSubString(
|
||||||
|
substring_filter.clone().into(),
|
||||||
|
)),
|
||||||
|
None
|
||||||
|
| Some(UserColumn::CreationDate)
|
||||||
|
| Some(UserColumn::Avatar)
|
||||||
|
| Some(UserColumn::Uuid) => Err(LdapError {
|
||||||
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
|
message: format!(
|
||||||
|
"Unsupported user attribute for substring filter: {:?}",
|
||||||
|
field
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
Some(field) => Ok(UserRequestFilter::SubString(
|
||||||
|
field,
|
||||||
|
substring_filter.clone().into(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Err(LdapError {
|
_ => Err(LdapError {
|
||||||
code: LdapResultCode::UnwillingToPerform,
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
message: format!("Unsupported user filter: {:?}", filter),
|
message: format!("Unsupported user filter: {:?}", filter),
|
||||||
|
@ -1,12 +1,29 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ldap3_proto::LdapResultCode;
|
use ldap3_proto::{proto::LdapSubstringFilter, LdapResultCode};
|
||||||
use tracing::{debug, instrument, warn};
|
use tracing::{debug, instrument, warn};
|
||||||
|
|
||||||
use crate::domain::{
|
use crate::domain::{
|
||||||
|
handler::SubStringFilter,
|
||||||
ldap::error::{LdapError, LdapResult},
|
ldap::error::{LdapError, LdapResult},
|
||||||
types::{GroupColumn, UserColumn, UserId},
|
types::{GroupColumn, UserColumn, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
impl From<LdapSubstringFilter> for SubStringFilter {
|
||||||
|
fn from(
|
||||||
|
LdapSubstringFilter {
|
||||||
|
initial,
|
||||||
|
any,
|
||||||
|
final_,
|
||||||
|
}: LdapSubstringFilter,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
initial,
|
||||||
|
any,
|
||||||
|
final_,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn make_dn_pair<I>(mut iter: I) -> LdapResult<(String, String)>
|
fn make_dn_pair<I>(mut iter: I) -> LdapResult<(String, String)>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = String>,
|
I: Iterator<Item = String>,
|
||||||
@ -141,8 +158,8 @@ pub fn map_user_field(field: &str) -> Option<UserColumn> {
|
|||||||
"uid" | "user_id" | "id" => UserColumn::UserId,
|
"uid" | "user_id" | "id" => UserColumn::UserId,
|
||||||
"mail" | "email" => UserColumn::Email,
|
"mail" | "email" => UserColumn::Email,
|
||||||
"cn" | "displayname" | "display_name" => UserColumn::DisplayName,
|
"cn" | "displayname" | "display_name" => UserColumn::DisplayName,
|
||||||
"givenname" | "first_name" => UserColumn::FirstName,
|
"givenname" | "first_name" | "firstname" => UserColumn::FirstName,
|
||||||
"sn" | "last_name" => UserColumn::LastName,
|
"sn" | "last_name" | "lastname" => UserColumn::LastName,
|
||||||
"avatar" | "jpegphoto" => UserColumn::Avatar,
|
"avatar" | "jpegphoto" => UserColumn::Avatar,
|
||||||
"creationdate" | "createtimestamp" | "modifytimestamp" | "creation_date" => {
|
"creationdate" | "createtimestamp" | "modifytimestamp" | "creation_date" => {
|
||||||
UserColumn::CreationDate
|
UserColumn::CreationDate
|
||||||
|
@ -7,7 +7,7 @@ use crate::domain::{
|
|||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
sea_query::{Cond, IntoCondition, SimpleExpr},
|
sea_query::{Alias, Cond, Expr, Func, IntoCondition, SimpleExpr},
|
||||||
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect,
|
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect,
|
||||||
QueryTrait,
|
QueryTrait,
|
||||||
};
|
};
|
||||||
@ -15,6 +15,7 @@ use tracing::{debug, instrument};
|
|||||||
|
|
||||||
fn get_group_filter_expr(filter: GroupRequestFilter) -> Cond {
|
fn get_group_filter_expr(filter: GroupRequestFilter) -> Cond {
|
||||||
use GroupRequestFilter::*;
|
use GroupRequestFilter::*;
|
||||||
|
let group_table = Alias::new("groups");
|
||||||
match filter {
|
match filter {
|
||||||
And(fs) => {
|
And(fs) => {
|
||||||
if fs.is_empty() {
|
if fs.is_empty() {
|
||||||
@ -46,6 +47,12 @@ fn get_group_filter_expr(filter: GroupRequestFilter) -> Cond {
|
|||||||
.into_query(),
|
.into_query(),
|
||||||
)
|
)
|
||||||
.into_condition(),
|
.into_condition(),
|
||||||
|
DisplayNameSubString(filter) => SimpleExpr::FunctionCall(Func::lower(Expr::col((
|
||||||
|
group_table,
|
||||||
|
GroupColumn::DisplayName,
|
||||||
|
))))
|
||||||
|
.like(filter.to_sql_filter())
|
||||||
|
.into_condition(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +153,7 @@ impl GroupBackendHandler for SqlBackendHandler {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::domain::{sql_backend_handler::tests::*, types::UserId};
|
use crate::domain::{handler::SubStringFilter, sql_backend_handler::tests::*, types::UserId};
|
||||||
|
|
||||||
async fn get_group_ids(
|
async fn get_group_ids(
|
||||||
handler: &SqlBackendHandler,
|
handler: &SqlBackendHandler,
|
||||||
@ -221,6 +228,24 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_list_groups_substring_filter() {
|
||||||
|
let fixture = TestFixture::new().await;
|
||||||
|
assert_eq!(
|
||||||
|
get_group_ids(
|
||||||
|
&fixture.handler,
|
||||||
|
Some(GroupRequestFilter::DisplayNameSubString(SubStringFilter {
|
||||||
|
initial: Some("be".to_owned()),
|
||||||
|
any: vec!["sT".to_owned()],
|
||||||
|
final_: Some("P".to_owned()),
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
// Best group
|
||||||
|
vec![fixture.groups[0]]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_group_details() {
|
async fn test_get_group_details() {
|
||||||
let fixture = TestFixture::new().await;
|
let fixture = TestFixture::new().await;
|
||||||
|
@ -8,7 +8,7 @@ use super::{
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use sea_orm::{
|
use sea_orm::{
|
||||||
entity::IntoActiveValue,
|
entity::IntoActiveValue,
|
||||||
sea_query::{Alias, Cond, Expr, IntoColumnRef, IntoCondition, SimpleExpr},
|
sea_query::{Alias, Cond, Expr, Func, IntoColumnRef, IntoCondition, SimpleExpr},
|
||||||
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, ModelTrait, QueryFilter, QueryOrder,
|
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, ModelTrait, QueryFilter, QueryOrder,
|
||||||
QuerySelect, QueryTrait, Set,
|
QuerySelect, QueryTrait, Set,
|
||||||
};
|
};
|
||||||
@ -49,8 +49,15 @@ fn get_user_filter_expr(filter: UserRequestFilter) -> Cond {
|
|||||||
MemberOfId(group_id) => Expr::col((group_table, GroupColumn::GroupId))
|
MemberOfId(group_id) => Expr::col((group_table, GroupColumn::GroupId))
|
||||||
.eq(group_id)
|
.eq(group_id)
|
||||||
.into_condition(),
|
.into_condition(),
|
||||||
|
UserIdSubString(filter) => UserColumn::UserId
|
||||||
|
.like(&filter.to_sql_filter())
|
||||||
|
.into_condition(),
|
||||||
|
SubString(col, filter) => SimpleExpr::FunctionCall(Func::lower(Expr::col(col)))
|
||||||
|
.like(filter.to_sql_filter())
|
||||||
|
.into_condition(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_value(opt_name: &Option<String>) -> ActiveValue<Option<String>> {
|
fn to_value(opt_name: &Option<String>) -> ActiveValue<Option<String>> {
|
||||||
match opt_name {
|
match opt_name {
|
||||||
None => ActiveValue::NotSet,
|
None => ActiveValue::NotSet,
|
||||||
@ -236,6 +243,7 @@ impl UserBackendHandler for SqlBackendHandler {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::domain::{
|
use crate::domain::{
|
||||||
|
handler::SubStringFilter,
|
||||||
sql_backend_handler::tests::*,
|
sql_backend_handler::tests::*,
|
||||||
types::{JpegPhoto, UserColumn},
|
types::{JpegPhoto, UserColumn},
|
||||||
};
|
};
|
||||||
@ -286,6 +294,31 @@ mod tests {
|
|||||||
assert_eq!(users, vec!["bob"]);
|
assert_eq!(users, vec!["bob"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_list_users_substring_filter() {
|
||||||
|
let fixture = TestFixture::new().await;
|
||||||
|
let users = get_user_names(
|
||||||
|
&fixture.handler,
|
||||||
|
Some(UserRequestFilter::And(vec![
|
||||||
|
UserRequestFilter::UserIdSubString(SubStringFilter {
|
||||||
|
initial: Some("Pa".to_owned()),
|
||||||
|
any: vec!["rI".to_owned()],
|
||||||
|
final_: Some("K".to_owned()),
|
||||||
|
}),
|
||||||
|
UserRequestFilter::SubString(
|
||||||
|
UserColumn::FirstName,
|
||||||
|
SubStringFilter {
|
||||||
|
initial: None,
|
||||||
|
any: vec!["r".to_owned(), "t".to_owned()],
|
||||||
|
final_: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
])),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(users, vec!["patrick"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_list_users_false_filter() {
|
async fn test_list_users_false_filter() {
|
||||||
let fixture = TestFixture::new().await;
|
let fixture = TestFixture::new().await;
|
||||||
|
@ -680,7 +680,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::TimeZone;
|
use chrono::TimeZone;
|
||||||
use ldap3_proto::proto::{LdapDerefAliases, LdapSearchScope};
|
use ldap3_proto::proto::{LdapDerefAliases, LdapSearchScope, LdapSubstringFilter};
|
||||||
use mockall::predicate::eq;
|
use mockall::predicate::eq;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use tokio;
|
use tokio;
|
||||||
@ -1322,6 +1322,11 @@ mod tests {
|
|||||||
true.into(),
|
true.into(),
|
||||||
GroupRequestFilter::Not(Box::new(false.into())),
|
GroupRequestFilter::Not(Box::new(false.into())),
|
||||||
false.into(),
|
false.into(),
|
||||||
|
GroupRequestFilter::DisplayNameSubString(SubStringFilter {
|
||||||
|
initial: Some("iNIt".to_owned()),
|
||||||
|
any: vec!["1".to_owned(), "2aA".to_owned()],
|
||||||
|
final_: Some("finAl".to_owned()),
|
||||||
|
}),
|
||||||
]))))
|
]))))
|
||||||
.times(1)
|
.times(1)
|
||||||
.return_once(|_| {
|
.return_once(|_| {
|
||||||
@ -1357,6 +1362,14 @@ mod tests {
|
|||||||
"random_attribUte".to_string(),
|
"random_attribUte".to_string(),
|
||||||
))),
|
))),
|
||||||
LdapFilter::Equality("unknown_attribute".to_string(), "randomValue".to_string()),
|
LdapFilter::Equality("unknown_attribute".to_string(), "randomValue".to_string()),
|
||||||
|
LdapFilter::Substring(
|
||||||
|
"cn".to_owned(),
|
||||||
|
LdapSubstringFilter {
|
||||||
|
initial: Some("iNIt".to_owned()),
|
||||||
|
any: vec!["1".to_owned(), "2aA".to_owned()],
|
||||||
|
final_: Some("finAl".to_owned()),
|
||||||
|
},
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
vec!["1.1"],
|
vec!["1.1"],
|
||||||
);
|
);
|
||||||
@ -1442,6 +1455,22 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_groups_unsupported_substring() {
|
||||||
|
let mut ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
||||||
|
let request = make_group_search_request(
|
||||||
|
LdapFilter::Substring("member".to_owned(), LdapSubstringFilter::default()),
|
||||||
|
vec!["cn"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Err(LdapError {
|
||||||
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
|
message: r#"Unsupported group attribute for substring filter: "member""#.to_owned()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_search_groups_error() {
|
async fn test_search_groups_error() {
|
||||||
let mut mock = MockTestBackendHandler::new();
|
let mut mock = MockTestBackendHandler::new();
|
||||||
@ -1478,9 +1507,9 @@ mod tests {
|
|||||||
async fn test_search_groups_filter_error() {
|
async fn test_search_groups_filter_error() {
|
||||||
let mut ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
let mut ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
||||||
let request = make_group_search_request(
|
let request = make_group_search_request(
|
||||||
LdapFilter::And(vec![LdapFilter::Substring(
|
LdapFilter::And(vec![LdapFilter::Approx(
|
||||||
"whatever".to_string(),
|
"whatever".to_owned(),
|
||||||
ldap3_proto::proto::LdapSubstringFilter::default(),
|
"value".to_owned(),
|
||||||
)]),
|
)]),
|
||||||
vec!["cn"],
|
vec!["cn"],
|
||||||
);
|
);
|
||||||
@ -1488,8 +1517,7 @@ mod tests {
|
|||||||
ldap_handler.do_search_or_dse(&request).await,
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
Err(LdapError {
|
Err(LdapError {
|
||||||
code: LdapResultCode::UnwillingToPerform,
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
message: r#"Unsupported group filter: Substring("whatever", LdapSubstringFilter { initial: None, any: [], final_: None })"#
|
message: r#"Unsupported group filter: Approx("whatever", "value")"#.to_string()
|
||||||
.to_string()
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1512,6 +1540,19 @@ mod tests {
|
|||||||
true.into(),
|
true.into(),
|
||||||
false.into(),
|
false.into(),
|
||||||
false.into(),
|
false.into(),
|
||||||
|
UserRequestFilter::UserIdSubString(SubStringFilter {
|
||||||
|
initial: Some("iNIt".to_owned()),
|
||||||
|
any: vec!["1".to_owned(), "2aA".to_owned()],
|
||||||
|
final_: Some("finAl".to_owned()),
|
||||||
|
}),
|
||||||
|
UserRequestFilter::SubString(
|
||||||
|
UserColumn::FirstName,
|
||||||
|
SubStringFilter {
|
||||||
|
initial: Some("iNIt".to_owned()),
|
||||||
|
any: vec!["1".to_owned(), "2aA".to_owned()],
|
||||||
|
final_: Some("finAl".to_owned()),
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)]))),
|
)]))),
|
||||||
eq(false),
|
eq(false),
|
||||||
@ -1539,6 +1580,22 @@ mod tests {
|
|||||||
LdapFilter::Present("uid".to_string()),
|
LdapFilter::Present("uid".to_string()),
|
||||||
LdapFilter::Present("unknown".to_string()),
|
LdapFilter::Present("unknown".to_string()),
|
||||||
LdapFilter::Equality("unknown_attribute".to_string(), "randomValue".to_string()),
|
LdapFilter::Equality("unknown_attribute".to_string(), "randomValue".to_string()),
|
||||||
|
LdapFilter::Substring(
|
||||||
|
"uid".to_owned(),
|
||||||
|
LdapSubstringFilter {
|
||||||
|
initial: Some("iNIt".to_owned()),
|
||||||
|
any: vec!["1".to_owned(), "2aA".to_owned()],
|
||||||
|
final_: Some("finAl".to_owned()),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LdapFilter::Substring(
|
||||||
|
"firstName".to_owned(),
|
||||||
|
LdapSubstringFilter {
|
||||||
|
initial: Some("iNIt".to_owned()),
|
||||||
|
any: vec!["1".to_owned(), "2aA".to_owned()],
|
||||||
|
final_: Some("finAl".to_owned()),
|
||||||
|
},
|
||||||
|
),
|
||||||
])]),
|
])]),
|
||||||
vec!["objectClass"],
|
vec!["objectClass"],
|
||||||
);
|
);
|
||||||
@ -1910,17 +1967,14 @@ mod tests {
|
|||||||
async fn test_search_unsupported_filters() {
|
async fn test_search_unsupported_filters() {
|
||||||
let mut ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
let mut ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
||||||
let request = make_user_search_request(
|
let request = make_user_search_request(
|
||||||
LdapFilter::Substring(
|
LdapFilter::Approx("uid".to_owned(), "value".to_owned()),
|
||||||
"uid".to_string(),
|
|
||||||
ldap3_proto::proto::LdapSubstringFilter::default(),
|
|
||||||
),
|
|
||||||
vec!["objectClass"],
|
vec!["objectClass"],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
Err(LdapError {
|
Err(LdapError {
|
||||||
code: LdapResultCode::UnwillingToPerform,
|
code: LdapResultCode::UnwillingToPerform,
|
||||||
message: r#"Unsupported user filter: Substring("uid", LdapSubstringFilter { initial: None, any: [], final_: None })"#.to_string()
|
message: r#"Unsupported user filter: Approx("uid", "value")"#.to_string()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user