LdapClient

Struct LdapClient 

Source
pub struct LdapClient { /* private fields */ }
Expand description

High-level LDAP client wrapper ontop of ldap3 crate. This wrapper provides a high-level interface to perform LDAP operations including authentication, search, update, delete

Implementations§

Source§

impl LdapClient

Source

pub async fn new(config: LdapConfig) -> Result<Self, Error>

Creates a new asynchronous LDAP client.s It’s capable of running multiple operations concurrently.

§Bind

This performs a simple bind on the connection so need to worry about that.

Source§

impl LdapClient

Source

pub fn get_inner(&self) -> Ldap

👎Deprecated: This abstraction leakage will be removed in a future release. Use the provided methods instead. If something’s missing, open an issue in github.

Returns the ldap3 client

Source

pub async fn unbind(self) -> Result<(), Error>

End the LDAP connection.

Caution advised!

This will close the connection for all clones of this client as well, including open streams. So make sure that you’re really good to close.

Closing an LDAP connection with an unbind is a curtesy. It’s fine to skip it, and because of the async hurdless outlined above, I would perhaps even recommend it.

Source

pub async fn authenticate( &mut self, base: &str, uid: &str, password: &str, filter: Box<dyn Filter>, ) -> Result<(), Error>

The user is authenticated by searching for the user in the LDAP server. The search is performed using the provided filter. The filter should be a filter that matches a single user.

§Arguments
  • base - The base DN to search for the user
  • uid - The uid of the user
  • password - The password of the user
  • filter - The filter to search for the user
§Returns
  • Result<(), Error> - Returns an error if the authentication fails
§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    filter::EqFilter
};
use url::Url;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();
    let name_filter = EqFilter::from("cn".to_string(), "Sam".to_string());

    let result = client.authenticate("", "Sam", "password", Box::new(name_filter)).await;
}
Source

pub async fn search<'a, F, A, S, T>( &mut self, base: &str, scope: Scope, filter: &F, attributes: A, ) -> Result<T, Error>
where F: Filter, A: AsRef<[S]> + Send + Sync + 'a, S: AsRef<str> + Send + Sync + 'a, T: for<'de> Deserialize<'de>,

Search a single value from the LDAP server. The search is performed using the provided filter. The filter should be a filter that matches a single record. if the filter matches multiple users, an error is returned. This operation will treat all the attributes as single-valued, silently ignoring the possible extra values.

§Arguments
  • base - The base DN to search for the user
  • scope - The scope of the search
  • filter - The filter to search for the user
  • attributes - The attributes to return from the search
§Returns
  • Result<T, Error> - The result will be mapped to a struct of type T
§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    filter::EqFilter,
    ldap3::Scope
};
use url::Url;
use serde::Deserialize;


#[derive(Debug, Deserialize)]
struct User {
    uid: String,
    cn: String,
    sn: String,
}

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let name_filter = EqFilter::from("cn".to_string(), "Sam".to_string());
    let user_result: User = client
        .search(
        "ou=people,dc=example,dc=com",
        Scope::OneLevel,
        &name_filter,
        vec!["cn", "sn", "uid"],
    ).await
    .unwrap();
}
Source

pub async fn search_multi_valued<T: for<'a> Deserialize<'a>>( &mut self, base: &str, scope: Scope, filter: &impl Filter, attributes: &Vec<&str>, ) -> Result<T, Error>

Search a single value from the LDAP server. The search is performed using the provided filter. The filter should be a filter that matches a single record. if the filter matches multiple users, an error is returned. This operatrion is useful when records has multi-valued attributes.

§Arguments
  • base - The base DN to search for the user
  • scope - The scope of the search
  • filter - The filter to search for the user
  • attributes - The attributes to return from the search
§Returns
  • Result<T, Error> - The result will be mapped to a struct of type T
§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    filter::EqFilter,
    ldap3::Scope
};
use url::Url;
use serde::Deserialize;


#[derive(Debug, Deserialize)]
struct TestMultiValued {
   key1: Vec<String>,
   key2: Vec<String>,
}

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let name_filter = EqFilter::from("cn".to_string(), "Sam".to_string());
    let user_result = client.search_multi_valued::<TestMultiValued>(
        "",
        Scope::OneLevel,
        &name_filter,
        &vec!["cn", "sn", "uid"]
    ).await;
}

This method is used to search multiple records from the LDAP server. The search is performed using the provided filter. Method will return a Stream. The stream will lazily fetch the results, resulting in a smaller memory footprint.

You might also want to take a look at [streaming_search_paged()].

§Arguments
  • base - The base DN to search for the user
  • scope - The scope of the search
  • filter - The filter to search for the user
  • attributes - The attributes to return from the search
§Returns

A stream that can be used to iterate through the search results.

§Blocking drop caveat

Dropping this stream may issue blocking network requests to cancel the search. Running the stream to it’s end will minimize the chances of this happening. You should take this into account if latency is critical to your application.

We’re waiting for AsyncDrop for implementing this properly.

§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    filter::EqFilter,
    ldap3::Scope
};
use url::Url;
use serde::Deserialize;
use futures::StreamExt;


#[derive(Deserialize, Debug)]
struct User {
    uid: String,
    cn: String,
    sn: String,
}

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let name_filter = EqFilter::from(String::from("cn"), String::from("Sam"));
    let attributes = vec!["cn", "sn", "uid"];

    let stream = client.streaming_search(
        "",
        Scope::OneLevel,
        &name_filter,
        attributes
    ).await.unwrap();

    // The returned stream is not Unpin, so you may need to pin it to use certain operations,
    // such as next() below.
    let mut pinned_steam = Box::pin(stream);

    while let Some(result) = pinned_steam.next().await {
        match result {
            Ok(element) => {
                let user: User = element.to_record().unwrap();
                println!("User: {:?}", user);
            }
            Err(err) => {
                println!("Error: {:?}", err);
            }
        }
    }
}
Source

pub async fn streaming_search_paged<'a, F, A, S>( &'a mut self, base: &str, scope: Scope, filter: &F, attributes: A, page_size: i32, ) -> Result<impl Stream<Item = Result<Record, Error>> + use<'a, F, A, S>, Error>
where F: Filter, A: AsRef<[S]> + Send + Sync + Clone + Debug + 'a, S: AsRef<str> + Send + Sync + Clone + Debug + 'a,

This method is used to search multiple records from the LDAP server and results will be paginated. Method will return a Stream. The stream will lazily fetch batches of results resulting in a smaller memory footprint.

This is the recommended search method, especially if you don’t know that the result set is going to be small.

§Arguments
  • base - The base DN to search for the user
  • scope - The scope of the search
  • filter - The filter to search for the user
  • page_size - The maximum number of records in a page
  • attributes - The attributes to return from the search
§Returns

A stream that can be used to iterate through the search results.

§Blocking drop caveat

Dropping this stream may issue blocking network requests to cancel the search. Running the stream to it’s end will minimize the chances of this happening. You should take this into account if latency is critical to your application.

We’re waiting for AsyncDrop for implementing this properly.

§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    filter::EqFilter,
    ldap3::Scope
};
use url::Url;
use serde::Deserialize;
use futures::{StreamExt, TryStreamExt};


#[derive(Deserialize, Debug)]
struct User {
    uid: String,
    cn: String,
    sn: String,
}

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let name_filter = EqFilter::from(String::from("cn"), String::from("Sam"));
    let attributes = vec!["cn", "sn", "uid"];

    let stream = client.streaming_search_paged(
        "",
        Scope::OneLevel,
        &name_filter,
        attributes,
        200 // The pagesize
    ).await.unwrap();

    // Map the search results to User type.
    stream.and_then(async |record| record.to_record())
         // Do something with the Users concurrently.
        .try_for_each(async |user: User| {
            println!("User: {:?}", user);
            Ok(())
        })
        .await
        .unwrap();
}
Source

pub async fn create( &mut self, uid: &str, base: &str, data: Vec<(&str, HashSet<&str>)>, ) -> Result<(), Error>

Create a new record in the LDAP server. The record will be created in the provided base DN.

§Arguments
  • uid - The uid of the record
  • base - The base DN to create the record
  • data - The attributes of the record
§Returns
  • Result<(), Error> - Returns an error if the record creation fails
§Example
use simple_ldap::{LdapClient, LdapConfig};
use url::Url;
use std::collections::HashSet;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let data = vec![
        ( "objectClass",HashSet::from(["organizationalPerson", "inetorgperson", "top", "person"]),),
        ("uid",HashSet::from(["bd9b91ec-7a69-4166-bf67-cc7e553b2fd9"]),),
        ("cn", HashSet::from(["Kasun"])),
        ("sn", HashSet::from(["Ranasingh"])),
    ];

    let result = client.create("bd9b91ec-7a69-4166-bf67-cc7e553b2fd9", "ou=people,dc=example,dc=com", data).await;
}
Source

pub async fn update( &mut self, uid: &str, base: &str, data: Vec<Mod<&str>>, new_uid: Option<&str>, ) -> Result<(), Error>

Update a record in the LDAP server. The record will be updated in the provided base DN.

§Arguments
  • uid - The uid of the record
  • base - The base DN to update the record
  • data - The attributes of the record
  • new_uid - The new uid of the record. If the new uid is provided, the uid of the record will be updated.
§Returns
  • Result<(), Error> - Returns an error if the record update fails
§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    ldap3::Mod
};
use url::Url;
use std::collections::HashSet;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let data = vec![
        Mod::Replace("cn", HashSet::from(["Jhon_Update"])),
        Mod::Replace("sn", HashSet::from(["Eliet_Update"])),
    ];

    let result = client.update(
        "e219fbc0-6df5-4bc3-a6ee-986843bb157e",
        "ou=people,dc=example,dc=com",
        data,
        None
    ).await;
}
Source

pub async fn delete(&mut self, uid: &str, base: &str) -> Result<(), Error>

Delete a record in the LDAP server. The record will be deleted in the provided base DN.

§Arguments
  • uid - The uid of the record
  • base - The base DN to delete the record
§Returns
  • Result<(), Error> - Returns an error if the record delete fails
§Example
use simple_ldap::{LdapClient, LdapConfig};
use url::Url;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let result = client.delete("e219fbc0-6df5-4bc3-a6ee-986843bb157e", "ou=people,dc=example,dc=com").await;
}
Source

pub async fn create_group( &mut self, group_name: &str, group_ou: &str, description: &str, ) -> Result<(), Error>

Create a new group in the LDAP server. The group will be created in the provided base DN.

§Arguments
  • group_name - The name of the group
  • group_ou - The ou of the group
  • description - The description of the group
§Returns
  • Result<(), Error> - Returns an error if the group creation fails
§Example
use simple_ldap::{LdapClient, LdapConfig};
use url::Url;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let result = client.create_group("test_group", "ou=groups,dc=example,dc=com", "test group").await;
}
Source

pub async fn add_users_to_group( &mut self, users: Vec<&str>, group_dn: &str, ) -> Result<(), Error>

Add users to a group in the LDAP server. The group will be updated in the provided base DN.

§Arguments
  • users - The list of users to add to the group
  • group_dn - The dn of the group
§Returns
  • Result<(), Error> - Returns an error if failed to add users to the group
§Example
use simple_ldap::{LdapClient, LdapConfig};
use url::Url;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let result = client.add_users_to_group(
        vec!["uid=bd9b91ec-7a69-4166-bf67-cc7e553b2fd9,ou=people,dc=example,dc=com"],
        "cn=test_group,ou=groups,dc=example,dc=com").await;
}
Source

pub async fn get_members<'a, A, S, T>( &mut self, group_dn: &str, base_dn: &str, scope: Scope, attributes: A, ) -> Result<Vec<T>, Error>
where A: AsRef<[S]> + Send + Sync + 'a, S: AsRef<str> + Send + Sync + 'a, T: for<'de> Deserialize<'de>,

Get users of a group in the LDAP server. The group will be searched in the provided base DN.

§Arguments
  • group_dn - The dn of the group
  • base_dn - The base dn to search for the users
  • scope - The scope of the search
  • attributes - The attributes to return from the search
§Returns
  • Result<Vec<T>, Error> - Returns a vector of structs of type T
§Example
use simple_ldap::{
    LdapClient, LdapConfig,
    ldap3::Scope
};
use url::Url;
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct User {
    uid: String,
    cn: String,
    sn: String,
}

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let members: Vec<User> = client.get_members(
        "cn=test_group,ou=groups,dc=example,dc=com",
        "ou=people,dc=example,dc=com",
        Scope::OneLevel,
        vec!["cn", "sn", "uid"]
    ).await
    .unwrap();
}
Source

pub async fn remove_users_from_group( &mut self, group_dn: &str, users: Vec<&str>, ) -> Result<(), Error>

Remove users from a group in the LDAP server. The group will be updated in the provided base DN. This method will remove all the users provided from the group.

§Arguments
  • group_dn - The dn of the group
  • users - The list of users to remove from the group
§Returns
  • Result<(), Error> - Returns an error if failed to remove users from the group
§Example
use simple_ldap::{LdapClient, LdapConfig};
use url::Url;
use std::collections::HashSet;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let result = client.remove_users_from_group("cn=test_group,ou=groups,dc=example,dc=com",
    vec!["uid=bd9b91ec-7a69-4166-bf67-cc7e553b2fd9,ou=people,dc=example,dc=com"]).await;
}
Source

pub async fn get_associtated_groups( &mut self, group_ou: &str, user_dn: &str, ) -> Result<Vec<String>, Error>

Get the groups associated with a user in the LDAP server. The user will be searched in the provided base DN.

§Arguments
  • group_ou - The ou to search for the groups
  • user_dn - The dn of the user
§Returns
  • Result<Vec<String>, Error> - Returns a vector of group names
§Example
use simple_ldap::{LdapClient, LdapConfig};
use url::Url;

#[tokio::main]
async fn main(){
    let ldap_config = LdapConfig {
        bind_dn: String::from("cn=manager"),
        bind_password: String::from("password"),
        ldap_url: Url::parse("ldaps://localhost:1389/dc=example,dc=com").unwrap(),
        dn_attribute: None,
        connection_settings: None
    };

    let mut client = LdapClient::new(ldap_config).await.unwrap();

    let result = client.get_associtated_groups("ou=groups,dc=example,dc=com",
    "uid=bd9b91ec-7a69-4166-bf67-cc7e553b2fd9,ou=people,dc=example,dc=com").await;
}

Trait Implementations§

Source§

impl Clone for LdapClient

Source§

fn clone(&self) -> LdapClient

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for LdapClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<'src, T> IntoMaybe<'src, T> for T
where T: 'src,

Source§

type Proj<U: 'src> = U

Source§

fn map_maybe<R>( self, _f: impl FnOnce(&'src T) -> &'src R, g: impl FnOnce(T) -> R, ) -> <T as IntoMaybe<'src, T>>::Proj<R>
where R: 'src,

Source§

impl<'p, T> Seq<'p, T> for T
where T: Clone,

Source§

type Item<'a> = &'a T where T: 'a

The item yielded by the iterator.
Source§

type Iter<'a> = Once<&'a T> where T: 'a

An iterator over the items within this container, by reference.
Source§

fn seq_iter(&self) -> <T as Seq<'p, T>>::Iter<'_>

Iterate over the elements of the container.
Source§

fn contains(&self, val: &T) -> bool
where T: PartialEq,

Check whether an item is contained within this sequence.
Source§

fn to_maybe_ref<'b>(item: <T as Seq<'p, T>>::Item<'b>) -> Maybe<T, &'p T>
where 'p: 'b,

Convert an item of the sequence into a MaybeRef.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> OrderedSeq<'_, T> for T
where T: Clone,