mirror of
https://github.com/lldap/lldap.git
synced 2026-03-31 15:07:48 +01:00
server: add tests for ldap modify
This commit is contained in:
committed by
nitnelave
parent
0a05a091d8
commit
c3ae149ae3
@@ -56,8 +56,11 @@ mod tests {
|
||||
ldap::handler::tests::setup_bound_admin_handler, test_utils::MockTestBackendHandler,
|
||||
};
|
||||
use chrono::TimeZone;
|
||||
use lldap_domain::{types::*, uuid};
|
||||
use lldap_domain_handlers::handler::*;
|
||||
use lldap_domain::{
|
||||
types::{Group, GroupId, User, UserAndGroups, UserId},
|
||||
uuid,
|
||||
};
|
||||
use lldap_domain_handlers::handler::{GroupRequestFilter, UserRequestFilter};
|
||||
use pretty_assertions::assert_eq;
|
||||
use tokio;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ use ldap3_proto::proto::{
|
||||
LdapResult as LdapResultOp, LdapResultCode, LdapSearchRequest, OID_PASSWORD_MODIFY, OID_WHOAMI,
|
||||
};
|
||||
use lldap_auth::access_control::ValidationResults;
|
||||
use lldap_domain::types::{AttributeName, UserId};
|
||||
use lldap_domain::types::AttributeName;
|
||||
use lldap_domain_handlers::handler::{BackendHandler, LoginHandler};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
@@ -235,7 +235,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug", fields(dn = %request.dn))]
|
||||
async fn do_modify_request(&mut self, request: &LdapModifyRequest) -> Vec<LdapOp> {
|
||||
pub async fn do_modify_request(&mut self, request: &LdapModifyRequest) -> Vec<LdapOp> {
|
||||
let credentials = match self.get_credentials() {
|
||||
Credentials::Bound(cred) => cred,
|
||||
Credentials::Unbound(err) => return err,
|
||||
@@ -245,7 +245,6 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
|credentials, user_id| {
|
||||
self.backend_handler
|
||||
.get_readable_handler(credentials, &user_id)
|
||||
.expect("Unexpected permission error")
|
||||
},
|
||||
&self.ldap_info,
|
||||
credentials,
|
||||
@@ -328,7 +327,10 @@ pub mod tests {
|
||||
};
|
||||
use chrono::TimeZone;
|
||||
use ldap3_proto::proto::{LdapBindCred, LdapWhoamiRequest};
|
||||
use lldap_domain::{types::*, uuid};
|
||||
use lldap_domain::{
|
||||
types::{GroupDetails, GroupId, UserId},
|
||||
uuid,
|
||||
};
|
||||
use lldap_domain_handlers::handler::*;
|
||||
use mockall::predicate::eq;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@@ -69,7 +69,10 @@ async fn handle_modify_change(
|
||||
|
||||
pub(crate) async fn handle_modify_request<'cred, UserBackendHandler>(
|
||||
opaque_handler: &impl OpaqueHandler,
|
||||
get_readable_handler: impl FnOnce(&'cred ValidationResults, UserId) -> &'cred UserBackendHandler,
|
||||
get_readable_handler: impl FnOnce(
|
||||
&'cred ValidationResults,
|
||||
UserId,
|
||||
) -> Option<&'cred UserBackendHandler>,
|
||||
ldap_info: &LdapInfo,
|
||||
credentials: &'cred ValidationResults,
|
||||
request: &LdapModifyRequest,
|
||||
@@ -85,6 +88,14 @@ where
|
||||
) {
|
||||
Ok(uid) => {
|
||||
let user_is_admin = get_readable_handler(credentials, uid.clone())
|
||||
.ok_or_else(|| LdapError {
|
||||
code: LdapResultCode::InsufficentAccessRights,
|
||||
message: format!(
|
||||
"User `{}` cannot modify user `{}`",
|
||||
credentials.user.as_str(),
|
||||
uid.as_str()
|
||||
),
|
||||
})?
|
||||
.get_user_groups(&uid)
|
||||
.await
|
||||
.map_err(|e| LdapError {
|
||||
@@ -114,3 +125,191 @@ where
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::*;
|
||||
use crate::infra::{
|
||||
ldap::{
|
||||
handler::tests::{
|
||||
setup_bound_admin_handler, setup_bound_handler_with_group,
|
||||
setup_bound_password_manager_handler,
|
||||
},
|
||||
password::tests::expect_password_change,
|
||||
},
|
||||
test_utils::MockTestBackendHandler,
|
||||
};
|
||||
use chrono::TimeZone;
|
||||
use ldap3_proto::proto::LdapResult as LdapResultOp;
|
||||
use lldap_domain::{
|
||||
types::{GroupDetails, GroupId, GroupName, UserId},
|
||||
uuid,
|
||||
};
|
||||
use mockall::predicate::eq;
|
||||
use pretty_assertions::assert_eq;
|
||||
use tokio;
|
||||
|
||||
fn setup_target_user_groups(
|
||||
mock: &mut MockTestBackendHandler,
|
||||
target_user: &str,
|
||||
groups: Vec<&'static str>,
|
||||
) {
|
||||
mock.expect_get_user_groups()
|
||||
.times(1)
|
||||
.with(eq(UserId::from(target_user)))
|
||||
.return_once(move |_| {
|
||||
let mut g = HashSet::<GroupDetails>::new();
|
||||
for group in groups {
|
||||
g.insert(GroupDetails {
|
||||
group_id: GroupId(42),
|
||||
display_name: GroupName::from(group),
|
||||
creation_date: chrono::Utc.timestamp_opt(42, 42).unwrap().naive_utc(),
|
||||
uuid: uuid!("a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8"),
|
||||
attributes: Vec::new(),
|
||||
});
|
||||
}
|
||||
Ok(g)
|
||||
});
|
||||
}
|
||||
|
||||
fn make_password_modify_request(target_user: &str) -> LdapModifyRequest {
|
||||
LdapModifyRequest {
|
||||
dn: format!("uid={},ou=people,dc=example,dc=com", target_user),
|
||||
changes: vec![LdapModify {
|
||||
operation: LdapModifyType::Replace,
|
||||
modification: ldap3_proto::LdapPartialAttribute {
|
||||
atype: "userPassword".to_string(),
|
||||
vals: vec![b"tommy".to_vec()],
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
fn make_modify_success_response() -> Vec<LdapOp> {
|
||||
vec![LdapOp::ModifyResponse(LdapResultOp {
|
||||
code: LdapResultCode::Success,
|
||||
matcheddn: "".to_string(),
|
||||
message: "".to_string(),
|
||||
referral: vec![],
|
||||
})]
|
||||
}
|
||||
|
||||
fn make_modify_failure_response(code: LdapResultCode, message: &str) -> Vec<LdapOp> {
|
||||
vec![LdapOp::ModifyResponse(LdapResultOp {
|
||||
code,
|
||||
matcheddn: "".to_string(),
|
||||
message: message.to_string(),
|
||||
referral: vec![],
|
||||
})]
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_of_regular_as_admin() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
setup_target_user_groups(&mut mock, "bob", Vec::new());
|
||||
expect_password_change(&mut mock, "bob");
|
||||
let mut ldap_handler = setup_bound_admin_handler(mock).await;
|
||||
let request = make_password_modify_request("bob");
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_success_response()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_of_regular_as_regular() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
setup_target_user_groups(&mut mock, "test", Vec::new());
|
||||
expect_password_change(&mut mock, "test");
|
||||
let mut ldap_handler = setup_bound_handler_with_group(mock, "regular").await;
|
||||
let request = make_password_modify_request("test");
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_success_response()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_of_regular_as_password_manager() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
setup_target_user_groups(&mut mock, "bob", Vec::new());
|
||||
expect_password_change(&mut mock, "bob");
|
||||
let mut ldap_handler = setup_bound_password_manager_handler(mock).await;
|
||||
let request = make_password_modify_request("bob");
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_success_response()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_of_admin_as_password_manager() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
setup_target_user_groups(&mut mock, "bob", vec!["lldap_admin"]);
|
||||
let mut ldap_handler = setup_bound_password_manager_handler(mock).await;
|
||||
let request = make_password_modify_request("bob");
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_failure_response(
|
||||
LdapResultCode::InsufficentAccessRights,
|
||||
"User `test` cannot modify the password of user `bob`"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_of_other_regular_as_regular() {
|
||||
let mut ldap_handler =
|
||||
setup_bound_handler_with_group(MockTestBackendHandler::new(), "regular").await;
|
||||
let request = make_password_modify_request("bob");
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_failure_response(
|
||||
LdapResultCode::InsufficentAccessRights,
|
||||
"User `test` cannot modify user `bob`"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_of_admin_as_admin() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
setup_target_user_groups(&mut mock, "test", vec!["lldap_admin"]);
|
||||
expect_password_change(&mut mock, "test");
|
||||
let mut ldap_handler = setup_bound_admin_handler(mock).await;
|
||||
let request = make_password_modify_request("test");
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_success_response()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_modify_password_invalid_number_of_values() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
setup_target_user_groups(&mut mock, "bob", Vec::new());
|
||||
let mut ldap_handler = setup_bound_admin_handler(mock).await;
|
||||
let request = {
|
||||
let target_user = "bob";
|
||||
LdapModifyRequest {
|
||||
dn: format!("uid={},ou=people,dc=example,dc=com", target_user),
|
||||
changes: vec![LdapModify {
|
||||
operation: LdapModifyType::Replace,
|
||||
modification: ldap3_proto::LdapPartialAttribute {
|
||||
atype: "userPassword".to_string(),
|
||||
vals: vec![b"tommy".to_vec(), b"other_value".to_vec()],
|
||||
},
|
||||
}],
|
||||
}
|
||||
};
|
||||
assert_eq!(
|
||||
ldap_handler.do_modify_request(&request).await,
|
||||
make_modify_failure_response(
|
||||
LdapResultCode::InvalidAttributeSyntax,
|
||||
"Wrong number of values for password attribute: 2"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,33 @@ pub mod tests {
|
||||
make_bind_result(LdapResultCode::Success, "")
|
||||
}
|
||||
|
||||
pub fn expect_password_change(mock: &mut MockTestBackendHandler, user: &str) {
|
||||
use lldap_auth::{opaque, registration};
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
let registration_start_request =
|
||||
opaque::client::registration::start_registration("password".as_bytes(), &mut rng)
|
||||
.unwrap();
|
||||
let request = registration::ClientRegistrationStartRequest {
|
||||
username: user.into(),
|
||||
registration_start_request: registration_start_request.message,
|
||||
};
|
||||
let start_response = opaque::server::registration::start_registration(
|
||||
&opaque::server::ServerSetup::new(&mut rng),
|
||||
request.registration_start_request,
|
||||
&request.username,
|
||||
)
|
||||
.unwrap();
|
||||
mock.expect_registration_start().times(1).return_once(|_| {
|
||||
Ok(registration::ServerRegistrationStartResponse {
|
||||
server_data: "".to_string(),
|
||||
registration_response: start_response.message,
|
||||
})
|
||||
});
|
||||
mock.expect_registration_finish()
|
||||
.times(1)
|
||||
.return_once(|_| Ok(()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_bind() {
|
||||
let mut mock = MockTestBackendHandler::new();
|
||||
@@ -323,30 +350,7 @@ pub mod tests {
|
||||
mock.expect_get_user_groups()
|
||||
.with(eq(UserId::new("bob")))
|
||||
.returning(|_| Ok(HashSet::new()));
|
||||
use lldap_auth::*;
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
let registration_start_request =
|
||||
opaque::client::registration::start_registration("password".as_bytes(), &mut rng)
|
||||
.unwrap();
|
||||
let request = registration::ClientRegistrationStartRequest {
|
||||
username: "bob".into(),
|
||||
registration_start_request: registration_start_request.message,
|
||||
};
|
||||
let start_response = opaque::server::registration::start_registration(
|
||||
&opaque::server::ServerSetup::new(&mut rng),
|
||||
request.registration_start_request,
|
||||
&request.username,
|
||||
)
|
||||
.unwrap();
|
||||
mock.expect_registration_start().times(1).return_once(|_| {
|
||||
Ok(registration::ServerRegistrationStartResponse {
|
||||
server_data: "".to_string(),
|
||||
registration_response: start_response.message,
|
||||
})
|
||||
});
|
||||
mock.expect_registration_finish()
|
||||
.times(1)
|
||||
.return_once(|_| Ok(()));
|
||||
expect_password_change(&mut mock, "bob");
|
||||
let mut ldap_handler = setup_bound_admin_handler(mock).await;
|
||||
let request = LdapOp::ExtendedRequest(
|
||||
LdapPasswordModifyRequest {
|
||||
|
||||
Reference in New Issue
Block a user