simple_ldap/sort/
adapter.rs1use async_trait::async_trait;
5use itertools::Itertools;
6use ldap3::{
7 LdapError, LdapResult, ResultEntry, Scope, SearchStream,
8 adapters::{Adapter, SoloMarker},
9 controls::{Control, MakeCritical, RawControl},
10};
11use std::{fmt::Debug, mem};
12use thiserror::Error;
13use tracing::debug;
14
15use crate::sort::{
16 SERVER_SIDE_SORT_REQUEST_OID, SERVER_SIDE_SORT_RESPONSE_OID,
17 control::{self, ServerSideSortResponse, SortResult},
18};
19
20#[derive(Debug, Clone)]
22pub(crate) struct ServerSideSort {
23 sorts: Vec<SortBy>,
31}
32
33#[derive(Debug, Error)]
34#[error("Attributes {} occur more than once in the sort list.",
35 attributes.iter().format(", ")
36)]
37pub struct DuplicateSortAttributes {
38 attributes: Vec<String>,
39}
40
41impl ServerSideSort {
42 pub fn new(sorts: Vec<SortBy>) -> Result<Self, DuplicateSortAttributes> {
49 let duplicates = sorts
51 .iter()
52 .map(|SortBy { attribute, .. }| attribute)
53 .duplicates()
54 .collect_vec();
55
56 if !duplicates.is_empty() {
57 let attributes = duplicates.into_iter().map(ToOwned::to_owned).collect();
58 Err(DuplicateSortAttributes { attributes })
59 }
60 else {
62 Ok(ServerSideSort { sorts })
63 }
64 }
65}
66
67#[derive(Debug, Clone)]
71pub struct SortBy {
72 pub attribute: String,
74 pub reverse: bool,
76}
77
78impl SoloMarker for ServerSideSort {}
80
81#[async_trait]
82impl<'a, S, A> Adapter<'a, S, A> for ServerSideSort
83where
84 S: AsRef<str> + Clone + Debug + Send + Sync + 'a,
85 A: AsRef<[S]> + Clone + Debug + Send + Sync + 'a,
86{
87 async fn start(
88 &mut self,
89 stream: &mut SearchStream<'a, S, A>,
90 base: &str,
91 scope: Scope,
92 filter: &str,
93 attrs: A,
94 ) -> ldap3::result::Result<()> {
95 let stream_ldap = stream.ldap_handle();
96
97 let sort_control_already_defined = stream_ldap.controls.as_ref().is_some_and(|vec| {
99 vec.iter()
100 .any(|control| control.ctype == SERVER_SIDE_SORT_REQUEST_OID)
101 });
102 if sort_control_already_defined {
103 return Err(LdapError::AdapterInit(String::from(
104 "found Server Side Sort control in op set already",
105 )));
106 }
107
108 let sorts = mem::take(&mut self.sorts);
110 let new_control = control::ServerSideSortRequest {
111 sort_key_list: sorts.into_iter().map_into().collect(),
113 } .critical();
115
116 stream_ldap
118 .controls
119 .get_or_insert_default()
120 .push(new_control.into());
121
122 stream.start(base, scope, filter, attrs).await
124 }
125
126 async fn next(
127 &mut self,
128 stream: &mut SearchStream<'a, S, A>,
129 ) -> ldap3::result::Result<Option<ResultEntry>> {
130 match stream.next().await? {
131 Some(result_entry) => {
132 let sss_control = stream.res.as_ref().and_then(
135 |LdapResult {
136 ctrls: controls, ..
137 }| get_response_control(controls.as_slice()),
138 );
139
140 match sss_control {
141 Some(ServerSideSortResponse {
142 sort_result: SortResult::Success,
143 ..
144 }) => {
145 Ok(Some(result_entry))
147 }
148 Some(ServerSideSortResponse { sort_result, .. }) => {
149 panic!(
150 "Server side sort result was {sort_result:?}. This should never be the case in this branch as the control was set to critical and so should have caused an error earlier."
151 )
152 }
153 None => {
154 debug!("No server side sort response control.");
155 Ok(Some(result_entry))
156 }
157 }
158 }
159 None => Ok(None),
162 }
163 }
164
165 async fn finish(&mut self, stream: &mut SearchStream<'a, S, A>) -> LdapResult {
166 let result = stream.finish().await;
169
170 let sss_control = get_response_control(result.ctrls.as_slice());
171
172 match sss_control {
173 None => debug!("No Server Side Sort control in the final result"),
174 Some(control) => debug!("The final Server Side Sort control: {control:?}"),
175 };
176
177 result
178 }
179}
180
181fn get_response_control(controls: &[Control]) -> Option<ServerSideSortResponse> {
186 controls
187 .iter()
188 .map(|Control(_, raw)| raw)
191 .find(|raw| raw.ctype == SERVER_SIDE_SORT_RESPONSE_OID)
192 .map(RawControl::parse)
193}