mirror of
				https://github.com/nitnelave/lldap.git
				synced 2023-04-12 14:25:13 +00:00 
			
		
		
		
	ldap: Switch to using LdapOp instead of ServerOp
This is in preparation of supporting the password change message, since this is from the Extended Operations that is not available in the simple ServerOp.
This commit is contained in:
		
							parent
							
								
									438ac2818a
								
							
						
					
					
						commit
						2b38afb22b
					
				@ -1,10 +1,13 @@
 | 
				
			|||||||
use crate::domain::handler::{
 | 
					use crate::domain::handler::{
 | 
				
			||||||
    BackendHandler, Group, GroupIdAndName, LoginHandler, RequestFilter, User,
 | 
					    BackendHandler, BindRequest, Group, GroupIdAndName, LoginHandler, RequestFilter, User,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use anyhow::{bail, Result};
 | 
					use anyhow::{bail, Result};
 | 
				
			||||||
use futures::stream::StreamExt;
 | 
					use futures::stream::StreamExt;
 | 
				
			||||||
use futures_util::TryStreamExt;
 | 
					use futures_util::TryStreamExt;
 | 
				
			||||||
use ldap3_server::simple::*;
 | 
					use ldap3_server::proto::{
 | 
				
			||||||
 | 
					    LdapBindCred, LdapBindRequest, LdapBindResponse, LdapExtendedResponse, LdapFilter, LdapOp,
 | 
				
			||||||
 | 
					    LdapPartialAttribute, LdapResult, LdapResultCode, LdapSearchRequest, LdapSearchResultEntry,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
use log::*;
 | 
					use log::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn make_dn_pair<I>(mut iter: I) -> Result<(String, String)>
 | 
					fn make_dn_pair<I>(mut iter: I) -> Result<(String, String)>
 | 
				
			||||||
@ -194,6 +197,19 @@ fn map_field(field: &str) -> Result<String> {
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_search_success() -> LdapOp {
 | 
				
			||||||
 | 
					    make_search_error(LdapResultCode::Success, "".to_string())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn make_search_error(code: LdapResultCode, message: String) -> LdapOp {
 | 
				
			||||||
 | 
					    LdapOp::SearchResultDone(LdapResult {
 | 
				
			||||||
 | 
					        code,
 | 
				
			||||||
 | 
					        matcheddn: "".to_string(),
 | 
				
			||||||
 | 
					        message,
 | 
				
			||||||
 | 
					        referral: vec![],
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct LdapHandler<Backend: BackendHandler + LoginHandler> {
 | 
					pub struct LdapHandler<Backend: BackendHandler + LoginHandler> {
 | 
				
			||||||
    dn: String,
 | 
					    dn: String,
 | 
				
			||||||
    backend_handler: Backend,
 | 
					    backend_handler: Backend,
 | 
				
			||||||
@ -218,33 +234,40 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn do_bind(&mut self, sbr: &SimpleBindRequest) -> LdapMsg {
 | 
					    pub async fn do_bind(&mut self, request: &LdapBindRequest) -> (LdapResultCode, String) {
 | 
				
			||||||
        info!(r#"Received bind request for "{}""#, &sbr.dn);
 | 
					        info!(r#"Received bind request for "{}""#, &request.dn);
 | 
				
			||||||
        let user_id =
 | 
					        let user_id = match get_user_id_from_distinguished_name(
 | 
				
			||||||
            match get_user_id_from_distinguished_name(&sbr.dn, &self.base_dn, &self.base_dn_str) {
 | 
					            &request.dn,
 | 
				
			||||||
                Ok(s) => s,
 | 
					            &self.base_dn,
 | 
				
			||||||
                Err(e) => return sbr.gen_error(LdapResultCode::NamingViolation, e.to_string()),
 | 
					            &self.base_dn_str,
 | 
				
			||||||
            };
 | 
					        ) {
 | 
				
			||||||
 | 
					            Ok(s) => s,
 | 
				
			||||||
 | 
					            Err(e) => return (LdapResultCode::NamingViolation, e.to_string()),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let LdapBindCred::Simple(password) = &request.cred;
 | 
				
			||||||
        match self
 | 
					        match self
 | 
				
			||||||
            .backend_handler
 | 
					            .backend_handler
 | 
				
			||||||
            .bind(crate::domain::handler::BindRequest {
 | 
					            .bind(BindRequest {
 | 
				
			||||||
                name: user_id,
 | 
					                name: user_id,
 | 
				
			||||||
                password: sbr.pw.clone(),
 | 
					                password: password.clone(),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Ok(()) => {
 | 
					            Ok(()) => {
 | 
				
			||||||
                self.dn = sbr.dn.clone();
 | 
					                self.dn = request.dn.clone();
 | 
				
			||||||
                sbr.gen_success()
 | 
					                (LdapResultCode::Success, "".to_string())
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            Err(_) => sbr.gen_invalid_cred(),
 | 
					            Err(_) => (LdapResultCode::InvalidCredentials, "".to_string()),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn do_search(&mut self, lsr: &SearchRequest) -> Vec<LdapMsg> {
 | 
					    pub async fn do_search(&mut self, request: &LdapSearchRequest) -> Vec<LdapOp> {
 | 
				
			||||||
        info!("Received search request with filters: {:?}", &lsr.filter);
 | 
					        info!(
 | 
				
			||||||
 | 
					            "Received search request with filters: {:?}",
 | 
				
			||||||
 | 
					            &request.filter
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        if self.dn != self.ldap_user_dn {
 | 
					        if self.dn != self.ldap_user_dn {
 | 
				
			||||||
            return vec![lsr.gen_error(
 | 
					            return vec![make_search_error(
 | 
				
			||||||
                LdapResultCode::InsufficentAccessRights,
 | 
					                LdapResultCode::InsufficentAccessRights,
 | 
				
			||||||
                format!(
 | 
					                format!(
 | 
				
			||||||
                    r#"Current user `{}` is not allowed to query LDAP, expected {}"#,
 | 
					                    r#"Current user `{}` is not allowed to query LDAP, expected {}"#,
 | 
				
			||||||
@ -252,43 +275,43 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
                ),
 | 
					                ),
 | 
				
			||||||
            )];
 | 
					            )];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let dn_parts = if lsr.base.is_empty() {
 | 
					        let dn_parts = if request.base.is_empty() {
 | 
				
			||||||
            self.base_dn.clone()
 | 
					            self.base_dn.clone()
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            match parse_distinguished_name(&lsr.base) {
 | 
					            match parse_distinguished_name(&request.base) {
 | 
				
			||||||
                Ok(dn) => dn,
 | 
					                Ok(dn) => dn,
 | 
				
			||||||
                Err(_) => {
 | 
					                Err(_) => {
 | 
				
			||||||
                    return vec![lsr.gen_error(
 | 
					                    return vec![make_search_error(
 | 
				
			||||||
                        LdapResultCode::OperationsError,
 | 
					                        LdapResultCode::OperationsError,
 | 
				
			||||||
                        format!(r#"Could not parse base DN: "{}""#, lsr.base),
 | 
					                        format!(r#"Could not parse base DN: "{}""#, request.base),
 | 
				
			||||||
                    )]
 | 
					                    )]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        if !is_subtree(&dn_parts, &self.base_dn) {
 | 
					        if !is_subtree(&dn_parts, &self.base_dn) {
 | 
				
			||||||
            // Search path is not in our tree, just return an empty success.
 | 
					            // Search path is not in our tree, just return an empty success.
 | 
				
			||||||
            return vec![lsr.gen_success()];
 | 
					            return vec![make_search_success()];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let mut results = Vec::new();
 | 
					        let mut results = Vec::new();
 | 
				
			||||||
        if dn_parts.len() == self.base_dn.len()
 | 
					        if dn_parts.len() == self.base_dn.len()
 | 
				
			||||||
            || (dn_parts.len() == self.base_dn.len() + 1
 | 
					            || (dn_parts.len() == self.base_dn.len() + 1
 | 
				
			||||||
                && dn_parts[0] == ("ou".to_string(), "people".to_string()))
 | 
					                && dn_parts[0] == ("ou".to_string(), "people".to_string()))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            results.extend(self.get_user_list(lsr).await);
 | 
					            results.extend(self.get_user_list(request).await);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if dn_parts.len() == self.base_dn.len() + 1
 | 
					        if dn_parts.len() == self.base_dn.len() + 1
 | 
				
			||||||
            && dn_parts[0] == ("ou".to_string(), "groups".to_string())
 | 
					            && dn_parts[0] == ("ou".to_string(), "groups".to_string())
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            results.extend(self.get_groups_list(lsr).await);
 | 
					            results.extend(self.get_groups_list(request).await);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        results
 | 
					        results
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn get_user_list(&self, lsr: &SearchRequest) -> Vec<LdapMsg> {
 | 
					    async fn get_user_list(&self, request: &LdapSearchRequest) -> Vec<LdapOp> {
 | 
				
			||||||
        let filters = match self.convert_user_filter(&lsr.filter) {
 | 
					        let filters = match self.convert_user_filter(&request.filter) {
 | 
				
			||||||
            Ok(f) => Some(f),
 | 
					            Ok(f) => Some(f),
 | 
				
			||||||
            Err(e) => {
 | 
					            Err(e) => {
 | 
				
			||||||
                return vec![lsr.gen_error(
 | 
					                return vec![make_search_error(
 | 
				
			||||||
                    LdapResultCode::UnwillingToPerform,
 | 
					                    LdapResultCode::UnwillingToPerform,
 | 
				
			||||||
                    format!("Unsupported user filter: {}", e),
 | 
					                    format!("Unsupported user filter: {}", e),
 | 
				
			||||||
                )]
 | 
					                )]
 | 
				
			||||||
@ -297,28 +320,33 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
        let users = match self.backend_handler.list_users(filters).await {
 | 
					        let users = match self.backend_handler.list_users(filters).await {
 | 
				
			||||||
            Ok(users) => users,
 | 
					            Ok(users) => users,
 | 
				
			||||||
            Err(e) => {
 | 
					            Err(e) => {
 | 
				
			||||||
                return vec![lsr.gen_error(
 | 
					                return vec![make_search_error(
 | 
				
			||||||
                    LdapResultCode::Other,
 | 
					                    LdapResultCode::Other,
 | 
				
			||||||
                    format!(r#"Error during searching user "{}": {}"#, lsr.base, e),
 | 
					                    format!(r#"Error during searching user "{}": {}"#, request.base, e),
 | 
				
			||||||
                )]
 | 
					                )]
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        users
 | 
					        users
 | 
				
			||||||
            .into_iter()
 | 
					            .into_iter()
 | 
				
			||||||
            .map(|u| make_ldap_search_user_result_entry(u, &self.base_dn_str, &lsr.attrs))
 | 
					            .map(|u| make_ldap_search_user_result_entry(u, &self.base_dn_str, &request.attrs))
 | 
				
			||||||
            .map(|entry| Ok(lsr.gen_result_entry(entry?)))
 | 
					            .map(|entry| Ok(LdapOp::SearchResultEntry(entry?)))
 | 
				
			||||||
            // If the processing succeeds, add a success message at the end.
 | 
					            // If the processing succeeds, add a success message at the end.
 | 
				
			||||||
            .chain(std::iter::once(Ok(lsr.gen_success())))
 | 
					            .chain(std::iter::once(Ok(make_search_success())))
 | 
				
			||||||
            .collect::<Result<Vec<_>>>()
 | 
					            .collect::<Result<Vec<_>>>()
 | 
				
			||||||
            .unwrap_or_else(|e| vec![lsr.gen_error(LdapResultCode::NoSuchAttribute, e.to_string())])
 | 
					            .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                vec![make_search_error(
 | 
				
			||||||
 | 
					                    LdapResultCode::NoSuchAttribute,
 | 
				
			||||||
 | 
					                    e.to_string(),
 | 
				
			||||||
 | 
					                )]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn get_groups_list(&self, lsr: &SearchRequest) -> Vec<LdapMsg> {
 | 
					    async fn get_groups_list(&self, request: &LdapSearchRequest) -> Vec<LdapOp> {
 | 
				
			||||||
        let for_user = match self.get_group_filter(&lsr.filter) {
 | 
					        let for_user = match self.get_group_filter(&request.filter) {
 | 
				
			||||||
            Ok(u) => u,
 | 
					            Ok(u) => u,
 | 
				
			||||||
            Err(e) => {
 | 
					            Err(e) => {
 | 
				
			||||||
                return vec![lsr.gen_error(
 | 
					                return vec![make_search_error(
 | 
				
			||||||
                    LdapResultCode::UnwillingToPerform,
 | 
					                    LdapResultCode::UnwillingToPerform,
 | 
				
			||||||
                    format!("Unsupported group filter: {}", e),
 | 
					                    format!("Unsupported group filter: {}", e),
 | 
				
			||||||
                )]
 | 
					                )]
 | 
				
			||||||
@ -343,9 +371,12 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
            let groups_without_users = match self.backend_handler.get_user_groups(&user).await {
 | 
					            let groups_without_users = match self.backend_handler.get_user_groups(&user).await {
 | 
				
			||||||
                Ok(groups) => groups,
 | 
					                Ok(groups) => groups,
 | 
				
			||||||
                Err(e) => {
 | 
					                Err(e) => {
 | 
				
			||||||
                    return vec![lsr.gen_error(
 | 
					                    return vec![make_search_error(
 | 
				
			||||||
                        LdapResultCode::Other,
 | 
					                        LdapResultCode::Other,
 | 
				
			||||||
                        format!(r#"Error while listing user groups: "{}": {}"#, lsr.base, e),
 | 
					                        format!(
 | 
				
			||||||
 | 
					                            r#"Error while listing user groups: "{}": {}"#,
 | 
				
			||||||
 | 
					                            request.base, e
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
                    )]
 | 
					                    )]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
@ -356,9 +387,9 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                Ok(groups) => groups,
 | 
					                Ok(groups) => groups,
 | 
				
			||||||
                Err(e) => {
 | 
					                Err(e) => {
 | 
				
			||||||
                    return vec![lsr.gen_error(
 | 
					                    return vec![make_search_error(
 | 
				
			||||||
                        LdapResultCode::Other,
 | 
					                        LdapResultCode::Other,
 | 
				
			||||||
                        format!(r#"Error while listing user groups: "{}": {}"#, lsr.base, e),
 | 
					                        format!(r#"Error while listing user groups: "{}": {}"#, request.base, e),
 | 
				
			||||||
                    )]
 | 
					                    )]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -366,9 +397,9 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
            match self.backend_handler.list_groups().await {
 | 
					            match self.backend_handler.list_groups().await {
 | 
				
			||||||
                Ok(groups) => groups,
 | 
					                Ok(groups) => groups,
 | 
				
			||||||
                Err(e) => {
 | 
					                Err(e) => {
 | 
				
			||||||
                    return vec![lsr.gen_error(
 | 
					                    return vec![make_search_error(
 | 
				
			||||||
                        LdapResultCode::Other,
 | 
					                        LdapResultCode::Other,
 | 
				
			||||||
                        format!(r#"Error while listing groups "{}": {}"#, lsr.base, e),
 | 
					                        format!(r#"Error while listing groups "{}": {}"#, request.base, e),
 | 
				
			||||||
                    )]
 | 
					                    )]
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -376,31 +407,49 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        groups
 | 
					        groups
 | 
				
			||||||
            .into_iter()
 | 
					            .into_iter()
 | 
				
			||||||
            .map(|u| make_ldap_search_group_result_entry(u, &self.base_dn_str, &lsr.attrs))
 | 
					            .map(|u| make_ldap_search_group_result_entry(u, &self.base_dn_str, &request.attrs))
 | 
				
			||||||
            .map(|entry| Ok(lsr.gen_result_entry(entry?)))
 | 
					            .map(|entry| Ok(LdapOp::SearchResultEntry(entry?)))
 | 
				
			||||||
            // If the processing succeeds, add a success message at the end.
 | 
					            // If the processing succeeds, add a success message at the end.
 | 
				
			||||||
            .chain(std::iter::once(Ok(lsr.gen_success())))
 | 
					            .chain(std::iter::once(Ok(make_search_success())))
 | 
				
			||||||
            .collect::<Result<Vec<_>>>()
 | 
					            .collect::<Result<Vec<_>>>()
 | 
				
			||||||
            .unwrap_or_else(|e| vec![lsr.gen_error(LdapResultCode::NoSuchAttribute, e.to_string())])
 | 
					            .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                vec![make_search_error(
 | 
				
			||||||
 | 
					                    LdapResultCode::NoSuchAttribute,
 | 
				
			||||||
 | 
					                    e.to_string(),
 | 
				
			||||||
 | 
					                )]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn do_whoami(&mut self, wr: &WhoamiRequest) -> LdapMsg {
 | 
					    pub async fn handle_ldap_message(&mut self, ldap_op: LdapOp) -> Option<Vec<LdapOp>> {
 | 
				
			||||||
        if self.dn == "Unauthenticated" {
 | 
					        Some(match ldap_op {
 | 
				
			||||||
            wr.gen_operror("Unauthenticated")
 | 
					            LdapOp::BindRequest(request) => {
 | 
				
			||||||
        } else {
 | 
					                let (code, message) = self.do_bind(&request).await;
 | 
				
			||||||
            wr.gen_success(format!("dn: {}", self.dn).as_str())
 | 
					                vec![LdapOp::BindResponse(LdapBindResponse {
 | 
				
			||||||
        }
 | 
					                    res: LdapResult {
 | 
				
			||||||
    }
 | 
					                        code,
 | 
				
			||||||
 | 
					                        matcheddn: "".to_string(),
 | 
				
			||||||
    pub async fn handle_ldap_message(&mut self, server_op: ServerOps) -> Option<Vec<LdapMsg>> {
 | 
					                        message,
 | 
				
			||||||
        Some(match server_op {
 | 
					                        referral: vec![],
 | 
				
			||||||
            ServerOps::SimpleBind(sbr) => vec![self.do_bind(&sbr).await],
 | 
					                    },
 | 
				
			||||||
            ServerOps::Search(sr) => self.do_search(&sr).await,
 | 
					                    saslcreds: None,
 | 
				
			||||||
            ServerOps::Unbind(_) => {
 | 
					                })]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            LdapOp::SearchRequest(request) => self.do_search(&request).await,
 | 
				
			||||||
 | 
					            LdapOp::UnbindRequest => {
 | 
				
			||||||
 | 
					                self.dn = "Unauthenticated".to_string();
 | 
				
			||||||
                // No need to notify on unbind (per rfc4511)
 | 
					                // No need to notify on unbind (per rfc4511)
 | 
				
			||||||
                return None;
 | 
					                return None;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ServerOps::Whoami(wr) => vec![self.do_whoami(&wr)],
 | 
					            op => vec![LdapOp::ExtendedResponse(LdapExtendedResponse {
 | 
				
			||||||
 | 
					                res: LdapResult {
 | 
				
			||||||
 | 
					                    code: LdapResultCode::UnwillingToPerform,
 | 
				
			||||||
 | 
					                    matcheddn: "".to_string(),
 | 
				
			||||||
 | 
					                    message: format!("Unsupported operation: {:#?}", op),
 | 
				
			||||||
 | 
					                    referral: vec![],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                name: None,
 | 
				
			||||||
 | 
					                value: None,
 | 
				
			||||||
 | 
					            })],
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -480,9 +529,26 @@ impl<Backend: BackendHandler + LoginHandler> LdapHandler<Backend> {
 | 
				
			|||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::domain::handler::{BindRequest, MockTestBackendHandler};
 | 
					    use crate::domain::handler::{BindRequest, MockTestBackendHandler};
 | 
				
			||||||
 | 
					    use ldap3_server::proto::{LdapDerefAliases, LdapSearchScope};
 | 
				
			||||||
    use mockall::predicate::eq;
 | 
					    use mockall::predicate::eq;
 | 
				
			||||||
    use tokio;
 | 
					    use tokio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn make_search_request<S: Into<String>>(
 | 
				
			||||||
 | 
					        filter: LdapFilter,
 | 
				
			||||||
 | 
					        attrs: Vec<S>,
 | 
				
			||||||
 | 
					    ) -> LdapSearchRequest {
 | 
				
			||||||
 | 
					        LdapSearchRequest {
 | 
				
			||||||
 | 
					            base: "ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
 | 
					            scope: LdapSearchScope::Base,
 | 
				
			||||||
 | 
					            aliases: LdapDerefAliases::Never,
 | 
				
			||||||
 | 
					            sizelimit: 0,
 | 
				
			||||||
 | 
					            timelimit: 0,
 | 
				
			||||||
 | 
					            typesonly: false,
 | 
				
			||||||
 | 
					            filter,
 | 
				
			||||||
 | 
					            attrs: attrs.into_iter().map(Into::into).collect(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async fn setup_bound_handler(
 | 
					    async fn setup_bound_handler(
 | 
				
			||||||
        mut mock: MockTestBackendHandler,
 | 
					        mut mock: MockTestBackendHandler,
 | 
				
			||||||
    ) -> LdapHandler<MockTestBackendHandler> {
 | 
					    ) -> LdapHandler<MockTestBackendHandler> {
 | 
				
			||||||
@ -494,12 +560,14 @@ mod tests {
 | 
				
			|||||||
            .return_once(|_| Ok(()));
 | 
					            .return_once(|_| Ok(()));
 | 
				
			||||||
        let mut ldap_handler =
 | 
					        let mut ldap_handler =
 | 
				
			||||||
            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "test".to_string());
 | 
					            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "test".to_string());
 | 
				
			||||||
        let request = SimpleBindRequest {
 | 
					        let request = LdapBindRequest {
 | 
				
			||||||
            msgid: 1,
 | 
					 | 
				
			||||||
            dn: "cn=test,ou=people,dc=example,dc=com".to_string(),
 | 
					            dn: "cn=test,ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
            pw: "pass".to_string(),
 | 
					            cred: LdapBindCred::Simple("pass".to_string()),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert_eq!(ldap_handler.do_bind(&request).await, request.gen_success());
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            ldap_handler.do_bind(&request).await.0,
 | 
				
			||||||
 | 
					            LdapResultCode::Success
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        ldap_handler
 | 
					        ldap_handler
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -516,23 +584,13 @@ mod tests {
 | 
				
			|||||||
        let mut ldap_handler =
 | 
					        let mut ldap_handler =
 | 
				
			||||||
            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "test".to_string());
 | 
					            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "test".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let request = WhoamiRequest { msgid: 1 };
 | 
					        let request = LdapBindRequest {
 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            ldap_handler.do_whoami(&request),
 | 
					 | 
				
			||||||
            request.gen_operror("Unauthenticated")
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let request = SimpleBindRequest {
 | 
					 | 
				
			||||||
            msgid: 2,
 | 
					 | 
				
			||||||
            dn: "cn=bob,ou=people,dc=example,dc=com".to_string(),
 | 
					            dn: "cn=bob,ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
            pw: "pass".to_string(),
 | 
					            cred: LdapBindCred::Simple("pass".to_string()),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert_eq!(ldap_handler.do_bind(&request).await, request.gen_success());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let request = WhoamiRequest { msgid: 3 };
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_whoami(&request),
 | 
					            ldap_handler.do_bind(&request).await.0,
 | 
				
			||||||
            request.gen_success("dn: cn=bob,ou=people,dc=example,dc=com")
 | 
					            LdapResultCode::Success
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -549,23 +607,13 @@ mod tests {
 | 
				
			|||||||
        let mut ldap_handler =
 | 
					        let mut ldap_handler =
 | 
				
			||||||
            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "test".to_string());
 | 
					            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "test".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let request = WhoamiRequest { msgid: 1 };
 | 
					        let request = LdapBindRequest {
 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            ldap_handler.do_whoami(&request),
 | 
					 | 
				
			||||||
            request.gen_operror("Unauthenticated")
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let request = SimpleBindRequest {
 | 
					 | 
				
			||||||
            msgid: 2,
 | 
					 | 
				
			||||||
            dn: "cn=test,ou=people,dc=example,dc=com".to_string(),
 | 
					            dn: "cn=test,ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
            pw: "pass".to_string(),
 | 
					            cred: LdapBindCred::Simple("pass".to_string()),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert_eq!(ldap_handler.do_bind(&request).await, request.gen_success());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let request = WhoamiRequest { msgid: 3 };
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_whoami(&request),
 | 
					            ldap_handler.do_bind(&request).await.0,
 | 
				
			||||||
            request.gen_success("dn: cn=test,ou=people,dc=example,dc=com")
 | 
					            LdapResultCode::Success
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -582,35 +630,19 @@ mod tests {
 | 
				
			|||||||
        let mut ldap_handler =
 | 
					        let mut ldap_handler =
 | 
				
			||||||
            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "admin".to_string());
 | 
					            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "admin".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let request = WhoamiRequest { msgid: 1 };
 | 
					        let request = LdapBindRequest {
 | 
				
			||||||
        assert_eq!(
 | 
					 | 
				
			||||||
            ldap_handler.do_whoami(&request),
 | 
					 | 
				
			||||||
            request.gen_operror("Unauthenticated")
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let request = SimpleBindRequest {
 | 
					 | 
				
			||||||
            msgid: 2,
 | 
					 | 
				
			||||||
            dn: "cn=test,ou=people,dc=example,dc=com".to_string(),
 | 
					            dn: "cn=test,ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
            pw: "pass".to_string(),
 | 
					            cred: LdapBindCred::Simple("pass".to_string()),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert_eq!(ldap_handler.do_bind(&request).await, request.gen_success());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let request = WhoamiRequest { msgid: 3 };
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_whoami(&request),
 | 
					            ldap_handler.do_bind(&request).await.0,
 | 
				
			||||||
            request.gen_success("dn: cn=test,ou=people,dc=example,dc=com")
 | 
					            LdapResultCode::Success
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let request = SearchRequest {
 | 
					        let request = make_search_request::<String>(LdapFilter::And(vec![]), vec![]);
 | 
				
			||||||
            msgid: 2,
 | 
					 | 
				
			||||||
            base: "ou=people,dc=example,dc=com".to_string(),
 | 
					 | 
				
			||||||
            scope: LdapSearchScope::Base,
 | 
					 | 
				
			||||||
            filter: LdapFilter::And(vec![]),
 | 
					 | 
				
			||||||
            attrs: vec![],
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_search(&request).await,
 | 
					            ldap_handler.do_search(&request).await,
 | 
				
			||||||
            vec![request.gen_error(
 | 
					            vec![make_search_error(
 | 
				
			||||||
                LdapResultCode::InsufficentAccessRights,
 | 
					                LdapResultCode::InsufficentAccessRights,
 | 
				
			||||||
                r#"Current user `cn=test,ou=people,dc=example,dc=com` is not allowed to query LDAP, expected cn=admin,ou=people,dc=example,dc=com"#.to_string()
 | 
					                r#"Current user `cn=test,ou=people,dc=example,dc=com` is not allowed to query LDAP, expected cn=admin,ou=people,dc=example,dc=com"#.to_string()
 | 
				
			||||||
            )]
 | 
					            )]
 | 
				
			||||||
@ -623,30 +655,21 @@ mod tests {
 | 
				
			|||||||
        let mut ldap_handler =
 | 
					        let mut ldap_handler =
 | 
				
			||||||
            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "admin".to_string());
 | 
					            LdapHandler::new(mock, "dc=example,dc=com".to_string(), "admin".to_string());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let request = SimpleBindRequest {
 | 
					        let request = LdapBindRequest {
 | 
				
			||||||
            msgid: 2,
 | 
					 | 
				
			||||||
            dn: "cn=bob,dc=example,dc=com".to_string(),
 | 
					            dn: "cn=bob,dc=example,dc=com".to_string(),
 | 
				
			||||||
            pw: "pass".to_string(),
 | 
					            cred: LdapBindCred::Simple("pass".to_string()),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_bind(&request).await,
 | 
					            ldap_handler.do_bind(&request).await.0,
 | 
				
			||||||
            request.gen_error(
 | 
					            LdapResultCode::NamingViolation,
 | 
				
			||||||
                LdapResultCode::NamingViolation,
 | 
					 | 
				
			||||||
                r#"Unexpected user DN format. Got "cn=bob,dc=example,dc=com", expected: "cn=username,ou=people,dc=example,dc=com""#.to_string()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        let request = SimpleBindRequest {
 | 
					        let request = LdapBindRequest {
 | 
				
			||||||
            msgid: 2,
 | 
					 | 
				
			||||||
            dn: "cn=bob,ou=groups,dc=example,dc=com".to_string(),
 | 
					            dn: "cn=bob,ou=groups,dc=example,dc=com".to_string(),
 | 
				
			||||||
            pw: "pass".to_string(),
 | 
					            cred: LdapBindCred::Simple("pass".to_string()),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_bind(&request).await,
 | 
					            ldap_handler.do_bind(&request).await.0,
 | 
				
			||||||
            request.gen_error(
 | 
					            LdapResultCode::NamingViolation,
 | 
				
			||||||
                LdapResultCode::NamingViolation,
 | 
					 | 
				
			||||||
                r#"Unexpected user DN format. Got "cn=bob,ou=groups,dc=example,dc=com", expected: "cn=username,ou=people,dc=example,dc=com""#
 | 
					 | 
				
			||||||
                    .to_string()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -702,25 +725,14 @@ mod tests {
 | 
				
			|||||||
            ])
 | 
					            ])
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        let mut ldap_handler = setup_bound_handler(mock).await;
 | 
					        let mut ldap_handler = setup_bound_handler(mock).await;
 | 
				
			||||||
        let request = SearchRequest {
 | 
					        let request = make_search_request(
 | 
				
			||||||
            msgid: 2,
 | 
					            LdapFilter::And(vec![]),
 | 
				
			||||||
            base: "ou=people,dc=example,dc=com".to_string(),
 | 
					            vec!["objectClass", "dn", "uid", "mail", "givenName", "sn", "cn"],
 | 
				
			||||||
            scope: LdapSearchScope::Base,
 | 
					        );
 | 
				
			||||||
            filter: LdapFilter::And(vec![]),
 | 
					 | 
				
			||||||
            attrs: vec![
 | 
					 | 
				
			||||||
                "objectClass".to_string(),
 | 
					 | 
				
			||||||
                "dn".to_string(),
 | 
					 | 
				
			||||||
                "uid".to_string(),
 | 
					 | 
				
			||||||
                "mail".to_string(),
 | 
					 | 
				
			||||||
                "givenName".to_string(),
 | 
					 | 
				
			||||||
                "sn".to_string(),
 | 
					 | 
				
			||||||
                "cn".to_string(),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_search(&request).await,
 | 
					            ldap_handler.do_search(&request).await,
 | 
				
			||||||
            vec![
 | 
					            vec![
 | 
				
			||||||
                request.gen_result_entry(LdapSearchResultEntry {
 | 
					                LdapOp::SearchResultEntry(LdapSearchResultEntry {
 | 
				
			||||||
                    dn: "cn=bob_1,ou=people,dc=example,dc=com".to_string(),
 | 
					                    dn: "cn=bob_1,ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
                    attributes: vec![
 | 
					                    attributes: vec![
 | 
				
			||||||
                        LdapPartialAttribute {
 | 
					                        LdapPartialAttribute {
 | 
				
			||||||
@ -758,7 +770,7 @@ mod tests {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
                request.gen_result_entry(LdapSearchResultEntry {
 | 
					                LdapOp::SearchResultEntry(LdapSearchResultEntry {
 | 
				
			||||||
                    dn: "cn=jim,ou=people,dc=example,dc=com".to_string(),
 | 
					                    dn: "cn=jim,ou=people,dc=example,dc=com".to_string(),
 | 
				
			||||||
                    attributes: vec![
 | 
					                    attributes: vec![
 | 
				
			||||||
                        LdapPartialAttribute {
 | 
					                        LdapPartialAttribute {
 | 
				
			||||||
@ -796,7 +808,7 @@ mod tests {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
                request.gen_success()
 | 
					                make_search_success(),
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -814,37 +826,31 @@ mod tests {
 | 
				
			|||||||
            .times(1)
 | 
					            .times(1)
 | 
				
			||||||
            .return_once(|_| Ok(vec![]));
 | 
					            .return_once(|_| Ok(vec![]));
 | 
				
			||||||
        let mut ldap_handler = setup_bound_handler(mock).await;
 | 
					        let mut ldap_handler = setup_bound_handler(mock).await;
 | 
				
			||||||
        let request = SearchRequest {
 | 
					        let request = make_search_request(
 | 
				
			||||||
            msgid: 2,
 | 
					            LdapFilter::And(vec![LdapFilter::Or(vec![LdapFilter::Not(Box::new(
 | 
				
			||||||
            base: "ou=people,dc=example,dc=com".to_string(),
 | 
					 | 
				
			||||||
            scope: LdapSearchScope::Base,
 | 
					 | 
				
			||||||
            filter: LdapFilter::And(vec![LdapFilter::Or(vec![LdapFilter::Not(Box::new(
 | 
					 | 
				
			||||||
                LdapFilter::Equality("uid".to_string(), "bob".to_string()),
 | 
					                LdapFilter::Equality("uid".to_string(), "bob".to_string()),
 | 
				
			||||||
            ))])]),
 | 
					            ))])]),
 | 
				
			||||||
            attrs: vec!["objectClass".to_string()],
 | 
					            vec!["objectClass"],
 | 
				
			||||||
        };
 | 
					        );
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_search(&request).await,
 | 
					            ldap_handler.do_search(&request).await,
 | 
				
			||||||
            vec![request.gen_success()]
 | 
					            vec![make_search_success()]
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[tokio::test]
 | 
					    #[tokio::test]
 | 
				
			||||||
    async fn test_search_unsupported_filters() {
 | 
					    async fn test_search_unsupported_filters() {
 | 
				
			||||||
        let mut ldap_handler = setup_bound_handler(MockTestBackendHandler::new()).await;
 | 
					        let mut ldap_handler = setup_bound_handler(MockTestBackendHandler::new()).await;
 | 
				
			||||||
        let request = SearchRequest {
 | 
					        let request = make_search_request(
 | 
				
			||||||
            msgid: 2,
 | 
					            LdapFilter::Substring(
 | 
				
			||||||
            base: "ou=people,dc=example,dc=com".to_string(),
 | 
					 | 
				
			||||||
            scope: LdapSearchScope::Base,
 | 
					 | 
				
			||||||
            filter: LdapFilter::Substring(
 | 
					 | 
				
			||||||
                "uid".to_string(),
 | 
					                "uid".to_string(),
 | 
				
			||||||
                ldap3_server::proto::LdapSubstringFilter::default(),
 | 
					                ldap3_server::proto::LdapSubstringFilter::default(),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            attrs: vec!["objectClass".to_string()],
 | 
					            vec!["objectClass"],
 | 
				
			||||||
        };
 | 
					        );
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            ldap_handler.do_search(&request).await,
 | 
					            ldap_handler.do_search(&request).await,
 | 
				
			||||||
            vec![request.gen_error(
 | 
					            vec![make_search_error(
 | 
				
			||||||
                LdapResultCode::UnwillingToPerform,
 | 
					                LdapResultCode::UnwillingToPerform,
 | 
				
			||||||
                "Unsupported user filter: Unsupported user filter: Substring(\"uid\", LdapSubstringFilter { initial: None, any: [], final_: None })".to_string()
 | 
					                "Unsupported user filter: Unsupported user filter: Substring(\"uid\", LdapSubstringFilter { initial: None, any: [], final_: None })".to_string()
 | 
				
			||||||
            )]
 | 
					            )]
 | 
				
			||||||
 | 
				
			|||||||
@ -4,10 +4,9 @@ use crate::infra::ldap_handler::LdapHandler;
 | 
				
			|||||||
use actix_rt::net::TcpStream;
 | 
					use actix_rt::net::TcpStream;
 | 
				
			||||||
use actix_server::ServerBuilder;
 | 
					use actix_server::ServerBuilder;
 | 
				
			||||||
use actix_service::{fn_service, ServiceFactoryExt};
 | 
					use actix_service::{fn_service, ServiceFactoryExt};
 | 
				
			||||||
use anyhow::{bail, Result};
 | 
					use anyhow::{anyhow, bail, Result};
 | 
				
			||||||
use futures_util::future::ok;
 | 
					use futures_util::future::ok;
 | 
				
			||||||
use ldap3_server::simple::*;
 | 
					use ldap3_server::{proto::LdapMsg, LdapCodec};
 | 
				
			||||||
use ldap3_server::LdapCodec;
 | 
					 | 
				
			||||||
use log::*;
 | 
					use log::*;
 | 
				
			||||||
use tokio::net::tcp::WriteHalf;
 | 
					use tokio::net::tcp::WriteHalf;
 | 
				
			||||||
use tokio_util::codec::{FramedRead, FramedWrite};
 | 
					use tokio_util::codec::{FramedRead, FramedWrite};
 | 
				
			||||||
@ -21,29 +20,19 @@ where
 | 
				
			|||||||
    Backend: BackendHandler + LoginHandler,
 | 
					    Backend: BackendHandler + LoginHandler,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use futures_util::SinkExt;
 | 
					    use futures_util::SinkExt;
 | 
				
			||||||
    use std::convert::TryFrom;
 | 
					    let msg = msg.map_err(|e| anyhow!("Error while receiving LDAP op: {:#}", e))?;
 | 
				
			||||||
    let server_op = match msg
 | 
					    match session.handle_ldap_message(msg.op).await {
 | 
				
			||||||
        .map_err(|e| warn!("Error while receiving LDAP op: {:#}", e))
 | 
					 | 
				
			||||||
        .and_then(ServerOps::try_from)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        Ok(a_value) => a_value,
 | 
					 | 
				
			||||||
        Err(an_error) => {
 | 
					 | 
				
			||||||
            let _err = resp
 | 
					 | 
				
			||||||
                .send(DisconnectionNotice::gen(
 | 
					 | 
				
			||||||
                    LdapResultCode::Other,
 | 
					 | 
				
			||||||
                    "Internal Server Error",
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
                .await;
 | 
					 | 
				
			||||||
            let _err = resp.flush().await;
 | 
					 | 
				
			||||||
            bail!("Internal server error: {:?}", an_error);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    match session.handle_ldap_message(server_op).await {
 | 
					 | 
				
			||||||
        None => return Ok(false),
 | 
					        None => return Ok(false),
 | 
				
			||||||
        Some(result) => {
 | 
					        Some(result) => {
 | 
				
			||||||
            for rmsg in result.into_iter() {
 | 
					            for result_op in result.into_iter() {
 | 
				
			||||||
                if let Err(e) = resp.send(rmsg).await {
 | 
					                if let Err(e) = resp
 | 
				
			||||||
 | 
					                    .send(LdapMsg {
 | 
				
			||||||
 | 
					                        msgid: msg.msgid,
 | 
				
			||||||
 | 
					                        op: result_op,
 | 
				
			||||||
 | 
					                        ctrl: vec![],
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .await
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
                    bail!("Error while sending a response: {:?}", e);
 | 
					                    bail!("Error while sending a response: {:?}", e);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user