mirror of
https://github.com/lldap/lldap.git
synced 2026-03-31 15:07:48 +01:00
server: Move LDAP search tests to their respective implementation files
Move user and group tests to their respective implementation files User tests → core/user.rs: - test_search_regular_user - test_search_readonly_user - test_search_member_of - test_search_user_as_scope - test_search_users - test_pwd_changed_time_format Group tests → core/group.rs: - test_search_groups - test_search_groups_by_groupid - test_search_groups_filter - test_search_groups_filter_2 - test_search_groups_filter_3 - test_search_group_as_scope Tests remain in search.rs: - DSE/schema tests - General search logic tests - Filter tests - Error handling tests - OU search tests - Mixed user/group tests
This commit is contained in:
@@ -388,3 +388,305 @@ pub fn convert_groups_to_ldap_op<'a>(
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
handler::tests::{make_group_search_request, setup_bound_admin_handler},
|
||||||
|
search::{make_search_request, make_search_success},
|
||||||
|
};
|
||||||
|
use ldap3_proto::proto::LdapSubstringFilter;
|
||||||
|
use lldap_domain::{
|
||||||
|
types::{GroupId, UserId},
|
||||||
|
uuid,
|
||||||
|
};
|
||||||
|
use lldap_domain_handlers::handler::*;
|
||||||
|
use lldap_test_utils::MockTestBackendHandler;
|
||||||
|
use mockall::predicate::eq;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_groups() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_groups()
|
||||||
|
.with(eq(Some(GroupRequestFilter::True)))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_| {
|
||||||
|
Ok(vec![
|
||||||
|
Group {
|
||||||
|
id: GroupId(1),
|
||||||
|
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"),
|
||||||
|
attributes: Vec::new(),
|
||||||
|
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
id: GroupId(3),
|
||||||
|
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"),
|
||||||
|
attributes: Vec::new(),
|
||||||
|
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_group_search_request(
|
||||||
|
LdapFilter::And(vec![]),
|
||||||
|
vec![
|
||||||
|
"objectClass",
|
||||||
|
"dn",
|
||||||
|
"cn",
|
||||||
|
"uniqueMember",
|
||||||
|
"entryUuid",
|
||||||
|
"entryDN",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "cn".to_string(),
|
||||||
|
vals: vec![b"group_1".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "entryDN".to_string(),
|
||||||
|
vals: vec![b"uid=group_1,ou=groups,dc=example,dc=com".to_vec()],
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "entryUuid".to_string(),
|
||||||
|
vals: vec![b"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_vec()],
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "objectClass".to_string(),
|
||||||
|
vals: vec![b"groupOfUniqueNames".to_vec(), b"groupOfNames".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "uniqueMember".to_string(),
|
||||||
|
vals: vec![
|
||||||
|
b"uid=bob,ou=people,dc=example,dc=com".to_vec(),
|
||||||
|
b"uid=john,ou=people,dc=example,dc=com".to_vec(),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "cn=BestGroup,ou=groups,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "cn".to_string(),
|
||||||
|
vals: vec![b"BestGroup".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "entryDN".to_string(),
|
||||||
|
vals: vec![b"uid=BestGroup,ou=groups,dc=example,dc=com".to_vec()],
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "entryUuid".to_string(),
|
||||||
|
vals: vec![b"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_vec()],
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "objectClass".to_string(),
|
||||||
|
vals: vec![b"groupOfUniqueNames".to_vec(), b"groupOfNames".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "uniqueMember".to_string(),
|
||||||
|
vals: vec![b"uid=john,ou=people,dc=example,dc=com".to_vec()],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
make_search_success(),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_groups_by_groupid() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_groups()
|
||||||
|
.with(eq(Some(GroupRequestFilter::GroupId(GroupId(1)))))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_| {
|
||||||
|
Ok(vec![Group {
|
||||||
|
display_name: "group_1".into(),
|
||||||
|
id: GroupId(1),
|
||||||
|
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
users: vec![],
|
||||||
|
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||||
|
attributes: Vec::new(),
|
||||||
|
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
}])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_group_search_request(
|
||||||
|
LdapFilter::Equality("groupid".to_string(), "1".to_string()),
|
||||||
|
vec!["dn"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![],
|
||||||
|
}),
|
||||||
|
make_search_success(),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_groups_filter() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_groups()
|
||||||
|
.with(eq(Some(GroupRequestFilter::And(vec![
|
||||||
|
GroupRequestFilter::DisplayName("group_1".into()),
|
||||||
|
GroupRequestFilter::Member(UserId::new("bob")),
|
||||||
|
GroupRequestFilter::DisplayName("rockstars".into()),
|
||||||
|
false.into(),
|
||||||
|
GroupRequestFilter::Uuid(uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc")),
|
||||||
|
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)
|
||||||
|
.return_once(|_| {
|
||||||
|
Ok(vec![Group {
|
||||||
|
display_name: "group_1".into(),
|
||||||
|
id: GroupId(1),
|
||||||
|
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
users: vec![],
|
||||||
|
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||||
|
attributes: Vec::new(),
|
||||||
|
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
}])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_group_search_request(
|
||||||
|
LdapFilter::And(vec![
|
||||||
|
LdapFilter::Equality("cN".to_string(), "Group_1".to_string()),
|
||||||
|
LdapFilter::Equality(
|
||||||
|
"uniqueMember".to_string(),
|
||||||
|
"uid=bob,ou=peopLe,Dc=eXample,dc=com".to_string(),
|
||||||
|
),
|
||||||
|
LdapFilter::Equality(
|
||||||
|
"dn".to_string(),
|
||||||
|
"uid=rockstars,ou=groups,dc=example,dc=com".to_string(),
|
||||||
|
),
|
||||||
|
LdapFilter::Equality(
|
||||||
|
"dn".to_string(),
|
||||||
|
"uid=rockstars,ou=people,dc=example,dc=com".to_string(),
|
||||||
|
),
|
||||||
|
LdapFilter::Equality(
|
||||||
|
"uuid".to_string(),
|
||||||
|
"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_string(),
|
||||||
|
),
|
||||||
|
LdapFilter::Equality("obJEctclass".to_string(), "groupofUniqueNames".to_string()),
|
||||||
|
LdapFilter::Equality("objectclass".to_string(), "groupOfNames".to_string()),
|
||||||
|
LdapFilter::Present("objectclass".to_string()),
|
||||||
|
LdapFilter::Present("dn".to_string()),
|
||||||
|
LdapFilter::Not(Box::new(LdapFilter::Present(
|
||||||
|
"random_attribUte".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"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![],
|
||||||
|
}),
|
||||||
|
make_search_success(),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_groups_filter_2() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_groups()
|
||||||
|
.with(eq(Some(GroupRequestFilter::Or(vec![
|
||||||
|
GroupRequestFilter::DisplayName("group_1".into()),
|
||||||
|
GroupRequestFilter::Member(UserId::new("bob")),
|
||||||
|
]))))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_| Ok(vec![]));
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_group_search_request(
|
||||||
|
LdapFilter::Or(vec![
|
||||||
|
LdapFilter::Equality("cn".to_string(), "group_1".to_string()),
|
||||||
|
LdapFilter::Equality(
|
||||||
|
"member".to_string(),
|
||||||
|
"uid=bob,ou=people,dc=example,dc=com".to_string(),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
vec!["cn"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![make_search_success()])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_groups_filter_3() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_groups()
|
||||||
|
.with(eq(Some(GroupRequestFilter::Not(Box::new(
|
||||||
|
GroupRequestFilter::DisplayName("group_1".into()),
|
||||||
|
)))))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_| Ok(vec![]));
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_group_search_request(
|
||||||
|
LdapFilter::Not(Box::new(LdapFilter::Equality(
|
||||||
|
"cn".to_string(),
|
||||||
|
"group_1".to_string(),
|
||||||
|
))),
|
||||||
|
vec!["cn"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![make_search_success()])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_group_as_scope() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_groups()
|
||||||
|
.with(eq(Some(GroupRequestFilter::DisplayName("group_1".into()))))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_| Ok(vec![]));
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_search_request(
|
||||||
|
"cn=group_1,ou=groups,dc=example,dc=com",
|
||||||
|
LdapFilter::And(vec![]),
|
||||||
|
vec!["objectClass"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![make_search_success()]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -400,3 +400,374 @@ pub fn convert_users_to_ldap_op<'a>(
|
|||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
handler::tests::{
|
||||||
|
make_user_search_request, setup_bound_admin_handler, setup_bound_handler_with_group,
|
||||||
|
setup_bound_readonly_handler,
|
||||||
|
},
|
||||||
|
search::{make_search_request, make_search_success},
|
||||||
|
};
|
||||||
|
use chrono::{DateTime, Duration, NaiveDateTime, TimeZone, Utc};
|
||||||
|
use lldap_domain::types::{Attribute, GroupDetails, JpegPhoto};
|
||||||
|
use lldap_test_utils::MockTestBackendHandler;
|
||||||
|
use mockall::predicate::eq;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
fn assert_timestamp_within_margin(
|
||||||
|
timestamp_bytes: &[u8],
|
||||||
|
base_timestamp_dt: DateTime<Utc>,
|
||||||
|
time_margin: Duration,
|
||||||
|
) {
|
||||||
|
let timestamp_str =
|
||||||
|
std::str::from_utf8(timestamp_bytes).expect("Invalid conversion from UTF-8 to string");
|
||||||
|
let timestamp_naive = NaiveDateTime::parse_from_str(timestamp_str, "%Y%m%d%H%M%SZ")
|
||||||
|
.expect("Invalid timestamp format");
|
||||||
|
let timestamp_dt: DateTime<Utc> = Utc.from_utc_datetime(×tamp_naive);
|
||||||
|
|
||||||
|
let within_range = (base_timestamp_dt - timestamp_dt).abs() <= time_margin;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
within_range,
|
||||||
|
"Timestamp not within range: expected within [{} - {}], got [{}]",
|
||||||
|
base_timestamp_dt - time_margin,
|
||||||
|
base_timestamp_dt + time_margin,
|
||||||
|
timestamp_dt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_regular_user() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_users()
|
||||||
|
.with(
|
||||||
|
eq(Some(UserRequestFilter::And(vec![
|
||||||
|
UserRequestFilter::True,
|
||||||
|
UserRequestFilter::UserId(UserId::new("test")),
|
||||||
|
]))),
|
||||||
|
eq(false),
|
||||||
|
)
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_, _| {
|
||||||
|
Ok(vec![UserAndGroups {
|
||||||
|
user: User {
|
||||||
|
user_id: UserId::new("test"),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
groups: None,
|
||||||
|
}])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_handler_with_group(mock, "regular").await;
|
||||||
|
|
||||||
|
let request =
|
||||||
|
make_user_search_request::<String>(LdapFilter::And(vec![]), vec!["1.1".to_string()]);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "uid=test,ou=people,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![],
|
||||||
|
}),
|
||||||
|
make_search_success()
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_readonly_user() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_users()
|
||||||
|
.with(eq(Some(UserRequestFilter::True)), eq(false))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_, _| Ok(vec![]));
|
||||||
|
let ldap_handler = setup_bound_readonly_handler(mock).await;
|
||||||
|
let request = make_user_search_request(LdapFilter::And(vec![]), vec!["1.1"]);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![make_search_success()]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_member_of() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_users()
|
||||||
|
.with(eq(Some(UserRequestFilter::True)), eq(true))
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_, _| {
|
||||||
|
Ok(vec![UserAndGroups {
|
||||||
|
user: User {
|
||||||
|
user_id: UserId::new("bob"),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
groups: Some(vec![GroupDetails {
|
||||||
|
group_id: lldap_domain::types::GroupId(42),
|
||||||
|
display_name: "rockstars".into(),
|
||||||
|
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
uuid: lldap_domain::uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||||
|
attributes: Vec::new(),
|
||||||
|
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||||
|
}]),
|
||||||
|
}])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_readonly_handler(mock).await;
|
||||||
|
let request = make_user_search_request::<String>(
|
||||||
|
LdapFilter::And(vec![]),
|
||||||
|
vec!["memberOf".to_string()],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "uid=bob,ou=people,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![LdapPartialAttribute {
|
||||||
|
atype: "memberOf".to_string(),
|
||||||
|
vals: vec![b"cn=rockstars,ou=groups,dc=example,dc=com".to_vec()]
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
make_search_success(),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_user_as_scope() {
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_users()
|
||||||
|
.with(
|
||||||
|
eq(Some(UserRequestFilter::UserId(UserId::new("bob")))),
|
||||||
|
eq(false),
|
||||||
|
)
|
||||||
|
.times(1)
|
||||||
|
.return_once(|_, _| Ok(vec![]));
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_search_request(
|
||||||
|
"uid=bob,ou=people,dc=example,dc=com",
|
||||||
|
LdapFilter::And(vec![]),
|
||||||
|
vec!["objectClass"],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![make_search_success()]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_users() {
|
||||||
|
use chrono::prelude::*;
|
||||||
|
use lldap_domain::uuid;
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_users().times(1).return_once(|_, _| {
|
||||||
|
Ok(vec![
|
||||||
|
UserAndGroups {
|
||||||
|
user: User {
|
||||||
|
user_id: UserId::new("bob_1"),
|
||||||
|
email: "bob@bobmail.bob".into(),
|
||||||
|
display_name: Some("Bôb Böbberson".to_string()),
|
||||||
|
uuid: uuid!("698e1d5f-7a40-3151-8745-b9b8a37839da"),
|
||||||
|
attributes: vec![
|
||||||
|
Attribute {
|
||||||
|
name: "first_name".into(),
|
||||||
|
value: "Bôb".to_string().into(),
|
||||||
|
},
|
||||||
|
Attribute {
|
||||||
|
name: "last_name".into(),
|
||||||
|
value: "Böbberson".to_string().into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
groups: None,
|
||||||
|
},
|
||||||
|
UserAndGroups {
|
||||||
|
user: User {
|
||||||
|
user_id: UserId::new("jim"),
|
||||||
|
email: "jim@cricket.jim".into(),
|
||||||
|
display_name: Some("Jimminy Cricket".to_string()),
|
||||||
|
attributes: vec![
|
||||||
|
Attribute {
|
||||||
|
name: "avatar".into(),
|
||||||
|
value: JpegPhoto::for_tests().into(),
|
||||||
|
},
|
||||||
|
Attribute {
|
||||||
|
name: "first_name".into(),
|
||||||
|
value: "Jim".to_string().into(),
|
||||||
|
},
|
||||||
|
Attribute {
|
||||||
|
name: "last_name".into(),
|
||||||
|
value: "Cricket".to_string().into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
||||||
|
creation_date: Utc
|
||||||
|
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||||
|
.unwrap()
|
||||||
|
.naive_utc(),
|
||||||
|
modified_date: Utc
|
||||||
|
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||||
|
.unwrap()
|
||||||
|
.naive_utc(),
|
||||||
|
password_modified_date: Utc
|
||||||
|
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||||
|
.unwrap()
|
||||||
|
.naive_utc(),
|
||||||
|
},
|
||||||
|
groups: None,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_user_search_request(
|
||||||
|
LdapFilter::And(vec![]),
|
||||||
|
vec![
|
||||||
|
"objectClass",
|
||||||
|
"dn",
|
||||||
|
"uid",
|
||||||
|
"mail",
|
||||||
|
"givenName",
|
||||||
|
"sn",
|
||||||
|
"cn",
|
||||||
|
"createTimestamp",
|
||||||
|
"entryUuid",
|
||||||
|
"jpegPhoto",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "uid=bob_1,ou=people,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "cn".to_string(),
|
||||||
|
vals: vec!["Bôb Böbberson".to_string().into_bytes()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "createTimestamp".to_string(),
|
||||||
|
vals: vec![b"19700101000000Z".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "entryUuid".to_string(),
|
||||||
|
vals: vec![b"698e1d5f-7a40-3151-8745-b9b8a37839da".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "givenName".to_string(),
|
||||||
|
vals: vec!["Bôb".to_string().into_bytes()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "mail".to_string(),
|
||||||
|
vals: vec![b"bob@bobmail.bob".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "objectClass".to_string(),
|
||||||
|
vals: vec![
|
||||||
|
b"inetOrgPerson".to_vec(),
|
||||||
|
b"posixAccount".to_vec(),
|
||||||
|
b"mailAccount".to_vec(),
|
||||||
|
b"person".to_vec(),
|
||||||
|
b"customUserClass".to_vec(),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "sn".to_string(),
|
||||||
|
vals: vec!["Böbberson".to_string().into_bytes()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "uid".to_string(),
|
||||||
|
vals: vec![b"bob_1".to_vec()]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
||||||
|
dn: "uid=jim,ou=people,dc=example,dc=com".to_string(),
|
||||||
|
attributes: vec![
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "cn".to_string(),
|
||||||
|
vals: vec![b"Jimminy Cricket".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "createTimestamp".to_string(),
|
||||||
|
vals: vec![b"20140708091011Z".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "entryUuid".to_string(),
|
||||||
|
vals: vec![b"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "givenName".to_string(),
|
||||||
|
vals: vec![b"Jim".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "jpegPhoto".to_string(),
|
||||||
|
vals: vec![JpegPhoto::for_tests().into_bytes()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "mail".to_string(),
|
||||||
|
vals: vec![b"jim@cricket.jim".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "objectClass".to_string(),
|
||||||
|
vals: vec![
|
||||||
|
b"inetOrgPerson".to_vec(),
|
||||||
|
b"posixAccount".to_vec(),
|
||||||
|
b"mailAccount".to_vec(),
|
||||||
|
b"person".to_vec(),
|
||||||
|
b"customUserClass".to_vec(),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "sn".to_string(),
|
||||||
|
vals: vec![b"Cricket".to_vec()]
|
||||||
|
},
|
||||||
|
LdapPartialAttribute {
|
||||||
|
atype: "uid".to_string(),
|
||||||
|
vals: vec![b"jim".to_vec()]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
make_search_success(),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_pwd_changed_time_format() {
|
||||||
|
use lldap_domain::uuid;
|
||||||
|
let mut mock = MockTestBackendHandler::new();
|
||||||
|
mock.expect_list_users().times(1).return_once(|_, _| {
|
||||||
|
Ok(vec![UserAndGroups {
|
||||||
|
user: User {
|
||||||
|
user_id: UserId::new("bob_1"),
|
||||||
|
email: "bob@bobmail.bob".into(),
|
||||||
|
uuid: uuid!("698e1d5f-7a40-3151-8745-b9b8a37839da"),
|
||||||
|
attributes: vec![],
|
||||||
|
password_modified_date: Utc
|
||||||
|
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
||||||
|
.unwrap()
|
||||||
|
.naive_utc(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
groups: None,
|
||||||
|
}])
|
||||||
|
});
|
||||||
|
let ldap_handler = setup_bound_admin_handler(mock).await;
|
||||||
|
let request = make_user_search_request(LdapFilter::And(vec![]), vec!["pwdChangedTime"]);
|
||||||
|
if let LdapOp::SearchResultEntry(entry) =
|
||||||
|
&ldap_handler.do_search_or_dse(&request).await.unwrap()[0]
|
||||||
|
{
|
||||||
|
assert_eq!(entry.attributes.len(), 1);
|
||||||
|
assert_eq!(entry.attributes[0].atype, "pwdChangedTime");
|
||||||
|
assert_eq!(entry.attributes[0].vals.len(), 1);
|
||||||
|
assert_timestamp_within_margin(
|
||||||
|
&entry.attributes[0].vals[0],
|
||||||
|
Utc.with_ymd_and_hms(2014, 7, 8, 9, 10, 11).unwrap(),
|
||||||
|
Duration::seconds(1),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Expected SearchResultEntry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+27
-736
@@ -434,16 +434,16 @@ mod tests {
|
|||||||
core::error::LdapError,
|
core::error::LdapError,
|
||||||
handler::tests::{
|
handler::tests::{
|
||||||
make_group_search_request, make_user_search_request, setup_bound_admin_handler,
|
make_group_search_request, make_user_search_request, setup_bound_admin_handler,
|
||||||
setup_bound_handler_with_group, setup_bound_readonly_handler,
|
setup_bound_readonly_handler,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Duration, NaiveDateTime, TimeZone};
|
use chrono::{DateTime, Duration, NaiveDateTime, TimeZone, Utc};
|
||||||
use ldap3_proto::proto::{LdapDerefAliases, LdapSearchScope, LdapSubstringFilter};
|
use ldap3_proto::proto::{LdapDerefAliases, LdapSearchScope, LdapSubstringFilter};
|
||||||
use lldap_domain::{
|
use lldap_domain::{
|
||||||
schema::{AttributeList, AttributeSchema, Schema},
|
schema::{AttributeList, AttributeSchema, Schema},
|
||||||
types::{
|
types::{
|
||||||
Attribute, AttributeName, AttributeType, GroupDetails, GroupId, JpegPhoto,
|
Attribute, AttributeName, AttributeType, GroupId, JpegPhoto, LdapObjectClass, User,
|
||||||
LdapObjectClass, User, UserId,
|
UserId,
|
||||||
},
|
},
|
||||||
uuid,
|
uuid,
|
||||||
};
|
};
|
||||||
@@ -453,28 +453,6 @@ mod tests {
|
|||||||
use mockall::predicate::eq;
|
use mockall::predicate::eq;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_root_dse() {
|
|
||||||
let ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
|
||||||
let request = LdapSearchRequest {
|
|
||||||
base: "".to_string(),
|
|
||||||
scope: LdapSearchScope::Base,
|
|
||||||
aliases: LdapDerefAliases::Never,
|
|
||||||
sizelimit: 0,
|
|
||||||
timelimit: 0,
|
|
||||||
typesonly: false,
|
|
||||||
filter: LdapFilter::Present("objectClass".to_string()),
|
|
||||||
attrs: vec!["supportedExtension".to_string()],
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
root_dse_response("dc=example,dc=com"),
|
|
||||||
make_search_success()
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_timestamp_within_margin(
|
fn assert_timestamp_within_margin(
|
||||||
timestamp_bytes: &[u8],
|
timestamp_bytes: &[u8],
|
||||||
base_timestamp_dt: DateTime<Utc>,
|
base_timestamp_dt: DateTime<Utc>,
|
||||||
@@ -497,6 +475,28 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_search_root_dse() {
|
||||||
|
let ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
||||||
|
let request = LdapSearchRequest {
|
||||||
|
base: "".to_string(),
|
||||||
|
scope: LdapSearchScope::Base,
|
||||||
|
aliases: LdapDerefAliases::Never,
|
||||||
|
sizelimit: 0,
|
||||||
|
timelimit: 0,
|
||||||
|
typesonly: false,
|
||||||
|
filter: LdapFilter::Present("objectClass".to_string()),
|
||||||
|
attrs: vec!["supportedExtension".to_string()],
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
ldap_handler.do_search_or_dse(&request).await,
|
||||||
|
Ok(vec![
|
||||||
|
root_dse_response("dc=example,dc=com"),
|
||||||
|
make_search_success()
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_subschema_response() {
|
async fn test_subschema_response() {
|
||||||
let ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
let ldap_handler = setup_bound_admin_handler(MockTestBackendHandler::new()).await;
|
||||||
@@ -659,661 +659,6 @@ mod tests {
|
|||||||
assert_eq!(actual_reponse[1], make_search_success());
|
assert_eq!(actual_reponse[1], make_search_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_regular_user() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_users()
|
|
||||||
.with(
|
|
||||||
eq(Some(UserRequestFilter::And(vec![
|
|
||||||
UserRequestFilter::True,
|
|
||||||
UserRequestFilter::UserId(UserId::new("test")),
|
|
||||||
]))),
|
|
||||||
eq(false),
|
|
||||||
)
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_, _| {
|
|
||||||
Ok(vec![UserAndGroups {
|
|
||||||
user: User {
|
|
||||||
user_id: UserId::new("test"),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
groups: None,
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_handler_with_group(mock, "regular").await;
|
|
||||||
|
|
||||||
let request =
|
|
||||||
make_user_search_request::<String>(LdapFilter::And(vec![]), vec!["1.1".to_string()]);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "uid=test,ou=people,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![],
|
|
||||||
}),
|
|
||||||
make_search_success()
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_readonly_user() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_users()
|
|
||||||
.with(eq(Some(UserRequestFilter::True)), eq(false))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_, _| Ok(vec![]));
|
|
||||||
let ldap_handler = setup_bound_readonly_handler(mock).await;
|
|
||||||
|
|
||||||
let request =
|
|
||||||
make_user_search_request::<String>(LdapFilter::And(vec![]), vec!["1.1".to_string()]);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![make_search_success()]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_member_of() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_users()
|
|
||||||
.with(eq(Some(UserRequestFilter::True)), eq(true))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_, _| {
|
|
||||||
Ok(vec![UserAndGroups {
|
|
||||||
user: User {
|
|
||||||
user_id: UserId::new("bob"),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
groups: Some(vec![GroupDetails {
|
|
||||||
group_id: GroupId(42),
|
|
||||||
display_name: "rockstars".into(),
|
|
||||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
}]),
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_readonly_handler(mock).await;
|
|
||||||
|
|
||||||
let request = make_user_search_request::<String>(
|
|
||||||
LdapFilter::And(vec![]),
|
|
||||||
vec!["memberOf".to_string()],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "uid=bob,ou=people,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![LdapPartialAttribute {
|
|
||||||
atype: "memberOf".to_string(),
|
|
||||||
vals: vec![b"cn=rockstars,ou=groups,dc=example,dc=com".to_vec()]
|
|
||||||
}],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_user_as_scope() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_users()
|
|
||||||
.with(
|
|
||||||
eq(Some(UserRequestFilter::UserId(UserId::new("bob")))),
|
|
||||||
eq(false),
|
|
||||||
)
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_, _| Ok(vec![]));
|
|
||||||
let ldap_handler = setup_bound_readonly_handler(mock).await;
|
|
||||||
|
|
||||||
let request = LdapSearchRequest {
|
|
||||||
base: "uid=bob,ou=people,Dc=example,dc=com".to_string(),
|
|
||||||
scope: LdapSearchScope::Base,
|
|
||||||
aliases: LdapDerefAliases::Never,
|
|
||||||
sizelimit: 0,
|
|
||||||
timelimit: 0,
|
|
||||||
typesonly: false,
|
|
||||||
filter: LdapFilter::And(vec![]),
|
|
||||||
attrs: vec!["1.1".to_string()],
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![make_search_success()]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_users() {
|
|
||||||
use chrono::prelude::*;
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_users().times(1).return_once(|_, _| {
|
|
||||||
Ok(vec![
|
|
||||||
UserAndGroups {
|
|
||||||
user: User {
|
|
||||||
user_id: UserId::new("bob_1"),
|
|
||||||
email: "bob@bobmail.bob".into(),
|
|
||||||
display_name: Some("Bôb Böbberson".to_string()),
|
|
||||||
uuid: uuid!("698e1d5f-7a40-3151-8745-b9b8a37839da"),
|
|
||||||
attributes: vec![
|
|
||||||
Attribute {
|
|
||||||
name: "first_name".into(),
|
|
||||||
value: "Bôb".to_string().into(),
|
|
||||||
},
|
|
||||||
Attribute {
|
|
||||||
name: "last_name".into(),
|
|
||||||
value: "Böbberson".to_string().into(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
groups: None,
|
|
||||||
},
|
|
||||||
UserAndGroups {
|
|
||||||
user: User {
|
|
||||||
user_id: UserId::new("jim"),
|
|
||||||
email: "jim@cricket.jim".into(),
|
|
||||||
display_name: Some("Jimminy Cricket".to_string()),
|
|
||||||
attributes: vec![
|
|
||||||
Attribute {
|
|
||||||
name: "avatar".into(),
|
|
||||||
value: JpegPhoto::for_tests().into(),
|
|
||||||
},
|
|
||||||
Attribute {
|
|
||||||
name: "first_name".into(),
|
|
||||||
value: "Jim".to_string().into(),
|
|
||||||
},
|
|
||||||
Attribute {
|
|
||||||
name: "last_name".into(),
|
|
||||||
value: "Cricket".to_string().into(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
|
||||||
creation_date: Utc
|
|
||||||
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
|
||||||
.unwrap()
|
|
||||||
.naive_utc(),
|
|
||||||
modified_date: Utc
|
|
||||||
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
|
||||||
.unwrap()
|
|
||||||
.naive_utc(),
|
|
||||||
password_modified_date: Utc
|
|
||||||
.with_ymd_and_hms(2014, 7, 8, 9, 10, 11)
|
|
||||||
.unwrap()
|
|
||||||
.naive_utc(),
|
|
||||||
},
|
|
||||||
groups: None,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
let request = make_user_search_request(
|
|
||||||
LdapFilter::And(vec![]),
|
|
||||||
vec![
|
|
||||||
"objectClass",
|
|
||||||
"dn",
|
|
||||||
"uid",
|
|
||||||
"mail",
|
|
||||||
"givenName",
|
|
||||||
"sn",
|
|
||||||
"cn",
|
|
||||||
"createTimestamp",
|
|
||||||
"entryUuid",
|
|
||||||
"jpegPhoto",
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "uid=bob_1,ou=people,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "cn".to_string(),
|
|
||||||
vals: vec!["Bôb Böbberson".to_string().into_bytes()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "createTimestamp".to_string(),
|
|
||||||
vals: vec![b"19700101000000Z".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "entryUuid".to_string(),
|
|
||||||
vals: vec![b"698e1d5f-7a40-3151-8745-b9b8a37839da".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "givenName".to_string(),
|
|
||||||
vals: vec!["Bôb".to_string().into_bytes()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "mail".to_string(),
|
|
||||||
vals: vec![b"bob@bobmail.bob".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "objectClass".to_string(),
|
|
||||||
vals: vec![
|
|
||||||
b"inetOrgPerson".to_vec(),
|
|
||||||
b"posixAccount".to_vec(),
|
|
||||||
b"mailAccount".to_vec(),
|
|
||||||
b"person".to_vec(),
|
|
||||||
b"customUserClass".to_vec(),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "sn".to_string(),
|
|
||||||
vals: vec!["Böbberson".to_string().into_bytes()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "uid".to_string(),
|
|
||||||
vals: vec![b"bob_1".to_vec()]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "uid=jim,ou=people,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "cn".to_string(),
|
|
||||||
vals: vec![b"Jimminy Cricket".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "createTimestamp".to_string(),
|
|
||||||
vals: vec![b"20140708091011Z".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "entryUuid".to_string(),
|
|
||||||
vals: vec![b"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "givenName".to_string(),
|
|
||||||
vals: vec![b"Jim".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "jpegPhoto".to_string(),
|
|
||||||
vals: vec![JpegPhoto::for_tests().into_bytes()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "mail".to_string(),
|
|
||||||
vals: vec![b"jim@cricket.jim".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "objectClass".to_string(),
|
|
||||||
vals: vec![
|
|
||||||
b"inetOrgPerson".to_vec(),
|
|
||||||
b"posixAccount".to_vec(),
|
|
||||||
b"mailAccount".to_vec(),
|
|
||||||
b"person".to_vec(),
|
|
||||||
b"customUserClass".to_vec(),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "sn".to_string(),
|
|
||||||
vals: vec![b"Cricket".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "uid".to_string(),
|
|
||||||
vals: vec![b"jim".to_vec()]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_groups() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_groups()
|
|
||||||
.with(eq(Some(GroupRequestFilter::True)))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_| {
|
|
||||||
Ok(vec![
|
|
||||||
Group {
|
|
||||||
id: GroupId(1),
|
|
||||||
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"),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
},
|
|
||||||
Group {
|
|
||||||
id: GroupId(3),
|
|
||||||
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"),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
let request = make_group_search_request(
|
|
||||||
LdapFilter::And(vec![]),
|
|
||||||
vec![
|
|
||||||
"objectClass",
|
|
||||||
"dn",
|
|
||||||
"cn",
|
|
||||||
"uniqueMember",
|
|
||||||
"entryUuid",
|
|
||||||
"entryDN",
|
|
||||||
],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "cn".to_string(),
|
|
||||||
vals: vec![b"group_1".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "entryDN".to_string(),
|
|
||||||
vals: vec![b"uid=group_1,ou=groups,dc=example,dc=com".to_vec()],
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "entryUuid".to_string(),
|
|
||||||
vals: vec![b"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_vec()],
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "objectClass".to_string(),
|
|
||||||
vals: vec![b"groupOfUniqueNames".to_vec(), b"groupOfNames".to_vec(),],
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "uniqueMember".to_string(),
|
|
||||||
vals: vec![
|
|
||||||
b"uid=bob,ou=people,dc=example,dc=com".to_vec(),
|
|
||||||
b"uid=john,ou=people,dc=example,dc=com".to_vec(),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "cn=BestGroup,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "cn".to_string(),
|
|
||||||
vals: vec![b"BestGroup".to_vec()]
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "entryDN".to_string(),
|
|
||||||
vals: vec![b"uid=BestGroup,ou=groups,dc=example,dc=com".to_vec()],
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "entryUuid".to_string(),
|
|
||||||
vals: vec![b"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_vec()],
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "objectClass".to_string(),
|
|
||||||
vals: vec![b"groupOfUniqueNames".to_vec(), b"groupOfNames".to_vec(),],
|
|
||||||
},
|
|
||||||
LdapPartialAttribute {
|
|
||||||
atype: "uniqueMember".to_string(),
|
|
||||||
vals: vec![b"uid=john,ou=people,dc=example,dc=com".to_vec()]
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_groups_by_groupid() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_groups()
|
|
||||||
.with(eq(Some(GroupRequestFilter::GroupId(GroupId(1)))))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_| {
|
|
||||||
Ok(vec![Group {
|
|
||||||
id: GroupId(1),
|
|
||||||
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"),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
let request = make_group_search_request(
|
|
||||||
LdapFilter::Equality("groupid".to_string(), "1".to_string()),
|
|
||||||
vec!["dn"],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_groups_filter() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_groups()
|
|
||||||
.with(eq(Some(GroupRequestFilter::And(vec![
|
|
||||||
GroupRequestFilter::DisplayName("group_1".into()),
|
|
||||||
GroupRequestFilter::Member(UserId::new("bob")),
|
|
||||||
GroupRequestFilter::DisplayName("rockstars".into()),
|
|
||||||
false.into(),
|
|
||||||
GroupRequestFilter::Uuid(uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc")),
|
|
||||||
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)
|
|
||||||
.return_once(|_| {
|
|
||||||
Ok(vec![Group {
|
|
||||||
display_name: "group_1".into(),
|
|
||||||
id: GroupId(1),
|
|
||||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
users: vec![],
|
|
||||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
let request = make_group_search_request(
|
|
||||||
LdapFilter::And(vec![
|
|
||||||
LdapFilter::Equality("cN".to_string(), "Group_1".to_string()),
|
|
||||||
LdapFilter::Equality(
|
|
||||||
"uniqueMember".to_string(),
|
|
||||||
"uid=bob,ou=peopLe,Dc=eXample,dc=com".to_string(),
|
|
||||||
),
|
|
||||||
LdapFilter::Equality(
|
|
||||||
"dn".to_string(),
|
|
||||||
"uid=rockstars,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
),
|
|
||||||
LdapFilter::Equality(
|
|
||||||
"dn".to_string(),
|
|
||||||
"uid=rockstars,ou=people,dc=example,dc=com".to_string(),
|
|
||||||
),
|
|
||||||
LdapFilter::Equality(
|
|
||||||
"uuid".to_string(),
|
|
||||||
"04ac75e0-2900-3e21-926c-2f732c26b3fc".to_string(),
|
|
||||||
),
|
|
||||||
LdapFilter::Equality("obJEctclass".to_string(), "groupofUniqueNames".to_string()),
|
|
||||||
LdapFilter::Equality("objectclass".to_string(), "groupOfNames".to_string()),
|
|
||||||
LdapFilter::Present("objectclass".to_string()),
|
|
||||||
LdapFilter::Present("dn".to_string()),
|
|
||||||
LdapFilter::Not(Box::new(LdapFilter::Present(
|
|
||||||
"random_attribUte".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"],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_groups_filter_2() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_groups()
|
|
||||||
.with(eq(Some(GroupRequestFilter::Not(Box::new(
|
|
||||||
GroupRequestFilter::DisplayName("group_2".into()),
|
|
||||||
)))))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_| {
|
|
||||||
Ok(vec![Group {
|
|
||||||
display_name: "group_1".into(),
|
|
||||||
id: GroupId(1),
|
|
||||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
users: vec![],
|
|
||||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
|
||||||
attributes: Vec::new(),
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
let request = make_group_search_request(
|
|
||||||
LdapFilter::Or(vec![LdapFilter::Not(Box::new(LdapFilter::Equality(
|
|
||||||
"displayname".to_string(),
|
|
||||||
"group_2".to_string(),
|
|
||||||
)))]),
|
|
||||||
vec!["cn"],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![LdapPartialAttribute {
|
|
||||||
atype: "cn".to_string(),
|
|
||||||
vals: vec![b"group_1".to_vec()]
|
|
||||||
},],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_groups_filter_3() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_groups()
|
|
||||||
.with(eq(Some(GroupRequestFilter::Or(vec![
|
|
||||||
GroupRequestFilter::AttributeEquality(
|
|
||||||
AttributeName::from("attr"),
|
|
||||||
"TEST".to_string().into(),
|
|
||||||
),
|
|
||||||
GroupRequestFilter::AttributeEquality(
|
|
||||||
AttributeName::from("attr"),
|
|
||||||
"test".to_string().into(),
|
|
||||||
),
|
|
||||||
]))))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_| {
|
|
||||||
Ok(vec![Group {
|
|
||||||
display_name: "group_1".into(),
|
|
||||||
id: GroupId(1),
|
|
||||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
users: vec![],
|
|
||||||
uuid: uuid!("04ac75e0-2900-3e21-926c-2f732c26b3fc"),
|
|
||||||
attributes: vec![Attribute {
|
|
||||||
name: "Attr".into(),
|
|
||||||
value: "TEST".to_string().into(),
|
|
||||||
}],
|
|
||||||
modified_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
mock.expect_get_schema().returning(|| {
|
|
||||||
Ok(Schema {
|
|
||||||
user_attributes: AttributeList {
|
|
||||||
attributes: Vec::new(),
|
|
||||||
},
|
|
||||||
group_attributes: AttributeList {
|
|
||||||
attributes: vec![AttributeSchema {
|
|
||||||
name: "Attr".into(),
|
|
||||||
attribute_type: AttributeType::String,
|
|
||||||
is_list: false,
|
|
||||||
is_visible: true,
|
|
||||||
is_editable: true,
|
|
||||||
is_hardcoded: false,
|
|
||||||
is_readonly: false,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
extra_user_object_classes: Vec::new(),
|
|
||||||
extra_group_object_classes: Vec::new(),
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
let request = make_group_search_request(
|
|
||||||
LdapFilter::Equality("Attr".to_string(), "TEST".to_string()),
|
|
||||||
vec!["cn"],
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![
|
|
||||||
LdapOp::SearchResultEntry(LdapSearchResultEntry {
|
|
||||||
dn: "cn=group_1,ou=groups,dc=example,dc=com".to_string(),
|
|
||||||
attributes: vec![LdapPartialAttribute {
|
|
||||||
atype: "cn".to_string(),
|
|
||||||
vals: vec![b"group_1".to_vec()]
|
|
||||||
},],
|
|
||||||
}),
|
|
||||||
make_search_success(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_search_group_as_scope() {
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
mock.expect_list_groups()
|
|
||||||
.with(eq(Some(GroupRequestFilter::DisplayName(
|
|
||||||
"rockstars".into(),
|
|
||||||
))))
|
|
||||||
.times(1)
|
|
||||||
.return_once(|_| Ok(vec![]));
|
|
||||||
let ldap_handler = setup_bound_readonly_handler(mock).await;
|
|
||||||
|
|
||||||
let request = LdapSearchRequest {
|
|
||||||
base: "uid=rockstars,ou=groups,Dc=example,dc=com".to_string(),
|
|
||||||
scope: LdapSearchScope::Base,
|
|
||||||
aliases: LdapDerefAliases::Never,
|
|
||||||
sizelimit: 0,
|
|
||||||
timelimit: 0,
|
|
||||||
typesonly: false,
|
|
||||||
filter: LdapFilter::And(vec![]),
|
|
||||||
attrs: vec!["1.1".to_string()],
|
|
||||||
};
|
|
||||||
assert_eq!(
|
|
||||||
ldap_handler.do_search_or_dse(&request).await,
|
|
||||||
Ok(vec![make_search_success()]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_search_groups_unsupported_substring() {
|
async fn test_search_groups_unsupported_substring() {
|
||||||
let ldap_handler = setup_bound_readonly_handler(MockTestBackendHandler::new()).await;
|
let ldap_handler = setup_bound_readonly_handler(MockTestBackendHandler::new()).await;
|
||||||
@@ -1541,6 +886,7 @@ mod tests {
|
|||||||
Ok(vec![make_search_success()])
|
Ok(vec![make_search_success()])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_search_member_of_filter_error() {
|
async fn test_search_member_of_filter_error() {
|
||||||
let mut mock = MockTestBackendHandler::new();
|
let mut mock = MockTestBackendHandler::new();
|
||||||
@@ -2101,59 +1447,4 @@ mod tests {
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_pwd_changed_time_format() {
|
|
||||||
use chrono::prelude::*;
|
|
||||||
let mut mock = MockTestBackendHandler::new();
|
|
||||||
let test_date = chrono::Utc
|
|
||||||
.with_ymd_and_hms(2024, 12, 31, 14, 30, 45)
|
|
||||||
.unwrap()
|
|
||||||
.naive_utc();
|
|
||||||
|
|
||||||
mock.expect_list_users().times(1).return_once(move |_, _| {
|
|
||||||
Ok(vec![UserAndGroups {
|
|
||||||
user: User {
|
|
||||||
user_id: UserId::new("testuser"),
|
|
||||||
email: "test@example.com".into(),
|
|
||||||
display_name: Some("Test User".to_string()),
|
|
||||||
uuid: uuid!("12345678-9abc-def0-1234-56789abcdef0"),
|
|
||||||
password_modified_date: test_date,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
groups: None,
|
|
||||||
}])
|
|
||||||
});
|
|
||||||
let ldap_handler = setup_bound_admin_handler(mock).await;
|
|
||||||
|
|
||||||
let request = make_search_request(
|
|
||||||
"ou=people,dc=example,dc=com",
|
|
||||||
LdapFilter::Equality("uid".into(), "testuser".into()),
|
|
||||||
vec!["pwdChangedTime"],
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = ldap_handler.do_search_or_dse(&request).await.unwrap();
|
|
||||||
|
|
||||||
if let LdapOp::SearchResultEntry(entry) = &result[0] {
|
|
||||||
assert_eq!(entry.dn, "uid=testuser,ou=people,dc=example,dc=com");
|
|
||||||
assert_eq!(entry.attributes.len(), 1);
|
|
||||||
|
|
||||||
let pwd_changed_time_attr = &entry.attributes[0];
|
|
||||||
assert_eq!(pwd_changed_time_attr.atype, "pwdChangedTime");
|
|
||||||
assert_eq!(pwd_changed_time_attr.vals.len(), 1);
|
|
||||||
|
|
||||||
let timestamp_str = std::str::from_utf8(&pwd_changed_time_attr.vals[0])
|
|
||||||
.expect("Invalid UTF-8 in timestamp");
|
|
||||||
|
|
||||||
// Verify it's in GeneralizedTime format (YYYYMMDDHHMMSSZ)
|
|
||||||
assert_eq!(timestamp_str, "20241231143045Z");
|
|
||||||
|
|
||||||
// Verify the format can be parsed back correctly
|
|
||||||
let parsed_time = chrono::NaiveDateTime::parse_from_str(timestamp_str, "%Y%m%d%H%M%SZ")
|
|
||||||
.expect("Invalid GeneralizedTime format");
|
|
||||||
assert_eq!(parsed_time, test_date);
|
|
||||||
} else {
|
|
||||||
panic!("Expected SearchResultEntry");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user