/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ldap-parser-0.5.0/src/parser.rs
Line | Count | Source |
1 | | // DEFINITIONS |
2 | | // IMPLICIT TAGS |
3 | | // EXTENSIBILITY IMPLIED |
4 | | |
5 | | use crate::error::*; |
6 | | use crate::filter::*; |
7 | | use crate::ldap::*; |
8 | | use asn1_rs::nom; |
9 | | use asn1_rs::{ |
10 | | Class, Enumerated, FromBer, Header, Implicit, OptTaggedParser, ParseResult, Sequence, Tag, |
11 | | TaggedParser, TaggedValue, |
12 | | }; |
13 | | use nom::bytes::streaming::take; |
14 | | use nom::combinator::{complete, map, opt, verify}; |
15 | | use nom::multi::{many0, many1}; |
16 | | use nom::Err; |
17 | | use std::borrow::Cow; |
18 | | |
19 | | // // maxInt INTEGER ::= 2147483647 -- (2^^31 - 1) -- |
20 | | // const MAX_INT: u32 = 2_147_483_647; |
21 | | |
22 | | // MessageID ::= INTEGER (0 .. maxInt) |
23 | | impl<'a> FromBer<'a, LdapError> for MessageID { |
24 | 707k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
25 | 707k | map(u32::from_ber, MessageID)(bytes).map_err(Err::convert) |
26 | 707k | } |
27 | | } |
28 | | |
29 | | // LDAPString ::= OCTET STRING -- UTF-8 encoded, |
30 | | // -- [ISO10646] characters |
31 | | impl<'a> FromBer<'a, LdapError> for LdapString<'a> { |
32 | 70.9k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
33 | 70.9k | let (i, b) = parse_ldap_octet_string_as_slice(bytes)?; |
34 | | // convert to UTF-8 |
35 | 48.5k | let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidString)))?; |
36 | 48.3k | Ok((i, LdapString(Cow::Borrowed(s)))) |
37 | 70.9k | } |
38 | | } |
39 | | |
40 | | #[inline] |
41 | 95.0k | pub(crate) fn parse_ldap_octet_string_as_slice(i: &[u8]) -> Result<&[u8]> { |
42 | 95.0k | <&[u8]>::from_ber(i).map_err(Err::convert) |
43 | 95.0k | } |
44 | | |
45 | | #[inline] |
46 | 25.4k | fn parse_ldap_int_as_u32(i: &[u8]) -> Result<u32> { |
47 | 25.4k | <u32>::from_ber(i).map_err(Err::convert) |
48 | 25.4k | } |
49 | | |
50 | | #[inline] |
51 | 44.7k | fn parse_ldap_enum_as_u32(i: &[u8]) -> Result<u32> { |
52 | 44.7k | let (i, obj) = Enumerated::from_ber(i).map_err(Err::convert)?; |
53 | 40.7k | Ok((i, obj.0)) |
54 | 44.7k | } |
55 | | |
56 | | // LDAPDN ::= LDAPString -- Constrained to <distinguishedName> |
57 | | // -- [RFC4514] |
58 | | impl<'a> FromBer<'a, LdapError> for LdapDN<'a> { |
59 | 58.0k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
60 | | // read bytes |
61 | 58.0k | let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?; |
62 | | // convert to UTF-8 |
63 | 48.1k | let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?; |
64 | 48.0k | Ok((i, LdapDN(Cow::Borrowed(s)))) |
65 | 58.0k | } |
66 | | } |
67 | | |
68 | | // RelativeLDAPDN ::= LDAPString -- Constrained to <name-component> |
69 | | // -- [RFC4514] |
70 | | impl<'a> FromBer<'a, LdapError> for RelativeLdapDN<'a> { |
71 | 1.84k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
72 | | // read bytes |
73 | 1.84k | let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?; |
74 | | // convert to UTF-8 |
75 | 1.57k | let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?; |
76 | 1.57k | Ok((i, RelativeLdapDN(Cow::Borrowed(s)))) |
77 | 1.84k | } |
78 | | } |
79 | | |
80 | | // LDAPOID ::= OCTET STRING -- Constrained to <numericoid> |
81 | | // -- [RFC4512] |
82 | | impl<'a> FromBer<'a, LdapError> for LdapOID<'a> { |
83 | 6.08k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
84 | | // read bytes |
85 | 6.08k | let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?; |
86 | | // convert to UTF-8 |
87 | 5.03k | let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?; |
88 | 4.83k | Ok((i, LdapOID(Cow::Borrowed(s)))) |
89 | 6.08k | } |
90 | | } |
91 | | |
92 | | // URI ::= LDAPString -- limited to characters permitted in |
93 | | // -- URIs |
94 | | #[inline] |
95 | 32.7k | fn parse_ldap_uri(i: &[u8]) -> Result<LdapString> { |
96 | 32.7k | LdapString::from_ber(i) |
97 | 32.7k | } |
98 | | |
99 | | // |
100 | | // |
101 | | // |
102 | | // |
103 | | // |
104 | | // ----------------------- LDAP OBJECTS ----------------------- |
105 | | // |
106 | | // |
107 | | // |
108 | | // |
109 | | // |
110 | | // |
111 | | |
112 | | // LDAPResult ::= SEQUENCE { |
113 | | // resultCode ENUMERATED { |
114 | | // success (0), |
115 | | // operationsError (1), |
116 | | // protocolError (2), |
117 | | // timeLimitExceeded (3), |
118 | | // sizeLimitExceeded (4), |
119 | | // compareFalse (5), |
120 | | // compareTrue (6), |
121 | | // authMethodNotSupported (7), |
122 | | // strongerAuthRequired (8), |
123 | | // -- 9 reserved -- |
124 | | // referral (10), |
125 | | // adminLimitExceeded (11), |
126 | | // unavailableCriticalExtension (12), |
127 | | // confidentialityRequired (13), |
128 | | // saslBindInProgress (14), |
129 | | // noSuchAttribute (16), |
130 | | // undefinedAttributeType (17), |
131 | | // inappropriateMatching (18), |
132 | | // constraintViolation (19), |
133 | | // attributeOrValueExists (20), |
134 | | // invalidAttributeSyntax (21), |
135 | | // -- 22-31 unused -- |
136 | | // noSuchObject (32), |
137 | | // aliasProblem (33), |
138 | | // invalidDNSyntax (34), |
139 | | // -- 35 reserved for undefined isLeaf -- |
140 | | // aliasDereferencingProblem (36), |
141 | | // -- 37-47 unused -- |
142 | | // inappropriateAuthentication (48), |
143 | | // invalidCredentials (49), |
144 | | // insufficientAccessRights (50), |
145 | | // busy (51), |
146 | | // unavailable (52), |
147 | | // unwillingToPerform (53), |
148 | | // loopDetect (54), |
149 | | // -- 55-63 unused -- |
150 | | // namingViolation (64), |
151 | | // objectClassViolation (65), |
152 | | // notAllowedOnNonLeaf (66), |
153 | | // notAllowedOnRDN (67), |
154 | | // entryAlreadyExists (68), |
155 | | // objectClassModsProhibited (69), |
156 | | // -- 70 reserved for CLDAP -- |
157 | | // affectsMultipleDSAs (71), |
158 | | // -- 72-79 unused -- |
159 | | // other (80), |
160 | | // ... }, |
161 | | // matchedDN LDAPDN, |
162 | | // diagnosticMessage LDAPString, |
163 | | // referral [3] Referral OPTIONAL } |
164 | 11.9k | fn parse_ldap_result_content(i: &[u8]) -> Result<LdapResult> { |
165 | 11.9k | let (i, result_code) = map(parse_ldap_enum_as_u32, ResultCode)(i)?; |
166 | 9.95k | let (i, matched_dn) = LdapDN::from_ber(i)?; |
167 | 9.36k | let (i, diagnostic_message) = LdapString::from_ber(i)?; |
168 | | // TODO: referral |
169 | 9.08k | let result = LdapResult { |
170 | 9.08k | result_code, |
171 | 9.08k | matched_dn, |
172 | 9.08k | diagnostic_message, |
173 | 9.08k | }; |
174 | 9.08k | Ok((i, result)) |
175 | 11.9k | } |
176 | | |
177 | | // LDAPMessage ::= SEQUENCE { |
178 | | // messageID MessageID, |
179 | | // protocolOp CHOICE { |
180 | | // bindRequest BindRequest, |
181 | | // bindResponse BindResponse, |
182 | | // unbindRequest UnbindRequest, |
183 | | // searchRequest SearchRequest, |
184 | | // searchResEntry SearchResultEntry, |
185 | | // searchResDone SearchResultDone, |
186 | | // searchResRef SearchResultReference, |
187 | | // modifyRequest ModifyRequest, |
188 | | // modifyResponse ModifyResponse, |
189 | | // addRequest AddRequest, |
190 | | // addResponse AddResponse, |
191 | | // delRequest DelRequest, |
192 | | // delResponse DelResponse, |
193 | | // modDNRequest ModifyDNRequest, |
194 | | // modDNResponse ModifyDNResponse, |
195 | | // compareRequest CompareRequest, |
196 | | // compareResponse CompareResponse, |
197 | | // abandonRequest AbandonRequest, |
198 | | // extendedReq ExtendedRequest, |
199 | | // extendedResp ExtendedResponse, |
200 | | // ..., |
201 | | // intermediateResponse IntermediateResponse }, |
202 | | // controls [0] Controls OPTIONAL } |
203 | | /// Parse a single LDAP message and return a structure borrowing fields from the input buffer |
204 | | /// |
205 | | /// ```rust |
206 | | /// use ldap_parser::FromBer; |
207 | | /// use ldap_parser::ldap::{LdapMessage, MessageID, ProtocolOp, ProtocolOpTag}; |
208 | | /// |
209 | | /// static DATA: &[u8] = include_bytes!("../assets/message-search-request-01.bin"); |
210 | | /// |
211 | | /// # fn main() { |
212 | | /// let res = LdapMessage::from_ber(DATA); |
213 | | /// match res { |
214 | | /// Ok((rem, msg)) => { |
215 | | /// assert!(rem.is_empty()); |
216 | | /// // |
217 | | /// assert_eq!(msg.message_id, MessageID(4)); |
218 | | /// assert_eq!(msg.protocol_op.tag(), ProtocolOpTag::SearchRequest); |
219 | | /// match msg.protocol_op { |
220 | | /// ProtocolOp::SearchRequest(req) => { |
221 | | /// assert_eq!(req.base_object.0, "dc=rccad,dc=net"); |
222 | | /// }, |
223 | | /// _ => panic!("Unexpected message type"), |
224 | | /// } |
225 | | /// }, |
226 | | /// _ => panic!("LDAP parsing failed: {:?}", res), |
227 | | /// } |
228 | | /// # } |
229 | | /// ``` |
230 | | impl<'a> FromBer<'a, LdapError> for LdapMessage<'a> { |
231 | 774k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
232 | 774k | Sequence::from_ber_and_then(bytes, |i| { |
233 | 707k | let (i, message_id) = MessageID::from_ber(i)?; |
234 | | // read header of next element and look tag value |
235 | 702k | let (_, header) = Header::from_ber(i).map_err(Err::convert)?; |
236 | 688k | let (i, protocol_op) = match header.tag().0 { |
237 | 9.29k | 0 => map(BindRequest::from_ber, ProtocolOp::BindRequest)(i), |
238 | 2.24k | 1 => map(BindResponse::from_ber, ProtocolOp::BindResponse)(i), |
239 | 272k | 2 => parse_ldap_unbind_request(i), |
240 | 20.8k | 3 => map(SearchRequest::from_ber, ProtocolOp::SearchRequest)(i), |
241 | 6.92k | 4 => map(SearchResultEntry::from_ber, ProtocolOp::SearchResultEntry)(i), |
242 | 1.35k | 5 => map(parse_ldap_search_result_done, ProtocolOp::SearchResultDone)(i), |
243 | 4.05k | 6 => map(ModifyRequest::from_ber, ProtocolOp::ModifyRequest)(i), |
244 | 1.82k | 7 => map(parse_ldap_modify_response, ProtocolOp::ModifyResponse)(i), |
245 | 7.83k | 8 => map(AddRequest::from_ber, ProtocolOp::AddRequest)(i), |
246 | 1.80k | 9 => map(parse_ldap_add_response, ProtocolOp::AddResponse)(i), |
247 | 321k | 10 => map(parse_ldap_del_request, ProtocolOp::DelRequest)(i), |
248 | 1.12k | 11 => map(parse_ldap_del_response, ProtocolOp::DelResponse)(i), |
249 | 2.45k | 12 => map(ModDnRequest::from_ber, ProtocolOp::ModDnRequest)(i), |
250 | 1.12k | 13 => map(parse_ldap_moddn_response, ProtocolOp::ModDnResponse)(i), |
251 | 2.52k | 14 => map(CompareRequest::from_ber, ProtocolOp::CompareRequest)(i), |
252 | 1.69k | 15 => map(parse_ldap_compare_response, ProtocolOp::CompareResponse)(i), |
253 | 2.08k | 16 => map(parse_ldap_abandon_request, ProtocolOp::AbandonRequest)(i), |
254 | 15.6k | 19 => map( |
255 | 15.6k | parse_ldap_search_result_ref, |
256 | 15.6k | ProtocolOp::SearchResultReference, |
257 | 15.6k | )(i), |
258 | 3.06k | 23 => map(ExtendedRequest::from_ber, ProtocolOp::ExtendedRequest)(i), |
259 | 4.24k | 24 => map(ExtendedResponse::from_ber, ProtocolOp::ExtendedResponse)(i), |
260 | 4.70k | 25 => map( |
261 | 4.70k | IntermediateResponse::from_ber, |
262 | 4.70k | ProtocolOp::IntermediateResponse, |
263 | 4.70k | )(i), |
264 | | _ => { |
265 | | // print_hex_dump(i, 32); |
266 | | // panic!("Protocol op {} not yet implemented", header.tag.0); |
267 | 25 | Err(Err::Error(LdapError::InvalidMessageType)) |
268 | | } |
269 | 41.4k | }?; |
270 | 647k | let (i, controls) = OptTaggedParser::new(Class::ContextSpecific, Tag(0)) |
271 | 647k | .parse_ber(i, |_, i| many0(complete(Control::from_ber))(i))?; |
272 | 631k | let msg = LdapMessage { |
273 | 631k | message_id, |
274 | 631k | protocol_op, |
275 | 631k | controls, |
276 | 631k | }; |
277 | 631k | Ok((i, msg)) |
278 | 707k | }) |
279 | 774k | } |
280 | | } |
281 | | |
282 | | #[deprecated( |
283 | | since = "0.3.0", |
284 | | note = "Parsing functions are deprecated. Users should instead use the FromBer trait" |
285 | | )] |
286 | | #[inline] |
287 | 0 | pub fn parse_ldap_message(i: &[u8]) -> Result<LdapMessage> { |
288 | 0 | LdapMessage::from_ber(i) |
289 | 0 | } |
290 | | |
291 | | /// Parse a list of LDAP messages and return a structure borrowing fields from the input buffer |
292 | | // Note: we don't use the trait because Vec<_>::from_ber forces the Error type |
293 | 0 | pub fn parse_ldap_messages(i: &[u8]) -> Result<Vec<LdapMessage>> { |
294 | | // println!("parse_ldap_message: len={}", i.len()); |
295 | | // print_hex_dump(i, 32); |
296 | 0 | many1(complete(LdapMessage::from_ber))(i) |
297 | 0 | } |
298 | | |
299 | | // BindRequest ::= [APPLICATION 0] SEQUENCE { |
300 | | // version INTEGER (1 .. 127), |
301 | | // name LDAPDN, |
302 | | // authentication AuthenticationChoice } |
303 | | impl<'a> FromBer<'a, LdapError> for BindRequest<'a> { |
304 | 9.29k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
305 | 9.29k | TaggedParser::from_ber_and_then(Class::Application, 0, bytes, |i| { |
306 | | // Sequence::from_ber_and_then(bytes, |i| { |
307 | 8.67k | let (i, version) = verify(u8::from_ber, |&n| n < 128)(i).map_err(Err::convert)?; |
308 | 8.29k | let (i, name) = LdapDN::from_ber(i)?; |
309 | 8.00k | let (i, authentication) = AuthenticationChoice::from_ber(i)?; |
310 | 7.11k | let req = BindRequest { |
311 | 7.11k | version, |
312 | 7.11k | name, |
313 | 7.11k | authentication, |
314 | 7.11k | }; |
315 | 7.11k | Ok((i, req)) |
316 | | // }) |
317 | 8.67k | }) |
318 | 9.29k | } |
319 | | } |
320 | | |
321 | | // BindResponse ::= [APPLICATION 1] SEQUENCE { |
322 | | // COMPONENTS OF LDAPResult, |
323 | | // serverSaslCreds [7] OCTET STRING OPTIONAL } |
324 | | impl<'a> FromBer<'a, LdapError> for BindResponse<'a> { |
325 | 2.24k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
326 | 2.24k | TaggedParser::from_ber_and_then(Class::Application, 1, bytes, |i| { |
327 | 1.87k | let (i, result) = parse_ldap_result_content(i)?; |
328 | 1.41k | let (i, server_sasl_creds) = OptTaggedParser::new(Class::ContextSpecific, Tag(7)) |
329 | 1.41k | .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?; |
330 | | |
331 | | // opt(complete(parse_ber_tagged_implicit_g(7, |content, _, _| { |
332 | | // Ok((&b""[..], Cow::Borrowed(content))) |
333 | | // })))(i)?; |
334 | 1.11k | let req = BindResponse { |
335 | 1.11k | result, |
336 | 1.11k | server_sasl_creds, |
337 | 1.11k | }; |
338 | 1.11k | Ok((i, req)) |
339 | 1.87k | }) |
340 | 2.24k | } |
341 | | } |
342 | | |
343 | | // UnbindRequest ::= [APPLICATION 2] NULL |
344 | 272k | fn parse_ldap_unbind_request(bytes: &[u8]) -> Result<ProtocolOp> { |
345 | 272k | TaggedParser::from_ber_and_then(Class::Application, 2, bytes, |i| { |
346 | | // accept empty input, otherwise expect NULL |
347 | 272k | if !i.is_empty() { |
348 | 813 | let (_, _) = <()>::from_ber(i).map_err(Err::convert)?; |
349 | 271k | } |
350 | 271k | Ok((i, ProtocolOp::UnbindRequest)) |
351 | 272k | }) |
352 | 272k | } |
353 | | |
354 | | // SearchRequest ::= [APPLICATION 3] SEQUENCE { |
355 | | // baseObject LDAPDN, |
356 | | // scope ENUMERATED { |
357 | | // baseObject (0), |
358 | | // singleLevel (1), |
359 | | // wholeSubtree (2), |
360 | | // ... }, |
361 | | // derefAliases ENUMERATED { |
362 | | // neverDerefAliases (0), |
363 | | // derefInSearching (1), |
364 | | // derefFindingBaseObj (2), |
365 | | // derefAlways (3) }, |
366 | | // sizeLimit INTEGER (0 .. maxInt), |
367 | | // timeLimit INTEGER (0 .. maxInt), |
368 | | // typesOnly BOOLEAN, |
369 | | // filter Filter, |
370 | | // attributes AttributeSelection } |
371 | | impl<'a> FromBer<'a, LdapError> for SearchRequest<'a> { |
372 | 20.8k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
373 | 20.8k | TaggedParser::from_ber_and_then(Class::Application, 3, bytes, |i| { |
374 | 19.6k | let (i, base_object) = LdapDN::from_ber(i)?; |
375 | 13.6k | let (i, scope) = map(parse_ldap_enum_as_u32, SearchScope)(i)?; |
376 | 13.2k | let (i, deref_aliases) = map(parse_ldap_enum_as_u32, DerefAliases)(i)?; |
377 | 12.9k | let (i, size_limit) = parse_ldap_int_as_u32(i)?; |
378 | 12.4k | let (i, time_limit) = parse_ldap_int_as_u32(i)?; |
379 | 12.2k | let (i, types_only) = <bool>::from_ber(i).map_err(Err::convert)?; |
380 | 11.9k | let (i, filter) = Filter::from_ber(i)?; |
381 | 9.49k | let (i, attributes) = parse_attribute_selection(i)?; |
382 | 4.47k | let req = SearchRequest { |
383 | 4.47k | base_object, |
384 | 4.47k | scope, |
385 | 4.47k | deref_aliases, |
386 | 4.47k | size_limit, |
387 | 4.47k | time_limit, |
388 | 4.47k | types_only, |
389 | 4.47k | filter, |
390 | 4.47k | attributes, |
391 | 4.47k | }; |
392 | 4.47k | Ok((i, req)) |
393 | 19.6k | }) |
394 | 20.8k | } |
395 | | } |
396 | | |
397 | | // SearchResultEntry ::= [APPLICATION 4] SEQUENCE { |
398 | | // objectName LDAPDN, |
399 | | // attributes PartialAttributeList } |
400 | | impl<'a> FromBer<'a, LdapError> for SearchResultEntry<'a> { |
401 | 6.92k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
402 | 6.92k | TaggedParser::from_ber_and_then(Class::Application, 4, bytes, |i| { |
403 | 4.88k | let (i, object_name) = LdapDN::from_ber(i)?; |
404 | 4.60k | let (i, attributes) = parse_partial_attribute_list(i)?; |
405 | 4.35k | let res = SearchResultEntry { |
406 | 4.35k | object_name, |
407 | 4.35k | attributes, |
408 | 4.35k | }; |
409 | 4.35k | Ok((i, res)) |
410 | 4.88k | }) |
411 | 6.92k | } |
412 | | } |
413 | | |
414 | | // SearchResultDone ::= [APPLICATION 5] LDAPResult |
415 | 1.35k | fn parse_ldap_search_result_done(bytes: &[u8]) -> Result<LdapResult> { |
416 | 1.35k | TaggedParser::from_ber_and_then(Class::Application, 5, bytes, parse_ldap_result_content) |
417 | 1.35k | } |
418 | | |
419 | | // ModifyRequest ::= [APPLICATION 6] SEQUENCE { |
420 | | // object LDAPDN, |
421 | | // changes SEQUENCE OF change SEQUENCE { |
422 | | // operation ENUMERATED { |
423 | | // add (0), |
424 | | // delete (1), |
425 | | // replace (2), |
426 | | // ... }, |
427 | | // modification PartialAttribute } } |
428 | | impl<'a> FromBer<'a, LdapError> for ModifyRequest<'a> { |
429 | 4.05k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
430 | 4.05k | TaggedParser::from_ber_and_then(Class::Application, 6, bytes, |i| { |
431 | 3.69k | let (i, object) = LdapDN::from_ber(i)?; |
432 | 3.37k | let (i, changes) = Sequence::from_ber_and_then(i, many1(complete(Change::from_ber)))?; |
433 | 3.06k | let res = ModifyRequest { object, changes }; |
434 | 3.06k | Ok((i, res)) |
435 | 3.69k | }) |
436 | 4.05k | } |
437 | | } |
438 | | |
439 | | // ModifyResponse ::= [APPLICATION 7] LDAPResult |
440 | 1.82k | fn parse_ldap_modify_response(bytes: &[u8]) -> Result<ModifyResponse> { |
441 | 1.82k | TaggedParser::from_ber_and_then(Class::Application, 7, bytes, |i| { |
442 | 1.50k | let (i, result) = parse_ldap_result_content(i)?; |
443 | 618 | let res = ModifyResponse { result }; |
444 | 618 | Ok((i, res)) |
445 | 1.50k | }) |
446 | 1.82k | } |
447 | | |
448 | | // AddRequest ::= [APPLICATION 8] SEQUENCE { |
449 | | // entry LDAPDN, |
450 | | // attributes AttributeList } |
451 | | impl<'a> FromBer<'a, LdapError> for AddRequest<'a> { |
452 | 7.83k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
453 | 7.83k | TaggedParser::from_ber_and_then(Class::Application, 8, bytes, |i| { |
454 | 7.54k | let (i, entry) = LdapDN::from_ber(i)?; |
455 | 5.62k | let (i, attributes) = parse_attribute_list(i)?; |
456 | 4.32k | let res = AddRequest { entry, attributes }; |
457 | 4.32k | Ok((i, res)) |
458 | 7.54k | }) |
459 | 7.83k | } |
460 | | } |
461 | | |
462 | | // AddResponse ::= [APPLICATION 9] LDAPResult |
463 | 1.80k | fn parse_ldap_add_response(bytes: &[u8]) -> Result<LdapResult> { |
464 | 1.80k | TaggedParser::from_ber_and_then(Class::Application, 9, bytes, parse_ldap_result_content) |
465 | 1.80k | } |
466 | | |
467 | | // DelRequest ::= [APPLICATION 10] LDAPDN |
468 | 321k | fn parse_ldap_del_request(bytes: &[u8]) -> Result<LdapDN> { |
469 | 321k | TaggedParser::from_ber_and_then(Class::Application, 10, bytes, |i| { |
470 | 320k | let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?; |
471 | 320k | let oid = LdapDN(Cow::Borrowed(s)); |
472 | 320k | Ok((&b""[..], oid)) |
473 | 320k | }) |
474 | 321k | } |
475 | | |
476 | | // DelResponse ::= [APPLICATION 11] LDAPResult |
477 | 1.12k | fn parse_ldap_del_response(bytes: &[u8]) -> Result<LdapResult> { |
478 | 1.12k | TaggedParser::from_ber_and_then(Class::Application, 11, bytes, parse_ldap_result_content) |
479 | 1.12k | } |
480 | | |
481 | | // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { |
482 | | // entry LDAPDN, |
483 | | // newrdn RelativeLDAPDN, |
484 | | // deleteoldrdn BOOLEAN, |
485 | | // newSuperior [0] LDAPDN OPTIONAL } |
486 | | impl<'a> FromBer<'a, LdapError> for ModDnRequest<'a> { |
487 | 2.45k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
488 | 2.45k | TaggedParser::from_ber_and_then(Class::Application, 12, bytes, |i| { |
489 | 2.08k | let (i, entry) = LdapDN::from_ber(i)?; |
490 | 1.84k | let (i, newrdn) = RelativeLdapDN::from_ber(i)?; |
491 | 1.57k | let (i, deleteoldrdn) = <bool>::from_ber(i).map_err(Err::convert)?; |
492 | 1.05k | let (i, newsuperior) = |
493 | 1.31k | OptTaggedParser::new(Class::ContextSpecific, Tag(0)).parse_ber(i, |_, i| { |
494 | 330 | let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?; |
495 | 328 | let oid = LdapDN(Cow::Borrowed(s)); |
496 | 328 | Ok((&b""[..], oid)) |
497 | 330 | })?; |
498 | 1.05k | let res = ModDnRequest { |
499 | 1.05k | entry, |
500 | 1.05k | newrdn, |
501 | 1.05k | deleteoldrdn, |
502 | 1.05k | newsuperior, |
503 | 1.05k | }; |
504 | 1.05k | Ok((i, res)) |
505 | 2.08k | }) |
506 | 2.45k | } |
507 | | } |
508 | | |
509 | | // ModifyDNResponse ::= [APPLICATION 13] LDAPResult |
510 | 1.12k | fn parse_ldap_moddn_response(bytes: &[u8]) -> Result<LdapResult> { |
511 | 1.12k | TaggedParser::from_ber_and_then(Class::Application, 13, bytes, parse_ldap_result_content) |
512 | 1.12k | } |
513 | | |
514 | | // CompareRequest ::= [APPLICATION 14] SEQUENCE { |
515 | | // entry LDAPDN, |
516 | | // ava AttributeValueAssertion } |
517 | | impl<'a> FromBer<'a, LdapError> for CompareRequest<'a> { |
518 | 2.52k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
519 | 2.52k | TaggedParser::from_ber_and_then(Class::Application, 14, bytes, |i| { |
520 | 1.88k | let (i, entry) = LdapDN::from_ber(i)?; |
521 | 1.60k | let (i, ava) = AttributeValueAssertion::from_ber(i)?; |
522 | 490 | let res = CompareRequest { entry, ava }; |
523 | 490 | Ok((i, res)) |
524 | 1.88k | }) |
525 | 2.52k | } |
526 | | } |
527 | | |
528 | | // CompareResponse ::= [APPLICATION 15] LDAPResult |
529 | 1.69k | fn parse_ldap_compare_response(bytes: &[u8]) -> Result<LdapResult> { |
530 | 1.69k | TaggedParser::from_ber_and_then(Class::Application, 15, bytes, parse_ldap_result_content) |
531 | 1.69k | } |
532 | | |
533 | | // AbandonRequest ::= [APPLICATION 16] MessageID |
534 | 2.08k | fn parse_ldap_abandon_request(bytes: &[u8]) -> Result<MessageID> { |
535 | 2.08k | let (rem, id) = TaggedValue::<u32, _, Implicit, { Class::APPLICATION }, 16>::from_ber(bytes) |
536 | 2.08k | .map_err(Err::convert)?; |
537 | 1.51k | Ok((rem, MessageID(id.into_inner()))) |
538 | 2.08k | } |
539 | | |
540 | | // SearchResultReference ::= [APPLICATION 19] SEQUENCE |
541 | | // SIZE (1..MAX) OF uri URI |
542 | 15.6k | fn parse_ldap_search_result_ref(bytes: &[u8]) -> Result<Vec<LdapString>> { |
543 | 15.6k | TaggedParser::from_ber_and_then( |
544 | 15.6k | Class::Application, |
545 | | 19, |
546 | 15.6k | bytes, |
547 | 15.6k | many1(complete(parse_ldap_uri)), |
548 | | ) |
549 | 15.6k | } |
550 | | |
551 | | // ExtendedRequest ::= [APPLICATION 23] SEQUENCE { |
552 | | // requestName [0] LDAPOID, |
553 | | // requestValue [1] OCTET STRING OPTIONAL } |
554 | | impl<'a> FromBer<'a, LdapError> for ExtendedRequest<'a> { |
555 | 3.06k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
556 | 3.06k | TaggedParser::from_ber_and_then(Class::Application, 23, bytes, |i| { |
557 | 1.80k | let (i, request_name) = |
558 | 2.30k | TaggedParser::from_ber_and_then(Class::ContextSpecific, 0, i, |i| { |
559 | 1.81k | let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?; |
560 | 1.80k | let oid = LdapOID(Cow::Borrowed(s)); |
561 | 1.80k | Ok((&b""[..], oid)) |
562 | 1.81k | })?; |
563 | 1.80k | let (i, request_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(1)) |
564 | 1.80k | .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?; |
565 | 1.59k | let req = ExtendedRequest { |
566 | 1.59k | request_name, |
567 | 1.59k | request_value, |
568 | 1.59k | }; |
569 | 1.59k | Ok((i, req)) |
570 | 2.30k | }) |
571 | 3.06k | } |
572 | | } |
573 | | |
574 | | // ExtendedResponse ::= [APPLICATION 24] SEQUENCE { |
575 | | // COMPONENTS OF LDAPResult, |
576 | | // responseName [10] LDAPOID OPTIONAL, |
577 | | // responseValue [11] OCTET STRING OPTIONAL } |
578 | | impl<'a> FromBer<'a, LdapError> for ExtendedResponse<'a> { |
579 | 4.24k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
580 | 4.24k | TaggedParser::from_ber_and_then(Class::Application, 24, bytes, |i| { |
581 | 3.95k | let (i, result) = parse_ldap_result_content(i)?; |
582 | 3.43k | let (i, response_name) = OptTaggedParser::new(Class::ContextSpecific, Tag(10)) |
583 | 3.43k | .parse_ber(i, |_, i| { |
584 | 433 | let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?; |
585 | 423 | let oid = LdapOID(Cow::Borrowed(s)); |
586 | 423 | Ok((&b""[..], oid)) |
587 | 433 | })?; |
588 | 3.22k | let (i, response_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(11)) |
589 | 3.22k | .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?; |
590 | 3.02k | let resp = ExtendedResponse { |
591 | 3.02k | result, |
592 | 3.02k | response_name, |
593 | 3.02k | response_value, |
594 | 3.02k | }; |
595 | 3.02k | Ok((i, resp)) |
596 | 3.95k | }) |
597 | 4.24k | } |
598 | | } |
599 | | |
600 | | // IntermediateResponse ::= [APPLICATION 25] SEQUENCE { |
601 | | // responseName [0] LDAPOID OPTIONAL, |
602 | | // responseValue [1] OCTET STRING OPTIONAL } |
603 | | impl<'a> FromBer<'a, LdapError> for IntermediateResponse<'a> { |
604 | 4.70k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
605 | 4.70k | TaggedParser::from_ber_and_then(Class::Application, 25, bytes, |i| { |
606 | 4.22k | let (i, response_name) = OptTaggedParser::new(Class::ContextSpecific, Tag(0)) |
607 | 4.22k | .parse_ber(i, |_, i| { |
608 | 474 | let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?; |
609 | 472 | let oid = LdapOID(Cow::Borrowed(s)); |
610 | 472 | Ok((&b""[..], oid)) |
611 | 474 | })?; |
612 | 3.94k | let (i, response_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(1)) |
613 | 3.94k | .parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?; |
614 | 3.74k | let resp = IntermediateResponse { |
615 | 3.74k | response_name, |
616 | 3.74k | response_value, |
617 | 3.74k | }; |
618 | 3.74k | Ok((i, resp)) |
619 | 4.22k | }) |
620 | 4.70k | } |
621 | | } |
622 | | |
623 | | // AuthenticationChoice ::= CHOICE { |
624 | | // simple [0] OCTET STRING, |
625 | | // -- 1 and 2 reserved |
626 | | // sasl [3] SaslCredentials, |
627 | | // ... } |
628 | | impl<'a> FromBer<'a, LdapError> for AuthenticationChoice<'a> { |
629 | 8.00k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
630 | 8.00k | let (rem, header) = Header::from_ber(bytes).map_err(Err::convert)?; |
631 | 7.76k | match header.tag().0 { |
632 | | 0 => { |
633 | | // assume len is primitive, and just take bytes |
634 | 6.58k | let sz = header |
635 | 6.58k | .length() |
636 | 6.58k | .definite() |
637 | 6.58k | .map_err(|e| Err::Error(LdapError::Ber(e)))?; |
638 | 6.58k | let (i, b) = take(sz)(rem)?; |
639 | | // // other solution: read content as octetstring and get slice |
640 | | // let (i, b) = map_res( |
641 | | // |d| { |
642 | | // ber_read_element_content_as( |
643 | | // d, |
644 | | // BerTag::OctetString, |
645 | | // header.len, |
646 | | // header.is_constructed(), |
647 | | // 1, |
648 | | // ) |
649 | | // }, |
650 | | // |o| o.as_slice(), |
651 | | // )(rem) |
652 | | // .map_err(Err::convert)?; |
653 | 6.30k | Ok((i, AuthenticationChoice::Simple(Cow::Borrowed(b)))) |
654 | | } |
655 | 1.00k | 3 => map(parse_sasl_credentials, AuthenticationChoice::Sasl)(rem), |
656 | 177 | _ => Err(Err::Error(LdapError::InvalidAuthenticationType)), |
657 | | } |
658 | 8.00k | } |
659 | | } |
660 | | |
661 | | // SaslCredentials ::= SEQUENCE { |
662 | | // mechanism LDAPString, |
663 | | // credentials OCTET STRING OPTIONAL } |
664 | 1.00k | fn parse_sasl_credentials(i: &[u8]) -> Result<SaslCredentials> { |
665 | 1.00k | let (i, mechanism) = LdapString::from_ber(i)?; |
666 | 805 | let (i, credentials) = opt(complete(map( |
667 | 805 | parse_ldap_octet_string_as_slice, |
668 | 805 | Cow::Borrowed, |
669 | 805 | )))(i)?; |
670 | 805 | let credentials = SaslCredentials { |
671 | 805 | mechanism, |
672 | 805 | credentials, |
673 | 805 | }; |
674 | 805 | Ok((i, credentials)) |
675 | 1.00k | } |
676 | | |
677 | | // AttributeSelection ::= SEQUENCE OF selector LDAPString |
678 | | // -- The LDAPString is constrained to |
679 | | // -- <attributeSelector> in Section 4.5.1.8 |
680 | 9.49k | fn parse_attribute_selection(bytes: &[u8]) -> Result<Vec<LdapString>> { |
681 | 9.49k | Sequence::from_ber_and_then(bytes, many0(complete(LdapString::from_ber))) |
682 | 9.49k | } |
683 | | |
684 | | // PartialAttributeList ::= SEQUENCE OF partialAttribute PartialAttribute |
685 | 4.60k | fn parse_partial_attribute_list(bytes: &[u8]) -> Result<Vec<PartialAttribute>> { |
686 | 4.60k | Sequence::from_ber_and_then(bytes, many0(complete(PartialAttribute::from_ber))) |
687 | 4.60k | } |
688 | | |
689 | | // AttributeList ::= SEQUENCE OF attribute Attribute |
690 | 5.62k | fn parse_attribute_list(bytes: &[u8]) -> Result<Vec<Attribute>> { |
691 | 5.62k | Sequence::from_ber_and_then(bytes, many0(complete(Attribute::from_ber))) |
692 | 5.62k | } |
693 | | |
694 | | // change SEQUENCE { |
695 | | // operation ENUMERATED { |
696 | | // add (0), |
697 | | // delete (1), |
698 | | // replace (2), |
699 | | // ... }, |
700 | | // modification PartialAttribute } |
701 | | impl<'a> FromBer<'a, LdapError> for Change<'a> { |
702 | 7.42k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
703 | 7.42k | Sequence::from_ber_and_then(bytes, |i| { |
704 | 5.89k | let (i, operation) = map(parse_ldap_enum_as_u32, Operation)(i)?; |
705 | 4.60k | let (i, modification) = PartialAttribute::from_ber(i)?; |
706 | 4.31k | let change = Change { |
707 | 4.31k | operation, |
708 | 4.31k | modification, |
709 | 4.31k | }; |
710 | 4.31k | Ok((i, change)) |
711 | 5.89k | }) |
712 | 7.42k | } |
713 | | } |
714 | | |
715 | | // Control ::= SEQUENCE { |
716 | | // controlType LDAPOID, |
717 | | // criticality BOOLEAN DEFAULT FALSE, |
718 | | // controlValue OCTET STRING OPTIONAL } |
719 | | impl<'a> FromBer<'a, LdapError> for Control<'a> { |
720 | 16.4k | fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self, LdapError> { |
721 | 16.4k | Sequence::from_ber_and_then(bytes, |i| { |
722 | 6.08k | let (i, control_type) = LdapOID::from_ber(i)?; |
723 | 4.83k | let (i, maybe_critical) = <Option<bool>>::from_ber(i).map_err(Err::convert)?; |
724 | | // opt(complete(bool::from_ber))(i).map_err(Err::convert)?; |
725 | 2.62k | let criticality = maybe_critical.unwrap_or(false); |
726 | 2.62k | let (i, control_value) = opt(complete(map( |
727 | 2.62k | parse_ldap_octet_string_as_slice, |
728 | 2.62k | Cow::Borrowed, |
729 | 2.62k | )))(i)?; |
730 | 2.62k | let control = Control { |
731 | 2.62k | control_type, |
732 | 2.62k | criticality, |
733 | 2.62k | control_value, |
734 | 2.62k | }; |
735 | 2.62k | Ok((i, control)) |
736 | 6.08k | }) |
737 | 16.4k | } |
738 | | } |
739 | | |
740 | | // |
741 | | // |
742 | | // |
743 | | // |
744 | | // |
745 | | // ----------------------- TESTS ----------------------- |
746 | | // |
747 | | // |
748 | | // |
749 | | // |
750 | | // |
751 | | // |
752 | | |
753 | | #[cfg(test)] |
754 | | mod tests { |
755 | | use super::*; |
756 | | use asn1_rs::oid; |
757 | | use hex_literal::hex; |
758 | | |
759 | | #[test] |
760 | | fn test_parse_bind_request() { |
761 | | const DATA: &[u8] = include_bytes!("../assets/bind_request.bin"); |
762 | | |
763 | | let (rem, req) = BindRequest::from_ber(DATA).expect("parsing failed"); |
764 | | // |
765 | | // dbg!(&req); |
766 | | // |
767 | | assert!(rem.is_empty()); |
768 | | assert_eq!(&req.name.0, "xxxxxxxxxxx@xx.xxx.xxxxx.net"); |
769 | | assert_eq!( |
770 | | req.authentication, |
771 | | AuthenticationChoice::Simple(Cow::Borrowed(b"passwor8d1")) |
772 | | ); |
773 | | } |
774 | | |
775 | | #[test] |
776 | | fn test_parse_bind_request_sasl() { |
777 | | const DATA: &[u8] = include_bytes!("../assets/bind_request_sasl.bin"); |
778 | | |
779 | | let (rem, req) = BindRequest::from_ber(DATA).expect("parsing failed"); |
780 | | // |
781 | | // dbg!(&req); |
782 | | // |
783 | | assert!(rem.is_empty()); |
784 | | assert_eq!(&req.name.0, ""); |
785 | | if let AuthenticationChoice::Sasl(sasl_credentials) = &req.authentication { |
786 | | assert_eq!(&sasl_credentials.mechanism.0, "GSS-SPNEGO"); |
787 | | } else { |
788 | | panic!("wrong authentication type"); |
789 | | } |
790 | | } |
791 | | |
792 | | #[test] |
793 | | fn test_parse_bind_response_minimal() { |
794 | | const DATA: &[u8] = &hex!("61 84 00 00 00 07 0a 01 00 04 00 04 00"); |
795 | | let (rem, resp) = BindResponse::from_ber(DATA).expect("parsing failed"); |
796 | | // |
797 | | // dbg!(&resp); |
798 | | // |
799 | | assert!(rem.is_empty()); |
800 | | assert_eq!(resp.result.result_code, ResultCode::Success); |
801 | | } |
802 | | |
803 | | #[test] |
804 | | fn test_parse_bind_response_sasl() { |
805 | | const DATA: &[u8] = include_bytes!("../assets/bind_response_sasl.bin"); |
806 | | let (rem, resp) = BindResponse::from_ber(DATA).expect("parsing failed"); |
807 | | // |
808 | | // dbg!(&resp); |
809 | | // |
810 | | assert!(rem.is_empty()); |
811 | | assert_eq!(resp.result.result_code, ResultCode::Success); |
812 | | assert!(resp.server_sasl_creds.is_some()); |
813 | | } |
814 | | |
815 | | #[test] |
816 | | fn test_parse_unbind_request() { |
817 | | const DATA: &[u8] = &hex!("42 00"); |
818 | | |
819 | | let (rem, req) = parse_ldap_unbind_request(DATA).expect("parsing failed"); |
820 | | // |
821 | | // dbg!(&req); |
822 | | // |
823 | | assert!(rem.is_empty()); |
824 | | assert_eq!(req, ProtocolOp::UnbindRequest); |
825 | | } |
826 | | |
827 | | #[test] |
828 | | fn test_parse_search_request() { |
829 | | const DATA: &[u8] = include_bytes!("../assets/search_request.bin"); |
830 | | let (rem, resp) = SearchRequest::from_ber(DATA).expect("parsing failed"); |
831 | | // |
832 | | // dbg!(&resp); |
833 | | // |
834 | | assert!(rem.is_empty()); |
835 | | assert_eq!(&resp.base_object.0, "DC=xx,DC=xxx,DC=xxxxx,DC=net"); |
836 | | assert_eq!(resp.scope, SearchScope::WholeSubtree); |
837 | | assert_eq!(resp.attributes.len(), 1); |
838 | | } |
839 | | |
840 | | #[test] |
841 | | fn test_parse_search_result_entry() { |
842 | | const DATA: &[u8] = include_bytes!("../assets/search_result_entry.bin"); |
843 | | let (rem, resp) = SearchResultEntry::from_ber(DATA).expect("parsing failed"); |
844 | | // |
845 | | // dbg!(&resp); |
846 | | // |
847 | | assert!(rem.is_empty()); |
848 | | assert_eq!(resp.attributes.len(), 1); |
849 | | } |
850 | | |
851 | | #[test] |
852 | | fn test_parse_search_result_done() { |
853 | | const DATA: &[u8] = include_bytes!("../assets/search_result_done.bin"); |
854 | | let (rem, resp) = parse_ldap_search_result_done(DATA).expect("parsing failed"); |
855 | | // |
856 | | // dbg!(&resp); |
857 | | // |
858 | | assert!(rem.is_empty()); |
859 | | assert_eq!(resp.result_code, ResultCode::Success); |
860 | | } |
861 | | |
862 | | #[test] |
863 | | fn test_parse_search_result_ref() { |
864 | | const DATA: &[u8] = include_bytes!("../assets/search_result_ref.bin"); |
865 | | let (rem, v) = parse_ldap_search_result_ref(DATA).expect("parsing failed"); |
866 | | // |
867 | | // dbg!(&v); |
868 | | // |
869 | | assert!(rem.is_empty()); |
870 | | assert_eq!(v.len(), 1); |
871 | | assert_eq!( |
872 | | &v[0].0, |
873 | | "ldap://DomainDnsZones.rccad.net/DC=DomainDnsZones,DC=rccad,DC=net" |
874 | | ); |
875 | | } |
876 | | |
877 | | #[test] |
878 | | fn test_parse_extended_req() { |
879 | | const DATA: &[u8] = include_bytes!("../assets/extended-req.bin"); |
880 | | let (rem, req) = ExtendedRequest::from_ber(DATA).expect("parsing failed"); |
881 | | // |
882 | | // dbg!(&req); |
883 | | // |
884 | | assert!(rem.is_empty()); |
885 | | assert_eq!( |
886 | | req.request_name.0, |
887 | | oid!(1.3.6 .1 .4 .1 .1466 .20037).to_string() |
888 | | ); |
889 | | assert!(req.request_value.is_none()); |
890 | | } |
891 | | |
892 | | #[test] |
893 | | fn test_parse_extended_response() { |
894 | | const DATA: &[u8] = &hex!("78 07 0a 01 00 04 00 04 00"); |
895 | | let (rem, resp) = ExtendedResponse::from_ber(DATA).expect("parsing failed"); |
896 | | // |
897 | | // dbg!(&resp); |
898 | | // |
899 | | assert!(rem.is_empty()); |
900 | | assert_eq!(resp.result.result_code, ResultCode::Success); |
901 | | } |
902 | | |
903 | | #[test] |
904 | | fn test_parse_modify_request() { |
905 | | const DATA: &[u8] = include_bytes!("../assets/modify-request.bin"); |
906 | | let (rem, req) = ModifyRequest::from_ber(DATA).expect("parsing failed"); |
907 | | // |
908 | | // dbg!(&req); |
909 | | // |
910 | | assert!(rem.is_empty()); |
911 | | assert_eq!(&req.object.0, "cn=username1,ou=users,dc=xxx,dc=internet"); |
912 | | assert_eq!(req.changes.len(), 1); |
913 | | assert_eq!(req.changes[0].modification.attr_type.0, "description"); |
914 | | } |
915 | | |
916 | | #[test] |
917 | | fn test_parse_modify_response() { |
918 | | const DATA: &[u8] = include_bytes!("../assets/modify-response.bin"); |
919 | | let (rem, resp) = parse_ldap_modify_response(DATA).expect("parsing failed"); |
920 | | // |
921 | | // dbg!(&resp); |
922 | | // |
923 | | assert!(rem.is_empty()); |
924 | | assert_eq!(resp.result.result_code, ResultCode::Success); |
925 | | } |
926 | | |
927 | | #[test] |
928 | | fn test_parse_add_request() { |
929 | | const DATA: &[u8] = include_bytes!("../assets/add-request.bin"); |
930 | | let (rem, req) = AddRequest::from_ber(DATA).expect("parsing failed"); |
931 | | // |
932 | | // dbg!(&req); |
933 | | // |
934 | | assert!(rem.is_empty()); |
935 | | assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet"); |
936 | | assert_eq!(req.attributes.len(), 4); |
937 | | } |
938 | | |
939 | | #[test] |
940 | | fn test_parse_add_response() { |
941 | | const DATA: &[u8] = include_bytes!("../assets/add-response.bin"); |
942 | | let (rem, resp) = parse_ldap_add_response(DATA).expect("parsing failed"); |
943 | | // |
944 | | // dbg!(&resp); |
945 | | // |
946 | | assert!(rem.is_empty()); |
947 | | assert_eq!(resp.result_code, ResultCode::Success); |
948 | | } |
949 | | |
950 | | #[test] |
951 | | fn test_parse_del_request() { |
952 | | const DATA: &[u8] = include_bytes!("../assets/del-request.bin"); |
953 | | let (rem, req) = parse_ldap_del_request(DATA).expect("parsing failed"); |
954 | | // |
955 | | // dbg!(&req); |
956 | | // |
957 | | assert!(rem.is_empty()); |
958 | | assert_eq!(&req.0, "cn=username2,ou=users2,dc=xxx,dc=internet"); |
959 | | } |
960 | | |
961 | | #[test] |
962 | | fn test_parse_del_response() { |
963 | | const DATA: &[u8] = include_bytes!("../assets/del-response.bin"); |
964 | | let (rem, resp) = parse_ldap_del_response(DATA).expect("parsing failed"); |
965 | | // |
966 | | // dbg!(&resp); |
967 | | // |
968 | | assert!(rem.is_empty()); |
969 | | assert_eq!(resp.result_code, ResultCode::Success); |
970 | | } |
971 | | |
972 | | #[test] |
973 | | fn test_parse_moddn_request() { |
974 | | const DATA: &[u8] = include_bytes!("../assets/moddn-request.bin"); |
975 | | let (rem, req) = ModDnRequest::from_ber(DATA).expect("parsing failed"); |
976 | | // |
977 | | // dbg!(&req); |
978 | | // |
979 | | assert!(rem.is_empty()); |
980 | | assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet"); |
981 | | assert_eq!(&req.newrdn.0, "cn=username2"); |
982 | | assert!(req.deleteoldrdn); |
983 | | assert_eq!(&req.newsuperior.unwrap().0, "ou=users,dc=xxx,dc=internet"); |
984 | | } |
985 | | |
986 | | #[test] |
987 | | fn test_parse_moddn_response() { |
988 | | const DATA: &[u8] = include_bytes!("../assets/moddn-response.bin"); |
989 | | let (rem, resp) = parse_ldap_moddn_response(DATA).expect("parsing failed"); |
990 | | // |
991 | | // dbg!(&resp); |
992 | | // |
993 | | assert!(rem.is_empty()); |
994 | | assert_eq!(resp.result_code, ResultCode::Success); |
995 | | } |
996 | | |
997 | | #[test] |
998 | | fn test_parse_compare_request() { |
999 | | const DATA: &[u8] = include_bytes!("../assets/compare-request.bin"); |
1000 | | let (rem, req) = CompareRequest::from_ber(DATA).expect("parsing failed"); |
1001 | | // |
1002 | | // dbg!(&req); |
1003 | | // |
1004 | | assert!(rem.is_empty()); |
1005 | | assert_eq!(&req.entry.0, "cn=username2,ou=users2,dc=xxx,dc=internet"); |
1006 | | assert_eq!(&req.ava.attribute_desc.0, "cn"); |
1007 | | } |
1008 | | |
1009 | | #[test] |
1010 | | fn test_parse_compare_response() { |
1011 | | const DATA: &[u8] = include_bytes!("../assets/compare-response.bin"); |
1012 | | let (rem, resp) = parse_ldap_compare_response(DATA).expect("parsing failed"); |
1013 | | // |
1014 | | // dbg!(&resp); |
1015 | | // |
1016 | | assert!(rem.is_empty()); |
1017 | | assert_eq!(resp.result_code, ResultCode::CompareTrue); |
1018 | | } |
1019 | | |
1020 | | #[test] |
1021 | | fn test_parse_abandon_request() { |
1022 | | const DATA: &[u8] = &[0x30, 0x06, 0x02, 0x01, 0x06, 0x50, 0x01, 0x05]; |
1023 | | |
1024 | | let (rem, msg) = LdapMessage::from_ber(DATA).expect("parsing failed"); |
1025 | | assert!(rem.is_empty()); |
1026 | | assert_eq!(msg.message_id, MessageID(6)); |
1027 | | assert!(matches!( |
1028 | | msg.protocol_op, |
1029 | | ProtocolOp::AbandonRequest(MessageID(5)) |
1030 | | )) |
1031 | | } |
1032 | | } |