mod_authz_ldap is configured through a set of directives
on the directory level. In particular, the server creates an LDAP server
connection for each directory configuration. Subsequent requests to
the same directory do not create a new LDAP connection, except when
Basic Authentication is done against the directory, as this is done
through a bind call in a separate connection each time authentication
mod_authz_ldap should accept that other authorization
modules may grant access to a user although
has denied it, it must be denied authority by the command
The default is that
mod_authz_ldap is authoritative.
mod_authz_ldap is supposed to authenticate or
authorize (if the user was authenticated by a certificate, only
the authorization part is left to the module) a user, it needs
to contact an LDAP directory. The following directives configure
If no server is configured, a server on the local host on the standard
LDAP port 389 is assumed. If no bind credentials are defined, an
anonymous bind is performed.
LDAP User Authentication becomes active when the
is set to ldap.
User authentication through basic authentication against an LDAP
directory is by default active if
AuthType are defined for a directory or location.
It works as follows:
As one can see, the module needs quite some additional information
to perform all these tasks.
If the user search scope has been set to something other than
base, a query is performed from the configured user base DN
for a node with the attribute
uid set to the name
entered by the user in the login dialog. The user's distinguished
name is set to the distinguished name of the node found, provided
the search returned a single node.
If the user search scope was
base, then the distinguished
name is constructed from the
the username from the dialog and the user search base.
The password is verified by binding to the directory as the user
whose distinguished name was found in the previous step, with the
password from the login dialog.
If the authentication succeeded, additional requirements are
If password aging is set by a
require age directive,
the last modification timestamp is checked as configured as
described in section 3.5 on password expiration below.
If particular users are required, they are verified in this step.
If the user name does not seem to have the format of a distinguished
name, a search in the directory is performed first using the same
algorithm as for the verification of the password.
If some group membership is required, the group name is searched for
and membership the user in the group verified.
As one can see,
mod_authz_ldap needs additional information
besides the LDAP server
to be able to
Find the user in the directory:
The user node in the DIT below the node specified by the
AuthzLDAPUserBase directive is expected to have an attribute
named by the value of
AuthzLDAPUserKey, the value
of which is supposed to be the user id from the basic authentication.
The default search scope for a user is base.
In that case, the distinguished name of the user will
be of the form
If none of the above values are set, the user must enter his/her
distinguished name in the password dialog.
Find the group for the user:
see the section 4. on group verification
below for details.
After successful authentication, the distinguished name of the user
is placed in the authorization header. Subsequent authorization
modules must therefore be able to deal with a distinguished name
as the user id.
require user directive will search for the user
according to the settings above and verify that exactly one user
is returned an matches the distinguished name obtained from the
LDAP authentication. If the
are not set, a
require user statement must specify the
full distinguished name of a user.
To active certificate mapping, set the
Certificate mapping tries to find a user based on the subject
and issuer DN. As uniqueness of distinguished names of subjects
across CAs is not guaranteed, only the pairs
(issuer, serial) are unique.
The LDAP server has to be prepared to perform this mapping. It needs to
contain nodes of the following type (described here in old
openldap version 1 notation):
attribute issuerDN ces
attribute subjectDN ces
Although it looks as both subjectDN and serialNumber can be omitted,
one of them is needed (see the discussion of the
directive), but this cannot be expressed in the above syntax.
A similar remark applies to the OpenLDAP syntax below.
A definition for the attributes
subjectDN and for the objectclass certificatemap
should be added to the directory server. Openldap version 1 users
can use the file authzldap.slapd.conf file for this purpose, version 2
users will use authzldap.schema. The latter contains official object
attributetype ( 220.127.116.11.4.1.4263.5.1 NAME 'issuerDN'
DESC 'The user friendly version of the distinguished name of the
issuer of a certificate'
SYNTAX 18.104.22.168.4.1.1422.214.171.124.40 SINGLE-VALUE )
attributetype ( 126.96.36.199.4.1.4263.5.2 NAME 'subjectDN'
DESC 'The user friendly version of the distinguished name of
the subject of a certificate'
SYNTAX 188.8.131.52.4.1.14184.108.40.206.40 SINGLE-VALUE )
objectclass ( 220.127.116.11.4.1.4263.5.3 NAME 'authzLDAPmap'
DESC 'Map Entry for mod_authz_ldap'
SUP top AUXILIARY
MUST ( issuerDN $ owner )
MAY ( subjectDN $ serialNumber $ userCertificate )
Certificate Mapping searches for a node in a subtree of the directory
that has issuerDN and subjectDN as read from the certificate.
It is configured through the following directives:
This only makes sense, if mod_ssl
has been configured to request a client certificate through the SSLRequireSSL
option (see the mod_ssl
documentation for details).
While earlier releases of this module read the subjectDN from the
basic authentication header, they now read it from the mod_ssl context,
as all the variables used for the mapping.
Last, but not least, it is possible to directly match a user against
her certificate. However, this requires that the directory server is
able to perform an equality match for the
This is not the case by default in OpenLDAP, but can be enabled by changing
the definition of
Change the definition from
attributetype ( 18.104.22.168 NAME 'userCertificate'
SYNTAX 22.214.171.124.4.1.14126.96.36.199.8 )
attributetype ( 188.8.131.52 NAME 'userCertificate'
SYNTAX 184.108.40.206.4.1.14220.127.116.11.40 )
Strictly speaking, this violates some generally accepted schema
standards, but it is so immensly useful.
mod_authz_ldap can now directly match the certificate if
the directive AuthzLDAPMapMethod
is set to certificate.
In this case, the module performs a search under the
the base specified by
with scope as set by
for a user having a
userCertificate attribute with the same
certificate as the SSL client supplied.
+FakeBasicAuth is no longer
needed for certificate authentication.
The module finds the subject and issuer distinguished names from
the SSL context, there is no necessity to misuse a fake basic authentication
+FakeBasicAuth is specified, the basic authentication
will simply be overwritten wherever the module is active.
It is possible to request both basic authentication with
LDAP credentials and a certificate from a user, by setting
require group directive in the context of
mod_authz_ldap module asks to verify membership
of a user in a group defined in the LDAP directory. The group
must be of objectclass
groupOfNames, the members
must be defined in
member attributes, which have
distinguished names of users as values.
Groups are expected to have a distinguished name of the form
A user is accepted if the group has a
with current user's distinguished name as value.
This can be changed using the
If either directive is not configured, the require statement
must specify the full distinguished name of a group.
5. Configure Roles and Filters
Starting with release 0.14,
mod_authz_ldap can verify
roles of a user. In the most general form, a role is a required value
of an attribute of the user's node.
simply needs to know the name of the attribute, which can be
specified with the configuration directive
If this is set, you can include a directive
require role rolename
in the server configuration file, which will cause a user to be allowed only
if he has an attribute of name attrname with value rolename.
* is a valid value for the role name, this results
in the user being accepted if he simply has that attribute. This can
be used e.g. to accept all users that have a mailbox (if some attribute
contains the name of his mailbox). Substring matches are also possible,
on could accept a user exactly if she has a mailbox in a given domain,
if an attribute
mailboxhost contains the mailbox host.
A requirement for a role of the form
*.dom.ain will do the
This generality of the role mechanism can often save you from having to
extend the schema and define a special role attribute.
Even greater generality is offered by the
directive of the form
require filter [ SCOPE ] filter-expression
SCOPE must be one of the strings
If the word after
filter is not one of these strings,
it is assumed that the scope was not specified. In this case, the default
BASE will be used and the rest of the line is
used as a filter expression.
The requirement succeeds if the filter returns something, it fails if
nothing is returned by the filter, or if the filter causes an LDAP error.
The filter-expression does not need to be static, the module is
able to replace certain strings in the filter by information retrieved
from the request. The following replacements are currently implemented:
- a literal percent sign (%)
- The name of the file requested.
- the request method (GET, POST, ...), so that we can control via ldap
what types of request a user can perform.
- The name or IP address of the requesting client, as in the apache
access log (so only the address if client name lookup is disabled).
- the server name
- The current time in the format YYYYMMDDhhmmss
6. Configure Authorization based on File Ownership
In some applications, it is necessary to base authorization decisions on
Unfortunately, as the apache process runs with rather low privileges,
ordinary access control mechanisms are not suitable.
However, using the ``
require owner'' and
require group-owner'' directives, one can restrict access to
a file to the owner or members of the group of a file.
This model of course assumes Unix file permissions, and is inherently
This is why this functionality must be explicitely enabled using
--with-owner configuration flags.
7. Configure Password Expiration
For password aging,
mod_authz_ldap must have a way to
find out the last modification time of the password. The user entry
in the directory needs to have an attribute for that. With OpenLDAP,
lastmod on needs to be set in the
configuration file. The configuration directive
AuthzLDAPModifyKey must be specified as follows:
requireing a maximal age, only users that have modifed their
password recently enough will be accepted:
require age 3.5
This denies users access that have last changed their password more
than 3.5 days ago.
8. Proxy Authentication
The module can also be used for proxy authentication.
The module will normally recognize automatically whether proxy authentication
or normal authentication is in effect.
In cases where it may not be clear which kind of authentication
is happening, the the flag
must be set to
on for proxy authentication, and to
off for normal authentication.
One such case is a reverse proxy,
which works as a proxy, but authenticates as a server.
mod_authz_ldap module has its own log level, which is
set by default to LOG_DEBUG. If the log level of the server is set to
debug, all the information available from the module will
be logged to the error log. However, the log information flowing from
the module can be reduced by setting a different log level with the
AuthzLDAPLogLevel directive. Acceptable parameters are
the same as for the
When using certificate authentication
AuthzLDAPUseCertificate set to
the basic authentication header is no longer necesary.
However, some applications will still need a user name, which e.g. in
CGI-programms is read from the basic authentication header.
For these programs, the basic authentication header is overwritten
with the distinguished name of the owner of the certificate.
In some cases, e.g. in a reverse proxy authenticating with certificates,
the application may require an additional athentication.
This means that the basic authentication header may not be overwritten
mod_authz_ldap, which can be prevented with the
The default is on.
Two examples show how this module can be used to secure a web server
or reverse proxy.
This example describes how
mod_authz_ldap can be used to
authorize a user authenticated by an X.509 certificate.
The LDAP server in use is an OpenLDAP
server, for other servers, the preparatory steps (modification of the
shema, user and group definitions) may be different.
- Prepare the directory to store short forms of certificates of
a user. This involves adding suitable object types and attribute definitions
to your directory, as described in above.
Add nodes for the certificate mapping to the directory.
You may want to modify the script
the distribution for this purpose:
ldapadd -c -D cn=root,dc=othello,dc=ch -w secret <<EOF
issuerDN: /C=CH/ST=Schwyz/L=Altendorf/O=Othello/CN=Othello internal
subjectDN: /C=CH/ST=Schwyz/L=Altendorf/O=Othello/CN=Andreas Mueller
- Configure Apache to authenticate through a client certificate,
to map the certificate DN to a user node in the directory and to
authorize access to the directory
based on the group membership of the user:
One particularly usefull application of apache and its proxy module is
as a security gateway to an internal web server.
in conjunction with the above configuration lead to a secure proxy
gateway to some internal server. Here es an example configuration:
ProxyPass / http://intrahost.doma.in/
ProxyPassReverse / http://intrahost.doma.in/
This grants a user authenticated through an X.509 certificate and belonging
to the group
authz access to the web server on
intrahost.doma.in. Note that you cannot do without the
Since the module modifies the basic authentication headers of a request,
a call to the authentication function in a subrequest will find an already
transformed user name, which cannot be authenticated again.
The authentication function only performs authentication for the
initial request. As a consequence, if a subrequest leads to a
directory differently authenticated than the initial request,
the mapping for the subrequest may be incorrect.
However, the authorization is performed so differing
clauses for the subrequest are handled correctly.
In a large directory, authentication with mod_authz_ldap becomes
slow as soon as one of the searches performed is slow.
Indexes can improve the performance considerably, the following
table shows the attributes that need to be indexed for the various
parts of mod_authz_ldap
The module measures the elapsed and the cpu time for each request and logs
it in log level debug to the error log.
On a 233MHz Pentium, one can see that an
immeasurable amount of cpu time is spent in the module (hardly ever more than
the 10ms resolution).
The elapsed time depends very much on whether this is the first call
to the module: during the first call, an LDAP connection is established,
which makes take the module around 70ms if the LDAP server resides on
the same machine.
Subsequent calls to the authorization function usually take just above
1ms, but calls to the authentication function less than 1ms.
The performance hit by this module is therefore negligible: a simple
directory listing request on the same machine takes around 150ms
to complete, so the impact of the module is around 1%.
Even a somewhat dated Sun SPARCstation 10 spends only a few milliseconds
in the authentication function, the authorization function is even cheaper.
All this changes for worse if the LDAP server is overloaded or otherwise
slow. E. g. if the certificate issuer or subject attribute is not indexed,
the search for the owner of the certficate may well be slow.
mod_authz_ldap makes extensive use of
to log debug messages to the servers error log. All critical actions
are documented there, and all errors generate an error message.
The first step when debugging
mod_authz_ldap is therefore
to raise the server's log level to
If you cannot solve the problem from the debug output, you may send
a problem report to the author. Please equip the message with a succinct
Subject:-line, or it may get lost between the junk mail messages
(if your subject is ``Help'', it may well happen that the message
is not read at all).