How To Install and Configure an LDAP Proxy-Cache Server

Background

To reduce network traffic overhead and avoid problems either logging in or performing user searches while sharing, it’s an excellent idea to implement an LDAP proxy cache. An LDAP proxy cache server, similar to other kinds of caching servers, is a special type of LDAP replica. It can cache a range of LDAP records, often resulting in improved LDAP server performance.

Specifically, the records which need to be cached for improved ownCloud performance are:

  • Users that are allowed to log in

  • Groups (limited to the allowed users)

  • Search fields (e.g., sAMAccountName, CN, SN, givenName, and displayName)

How To Set Up the Server

To set up the LDAP Proxy-Cache server work through the following five steps:

Install OpenLDAP

There are a number of LDAP server implementations available. The one used in this guide is OpenLDAP.

While OpenLDAP does work on most of the common operating systems, for the purposes of this guide we’ll be using a Debian-based Linux distribution.

First, update your system to ensure that you are using the latest packages. Then, run the following command:

sudo apt-get update && apt-get upgrade -y

Next, install OpenLDAP and its associated packages by running the following command:

sudo apt-get install slapd ldap-utils -y

Configure the Server

With OpenLDAP installed and running, you now need to configure it. One way of doing so is to create a configuration file. Create /etc/ldap/slapd.conf with your text editor of choice, and add the following configuration to it.

# This an example of a config file:

# See slapd.conf(5)

# Global Directives:

# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema

# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile         /var/run/slapd/slapd.pid

# List of arguments that were passed to the server
argsfile        /var/run/slapd/slapd.args

# Read slapd.conf(5) for possible values
# Change loglevel to "any" if you want to see everything.
loglevel        none

# Where the dynamically loaded modules are stored
modulepath      /usr/lib/ldap

# Here are the recommended modules:

# module for the target ldap-server
moduleload	back_ldap.la

# module for your local database
moduleload	back_hdb.la

# module for rewriting attributes
moduleload	rwm

# caching module
moduleload	pcache.la

# module to enable memberof in LDAP
moduleload memberof.la

# The maximum number of entries that is returned for a search operation
sizelimit 500

# The tool-threads parameter sets the actual amount of cpu's that is used
# for indexing.
tool-threads 1

# Type of backend, for example "ldap"
backend         ldap

# Type of database
database		ldap

# If you only have read access, set this to "yes"
readonly        yes

# Set which protocol to use, we suggest "3"
protocol-version  3

# remember bind credentials
rebind-as-user

# If you want to save time and don't want to list all the refferals, set to "yes"
norefs  yes

# Same as above
chase-referrals no

# Specify the URL of your ldap server and the port.
# For unencrypted access use the port 389, for encrypted 636
# If you have to use 636, you will also probably have to import
# the certificate of your target server. restart your webserver after you do.
uri "ldap://192.168.178.2:389"

# The base of your directory in database, for example "dc=ldap01,dc=com"
suffix          "dc=ldap01,dc=com"

# rootdn directive for specifying a superuser on the database.
# If you don't have access to the admin user, use the one you have.
rootdn          "cn=admin,dc=ldap01,dc=com"

# Now we start initialising the modules
# First the rewrite module
overlay         rwm

# Now we rewrite the attributes
rwm-map         attribute uid sAMAccountName
rwm-map         attribute dn distinguishedName

# Next one is optional, if you want memberof, for the groups,
# you have to load it.
overlay         memberof

# Now we load the caching module
overlay pcache

# The directive enables proxy caching
# See slapo-pcache

# pcache <database> <max_entries> <numattrsets> <entry_limit> <cc_period>
# Parameters:
#
# <database> for cached entries.
# <max_entries> when reached - cache replacement is invoked
# <numattrsets> = pcacheAttrset
# <entry_limit> limit to the number of entries returned
# <cc_period> Consistency check time to wait
pcache hdb 100000 3 1000 100

# pcachePersist { TRUE | FALSE }
# Write cached results into the database
# Results remain in database after restart
pcachePersist TRUE

# Where the database file are physically stored for database #1
directory       "/var/lib/ldap"

# Caching templates for general search

# pcacheAttrset <index> <attrs...>
# First set the index number
# Then set the attribute to cache
pcacheAttrset   0 1.1

# pcacheTemplate <template_string> <attrset_index> <ttl>
# First define the querry sting to cache
# Then reference the Attrset
# Last set the time-to-live
pcacheTemplate  (&(|(objectClass=))) 0 3600
pcacheTemplate (objectClass=*) 0 3600

# User Name Field (Advanced Tab)
pcacheAttrset   1 displayname
pcacheTemplate (objectClass=*) 1 3600

# Group Field
pcacheAttrset   2 memberOf
pcacheTemplate (objectClass=*) 2 3600


# This an example of a config file:

# See slapd.conf(5)

# Global Directives:

# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema

# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile         /var/run/slapd/slapd.pid

# List of arguments that were passed to the server
argsfile        /var/run/slapd/slapd.args

# Read slapd.conf(5) for possible values
# Change loglevel to "any" if you want to see everything.
loglevel        none

# Where the dynamically loaded modules are stored
modulepath      /usr/lib/ldap

# Here are the recommended modules:

# module for the target ldap-server
moduleload	back_ldap.la

# module for your local database
moduleload	back_hdb.la

# module for rewriting attributes
moduleload	rwm

# caching module
moduleload	pcache.la

# module to enable memberof in LDAP
moduleload memberof.la


# The maximum number of entries that is returned for a search operation
sizelimit 500

# The tool-threads parameter sets the actual amount of cpu's that is used
# for indexing.
tool-threads 1

# Type of backend, for example "ldap"
backend         ldap

# If you only have read access, set this to "yes"
readonly        yes

# Set which protocol to use, we suggest "3"
protocol-version  3

# remember bind credentials
rebind-as-user

# If you want to save time and don't want to list all the refferals, set to "yes"
norefs  yes

# Same as above
chase-referrals no

# Specify the URL of your ldap server and the port.
# For unencrypted access use the port 389, for encrypted 636
# If you have to use 636, you will also probably have to import
# the certificate of your target server.
# Restart your webserver after you do.
uri "ldap://192.168.178.2:389"

# The base of your directory in database, for example "dc=ldap01,dc=com"
suffix          "dc=ldap01,dc=com"

# rootdn directive for specifying a superuser on the database.
# If you don't have access to the admin user, use the one you have.
rootdn          "cn=admin,dc=ldap01,dc=com"

# Now we start initialising the modules
# First the rewrite module
overlay         rwm

# Now we rewrite the attributes
rwm-map         attribute uid sAMAccountName
rwm-map         attribute dn distinguishedName

# Next one is optional, if you want memberof, for the groups,
# you have to load it.
overlay         memberof

# Now we load the caching module
overlay pcache

# The directive enables proxy caching
# See slapd-pcache

# pcache <database> <max_entries> <numattrsets> <entry_limit> <cc_period>
# Parameters:
#
# <database> for cached entries.
# <max_entries> when reached - cache replacement is invoked
# <numattrsets> = pcacheAttrset
# <entry_limit> limit to the number of entries returned
# <cc_period> Consistency check time to wait
pcache hdb 100000 3 1000 100

# pcachePersist { TRUE | FALSE }
# Write cached results into the database
# Results remain in database after restart
pcachePersist TRUE

# Where the database file are physically stored for database #1
directory       "/var/lib/ldap"

# Caching templates for general search

# pcacheAttrset <index> <attrs...>
# First set the index number
# Then set the attribute to cache
pcacheAttrset   0 1.1

# pcacheTemplate <template_string> <attrset_index> <ttl>
# First define the query string to cache
# Then reference the Attrset
# Last set the time-to-live
pcacheTemplate  (&(|(objectClass=))) 0 3600
pcacheTemplate (objectClass=*) 0 3600

# User Name Field (Advanced Tab)
pcacheAttrset   1 displayname
pcacheTemplate (objectClass=*) 1 3600

# Group Field
pcacheAttrset   2 memberOf
pcacheTemplate (objectClass=*) 2 3600
This configuration only caches queries from a single Active Directory server. To cache queries from multiple Active Directory servers, a configuration is available below.

After you’ve done that, save the file and test that there are no errors in the configuration by running:

sudo slaptest -f /etc/ldap/slapd.conf
If you see warnings in the console output, they are not crucial.

Enable the Configuration File

Next, we need to tell OpenLDAP to use our configuration. To do so, open /etc/default/slapd and add the following line to it:

SLAPD_CONF=/etc/ldap/slapd.conf

With that done, restart OpenLDAP by running the following command:

sudo service slapd restart

Open the Log

With OpenLDAP running, review the system log output with the following command:

tail -f /var/log/syslog | grep QUERY

If there is no such file, you need to install a Syslog daemon. We recommend using Rsyslog. To install it, run the following command:

sudo apt install rsyslog

Now that the server’s installed, configured, and running, we next need to perform a test search. This will check that records are being correctly cached. To do so, run one of the following commands below, after updating it with values from your Active Directory server configuration.

sudo ldapsearch -h localhost -x -LLL \
    -D "cn=admin,cn=users,dc=example,dc=com" \
    -b "cn=users,dc=example,dc=com" \
    -w "Password" "(cn=Administrator)" name
sudo ldapsearch -H ldaps://localhost:636 -x -LLL \
    -D "cn=admin,cn=users,dc=example,dc=com" \
    -b "cn=users,dc=example,dc=com" \
    -W "(cn=Administrator)" name
Table 1. Description of Options
Option Description

-h

Host address (Example: localhost or 192.168.1.1)

-H

Host address (Example: ldap:// or ldaps:// hostname or ip and port :389 or :636)

-x

Simple authentication

-b

Search Base, (Example: cn=Users,dc=example,dc=com)

-D

User with permissions (Example: cn=Admin,dc=example,dc=com)

-LLL

Show only results, no extra information

-w

Password ("Password")

-W

Password, will ask for password and hide your input

(cn=Administrator)

Filter the search

name

Show only these attributes

If the results include: "Query cachable" and "Query answered (x) times", then the setup works.

Configure ownCloud LDAP App

Configuring the ownCloud LDAP application involves several step; these are:

Enable the LDAP Application

First, login to your ownCloud server as an ownCloud admin; then:

  • Click on the Settings dropdown menu in the top-right corner.

    • Then, click on Admin  Apps.

    • Click on Show Disabled Apps and enable the "LDAP Integration" app, and reload the page.

  • Click on the menu in the left-hand side, Admin  User Authentication.

    • Select LDAP, if available and not already selected.

Configure the LDAP Application

ownCloud’s LDAP configuration form.
  • Select the Server tab.

    • In the first field, enter the server address (either the IP address or hostname).
      TIP: You can click on the button to detect your server’s port or enter it manually.

    • In the next two fields, enter the user DN of the user you want to log in with, and the password.

    • Click on Detect Base DN, or enter the base DN manually.

    • Click on Test Base DN.

  • If you fulfill all the requirements, you should get a green light and see the message: Configuration OK.

  • Select Users tab.

    • Select the objectclass for the users, for example user.

    • Click Verify settings and count users near the bottom of the form. You will then see the number of users found.

  • Select Login Attributes tab.

    • A configuration appears; adjust it to your users configuration.

    • If required, adjust the login parameters additional login attributes.

    • You can check users with any of the allowed login options. You can adjust them or leave them the way they are.

  • Select Groups tab.

    • Select all the objectclasses for your groups, for example group. Then, verify your settings

  • Select Advanced tab.

    • Under "Configuration Settings":

  • Configuration Active should be selected.

  • Adjust the Cache TTL (time to live) value as required. However, ownCloud usually auto-selects the best settings for each AD configuration.

    • Under "Directory Settings"

  • Check if the Group-Member association is Member (AD). This is important for the users being shown in their respective groups.

  • Select Nested groups, if you have them.

  • Select Expert tab.

    • In the "Internal Username Attribute" field, we need to set CN for the users being shown with their unique name. If you leave that field empty, each user will get a unique UID as a string of numbers and letters.

    • At the bottom of the form, click both Clear Username-LDAP User Mapping and Clear Groupname-LDAP Group Mapping, and then test your configuration by clicking Test Configuration.

  • Navigate to our ownCloud User administration page and check if all your users are listed properly, and shown in the right groups.

  • Go to the homepage of your ownCloud server and try to share something with one of your users

If everything is set up correctly, you now have an LDAP proxy server to your active directory that will reduce the network traffic by caching the searches your perform.

Cache Multiple Active Directory Servers

If you have more than one Active Directory Server that you want to cache, in /etc/ldap/slapd.conf add the following configuration instead, adjusting it as necessary. The ownCloud LDAP app settings are the same as in section 6.

# This an example of a config file:

# See slapd.conf(5)

# Global Directives:

# Schema and objectClass definitions
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
include 	/etc/ldap/schema/misc.schema

# Where the pid file is put. The init.d script
# will not stop the server if you change this.
pidfile         /var/run/slapd/slapd.pid

# List of arguments that were passed to the server
argsfile        /var/run/slapd/slapd.args

# Read slapd.conf(5) for possible values
# Change loglevel to "any" if you want to see everything.
loglevel        none

# Where the dynamically loaded modules are stored
modulepath      /usr/lib/ldap

# Here are the recommended modules:

# module for meta-database
moduleload back_meta.la

# module for the target ldap-server
moduleload	back_ldap.la

# module for your local database
moduleload	back_hdb.la

# module for rewriting attributes
moduleload	rwm

# caching module
moduleload	pcache.la

# module to enable memberof in ldap
moduleload memberof.la

# The maximum number of entries that is returned for a search operation
sizelimit 500

# The tool-threads parameter sets the actual amount of cpu's that is used
# for indexing.
tool-threads 1

# If you want to save time and don't want to list all the refferals, set "yes"
norefs  yes

# Same as above
chase-referrals no

# See slapd-meta

# database type, for multiple ADS "meta" is required
database	meta

# now we create a local ldap tree
# in our tree we put the multiple ADS on different branches
# we need a suffix, an admin, and a password
suffix          "dc=owncloud,dc=com"
rootdn		"cn=Administrator,cn=Users,dc=example,dc=com"
rootpw "Password"

# now we specify our ADs
# First-AD
# uri <protocol>://[<host>]/<naming context>
uri             "ldap://first.ad.com:389/
cn=users,dc=first,dc=example,dc=com"

# here we need to set the virtual name to the real name
# the virtual name is a branch in our new created ldap tree
# suffixmassage <virtual naming context> <real naming context>
suffixmassage   "cn=users,dc=first,dc=example,dc=com" "cn=users,dc=first,dc=ad,dc=com"

# authentication parameters
idassert-bind	bindmethod=simple
		binddn="cn=user01,cn=users,dc=first,dc=owncloud,dc=com"
credentials="Password01"

# Second-AD
uri             "ldaps://second.ad.com:636/cn=users,dc=second,dc=example,dc=com"
suffixmassage   "cn=users,dc=second,dc=example,dc=com" "cn=users,dc=second,dc=ad,dc=com"
idassert-bind   bindmethod=simple
                binddn="cn=user02,cn=users,dc=second,dc=owncloud,dc=com"
                credentials="Password02"

# Now we start initialising the modules
# First the rewrite module
overlay         rwm

# Now we rewrite the attributes
rwm-map         attribute uid sAMAccountName
rwm-map         attribute dn distinguishedName

# Next one is optional, if you want memberof, for the groups,
# you have to load it.
overlay         memberof

# Now we load the caching module
overlay pcache

# The directive enables proxy caching
# See slapo-pcache

# pcache <database> <max_entries> <numattrsets> <entry_limit> <cc_period>
# Parameters:
#
# <database> for cached entries.
# <max_entries> when reached - cache replacement is invoked
# <numattrsets> = pcacheAttrset
# <entry_limit> limit to the number of entries returned
# <cc_period> Consistency check time to wait
pcache hdb 100000 3 1000 100

# pcachePersist { TRUE | FALSE }
# Write cached results into the database
# Results remain in database after restart
pcachePersist TRUE

# Where the database files are physically stored for database #1
directory       "/var/lib/ldap"

# Caching templates for general search

# pcacheAttrset <index> <attrs...>
# First set the index number
# Then set the attribute to cache
pcacheAttrset   0 1.1

# pcacheTemplate <template_string> <attrset_index> <ttl>
# First define the query sting to cache
# Then reference the Attrset
# Last set the time-to-live
pcacheTemplate  (&(|(objectClass=))) 0 3600
pcacheTemplate (objectClass=*) 0 3600

# User Name Field (Advanced Tab)
pcacheAttrset   1 displayname
pcacheTemplate (objectClass=*) 1 3600

# Group Field
pcacheAttrset   2 memberOf
pcacheTemplate (objectClass=*) 2 3600