Professional Documents
Culture Documents
Reading and Interacting With LDAP Servers
Reading and Interacting With LDAP Servers
Reading and Interacting With LDAP Servers
LDAP has a client/server architecture, where the server can use a variety of
databases to store a directory, each optimized for fast, high-volume read
operations. When a client application is connected to an LDAP server, most of
the time it will be for queries, although it is also possible to make changes to the
directory entries. If the client application is trying to modify the information in
an LDAP directory, the server will try to verify that the user has the necessary
permissions to update the information.
The biggest advantage of LDAP is that you can consolidate information for an
entire organization within a central repository. For example, instead of managing
user lists for each group within an organization, you can use LDAP as a central
directory, which is accessible from anywhere in the network. Since LDAP
supports Secure Connection Layer (SSL) and Transport Layer Security
(TLS), confidential data can be protected from hackers.
Another advantage of LDAP is that your company can access the LDAP
directory from almost any computing platform, from any of the applications that
is readily available for LDAP. It is also easy to customize your internal business
applications to add LDAP support.
LDAP terminology
LDAP stands for Lightweight Directory Access Protocol. It is an application-
level protocol that allows queries about a directory service to search for
information.
LDAP defines the way to access that directory, that is, it is optimized to carry out
read operations on the directory, such as validating authenticated access to a user
stored in the directory.
Classes: The objects and their characteristics are defined in classes. For
example, the type of object to be defined and the attributes that it will
contain depend on the type of object. In the scheme, each class is defined
with the attributes that will be obligatory and optional for each created
entry.
Objects: Entries in the directory. Objects are instances that are created from
a certain class or several, depending on the attributes required for an object.
The entire directory will be composed of objects (such as users, groups, or
organizational units).
A directory service is like a database where we organize and store
information with objects of different classes. This hierarchically-organized
structure of the objects is achieved with the implementation of LDAP.
entry: A unit in an LDAP directory. Each entry is identified by its unique
distinguished name (DN).
DN: The distinguished name to uniquely identify a specific object in the
directory. That is, each entry defined is unique throughout the directory. As
we can see, the DN of that object (user type) will be unique throughout the
directory and will uniquely identify you.
Attributes: Pieces of information directly associated with the input. For
example, an organization can be represented as an LDAP entry. The
attributes associated with the organization can be your fax number or your
address, for example. In an LDAP directory, the entries can also be people,
with common attributes such as their telephone number and email
addresses. Some attributes are mandatory while others are optional.
The LDAP Data Exchange Format (LDIF): An ASCII text representation
of LDAP entries. The files used to import data to the LDAP servers must be
in LDIF format.
Introduction to python-ldap
Python's python-ldap (https://www.python-ldap.org/en/latest/) third-party package
provides the necessary functionality to interact with an LDAP server.
To begin, you will have to initialize the LDAP connection, where we can replace
ldap_server with the IP address of the server and the port number:
import ldap
ldap_client = ldap.initialize("ldap://<ldap_server>:port_number/")
This method initializes a new connection object to access the given LDAP
server, and return an LDAP object that's used to perform operations on that
server. The next step is bind/authenticate with a user with appropriate rights:
ldap_client.simple_bind(user,password)
Then, you can perform an ldap search. It requires you to specify the necessary
parameters, such as base DN, filter, and attributes. Here is an example of the
syntax that is required to search for users on an LDAP server:
ldap_client.search_s( base_dn, ldap.SCOPE_SUBTREE, filter, attrs)
Here is a complete example to find user information using the LDAP protocol. It
demonstrates how to open a connection to an LDAP server using the ldap module
and invoke a synchronous subtree search.
if __name__ == '__main__':
main ()
The previous script verifies credentials for the username and password against a
LDAP server. It returns some of the user attributes on success, or a string that
describes the error on failure. The script will search the LDAP directory subtree
with the ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org base DN. The search is limited
to person objects.
We need to define some global variables so that we can establish the URL of the
LDAP server, that is, the base DN to search for users within the LDAP directory
and the user attributes that you want to recover.
First, we need to initialize an instance of the ldap class and define the options that
are required for the connection. Then, try to connect to the server using the
simple_bind function. In case of success, the user's attributes are retrieved using
the search_s function.
The LDAP FreeIPA server
FreeIPA (https://www.freeipa.org/page/Demo) is a fully-featured identity management
solution that provides LDAP server. We can find a free public instance of the
FreeIPA server at https://ipa.demo1.freeipa.org. The FreeIPA domain is configured
with the following users (the password is Secret123 for all of them):
admin: This user has all the privileges and is considered the administrator
account
helpdesk: A regular user with the helpdesk role
employee: A regular user with no special permissions
manager: A regular user, set as the manager of the employee user
In the following screenshot, we can see the active users that are available:
In this example, we are accessing the LDAP server with an anonymous bind.
The auto_bind=True parameter forces the Bind operation to execute after creating
the Connection object. You can get information with the info property of the
Server object.
import argparse
from ldap3 import Server, Connection, ALL
def main(address):
# Create the Server object with the given address.
# Get ALL information.
server = Server(address, get_info=ALL)
#Create a connection object, and bind with auto bind set to true.
conn = Connection(server, auto_bind=True)
# Print the LDAP Server Information.
print('******************Server Info**************')
print(server.info)
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Query LDAP Server')
parser.add_argument('--address', action="store", dest="address", default='ipa.demo1.freeipa.org')
given_args = parser.parse_args()
address = given_args.address
main(address)
The following is the output of the previous script. From this response, we know
that this server is a standalone LDAP server that can hold entries in the dc=demo1,
dc=freeipa, and dc=org contexts:
search_base: The location in the ldap directory where the search will start
search_filter: A string that describes what you are searching for
attributes: Attributes to extract
In this script, we are going to search all users in the FreeIPA demo LDAP
server. You can find the following code in the entries_ldap_server.py file:
#!/usr/bin/env python3
from ldap3 import Server, Connection, ObjectDef, AttrDef, Reader, Writer, ALL
LDAP_SERVER ="ipa.demo1.freeipa.org"
LDAP_USER ="uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org"
LDAP_PASSWORD ="Secret123"
LDAP_FILTER = '(objectclass=person)'
LDAP_ATTRS = ["cn", "dn", "sn", "givenName"]
def main():
# Create the Server object with the given address.
server = Server(LDAP_SERVER, get_info=ALL)
#Create a connection object, and bind with the given DN and password.
try:
conn = Connection(server, LDAP_USER, LDAP_PASSWORD, auto_bind=True)
print('LDAP Bind Successful.')
# Perform a search for a pre-defined criteria.
# Mention the search filter / filter type and attributes.
conn.search('dc=demo1,dc=freeipa,dc=org', LDAP_FILTER , attributes=LDAP_ATTRS)
# Print the resulting entries.
for entry in conn.entries:
print(entry)
except core.exceptions.LDAPBindError as e:
# If the LDAP bind failed for reasons such as authentication failure.
print('LDAP Bind Failed: ', e)
if __name__ == '__main__':
main()
This is the execution of the previous script. Here, you request all the entries of
person class , starting from the dc=demo1, dc=freeipa, and dc=org contexts with the
default subtree scope:
[DN: uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
, DN: uid=manager,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
, DN: uid=employee,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
, DN: uid=helpdesk,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
]