Configure LDAP authentication on Apache
Spoiler: Rather than dealing with complicated extensions and frameworks, why not let Apache authenticate your users via LDAP?
Self-hosting is cool. But user management can be really annoying. What is much less cool is creating accounts everywhere and having to update passwords every time you want to change them. In this case, an LDAP/AD directory comes in useful
Recently, I encountered this kind of problem trying to install an RSS feed aggregator. At the Arsouyes’ we like RSS feeds. It’s low tech and low intrusive. But, as a geek with many computers and dual boot systems, I had some synchronization problems :
- maintaining the list of the feeds on each computer or OS
- maintaining the list of what I have already read or not
- sharing my feeds.
Without going into detail1, I chose FreshRSS. And I will not explain how to install it, their documentation is well done.
I didn’t want to create a specific user for each of my users. The cool thing is that I can ask Apache to handle the authentication by querying my domain controller, and FreshRSS is able to take it into account. Even better, it is not FreshRSS specific, every website you code can interface easily with an AD.2.
Apache and LDAP
In order for our Apache to communicate with our LDAP, a few lines of configuration are required.
First, it is necessary to install the following modules and activate them: : mod_ldap and mod_authnz_ldap3.
a2enmod ldap authnz_ldapNext, in the configuration file corresponding to your website, restrict access to the directory to the users connected with LDAP. The following configuration must be placed in the virtual host configuration corresponding to the website (VirtualHost tag).
In order to make the configuration file more readable, we will use Define to define the variables, next, we will call them using the syntax ${variable_name}. Here is what your configuration file will look like. You will of course need to give a value to each of the directives.
<Directory ${dir}>
AuthName ${auth_mess}
AuthType ${type}
AuthBasicProvider ${module}
AuthLDAPURL ${url}
AuthLDAPBindDN ${bindname}
AuthLDAPBindPassword ${password}
Require ${who}
</Directory>The settings must be configured according to your directory. In our case, we are using a Netserver7 so I explain the details of what we had to use in our case
The directory on which the settings must be applied. In our case, our website is in /var/www/html
Define dir /var/www/html/The authentication message that will be sent to the client when they are asked to send their username and password. In our case, we have chosen to send “Knock knock, who's there?”4.
Define auth_mess "Knock knock, who's there?"The type of authentication that will be used to transmit the username and password to the server. In our case, we want the browser to transmit the username and password using the basic protocol5 .
Define type BasicThe module that manages password verification. In our case, we want it to be ldap.
Define module ldapThe search URL in the LDAP directory. Most of the information you need should be somewhere in your LDAP server interface (in our case, under System/Users and Groups). In our case, for it to work with a Netserver7 :
Define url "ldaps://my.server.my.domain.org:636/dc=my,dc=domain,dc=org?sAMAccountName?base?(objectClass=user)"where :
ldaps://: use ldap protocol with its securised version6my.server.my.domain.org: enter here the address of your ldap directory:636: This is the default port for LDAPS./dc=my,dc=domain,dc=org: This is the base DN, i.e., the branch of the directory where searches are performed. Here, it corresponds to the structure my.domain.org.?sAMAccountName: Basically, it says that the search is done on thesAMAccountNameattribute and that it must be equal to the user name provided.?base: Scope of the search. Basically, in our directory, there is no need to perform a recursive search.7?(objectClass=user): informs us that any corresponding object will do. For our part, we want to authenticate users (our machines do not need to access an RSS feed).
The username that can make requests on the LDAP directory. This information is also available somewhere in your directory interface. In our case, the user is named ldapservice.
Define bindname ldapservice@my.domain.orgThe password of the user that you just entered. We're not going to put ours here, you know how to enter your own :).
Define password M4rV3l0USp4ssW0RdFinally, who has the right to access the directory. It is possible to filter by groups or users, but in our case, a valid user in the directory is more than sufficient8.
Define who valid-userThis produces a file like this:
Define dir /var/www/html/
Define auth_mess "Knock knock, who's there?"
Define type Basic
Define module ldap
Define url "ldaps://my.server.my.domain.org:636/dc=my,dc=domain,dc=org?sAMAccountName?base?(objectClass=user)"
Define bindname ldapservice@my.domain.org
Define password M4rV3l0USp4ssW0Rd
Define who valid-user
<Directory ${dir}>
AuthName ${auth_mess}
AuthType ${type}
AuthBasicProvider ${module}
AuthLDAPURL ${url}
AuthLDAPBindDN ${bindname}
AuthLDAPBindPassword ${password}
Require ${who}
</Directory>After saving the file, restart Apache.
On Debian, use the following command:
systemctl restart apache2FreshRSS case
It is very easy to let FreshRSS know that the web server handles authentication, as this is a built-in feature.
In the configuration (small gear icon), go to Administration/Authentication. In the drop-down menu, simply select the HTTP authentication method.
From now, all my users registered on my Nethserver can use the service 🎉.
What next?
In fact, it’s not a magical feature of FreshRSS that suddenly start to talk to LDAP. FreshRSS just trusts Apache for Authentication : once Apache validate a user, FreshRSS assumes everything is fine and simply retrieves the informations.
This means that, technically, any site can rely on Apache to identify its visitors. Just read the REMOTE_USER variable which contains the name of who is logged-in.
By exemple, in PHP, user authentication can be made by using the following few lines of code 9:
<?php
$username = htmlspecialchars($_SERVER['REMOTE_USER']);
echo "<h1>Hello, $username !</h1>";It's simple and elegant. No need to add weird frameworks to try to interface your code with LDAP; Apache and other web servers do it natively. And for application code, freed from authentication issues, it can now focus on what's important. For FreshRSS: retrieving articles from RSS feeds.10.
Two birds with one stone, since the interface provided by the identity provider is very simple (it puts the user name in a variable), it can be replaced easily. A little bit of configuration and you can put your users in an htpasswd file , an SQL database or, let's go crazy, using Kerberos11.