server: extract ldap operations to a crate

This commit is contained in:
Valentin Tolmer
2025-04-04 21:52:19 -05:00
committed by nitnelave
parent a49ddeaa02
commit ee21d83056
28 changed files with 239 additions and 136 deletions
Generated
+41
View File
@@ -2547,7 +2547,9 @@ dependencies = [
"lldap_domain_handlers",
"lldap_domain_model",
"lldap_frontend_options",
"lldap_ldap",
"lldap_opaque_handler",
"lldap_test_utils",
"lldap_validation",
"log",
"mockall",
@@ -2713,6 +2715,28 @@ dependencies = [
"serde",
]
[[package]]
name = "lldap_ldap"
version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"ldap3_proto",
"lldap_access_control",
"lldap_auth",
"lldap_domain",
"lldap_domain_handlers",
"lldap_domain_model",
"lldap_opaque_handler",
"lldap_test_utils",
"mockall",
"pretty_assertions",
"rand 0.8.5",
"tokio",
"tracing",
"uuid 1.11.0",
]
[[package]]
name = "lldap_migration_tool"
version = "0.4.2"
@@ -2738,6 +2762,7 @@ dependencies = [
"lldap_auth",
"lldap_domain",
"lldap_domain_model",
"mockall",
]
[[package]]
@@ -2753,6 +2778,22 @@ dependencies = [
"serde_json",
]
[[package]]
name = "lldap_test_utils"
version = "0.1.0"
dependencies = [
"async-trait",
"ldap3_proto",
"lldap_access_control",
"lldap_domain",
"lldap_domain_handlers",
"lldap_domain_model",
"lldap_opaque_handler",
"mockall",
"tracing",
"uuid 1.11.0",
]
[[package]]
name = "lldap_validation"
version = "0.6.0"
@@ -1,5 +1,5 @@
use crate::types::{AttributeType, AttributeValue, JpegPhoto};
use anyhow::{Context as AnyhowContext, Result, bail};
use lldap_domain::types::{AttributeType, AttributeValue, JpegPhoto};
pub fn deserialize_attribute_value(
value: &[String],
+1
View File
@@ -1,3 +1,4 @@
pub mod deserialize;
pub mod public_schema;
pub mod requests;
pub mod schema;
+56
View File
@@ -0,0 +1,56 @@
[package]
name = "lldap_ldap"
version = "0.1.0"
description = "LDAP operations support"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
anyhow = "*"
ldap3_proto = "0.6.0"
tracing = "*"
[dependencies.chrono]
features = ["serde"]
version = "*"
[dependencies.rand]
features = ["small_rng", "getrandom"]
version = "0.8"
[dependencies.uuid]
version = "1"
features = ["v1", "v3"]
[dependencies.lldap_access_control]
path = "../access-control"
[dependencies.lldap_auth]
path = "../auth"
features = ["opaque_server", "opaque_client", "sea_orm"]
[dependencies.lldap_domain]
path = "../domain"
[dependencies.lldap_domain_handlers]
path = "../domain-handlers"
[dependencies.lldap_domain_model]
path = "../domain-model"
[dependencies.lldap_opaque_handler]
path = "../opaque-handler"
[dev-dependencies.lldap_test_utils]
path = "../test-utils"
[dev-dependencies]
mockall = "0.11.4"
pretty_assertions = "1"
[dev-dependencies.tokio]
features = ["full"]
version = "1.25"
@@ -1,4 +1,4 @@
use crate::domain::ldap::error::{LdapError, LdapResult};
use crate::core::error::{LdapError, LdapResult};
use ldap3_proto::proto::{LdapCompareRequest, LdapOp, LdapResult as LdapResultOp, LdapResultCode};
use lldap_domain::types::AttributeName;
@@ -52,17 +52,16 @@ pub fn compare(
#[cfg(test)]
mod tests {
use super::*;
use crate::infra::{
ldap::handler::tests::setup_bound_admin_handler, test_utils::MockTestBackendHandler,
};
use crate::handler::tests::setup_bound_admin_handler;
use chrono::TimeZone;
use lldap_domain::{
types::{Group, GroupId, User, UserAndGroups, UserId},
uuid,
};
use lldap_domain_handlers::handler::{GroupRequestFilter, UserRequestFilter};
use lldap_test_utils::MockTestBackendHandler;
use pretty_assertions::assert_eq;
use tokio;
#[tokio::test]
async fn test_compare_user() {
@@ -1,25 +1,22 @@
use crate::core::{
error::{LdapError, LdapResult},
utils::{
ExpandedAttributes, GroupFieldType, LdapInfo, expand_attribute_wildcards,
get_custom_attribute, get_group_id_from_distinguished_name_or_plain_name,
get_user_id_from_distinguished_name_or_plain_name, map_group_field,
},
};
use chrono::TimeZone;
use ldap3_proto::{
LdapFilter, LdapPartialAttribute, LdapResultCode, LdapSearchResultEntry, proto::LdapOp,
};
use tracing::{debug, instrument, warn};
use crate::domain::{
deserialize::deserialize_attribute_value,
ldap::{
error::{LdapError, LdapResult},
utils::{
ExpandedAttributes, GroupFieldType, LdapInfo, expand_attribute_wildcards,
get_custom_attribute, get_group_id_from_distinguished_name_or_plain_name,
get_user_id_from_distinguished_name_or_plain_name, map_group_field,
},
},
};
use lldap_domain::{
deserialize::deserialize_attribute_value,
public_schema::PublicSchema,
types::{AttributeName, AttributeType, Group, GroupId, LdapObjectClass, UserId, Uuid},
};
use lldap_domain_handlers::handler::{GroupListerBackendHandler, GroupRequestFilter};
use tracing::{debug, instrument, warn};
pub fn get_group_attribute(
group: &Group,
@@ -1,21 +1,17 @@
use crate::core::{
error::{LdapError, LdapResult},
utils::{
ExpandedAttributes, LdapInfo, UserFieldType, expand_attribute_wildcards,
get_custom_attribute, get_group_id_from_distinguished_name_or_plain_name,
get_user_id_from_distinguished_name_or_plain_name, map_user_field,
},
};
use chrono::TimeZone;
use ldap3_proto::{
LdapFilter, LdapPartialAttribute, LdapResultCode, LdapSearchResultEntry, proto::LdapOp,
};
use tracing::{debug, instrument, warn};
use crate::domain::{
deserialize::deserialize_attribute_value,
ldap::{
error::{LdapError, LdapResult},
utils::{
ExpandedAttributes, LdapInfo, UserFieldType, expand_attribute_wildcards,
get_custom_attribute, get_group_id_from_distinguished_name_or_plain_name,
get_user_id_from_distinguished_name_or_plain_name, map_user_field,
},
},
};
use lldap_domain::{
deserialize::deserialize_attribute_value,
public_schema::PublicSchema,
types::{
AttributeName, AttributeType, GroupDetails, LdapObjectClass, User, UserAndGroups, UserId,
@@ -23,6 +19,7 @@ use lldap_domain::{
};
use lldap_domain_handlers::handler::{UserListerBackendHandler, UserRequestFilter};
use lldap_domain_model::model::UserColumn;
use tracing::{debug, instrument, warn};
pub fn get_user_attribute(
user: &User,
@@ -1,10 +1,6 @@
use std::collections::BTreeMap;
use crate::core::error::{LdapError, LdapResult};
use chrono::TimeZone;
use ldap3_proto::LdapResultCode;
use tracing::{debug, instrument, warn};
use crate::domain::ldap::error::{LdapError, LdapResult};
use lldap_domain::{
public_schema::PublicSchema,
types::{
@@ -12,6 +8,8 @@ use lldap_domain::{
},
};
use lldap_domain_model::model::UserColumn;
use std::collections::BTreeMap;
use tracing::{debug, instrument, warn};
fn make_dn_pair<I>(mut iter: I) -> LdapResult<(String, String)>
where
@@ -1,18 +1,16 @@
use crate::{
domain::{
deserialize,
ldap::{
error::{LdapError, LdapResult},
utils::{LdapInfo, UserOrGroupName, get_user_or_group_id_from_distinguished_name},
},
core::{
error::{LdapError, LdapResult},
utils::{LdapInfo, UserOrGroupName, get_user_or_group_id_from_distinguished_name},
},
infra::ldap::handler::make_add_response,
handler::make_add_response,
};
use ldap3_proto::proto::{
LdapAddRequest, LdapAttribute, LdapOp, LdapPartialAttribute, LdapResultCode,
};
use lldap_access_control::AdminBackendHandler;
use lldap_domain::{
deserialize,
requests::{CreateGroupRequest, CreateUserRequest},
types::{Attribute, AttributeName, AttributeType, Email, GroupName, UserId},
};
@@ -169,13 +167,12 @@ async fn create_group(
#[cfg(test)]
mod tests {
use super::*;
use crate::infra::{
ldap::handler::tests::setup_bound_admin_handler, test_utils::MockTestBackendHandler,
};
use crate::handler::tests::setup_bound_admin_handler;
use lldap_domain::types::*;
use lldap_test_utils::MockTestBackendHandler;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use tokio;
#[tokio::test]
async fn test_create_user() {
@@ -1,4 +1,4 @@
use crate::domain::ldap::{
use crate::core::{
error::{LdapError, LdapResult},
utils::{LdapInfo, UserOrGroupName, get_user_or_group_id_from_distinguished_name},
};
@@ -105,18 +105,17 @@ async fn delete_group(
#[cfg(test)]
mod tests {
use super::*;
use crate::infra::{
ldap::handler::tests::setup_bound_admin_handler, test_utils::MockTestBackendHandler,
};
use crate::handler::tests::setup_bound_admin_handler;
use chrono::TimeZone;
use lldap_domain::{
types::{Group, GroupId, User},
uuid,
};
use lldap_domain_model::error::DomainError;
use lldap_test_utils::MockTestBackendHandler;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use tokio;
#[tokio::test]
async fn test_delete_user() {
@@ -1,15 +1,14 @@
use crate::{
domain::ldap::{
compare,
core::{
error::{LdapError, LdapResult},
utils::{LdapInfo, parse_distinguished_name},
},
infra::ldap::{
compare, create, delete, modify,
password::{self, do_password_modification},
search::{
self, is_root_dse_request, make_search_error, make_search_request, make_search_success,
root_dse_response,
},
create, delete, modify,
password::{self, do_password_modification},
search::{
self, is_root_dse_request, make_search_error, make_search_request, make_search_success,
root_dse_response,
},
};
use ldap3_proto::proto::{
@@ -333,10 +332,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
#[cfg(test)]
pub mod tests {
use super::*;
use crate::infra::{
ldap::password::tests::make_bind_success,
test_utils::{MockTestBackendHandler, setup_default_schema},
};
use crate::password::tests::make_bind_success;
use chrono::TimeZone;
use ldap3_proto::proto::{LdapBindCred, LdapWhoamiRequest};
use lldap_domain::{
@@ -344,6 +340,7 @@ pub mod tests {
uuid,
};
use lldap_domain_handlers::handler::*;
use lldap_test_utils::{MockTestBackendHandler, setup_default_schema};
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use std::collections::HashSet;
+11
View File
@@ -0,0 +1,11 @@
pub(crate) mod compare;
pub(crate) mod core;
pub(crate) mod create;
pub(crate) mod delete;
pub(crate) mod handler;
pub(crate) mod modify;
pub(crate) mod password;
pub(crate) mod search;
pub use core::utils::{UserFieldType, map_group_field, map_user_field};
pub use handler::LdapHandler;
@@ -1,12 +1,10 @@
use crate::{
domain::ldap::{
core::{
error::{LdapError, LdapResult},
utils::{LdapInfo, get_user_id_from_distinguished_name},
},
infra::ldap::{
handler::make_modify_response,
password::{self},
},
handler::make_modify_response,
password::{self},
};
use ldap3_proto::proto::{LdapModify, LdapModifyRequest, LdapModifyType, LdapOp, LdapResultCode};
use lldap_access_control::UserReadableBackendHandler;
@@ -124,18 +122,13 @@ 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,
use crate::{
handler::tests::{
setup_bound_admin_handler, setup_bound_handler_with_group,
setup_bound_password_manager_handler,
},
test_utils::MockTestBackendHandler,
password::tests::expect_password_change,
};
use chrono::TimeZone;
use ldap3_proto::proto::LdapResult as LdapResultOp;
@@ -143,9 +136,11 @@ mod tests {
types::{GroupDetails, GroupId, GroupName, UserId},
uuid,
};
use lldap_test_utils::MockTestBackendHandler;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use tokio;
use std::collections::HashSet;
fn setup_target_user_groups(
mock: &mut MockTestBackendHandler,
@@ -1,9 +1,9 @@
use crate::{
domain::ldap::{
core::{
error::{LdapError, LdapResult},
utils::{LdapInfo, get_user_id_from_distinguished_name},
},
infra::ldap::handler::make_extended_response,
handler::make_extended_response,
};
use anyhow::Result;
use ldap3_proto::proto::{
@@ -156,15 +156,12 @@ pub(crate) async fn do_password_modification<Handler: BackendHandler>(
#[cfg(test)]
pub mod tests {
use super::*;
use crate::infra::{
ldap::handler::{
LdapHandler, make_modify_response,
tests::{
setup_bound_admin_handler, setup_bound_password_manager_handler,
setup_bound_readonly_handler,
},
use crate::handler::{
LdapHandler, make_modify_response,
tests::{
setup_bound_admin_handler, setup_bound_password_manager_handler,
setup_bound_readonly_handler,
},
test_utils::MockTestBackendHandler,
};
use chrono::TimeZone;
use ldap3_proto::proto::{
@@ -173,6 +170,7 @@ pub mod tests {
};
use ldap3_proto::{LdapPartialAttribute, proto::LdapExtendedRequest};
use lldap_domain::{types::*, uuid};
use lldap_test_utils::MockTestBackendHandler;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use std::collections::HashSet;
@@ -1,4 +1,4 @@
use crate::domain::ldap::{
use crate::core::{
error::{LdapError, LdapResult},
group::{convert_groups_to_ldap_op, get_groups_list},
user::{convert_users_to_ldap_op, get_user_list},
@@ -312,13 +312,10 @@ pub async fn do_search(
mod tests {
use super::*;
use crate::{
domain::ldap::error::LdapError,
infra::{
ldap::handler::tests::{
make_group_search_request, make_user_search_request, setup_bound_admin_handler,
setup_bound_handler_with_group, setup_bound_readonly_handler,
},
test_utils::MockTestBackendHandler,
core::error::LdapError,
handler::tests::{
make_group_search_request, make_user_search_request, setup_bound_admin_handler,
setup_bound_handler_with_group, setup_bound_readonly_handler,
},
};
use chrono::TimeZone;
@@ -333,9 +330,10 @@ mod tests {
};
use lldap_domain_handlers::handler::*;
use lldap_domain_model::model::UserColumn;
use lldap_test_utils::MockTestBackendHandler;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use tokio;
#[tokio::test]
async fn test_search_root_dse() {
+3
View File
@@ -23,3 +23,6 @@ path = "../domain"
[dependencies.lldap_domain_model]
path = "../domain-model"
[dev-dependencies]
mockall = "0.11.4"
+34
View File
@@ -0,0 +1,34 @@
[package]
name = "lldap_test_utils"
version = "0.1.0"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
[dependencies]
async-trait = "0.1"
ldap3_proto = "0.6.0"
mockall = "0.11.4"
tracing = "*"
[dependencies.uuid]
version = "1"
features = ["v1", "v3"]
[dependencies.lldap_access_control]
path = "../access-control"
[dependencies.lldap_domain]
path = "../domain"
[dependencies.lldap_domain_handlers]
path = "../domain-handlers"
[dependencies.lldap_domain_model]
path = "../domain-model"
[dependencies.lldap_opaque_handler]
path = "../opaque-handler"
features = ["test"]
@@ -1,3 +1,4 @@
use async_trait::async_trait;
use lldap_domain::{
requests::{
CreateAttributeRequest, CreateGroupRequest, CreateUserRequest, UpdateGroupRequest,
@@ -16,8 +17,6 @@ use lldap_domain_handlers::handler::{
};
use lldap_domain_model::error::Result;
use lldap_opaque_handler::{OpaqueHandler, login, registration};
use async_trait::async_trait;
use std::collections::HashSet;
mockall::mock! {
+6
View File
@@ -102,6 +102,9 @@ path = "../crates/domain-handlers"
[dependencies.lldap_frontend_options]
path = "../crates/frontend-options"
[dependencies.lldap_ldap]
path = "../crates/ldap"
[dependencies.lldap_opaque_handler]
path = "../crates/opaque-handler"
@@ -189,6 +192,9 @@ features = ["test"]
path = "../crates/opaque-handler"
features = ["test"]
[dev-dependencies.lldap_test_utils]
path = "../crates/test-utils"
[dev-dependencies.reqwest]
version = "*"
default-features = false
-2
View File
@@ -1,5 +1,3 @@
pub mod deserialize;
pub mod ldap;
pub mod sql_backend_handler;
pub mod sql_group_backend_handler;
pub mod sql_migrations;
-1
View File
@@ -1,6 +1,5 @@
use crate::{domain::sql_tables::DbConnection, infra::configuration::Configuration};
use async_trait::async_trait;
use lldap_domain_handlers::handler::BackendHandler;
#[derive(Clone)]
+4 -6
View File
@@ -1,7 +1,4 @@
use crate::{
domain::deserialize::deserialize_attribute_value,
infra::graphql::api::{Context, field_error_callback},
};
use crate::infra::graphql::api::{Context, field_error_callback};
use anyhow::{Context as AnyhowContext, anyhow};
use juniper::{FieldError, FieldResult, GraphQLInputObject, GraphQLObject, graphql_object};
use lldap_access_control::{
@@ -9,6 +6,7 @@ use lldap_access_control::{
UserWriteableBackendHandler,
};
use lldap_domain::{
deserialize::deserialize_attribute_value,
public_schema::PublicSchema,
requests::{
CreateAttributeRequest, CreateGroupRequest, CreateUserRequest, UpdateGroupRequest,
@@ -779,15 +777,15 @@ fn deserialize_attribute(
#[cfg(test)]
mod tests {
use super::*;
use crate::infra::{graphql::query::Query, test_utils::MockTestBackendHandler};
use crate::infra::graphql::query::Query;
use juniper::{
DefaultScalarValue, EmptySubscription, GraphQLType, InputValue, RootNode, Variables,
execute, graphql_value,
};
use lldap_auth::access_control::{Permission, ValidationResults};
use lldap_domain::types::{AttributeName, AttributeType};
use lldap_test_utils::MockTestBackendHandler;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
+5 -10
View File
@@ -1,23 +1,18 @@
use std::sync::Arc;
use crate::{
domain::{
deserialize::deserialize_attribute_value,
ldap::utils::{UserFieldType, map_user_field},
},
infra::graphql::api::{Context, field_error_callback},
};
use crate::infra::graphql::api::{Context, field_error_callback};
use anyhow::Context as AnyhowContext;
use chrono::TimeZone;
use juniper::{FieldResult, GraphQLInputObject, graphql_object};
use lldap_access_control::{ReadonlyBackendHandler, UserReadableBackendHandler};
use lldap_domain::{
deserialize::deserialize_attribute_value,
public_schema::PublicSchema,
types::{AttributeType, Cardinality, GroupDetails, GroupId, LdapObjectClass, UserId},
};
use lldap_domain_handlers::handler::{BackendHandler, ReadSchemaBackendHandler};
use lldap_domain_model::model::UserColumn;
use lldap_ldap::{UserFieldType, map_user_field};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tracing::{Instrument, Span, debug, debug_span};
type DomainRequestFilter = lldap_domain_handlers::handler::UserRequestFilter;
@@ -784,7 +779,6 @@ impl<Handler: BackendHandler> AttributeValue<Handler> {
#[cfg(test)]
mod tests {
use super::*;
use crate::infra::test_utils::{MockTestBackendHandler, setup_default_schema};
use chrono::TimeZone;
use juniper::{
DefaultScalarValue, EmptyMutation, EmptySubscription, GraphQLType, RootNode, Variables,
@@ -795,6 +789,7 @@ mod tests {
schema::{AttributeList, Schema},
types::{AttributeName, AttributeType, LdapObjectClass},
};
use lldap_test_utils::{MockTestBackendHandler, setup_default_schema};
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
use std::collections::HashSet;
-7
View File
@@ -1,7 +0,0 @@
pub mod compare;
pub mod create;
pub mod delete;
pub mod handler;
pub mod modify;
pub mod password;
pub mod search;
+2 -4
View File
@@ -1,7 +1,4 @@
use crate::infra::{
configuration::{Configuration, LdapsOptions},
ldap::handler::LdapHandler,
};
use crate::infra::configuration::{Configuration, LdapsOptions};
use actix_rt::net::TcpStream;
use actix_server::ServerBuilder;
use actix_service::{ServiceFactoryExt, fn_service};
@@ -10,6 +7,7 @@ use ldap3_proto::{LdapCodec, control::LdapControl, proto::LdapMsg, proto::LdapOp
use lldap_access_control::AccessControlledBackendHandler;
use lldap_domain::types::AttributeName;
use lldap_domain_handlers::handler::{BackendHandler, LoginHandler};
use lldap_ldap::LdapHandler;
use lldap_opaque_handler::OpaqueHandler;
use rustls::PrivateKey;
use tokio_rustls::TlsAcceptor as RustlsTlsAcceptor;
-4
View File
@@ -6,13 +6,9 @@ pub mod db_cleaner;
pub mod graphql;
pub mod healthcheck;
pub mod jwt_sql_tables;
pub mod ldap;
pub mod ldap_server;
pub mod logging;
pub mod mail;
pub mod sql_backend_handler;
pub mod tcp_backend_handler;
pub mod tcp_server;
#[cfg(test)]
pub mod test_utils;