use crate::error::*;
use crate::filter::*;
use crate::ldap::*;
use asn1_rs::nom;
use asn1_rs::{
Class, Enumerated, FromBer, Header, OptTaggedParser, ParseResult, Sequence, Tag,
TaggedImplicit, TaggedParser,
};
use nom::bytes::streaming::take;
use nom::combinator::{complete, map, opt, verify};
use nom::multi::{many0, many1};
use nom::Err;
use std::borrow::Cow;
impl<'a> FromBer<'a, LdapError> for MessageID {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
map(u32::from_ber, MessageID)(bytes).map_err(Err::convert)
}
}
impl<'a> FromBer<'a, LdapError> for LdapString<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
let (i, b) = parse_ldap_octet_string_as_slice(bytes)?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidString)))?;
Ok((i, LdapString(Cow::Borrowed(s))))
}
}
#[inline]
pub(crate) fn parse_ldap_octet_string_as_slice(i: &[u8]) -> Result<&[u8]> {
<&[u8]>::from_ber(i).map_err(Err::convert)
}
#[inline]
fn parse_ldap_int_as_u32(i: &[u8]) -> Result<u32> {
<u32>::from_ber(i).map_err(Err::convert)
}
#[inline]
fn parse_ldap_enum_as_u32(i: &[u8]) -> Result<u32> {
let (i, obj) = Enumerated::from_ber(i).map_err(Err::convert)?;
Ok((i, obj.0))
}
impl<'a> FromBer<'a, LdapError> for LdapDN<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
Ok((i, LdapDN(Cow::Borrowed(s))))
}
}
impl<'a> FromBer<'a, LdapError> for RelativeLdapDN<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
Ok((i, RelativeLdapDN(Cow::Borrowed(s))))
}
}
impl<'a> FromBer<'a, LdapError> for LdapOID<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
let (i, b) = <&[u8]>::from_ber(bytes).map_err(Err::convert)?;
let s = std::str::from_utf8(b).or(Err(Err::Error(LdapError::InvalidDN)))?;
Ok((i, LdapOID(Cow::Borrowed(s))))
}
}
#[inline]
fn parse_ldap_uri(i: &[u8]) -> Result<LdapString> {
LdapString::from_ber(i)
}
fn parse_ldap_result_content(i: &[u8]) -> Result<LdapResult> {
let (i, result_code) = map(parse_ldap_enum_as_u32, ResultCode)(i)?;
let (i, matched_dn) = LdapDN::from_ber(i)?;
let (i, diagnostic_message) = LdapString::from_ber(i)?;
let result = LdapResult {
result_code,
matched_dn,
diagnostic_message,
};
Ok((i, result))
}
impl<'a> FromBer<'a, LdapError> for LdapMessage<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
Sequence::from_ber_and_then(bytes, |i| {
let (i, message_id) = MessageID::from_ber(i)?;
let (_, header) = Header::from_ber(i).map_err(Err::convert)?;
let (i, protocol_op) = match header.tag().0 {
0 => map(BindRequest::from_ber, ProtocolOp::BindRequest)(i),
1 => map(BindResponse::from_ber, ProtocolOp::BindResponse)(i),
2 => parse_ldap_unbind_request(i),
3 => map(SearchRequest::from_ber, ProtocolOp::SearchRequest)(i),
4 => map(SearchResultEntry::from_ber, ProtocolOp::SearchResultEntry)(i),
5 => map(parse_ldap_search_result_done, ProtocolOp::SearchResultDone)(i),
6 => map(ModifyRequest::from_ber, ProtocolOp::ModifyRequest)(i),
7 => map(parse_ldap_modify_response, ProtocolOp::ModifyResponse)(i),
8 => map(AddRequest::from_ber, ProtocolOp::AddRequest)(i),
9 => map(parse_ldap_add_response, ProtocolOp::AddResponse)(i),
10 => map(parse_ldap_del_request, ProtocolOp::DelRequest)(i),
11 => map(parse_ldap_del_response, ProtocolOp::DelResponse)(i),
12 => map(ModDnRequest::from_ber, ProtocolOp::ModDnRequest)(i),
13 => map(parse_ldap_moddn_response, ProtocolOp::ModDnResponse)(i),
14 => map(CompareRequest::from_ber, ProtocolOp::CompareRequest)(i),
15 => map(parse_ldap_compare_response, ProtocolOp::CompareResponse)(i),
16 => map(parse_ldap_abandon_request, ProtocolOp::AbandonRequest)(i),
19 => map(
parse_ldap_search_result_ref,
ProtocolOp::SearchResultReference,
)(i),
23 => map(ExtendedRequest::from_ber, ProtocolOp::ExtendedRequest)(i),
24 => map(ExtendedResponse::from_ber, ProtocolOp::ExtendedResponse)(i),
25 => map(
IntermediateResponse::from_ber,
ProtocolOp::IntermediateResponse,
)(i),
_ => {
Err(Err::Error(LdapError::InvalidMessageType))
}
}?;
let (i, controls) = OptTaggedParser::new(Class::ContextSpecific, Tag(0))
.parse_ber(i, |_, i| many0(complete(Control::from_ber))(i))?;
let msg = LdapMessage {
message_id,
protocol_op,
controls,
};
Ok((i, msg))
})
}
}
#[deprecated(
since = "0.3.0",
note = "Parsing functions are deprecated. Users should instead use the FromBer trait"
)]
#[inline]
pub fn parse_ldap_message(i: &[u8]) -> Result<LdapMessage> {
LdapMessage::from_ber(i)
}
pub fn parse_ldap_messages(i: &[u8]) -> Result<Vec<LdapMessage>> {
many1(complete(LdapMessage::from_ber))(i)
}
impl<'a> FromBer<'a, LdapError> for BindRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 0, bytes, |i| {
let (i, version) = verify(u8::from_ber, |&n| n < 128)(i).map_err(Err::convert)?;
let (i, name) = LdapDN::from_ber(i)?;
let (i, authentication) = AuthenticationChoice::from_ber(i)?;
let req = BindRequest {
version,
name,
authentication,
};
Ok((i, req))
})
}
}
impl<'a> FromBer<'a, LdapError> for BindResponse<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 1, bytes, |i| {
let (i, result) = parse_ldap_result_content(i)?;
let (i, server_sasl_creds) = OptTaggedParser::new(Class::ContextSpecific, Tag(7))
.parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
let req = BindResponse {
result,
server_sasl_creds,
};
Ok((i, req))
})
}
}
fn parse_ldap_unbind_request(bytes: &[u8]) -> Result<ProtocolOp> {
TaggedParser::from_ber_and_then(Class::Application, 2, bytes, |i| {
if !i.is_empty() {
let (_, _) = <()>::from_ber(i).map_err(Err::convert)?;
}
Ok((i, ProtocolOp::UnbindRequest))
})
}
impl<'a> FromBer<'a, LdapError> for SearchRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 3, bytes, |i| {
let (i, base_object) = LdapDN::from_ber(i)?;
let (i, scope) = map(parse_ldap_enum_as_u32, SearchScope)(i)?;
let (i, deref_aliases) = map(parse_ldap_enum_as_u32, DerefAliases)(i)?;
let (i, size_limit) = parse_ldap_int_as_u32(i)?;
let (i, time_limit) = parse_ldap_int_as_u32(i)?;
let (i, types_only) = <bool>::from_ber(i).map_err(Err::convert)?;
let (i, filter) = Filter::from_ber(i)?;
let (i, attributes) = parse_attribute_selection(i)?;
let req = SearchRequest {
base_object,
scope,
deref_aliases,
size_limit,
time_limit,
types_only,
filter,
attributes,
};
Ok((i, req))
})
}
}
impl<'a> FromBer<'a, LdapError> for SearchResultEntry<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 4, bytes, |i| {
let (i, object_name) = LdapDN::from_ber(i)?;
let (i, attributes) = parse_partial_attribute_list(i)?;
let res = SearchResultEntry {
object_name,
attributes,
};
Ok((i, res))
})
}
}
fn parse_ldap_search_result_done(bytes: &[u8]) -> Result<LdapResult> {
TaggedParser::from_ber_and_then(Class::Application, 5, bytes, parse_ldap_result_content)
}
impl<'a> FromBer<'a, LdapError> for ModifyRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 6, bytes, |i| {
let (i, object) = LdapDN::from_ber(i)?;
let (i, changes) = Sequence::from_ber_and_then(i, many1(complete(Change::from_ber)))?;
let res = ModifyRequest { object, changes };
Ok((i, res))
})
}
}
fn parse_ldap_modify_response(bytes: &[u8]) -> Result<ModifyResponse> {
TaggedParser::from_ber_and_then(Class::Application, 7, bytes, |i| {
let (i, result) = parse_ldap_result_content(i)?;
let res = ModifyResponse { result };
Ok((i, res))
})
}
impl<'a> FromBer<'a, LdapError> for AddRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 8, bytes, |i| {
let (i, entry) = LdapDN::from_ber(i)?;
let (i, attributes) = parse_attribute_list(i)?;
let res = AddRequest { entry, attributes };
Ok((i, res))
})
}
}
fn parse_ldap_add_response(bytes: &[u8]) -> Result<LdapResult> {
TaggedParser::from_ber_and_then(Class::Application, 9, bytes, parse_ldap_result_content)
}
fn parse_ldap_del_request(bytes: &[u8]) -> Result<LdapDN> {
TaggedParser::from_ber_and_then(Class::Application, 10, bytes, |i| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapDN(Cow::Borrowed(s));
Ok((&b""[..], oid))
})
}
fn parse_ldap_del_response(bytes: &[u8]) -> Result<LdapResult> {
TaggedParser::from_ber_and_then(Class::Application, 11, bytes, parse_ldap_result_content)
}
impl<'a> FromBer<'a, LdapError> for ModDnRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 12, bytes, |i| {
let (i, entry) = LdapDN::from_ber(i)?;
let (i, newrdn) = RelativeLdapDN::from_ber(i)?;
let (i, deleteoldrdn) = <bool>::from_ber(i).map_err(Err::convert)?;
let (i, newsuperior) =
OptTaggedParser::new(Class::ContextSpecific, Tag(0)).parse_ber(i, |_, i| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapDN(Cow::Borrowed(s));
Ok((&b""[..], oid))
})?;
let res = ModDnRequest {
entry,
newrdn,
deleteoldrdn,
newsuperior,
};
Ok((i, res))
})
}
}
fn parse_ldap_moddn_response(bytes: &[u8]) -> Result<LdapResult> {
TaggedParser::from_ber_and_then(Class::Application, 13, bytes, parse_ldap_result_content)
}
impl<'a> FromBer<'a, LdapError> for CompareRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 14, bytes, |i| {
let (i, entry) = LdapDN::from_ber(i)?;
let (i, ava) = AttributeValueAssertion::from_ber(i)?;
let res = CompareRequest { entry, ava };
Ok((i, res))
})
}
}
fn parse_ldap_compare_response(bytes: &[u8]) -> Result<LdapResult> {
TaggedParser::from_ber_and_then(Class::Application, 15, bytes, parse_ldap_result_content)
}
fn parse_ldap_abandon_request(bytes: &[u8]) -> Result<MessageID> {
let (rem, id) =
TaggedImplicit::<u32, asn1_rs::Error, 16>::from_ber(bytes).map_err(Err::convert)?;
Ok((rem, MessageID(id.into_inner())))
}
fn parse_ldap_search_result_ref(bytes: &[u8]) -> Result<Vec<LdapString>> {
TaggedParser::from_ber_and_then(
Class::Application,
19,
bytes,
many1(complete(parse_ldap_uri)),
)
}
impl<'a> FromBer<'a, LdapError> for ExtendedRequest<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 23, bytes, |i| {
let (i, request_name) =
TaggedParser::from_ber_and_then(Class::ContextSpecific, 0, i, |i| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapOID(Cow::Borrowed(s));
Ok((&b""[..], oid))
})?;
let (i, request_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(1))
.parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
let req = ExtendedRequest {
request_name,
request_value,
};
Ok((i, req))
})
}
}
impl<'a> FromBer<'a, LdapError> for ExtendedResponse<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 24, bytes, |i| {
let (i, result) = parse_ldap_result_content(i)?;
let (i, response_name) = OptTaggedParser::new(Class::ContextSpecific, Tag(10))
.parse_ber(i, |_, i| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapOID(Cow::Borrowed(s));
Ok((&b""[..], oid))
})?;
let (i, response_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(11))
.parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
let resp = ExtendedResponse {
result,
response_name,
response_value,
};
Ok((i, resp))
})
}
}
impl<'a> FromBer<'a, LdapError> for IntermediateResponse<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
TaggedParser::from_ber_and_then(Class::Application, 25, bytes, |i| {
let (i, response_name) = OptTaggedParser::new(Class::ContextSpecific, Tag(0))
.parse_ber(i, |_, i| {
let s = std::str::from_utf8(i).or(Err(Err::Error(LdapError::InvalidDN)))?;
let oid = LdapOID(Cow::Borrowed(s));
Ok((&b""[..], oid))
})?;
let (i, response_value) = OptTaggedParser::new(Class::ContextSpecific, Tag(1))
.parse_ber(i, |_, data| Ok((&b""[..], Cow::Borrowed(data))))?;
let resp = IntermediateResponse {
response_name,
response_value,
};
Ok((i, resp))
})
}
}
impl<'a> FromBer<'a, LdapError> for AuthenticationChoice<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
let (rem, header) = Header::from_ber(bytes).map_err(Err::convert)?;
match header.tag().0 {
0 => {
let sz = header
.length()
.definite()
.map_err(|e| Err::Error(LdapError::Ber(e)))?;
let (i, b) = take(sz)(rem)?;
Ok((i, AuthenticationChoice::Simple(Cow::Borrowed(b))))
}
3 => map(parse_sasl_credentials, AuthenticationChoice::Sasl)(rem),
_ => Err(Err::Error(LdapError::InvalidAuthenticationType)),
}
}
}
fn parse_sasl_credentials(i: &[u8]) -> Result<SaslCredentials> {
let (i, mechanism) = LdapString::from_ber(i)?;
let (i, credentials) = opt(complete(map(
parse_ldap_octet_string_as_slice,
Cow::Borrowed,
)))(i)?;
let credentials = SaslCredentials {
mechanism,
credentials,
};
Ok((i, credentials))
}
fn parse_attribute_selection(bytes: &[u8]) -> Result<Vec<LdapString>> {
Sequence::from_ber_and_then(bytes, many0(complete(LdapString::from_ber)))
}
fn parse_partial_attribute_list(bytes: &[u8]) -> Result<Vec<PartialAttribute>> {
Sequence::from_ber_and_then(bytes, many0(complete(PartialAttribute::from_ber)))
}
fn parse_attribute_list(bytes: &[u8]) -> Result<Vec<Attribute>> {
Sequence::from_ber_and_then(bytes, many0(complete(Attribute::from_ber)))
}
impl<'a> FromBer<'a, LdapError> for Change<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
Sequence::from_ber_and_then(bytes, |i| {
let (i, operation) = map(parse_ldap_enum_as_u32, Operation)(i)?;
let (i, modification) = PartialAttribute::from_ber(i)?;
let change = Change {
operation,
modification,
};
Ok((i, change))
})
}
}
impl<'a> FromBer<'a, LdapError> for Control<'a> {
fn from_ber(bytes: &'a [u8]) -> ParseResult<Self, LdapError> {
Sequence::from_ber_and_then(bytes, |i| {
let (i, control_type) = LdapOID::from_ber(i)?;
let (i, maybe_critical) = <Option<bool>>::from_ber(i).map_err(Err::convert)?;
let criticality = maybe_critical.unwrap_or(false);
let (i, control_value) = opt(complete(map(
parse_ldap_octet_string_as_slice,
Cow::Borrowed,
)))(i)?;
let control = Control {
control_type,
criticality,
control_value,
};
Ok((i, control))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use asn1_rs::oid;
use hex_literal::hex;
#[test]
fn test_parse_bind_request() {
const DATA: &[u8] = include_bytes!("../assets/bind_request.bin");
let (rem, req) = BindRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.name.0, "xxxxxxxxxxx@xx.xxx.xxxxx.net");
assert_eq!(
req.authentication,
AuthenticationChoice::Simple(Cow::Borrowed(b"passwor8d1"))
);
}
#[test]
fn test_parse_bind_request_sasl() {
const DATA: &[u8] = include_bytes!("../assets/bind_request_sasl.bin");
let (rem, req) = BindRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.name.0, "");
if let AuthenticationChoice::Sasl(sasl_credentials) = &req.authentication {
assert_eq!(&sasl_credentials.mechanism.0, "GSS-SPNEGO");
} else {
panic!("wrong authentication type");
}
}
#[test]
fn test_parse_bind_response_minimal() {
const DATA: &[u8] = &hex!("61 84 00 00 00 07 0a 01 00 04 00 04 00");
let (rem, resp) = BindResponse::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
}
#[test]
fn test_parse_bind_response_sasl() {
const DATA: &[u8] = include_bytes!("../assets/bind_response_sasl.bin");
let (rem, resp) = BindResponse::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
assert!(resp.server_sasl_creds.is_some());
}
#[test]
fn test_parse_unbind_request() {
const DATA: &[u8] = &hex!("42 00");
let (rem, req) = parse_ldap_unbind_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(req, ProtocolOp::UnbindRequest);
}
#[test]
fn test_parse_search_request() {
const DATA: &[u8] = include_bytes!("../assets/search_request.bin");
let (rem, resp) = SearchRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&resp.base_object.0, "DC=xx,DC=xxx,DC=xxxxx,DC=net");
assert_eq!(resp.scope, SearchScope::WholeSubtree);
assert_eq!(resp.attributes.len(), 1);
}
#[test]
fn test_parse_search_result_entry() {
const DATA: &[u8] = include_bytes!("../assets/search_result_entry.bin");
let (rem, resp) = SearchResultEntry::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.attributes.len(), 1);
}
#[test]
fn test_parse_search_result_done() {
const DATA: &[u8] = include_bytes!("../assets/search_result_done.bin");
let (rem, resp) = parse_ldap_search_result_done(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_search_result_ref() {
const DATA: &[u8] = include_bytes!("../assets/search_result_ref.bin");
let (rem, v) = parse_ldap_search_result_ref(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(v.len(), 1);
assert_eq!(
&v[0].0,
"ldap://DomainDnsZones.rccad.net/DC=DomainDnsZones,DC=rccad,DC=net"
);
}
#[test]
fn test_parse_extended_req() {
const DATA: &[u8] = include_bytes!("../assets/extended-req.bin");
let (rem, req) = ExtendedRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(
req.request_name.0,
oid!(1.3.6 .1 .4 .1 .1466 .20037).to_string()
);
assert!(req.request_value.is_none());
}
#[test]
fn test_parse_extended_response() {
const DATA: &[u8] = &hex!("78 07 0a 01 00 04 00 04 00");
let (rem, resp) = ExtendedResponse::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
}
#[test]
fn test_parse_modify_request() {
const DATA: &[u8] = include_bytes!("../assets/modify-request.bin");
let (rem, req) = ModifyRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.object.0, "cn=username1,ou=users,dc=xxx,dc=internet");
assert_eq!(req.changes.len(), 1);
assert_eq!(req.changes[0].modification.attr_type.0, "description");
}
#[test]
fn test_parse_modify_response() {
const DATA: &[u8] = include_bytes!("../assets/modify-response.bin");
let (rem, resp) = parse_ldap_modify_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result.result_code, ResultCode::Success);
}
#[test]
fn test_parse_add_request() {
const DATA: &[u8] = include_bytes!("../assets/add-request.bin");
let (rem, req) = AddRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet");
assert_eq!(req.attributes.len(), 4);
}
#[test]
fn test_parse_add_response() {
const DATA: &[u8] = include_bytes!("../assets/add-response.bin");
let (rem, resp) = parse_ldap_add_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_del_request() {
const DATA: &[u8] = include_bytes!("../assets/del-request.bin");
let (rem, req) = parse_ldap_del_request(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.0, "cn=username2,ou=users2,dc=xxx,dc=internet");
}
#[test]
fn test_parse_del_response() {
const DATA: &[u8] = include_bytes!("../assets/del-response.bin");
let (rem, resp) = parse_ldap_del_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_moddn_request() {
const DATA: &[u8] = include_bytes!("../assets/moddn-request.bin");
let (rem, req) = ModDnRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.entry.0, "cn=username1,ou=users,dc=xxx,dc=internet");
assert_eq!(&req.newrdn.0, "cn=username2");
assert!(req.deleteoldrdn);
assert_eq!(&req.newsuperior.unwrap().0, "ou=users,dc=xxx,dc=internet");
}
#[test]
fn test_parse_moddn_response() {
const DATA: &[u8] = include_bytes!("../assets/moddn-response.bin");
let (rem, resp) = parse_ldap_moddn_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::Success);
}
#[test]
fn test_parse_compare_request() {
const DATA: &[u8] = include_bytes!("../assets/compare-request.bin");
let (rem, req) = CompareRequest::from_ber(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(&req.entry.0, "cn=username2,ou=users2,dc=xxx,dc=internet");
assert_eq!(&req.ava.attribute_desc.0, "cn");
}
#[test]
fn test_parse_compare_response() {
const DATA: &[u8] = include_bytes!("../assets/compare-response.bin");
let (rem, resp) = parse_ldap_compare_response(DATA).expect("parsing failed");
assert!(rem.is_empty());
assert_eq!(resp.result_code, ResultCode::CompareTrue);
}
}