#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LdapAttributeResultValues {
pub entry_dn: String,
pub attribute_name: String,
pub string_values: Vec<String>,
pub binary_values: Vec<Vec<u8>>,
}
#[cfg(feature = "ldap3")]
pub trait SearchEntryExt {
fn attribute_results(&self, attribute_name: &str) -> LdapAttributeResultValues;
}
#[cfg(feature = "ldap3")]
impl SearchEntryExt for ldap3::SearchEntry {
fn attribute_results(&self, attribute_name: &str) -> LdapAttributeResultValues {
let string_values = self.attrs.get(attribute_name);
let binary_values = self.bin_attrs.get(attribute_name);
LdapAttributeResultValues {
entry_dn: self.dn.to_owned(),
attribute_name: attribute_name.to_owned(),
string_values: string_values.map_or(Vec::new(), |v| v.to_vec()),
binary_values: binary_values.map_or(Vec::new(), |v| v.to_vec()),
}
}
}
pub trait FromStringLdapType {
type Error;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized;
}
impl FromStringLdapType for String {
type Error = std::convert::Infallible;
fn parse(_entry_dn: &str, _attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
Ok(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnexpectedStringValue {
source_entry_dn: String,
source_attribute_name: String,
conversion_target_name: String,
unexpected_value: String,
}
impl std::fmt::Display for UnexpectedStringValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Unexpected value in conversion of {} attribute {} to {}: {}",
self.source_entry_dn,
self.source_attribute_name,
self.conversion_target_name,
self.unexpected_value,
)
}
}
impl std::error::Error for UnexpectedStringValue {}
impl FromStringLdapType for bool {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
match std::ops::Deref::deref(&value) {
"TRUE" => Ok(true),
"FALSE" => Ok(false),
v => Err(UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "bool".to_string(),
unexpected_value: v.to_owned(),
}),
}
}
}
impl FromStringLdapType for u8 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "u8".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for i8 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "i8".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for u16 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "u16".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for i16 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "i16".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for u32 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "u32".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for i32 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "i32".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for u64 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "u64".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for i64 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "i64".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for u128 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "u128".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for i128 {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "i128".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for usize {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "usize".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for isize {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "isize".to_string(),
unexpected_value: value,
})
}
}
#[cfg(feature = "chumsky")]
impl FromStringLdapType for crate::basic::DistinguishedName {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as std::str::FromStr>::from_str(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "DistinguishedName".to_string(),
unexpected_value: value,
})
}
}
impl FromStringLdapType for oid::ObjectIdentifier {
type Error = UnexpectedStringValue;
fn parse(entry_dn: &str, attribute_name: &str, value: String) -> Result<Self, Self::Error>
where
Self: Sized,
{
<Self as TryFrom<&str>>::try_from(&value).map_err(|_err| UnexpectedStringValue {
source_entry_dn: entry_dn.to_owned(),
source_attribute_name: attribute_name.to_owned(),
conversion_target_name: "ObjectIdentifier".to_string(),
unexpected_value: value,
})
}
}
pub trait FromLdapType {
type Error;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized;
}
#[derive(Debug, Clone)]
pub enum VecOfFromStringLdapTypeError<E> {
LdapShouldNotReturnBinaryResult {
entry_dn: String,
attribute_name: String,
},
PrimitiveValueConversionError(E),
}
impl<E> std::fmt::Display for VecOfFromStringLdapTypeError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LdapShouldNotReturnBinaryResult {
entry_dn,
attribute_name,
} => {
write!(f, "encountered binary values in input for {entry_dn} attribute {attribute_name} when converting a Vec of a type that only supports String inputs")
}
Self::PrimitiveValueConversionError(err) => {
write!(
f,
"encountered error converting a primitive value from String: {err}",
)
}
}
}
}
impl<E> std::error::Error for VecOfFromStringLdapTypeError<E> where E: std::error::Error {}
impl<T> FromLdapType for Vec<T>
where
T: FromStringLdapType,
{
type Error = VecOfFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized,
{
if !values.binary_values.is_empty() {
return Err(
VecOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
values
.string_values
.into_iter()
.map(|v| <T as FromStringLdapType>::parse(&values.entry_dn, &values.attribute_name, v))
.collect::<Result<Self, <T as FromStringLdapType>::Error>>()
.map_err(VecOfFromStringLdapTypeError::PrimitiveValueConversionError)
}
}
#[derive(Debug, Clone)]
pub enum OptionOfFromStringLdapTypeError<E> {
LdapShouldNotReturnBinaryResult {
entry_dn: String,
attribute_name: String,
},
LdapShouldNotReturnMultipleResults {
entry_dn: String,
attribute_name: String,
},
PrimitiveValueConversionError(E),
}
impl<E> std::fmt::Display for OptionOfFromStringLdapTypeError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LdapShouldNotReturnBinaryResult {
entry_dn,
attribute_name,
} => {
write!(f, "encountered binary values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports String inputs")
}
Self::LdapShouldNotReturnMultipleResults {
entry_dn,
attribute_name,
} => {
write!(f, "encountered multiple string values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports String inputs")
}
Self::PrimitiveValueConversionError(err) => {
write!(
f,
"encountered error converting a primitive value from String: {err}",
)
}
}
}
}
impl<E> std::error::Error for OptionOfFromStringLdapTypeError<E> where E: std::error::Error {}
impl<T> FromLdapType for Option<T>
where
T: FromStringLdapType,
{
type Error = OptionOfFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized,
{
if !values.binary_values.is_empty() {
return Err(
OptionOfFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
if values.string_values.len() > 1 {
return Err(
OptionOfFromStringLdapTypeError::LdapShouldNotReturnMultipleResults {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
if let Some(value) = values.string_values.first() {
Ok(Some(
<T as FromStringLdapType>::parse(
&values.entry_dn,
&values.attribute_name,
value.to_owned(),
)
.map_err(OptionOfFromStringLdapTypeError::PrimitiveValueConversionError)?,
))
} else {
Ok(None)
}
}
}
#[derive(Debug, Clone)]
pub enum RequiredFromStringLdapTypeError<E> {
LdapShouldNotReturnBinaryResult {
entry_dn: String,
attribute_name: String,
},
LdapShouldReturnExactlyOneResult {
entry_dn: String,
attribute_name: String,
count: usize,
},
PrimitiveValueConversionError(E),
}
impl<E> std::fmt::Display for RequiredFromStringLdapTypeError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LdapShouldNotReturnBinaryResult {
entry_dn,
attribute_name,
} => {
write!(f, "encountered binary values in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports String inputs")
}
Self::LdapShouldReturnExactlyOneResult {
entry_dn,
attribute_name,
count,
} => {
write!(f, "encountered {count} string values (expected exactly one) in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports String inputs")
}
Self::PrimitiveValueConversionError(err) => {
write!(
f,
"encountered error converting a primitive value from String: {err}",
)
}
}
}
}
impl<E> std::error::Error for RequiredFromStringLdapTypeError<E> where E: std::error::Error {}
impl<T> FromLdapType for T
where
T: FromStringLdapType,
{
type Error = RequiredFromStringLdapTypeError<<T as FromStringLdapType>::Error>;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized,
{
if !values.binary_values.is_empty() {
return Err(
RequiredFromStringLdapTypeError::LdapShouldNotReturnBinaryResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
if values.string_values.len() != 1 {
return Err(
RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
count: values.string_values.len(),
},
);
}
if let Some(value) = values.string_values.first() {
Ok(<T as FromStringLdapType>::parse(
&values.entry_dn,
&values.attribute_name,
value.to_owned(),
)
.map_err(RequiredFromStringLdapTypeError::PrimitiveValueConversionError)?)
} else {
Err(
RequiredFromStringLdapTypeError::LdapShouldReturnExactlyOneResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
count: values.string_values.len(),
},
)
}
}
}
pub trait FromBinaryLdapType {
type Error;
fn parse(entry_dn: &str, attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
where
Self: Sized;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnexpectedBinaryValue {
source_entry_dn: String,
source_attribute_name: String,
conversion_target_name: String,
unexpected_value: Vec<u8>,
}
impl std::fmt::Display for UnexpectedBinaryValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Unexpected value in conversion of {} attribute {} to {}: {:?}",
self.source_entry_dn,
self.source_attribute_name,
self.conversion_target_name,
self.unexpected_value,
)
}
}
impl std::error::Error for UnexpectedBinaryValue {}
impl FromBinaryLdapType for Vec<u8> {
type Error = std::convert::Infallible;
fn parse(_entry_dn: &str, _attribute_name: &str, value: Vec<u8>) -> Result<Self, Self::Error>
where
Self: Sized,
{
Ok(value)
}
}
#[derive(Debug, Clone)]
pub struct Binary<T>(pub T);
#[derive(Debug, Clone)]
pub enum VecOfFromBinaryLdapTypeError<E> {
LdapShouldNotReturnStringResult {
entry_dn: String,
attribute_name: String,
},
PrimitiveValueConversionError(E),
}
impl<E> std::fmt::Display for VecOfFromBinaryLdapTypeError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LdapShouldNotReturnStringResult {
entry_dn,
attribute_name,
} => {
write!(f, "encountered String values in input for {entry_dn} attribute {attribute_name} when converting a Vec of a type that only supports binary inputs")
}
Self::PrimitiveValueConversionError(err) => {
write!(
f,
"encountered error converting a primitive value from binary: {err}",
)
}
}
}
}
impl<E> std::error::Error for VecOfFromBinaryLdapTypeError<E> where E: std::error::Error {}
impl<T> FromLdapType for Binary<Vec<T>>
where
T: FromBinaryLdapType,
{
type Error = VecOfFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized,
{
if !values.string_values.is_empty() {
return Err(
VecOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
values
.binary_values
.into_iter()
.map(|v| <T as FromBinaryLdapType>::parse(&values.entry_dn, &values.attribute_name, v))
.collect::<Result<Vec<T>, <T as FromBinaryLdapType>::Error>>()
.map(Binary)
.map_err(VecOfFromBinaryLdapTypeError::PrimitiveValueConversionError)
}
}
#[derive(Debug, Clone)]
pub enum OptionOfFromBinaryLdapTypeError<E> {
LdapShouldNotReturnStringResult {
entry_dn: String,
attribute_name: String,
},
LdapShouldNotReturnMultipleResults {
entry_dn: String,
attribute_name: String,
},
PrimitiveValueConversionError(E),
}
impl<E> std::fmt::Display for OptionOfFromBinaryLdapTypeError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LdapShouldNotReturnStringResult {
entry_dn,
attribute_name,
} => {
write!(f, "encountered String values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports binary inputs")
}
Self::LdapShouldNotReturnMultipleResults {
entry_dn,
attribute_name,
} => {
write!(f, "encountered multiple binary values in input for {entry_dn} attribute {attribute_name} when converting an Option of a type that only supports binary inputs")
}
Self::PrimitiveValueConversionError(err) => {
write!(
f,
"encountered error converting a primitive value from binary: {err}",
)
}
}
}
}
impl<E> std::error::Error for OptionOfFromBinaryLdapTypeError<E> where E: std::error::Error {}
impl<T> FromLdapType for Binary<Option<T>>
where
T: FromBinaryLdapType,
{
type Error = OptionOfFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized,
{
if !values.string_values.is_empty() {
return Err(
OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
if values.binary_values.len() > 1 {
return Err(
OptionOfFromBinaryLdapTypeError::LdapShouldNotReturnMultipleResults {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
if let Some(value) = values.binary_values.first() {
Ok(Self(Some(
<T as FromBinaryLdapType>::parse(
&values.entry_dn,
&values.attribute_name,
value.to_owned(),
)
.map_err(OptionOfFromBinaryLdapTypeError::PrimitiveValueConversionError)?,
)))
} else {
Ok(Self(None))
}
}
}
#[derive(Debug, Clone)]
pub enum RequiredFromBinaryLdapTypeError<E> {
LdapShouldNotReturnStringResult {
entry_dn: String,
attribute_name: String,
},
LdapShouldReturnExactlyOneResult {
entry_dn: String,
attribute_name: String,
count: usize,
},
PrimitiveValueConversionError(E),
}
impl<E> std::fmt::Display for RequiredFromBinaryLdapTypeError<E>
where
E: std::error::Error,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LdapShouldNotReturnStringResult {
entry_dn,
attribute_name,
} => {
write!(f, "encountered String values in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports binary inputs")
}
Self::LdapShouldReturnExactlyOneResult {
entry_dn,
attribute_name,
count,
} => {
write!(f, "encountered {count} binary values (expected exactly one) in input for {entry_dn} attribute {attribute_name} when converting a required value of a type that only supports binary inputs")
}
Self::PrimitiveValueConversionError(err) => {
write!(
f,
"encountered error converting a primitive value from binary: {err}",
)
}
}
}
}
impl<E> std::error::Error for RequiredFromBinaryLdapTypeError<E> where E: std::error::Error {}
impl<T> FromLdapType for Binary<T>
where
T: FromBinaryLdapType,
{
type Error = RequiredFromBinaryLdapTypeError<<T as FromBinaryLdapType>::Error>;
fn parse(values: LdapAttributeResultValues) -> Result<Self, Self::Error>
where
Self: Sized,
{
if !values.string_values.is_empty() {
return Err(
RequiredFromBinaryLdapTypeError::LdapShouldNotReturnStringResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
},
);
}
if values.binary_values.len() != 1 {
return Err(
RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
count: values.string_values.len(),
},
);
}
if let Some(value) = values.binary_values.first() {
Ok(<T as FromBinaryLdapType>::parse(
&values.entry_dn,
&values.attribute_name,
value.to_owned(),
)
.map(Binary)
.map_err(RequiredFromBinaryLdapTypeError::PrimitiveValueConversionError)?)
} else {
Err(
RequiredFromBinaryLdapTypeError::LdapShouldReturnExactlyOneResult {
entry_dn: values.entry_dn,
attribute_name: values.attribute_name,
count: values.string_values.len(),
},
)
}
}
}