ldap_rs/
request.rs

1//! LDAP request
2
3use std::time::Duration;
4
5use rasn_ldap::{ChangeOperation, ModifyRequestChanges};
6
7use crate::{
8    error::Error,
9    filter::parse_filter,
10    model::{SearchRequestDerefAliases, SearchRequestScope},
11    Attribute,
12};
13
14/// LDAP search request builder
15#[derive(Debug, Clone, Eq, PartialEq)]
16pub struct SearchRequestBuilder {
17    base_dn: String,
18    scope: SearchRequestScope,
19    deref_aliases: SearchRequestDerefAliases,
20    size_limit: u32,
21    time_limit: Duration,
22    types_only: bool,
23    filter: String,
24    attributes: Vec<String>,
25}
26
27impl SearchRequestBuilder {
28    pub(crate) fn new() -> Self {
29        Self {
30            base_dn: Default::default(),
31            scope: SearchRequestScope::BaseObject,
32            deref_aliases: SearchRequestDerefAliases::NeverDerefAliases,
33            size_limit: 0,
34            time_limit: Duration::default(),
35            types_only: false,
36            filter: Default::default(),
37            attributes: Vec::new(),
38        }
39    }
40
41    /// Set base DN
42    pub fn base_dn<S: AsRef<str>>(mut self, base_dn: S) -> Self {
43        base_dn.as_ref().clone_into(&mut self.base_dn);
44        self
45    }
46
47    /// Set search scope
48    pub fn scope(mut self, scope: SearchRequestScope) -> Self {
49        self.scope = scope;
50        self
51    }
52
53    /// Set aliases dereference policy
54    pub fn deref_aliases(mut self, deref_aliases: SearchRequestDerefAliases) -> Self {
55        self.deref_aliases = deref_aliases;
56        self
57    }
58
59    /// Set search size limit
60    pub fn size_limit(mut self, size_limit: u32) -> Self {
61        self.size_limit = size_limit;
62        self
63    }
64
65    /// Set search time limit
66    pub fn time_limit(mut self, time_limit: Duration) -> Self {
67        self.time_limit = time_limit;
68        self
69    }
70
71    /// Set flag indicating to only search types
72    pub fn types_only(mut self, types_only: bool) -> Self {
73        self.types_only = types_only;
74        self
75    }
76
77    /// Set search filter
78    pub fn filter<S: AsRef<str>>(mut self, filter: S) -> Self {
79        filter.as_ref().clone_into(&mut self.filter);
80        self
81    }
82
83    /// Specify attributes to return
84    pub fn attributes<I, S>(mut self, attributes: I) -> Self
85    where
86        I: IntoIterator<Item = S>,
87        S: AsRef<str>,
88    {
89        self.attributes
90            .extend(attributes.into_iter().map(|a| a.as_ref().to_owned()));
91        self
92    }
93
94    /// Add attribute to return
95    pub fn attribute<S>(mut self, attribute: S) -> Self
96    where
97        S: AsRef<str>,
98    {
99        self.attributes.push(attribute.as_ref().to_owned());
100        self
101    }
102
103    /// Create a search request
104    pub fn build(self) -> Result<SearchRequest, Error> {
105        Ok(SearchRequest(rasn_ldap::SearchRequest::new(
106            self.base_dn.into(),
107            self.scope,
108            self.deref_aliases,
109            self.size_limit,
110            self.time_limit.as_secs() as u32,
111            self.types_only,
112            parse_filter(self.filter)?,
113            self.attributes.into_iter().map(Into::into).collect(),
114        )))
115    }
116}
117
118/// Search request
119#[derive(Clone, Debug, Eq, PartialEq)]
120pub struct SearchRequest(pub(crate) rasn_ldap::SearchRequest);
121
122impl SearchRequest {
123    /// Create search request  builder
124    pub fn builder() -> SearchRequestBuilder {
125        SearchRequestBuilder::new()
126    }
127
128    /// Create search request to query root DSE object
129    pub fn root_dse() -> Self {
130        Self::builder().filter("(objectClass=*)").build().unwrap()
131    }
132}
133
134impl From<SearchRequest> for rasn_ldap::SearchRequest {
135    fn from(req: SearchRequest) -> Self {
136        req.0
137    }
138}
139
140/// Search request
141#[derive(Clone, Debug, Eq, PartialEq)]
142pub struct ModifyRequest(pub(crate) rasn_ldap::ModifyRequest);
143
144impl ModifyRequest {
145    /// Create modification request builder for a given object DN
146    pub fn builder<S: AsRef<str>>(object: S) -> ModifyRequestBuilder {
147        ModifyRequestBuilder::new(object)
148    }
149}
150
151impl From<ModifyRequest> for rasn_ldap::ModifyRequest {
152    fn from(req: ModifyRequest) -> Self {
153        req.0
154    }
155}
156
157/// LDAP search request builder
158#[derive(Debug, Clone, Eq, PartialEq)]
159pub struct ModifyRequestBuilder {
160    object: String,
161    operations: Vec<(ChangeOperation, Attribute)>,
162}
163
164impl ModifyRequestBuilder {
165    pub(crate) fn new<S: AsRef<str>>(object: S) -> Self {
166        Self {
167            object: object.as_ref().to_owned(),
168            operations: Vec::new(),
169        }
170    }
171
172    /// Append add operation to the request builder
173    pub fn add_op(mut self, attribute: Attribute) -> Self {
174        self.operations.push((ChangeOperation::Add, attribute));
175        self
176    }
177
178    /// Append delete operation to the request builder
179    pub fn delete_op(mut self, attribute: Attribute) -> Self {
180        self.operations.push((ChangeOperation::Delete, attribute));
181        self
182    }
183
184    /// Append replace operation to the request builder
185    pub fn replace_op(mut self, attribute: Attribute) -> Self {
186        self.operations.push((ChangeOperation::Replace, attribute));
187        self
188    }
189
190    /// Build the modification request
191    pub fn build(self) -> ModifyRequest {
192        let req = rasn_ldap::ModifyRequest {
193            object: self.object.into(),
194            changes: self
195                .operations
196                .into_iter()
197                .map(|(operation, attribute)| ModifyRequestChanges {
198                    operation,
199                    modification: attribute.into(),
200                })
201                .collect(),
202        };
203        ModifyRequest(req)
204    }
205}