mirror of
https://github.com/lldap/lldap.git
synced 2026-03-31 15:07:48 +01:00
ldap: normalize base DN in LdapInfo, reduce memory usage
By making it a &'static, we can have a single allocation for all the threads/async contexts. This also normalizes the whitespace from the user input; a trailing \n can cause weird issues with clients
This commit is contained in:
committed by
nitnelave
parent
f7fe0c6ea0
commit
8a803bfb11
@@ -300,6 +300,23 @@ pub struct LdapInfo {
|
||||
pub ignored_group_attributes: Vec<AttributeName>,
|
||||
}
|
||||
|
||||
impl LdapInfo {
|
||||
pub fn new(
|
||||
base_dn: &str,
|
||||
ignored_user_attributes: Vec<AttributeName>,
|
||||
ignored_group_attributes: Vec<AttributeName>,
|
||||
) -> LdapResult<Self> {
|
||||
let base_dn = parse_distinguished_name(&base_dn.to_ascii_lowercase())?;
|
||||
let base_dn_str = join(base_dn.iter().map(|(k, v)| format!("{k}={v}")), ",");
|
||||
Ok(Self {
|
||||
base_dn,
|
||||
base_dn_str,
|
||||
ignored_user_attributes,
|
||||
ignored_group_attributes,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_custom_attribute(
|
||||
attributes: &[Attribute],
|
||||
attribute_name: &AttributeName,
|
||||
@@ -521,4 +538,14 @@ mod tests {
|
||||
parsed_dn
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_whitespace_in_ldap_info() {
|
||||
assert_eq!(
|
||||
LdapInfo::new(" ou=people, dc =example, dc=com \n", vec![], vec![])
|
||||
.unwrap()
|
||||
.base_dn_str,
|
||||
"ou=people,dc=example,dc=com"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-24
@@ -2,7 +2,7 @@ use crate::{
|
||||
compare,
|
||||
core::{
|
||||
error::{LdapError, LdapResult},
|
||||
utils::{LdapInfo, parse_distinguished_name},
|
||||
utils::LdapInfo,
|
||||
},
|
||||
create, delete, modify,
|
||||
password::{self, do_password_modification},
|
||||
@@ -18,7 +18,7 @@ use ldap3_proto::proto::{
|
||||
};
|
||||
use lldap_access_control::AccessControlledBackendHandler;
|
||||
use lldap_auth::access_control::ValidationResults;
|
||||
use lldap_domain::{public_schema::PublicSchema, types::AttributeName};
|
||||
use lldap_domain::public_schema::PublicSchema;
|
||||
use lldap_domain_handlers::handler::{BackendHandler, LoginHandler, ReadSchemaBackendHandler};
|
||||
use lldap_opaque_handler::OpaqueHandler;
|
||||
use tracing::{debug, instrument};
|
||||
@@ -59,7 +59,7 @@ pub(crate) fn make_modify_response(code: LdapResultCode, message: String) -> Lda
|
||||
pub struct LdapHandler<Backend> {
|
||||
user_info: Option<ValidationResults>,
|
||||
backend_handler: AccessControlledBackendHandler<Backend>,
|
||||
ldap_info: LdapInfo,
|
||||
ldap_info: &'static LdapInfo,
|
||||
session_uuid: uuid::Uuid,
|
||||
}
|
||||
|
||||
@@ -89,23 +89,13 @@ enum Credentials<'s> {
|
||||
impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend> {
|
||||
pub fn new(
|
||||
backend_handler: AccessControlledBackendHandler<Backend>,
|
||||
mut ldap_base_dn: String,
|
||||
ignored_user_attributes: Vec<AttributeName>,
|
||||
ignored_group_attributes: Vec<AttributeName>,
|
||||
ldap_info: &'static LdapInfo,
|
||||
session_uuid: uuid::Uuid,
|
||||
) -> Self {
|
||||
ldap_base_dn.make_ascii_lowercase();
|
||||
Self {
|
||||
user_info: None,
|
||||
backend_handler,
|
||||
ldap_info: LdapInfo {
|
||||
base_dn: parse_distinguished_name(&ldap_base_dn).unwrap_or_else(|_| {
|
||||
panic!("Invalid value for ldap_base_dn in configuration: {ldap_base_dn}")
|
||||
}),
|
||||
base_dn_str: ldap_base_dn,
|
||||
ignored_user_attributes,
|
||||
ignored_group_attributes,
|
||||
},
|
||||
ldap_info,
|
||||
session_uuid,
|
||||
}
|
||||
}
|
||||
@@ -114,9 +104,9 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
pub fn new_for_tests(backend_handler: Backend, ldap_base_dn: &str) -> Self {
|
||||
Self::new(
|
||||
AccessControlledBackendHandler::new(backend_handler),
|
||||
ldap_base_dn.to_string(),
|
||||
vec![],
|
||||
vec![],
|
||||
Box::leak(Box::new(
|
||||
LdapInfo::new(ldap_base_dn, Vec::new(), Vec::new()).unwrap(),
|
||||
)),
|
||||
uuid::Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
|
||||
)
|
||||
}
|
||||
@@ -171,13 +161,13 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
let backend_handler = self
|
||||
.backend_handler
|
||||
.get_user_restricted_lister_handler(user_info);
|
||||
search::do_search(&backend_handler, &self.ldap_info, request).await
|
||||
search::do_search(&backend_handler, self.ldap_info, request).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug", fields(dn = %request.dn))]
|
||||
pub async fn do_bind(&mut self, request: &LdapBindRequest) -> Vec<LdapOp> {
|
||||
let (code, message) =
|
||||
match password::do_bind(&self.ldap_info, request, self.get_login_handler()).await {
|
||||
match password::do_bind(self.ldap_info, request, self.get_login_handler()).await {
|
||||
Ok(user_id) => {
|
||||
self.user_info = self
|
||||
.backend_handler
|
||||
@@ -211,7 +201,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
};
|
||||
do_password_modification(
|
||||
credentials,
|
||||
&self.ldap_info,
|
||||
self.ldap_info,
|
||||
&self.backend_handler,
|
||||
self.get_opaque_handler(),
|
||||
&password_request,
|
||||
@@ -257,7 +247,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
self.backend_handler
|
||||
.get_readable_handler(credentials, &user_id)
|
||||
},
|
||||
&self.ldap_info,
|
||||
self.ldap_info,
|
||||
credentials,
|
||||
request,
|
||||
)
|
||||
@@ -275,7 +265,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
code: LdapResultCode::InsufficentAccessRights,
|
||||
message: "Unauthorized write".to_string(),
|
||||
})?;
|
||||
create::create_user_or_group(backend_handler, &self.ldap_info, request).await
|
||||
create::create_user_or_group(backend_handler, self.ldap_info, request).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
@@ -288,7 +278,7 @@ impl<Backend: BackendHandler + LoginHandler + OpaqueHandler> LdapHandler<Backend
|
||||
code: LdapResultCode::InsufficentAccessRights,
|
||||
message: "Unauthorized write".to_string(),
|
||||
})?;
|
||||
delete::delete_user_or_group(backend_handler, &self.ldap_info, request).await
|
||||
delete::delete_user_or_group(backend_handler, self.ldap_info, request).await
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
|
||||
@@ -7,7 +7,7 @@ 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 core::utils::{LdapInfo, UserFieldType, map_group_field, map_user_field};
|
||||
pub use handler::LdapHandler;
|
||||
|
||||
pub use core::group::get_default_group_object_classes;
|
||||
|
||||
@@ -17,7 +17,7 @@ use lldap_domain::{
|
||||
public_schema::PublicSchema,
|
||||
types::{Group, UserAndGroups},
|
||||
};
|
||||
use tracing::{debug, instrument, warn};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum SearchScope {
|
||||
@@ -396,7 +396,6 @@ async fn do_search_internal(
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip_all, level = "debug")]
|
||||
pub async fn do_search(
|
||||
backend_handler: &impl UserAndGroupListerBackendHandler,
|
||||
ldap_info: &LdapInfo,
|
||||
|
||||
+18
-30
@@ -5,9 +5,8 @@ use actix_service::{ServiceFactoryExt, fn_service};
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
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_ldap::{LdapHandler, LdapInfo};
|
||||
use lldap_opaque_handler::OpaqueHandler;
|
||||
use rustls::PrivateKey;
|
||||
use tokio_rustls::TlsAcceptor as RustlsTlsAcceptor;
|
||||
@@ -71,9 +70,7 @@ where
|
||||
async fn handle_ldap_stream<Stream, Backend>(
|
||||
stream: Stream,
|
||||
backend_handler: Backend,
|
||||
ldap_base_dn: String,
|
||||
ignored_user_attributes: Vec<AttributeName>,
|
||||
ignored_group_attributes: Vec<AttributeName>,
|
||||
ldap_info: &'static LdapInfo,
|
||||
) -> Result<Stream>
|
||||
where
|
||||
Backend: BackendHandler + LoginHandler + OpaqueHandler + 'static,
|
||||
@@ -88,9 +85,7 @@ where
|
||||
let session_uuid = Uuid::new_v4();
|
||||
let mut session = LdapHandler::new(
|
||||
AccessControlledBackendHandler::new(backend_handler),
|
||||
ldap_base_dn,
|
||||
ignored_user_attributes,
|
||||
ignored_group_attributes,
|
||||
ldap_info,
|
||||
session_uuid,
|
||||
);
|
||||
|
||||
@@ -170,9 +165,19 @@ where
|
||||
{
|
||||
let context = (
|
||||
backend_handler,
|
||||
config.ldap_base_dn.clone(),
|
||||
Box::leak(Box::new(
|
||||
LdapInfo::new(
|
||||
&config.ldap_base_dn,
|
||||
config.ignored_user_attributes.clone(),
|
||||
config.ignored_group_attributes.clone(),
|
||||
)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Invalid value for ldap_base_dn in configuration: {}",
|
||||
&config.ldap_base_dn
|
||||
)
|
||||
})?,
|
||||
)) as &'static LdapInfo,
|
||||
);
|
||||
|
||||
let context_for_tls = context.clone();
|
||||
@@ -182,15 +187,8 @@ where
|
||||
fn_service(move |stream: TcpStream| {
|
||||
let context = context.clone();
|
||||
async move {
|
||||
let (handler, base_dn, ignored_user_attributes, ignored_group_attributes) = context;
|
||||
handle_ldap_stream(
|
||||
stream,
|
||||
handler,
|
||||
base_dn,
|
||||
ignored_user_attributes,
|
||||
ignored_group_attributes,
|
||||
)
|
||||
.await
|
||||
let (handler, ldap_info) = context;
|
||||
handle_ldap_stream(stream, handler, ldap_info).await
|
||||
}
|
||||
})
|
||||
.map_err(|err: anyhow::Error| error!("[LDAP] Service Error: {:#}", err))
|
||||
@@ -211,19 +209,9 @@ where
|
||||
fn_service(move |stream: TcpStream| {
|
||||
let tls_context = tls_context.clone();
|
||||
async move {
|
||||
let (
|
||||
(handler, base_dn, ignored_user_attributes, ignored_group_attributes),
|
||||
tls_acceptor,
|
||||
) = tls_context;
|
||||
let ((handler, ldap_info), tls_acceptor) = tls_context;
|
||||
let tls_stream = tls_acceptor.accept(stream).await?;
|
||||
handle_ldap_stream(
|
||||
tls_stream,
|
||||
handler,
|
||||
base_dn,
|
||||
ignored_user_attributes,
|
||||
ignored_group_attributes,
|
||||
)
|
||||
.await
|
||||
handle_ldap_stream(tls_stream, handler, ldap_info).await
|
||||
}
|
||||
})
|
||||
.map_err(|err: anyhow::Error| error!("[LDAPS] Service Error: {:#}", err))
|
||||
|
||||
Reference in New Issue
Block a user