LDAP (Lightweight Directory Access Protocol) Module
The ldap
module allows LDAP directory entries to be retrieved, modified,
inserted and deleted.
May also perform user authentication using LDAP binds, or by retrieving
the contents of a password attribute for later comparison by a module such
as pap , or an eap method.
|
Please see the file global.d/ldap
for server-global configuration items
which control LDAP library debugging.
Configuration Settings
- ldap { … }
- server
-
Note that this needs to match the name(s) in the LDAP server certificate, if you’re using ldaps. See OpenLDAP documentation for the behavioral semantics of specifying more than one host.
Depending on the libldap
in use, server may be specified as an LDAP
URI. In the case of OpenLDAP
this allows the following
additional schemes:
Scheme | Description |
---|---|
ldaps:// |
(LDAP over SSL) |
ldapi:// |
(LDAP over Unix socket) |
ldapc:// |
(Connectionless LDAP) |
- port
-
Port to connect on, defaults to 389, will be ignored for LDAP URIs.
- identity
-
Administrator account for searching and possibly modifying.
If using SASL + (KRB5 | EXTERNAL) identity should be commented out as it will set an authzid, which is likely not what you want. |
- password
-
Password for the
identity
account. - base_dn
-
Unless overridden in another section, the dn from which all searches will start from.
You can run the ldapsearch -D ${identity} -w ${password} -h ${server} -b 'CN=user,${base_dn}' That will give you the LDAP information for 'user'. Group membership can be queried by using the above "ldapsearch" string, and adding "memberof" qualifiers. For ActiveDirectory, use: ldapsearch ... '(&(objectClass=user)(sAMAccountName=user)(memberof=CN=group,${base_dn}))' Where 'user' is the user as above, and 'group' is the group you are querying for. |
SASL parameters to use for admin binds
- sasl { … }
-
When we’re prompted by the SASL library, the config items in the SASL section (in addition to the identity password config items above) determine the responses given.
If any directive is commented out, a NULL response will be provided to cyrus-sasl.
Unfortunately the only way to control Keberos here is through environmental variables, as cyrus-sasl provides no API to set the kerberos (libkrb5) config directly.
Full documentation for MIT krb5 can be found at http://web.mit.edu/kerberos/krb5-devel/doc/admin/env_variables.html
At a minimum you probably want to set KRB5_CLIENT_KTNAME
.
- mech
-
SASL mechanism.
- proxy
-
SASL authorisation identity to proxy.
- realm
-
SASL realm. Used for kerberos.
Generic valuepair attribute
If set, this will attribute will be retrieved in addition to any mapped attributes.
Values should be in the format:
<fr attr> <op> <value>
Where:
Parameter | Description |
---|---|
<fr attr> |
Is the attribute you wish to create, with any valid list and request qualifiers. |
<op> |
Is any assignment operator ( |
<value> |
Is the value to parse into the new attribute. If the value is wrapped in double quotes it will be xlat expanded. |
Mapping of LDAP directory attributes to RADIUS dictionary attributes.
Although this format is almost identical to the unlang
update section format, it does NOT mean that you can use other
unlang constructs in module configuration files.
|
Configuration items are in the format:
<fr attr> <op> <ldap attr>
Where:
Parameter | Description |
---|---|
<fr attr> |
Is the destination RADIUS attribute with any valid list and request qualifiers. |
<op> |
Is any assignment attribute (=, :=, +=, -=). |
<ldap attr> |
Is the attribute associated with user or
profile objects in the LDAP directory.
If the attribute name is wrapped in double quotes
it will be |
Request and list qualifiers may be placed after the update
section name to set default destination requests/lists
for <fr attr>s
with no list qualifiers.
These attribute maps are applied before any profiles, meaning that the values here can be referenced in profiles using expansions.
LDAP attribute names should be single quoted unless you want the name to be derived from an xlat expansion, or an attribute ref. |
- update { … }
-
NOTE: Where only a list is specified as the RADIUS attribute, the value of the LDAP attribute is parsed as a valuepair in the same format as the 'valuepair_attribute' (above).
- edir
-
Set to
yes
if you have eDirectory and want to use the universal password mechanism. - edir_autz
-
Set to
yes
if you want to bind as the user after retrieving thePassword.Cleartext
. This will consume the login grace, and verify user authorization.
e.g:
|
User object Identification
- base_dn
-
Where to start searching in the tree for users.
- filter
-
Filter for user objects, should be specific enough to identify a single user object.
For Active Directory nested group, you should comment out the previous 'filter = …' and use the below. Where 'group' is the group you are querying for.
The string '1.2.840.113556.1.4.1941' specifies LDAP_MATCHING_RULE_IN_CHAIN. This applies only to DN attributes. This is an extended match operator that walks the chain of ancestry in objects all the way to the root until it finds a match. This reveals group nesting. It is available only on domain controllers with Windows Server 2003 SP2 or Windows Server 2008 (or above). |
- sasl { … }
-
SASL parameters to use for user binds
When we’re prompted by the SASL library, these control the responses given.
Any of the config items below may be an attribute ref or and expansion. This allows different SASL mechs, proxy IDs and realms to be used for different users. |
- mech
-
SASL mechanism.
- authname
-
SASL authentication name. Mechanism specific value to use when prompted for the client authentication name.
- proxy
-
SASL authorisation identity to proxy.
- realm
-
SASL realm. Used for kerberos.
- password_attribute
-
Which attribute in the request should be used as the password when performing user binds.
Note that Active Directory will allow unauthenticated user binds by default!
You can fix this by choosing the "ADSI Edit" command from the Server Manager’s Tools menu.
Then, open the Configuration subtree, and then open the properties of the CN=Directory
Service, CN=Windows NT, CN=Services, CN=Configuration
object. Modify the
msDS-Other-Settings
attribute, and add a new entry for DenyUnauthenticatedBind=1
.
- scope
-
Search scope, may be
base
,one
,sub' or `children
. - sort_by
-
Server side result sorting.
A list of space delimited attributes to order the result set by.
-
If the filter matches multiple objects only the first result will be processed.
-
If the attribute name is prefixed with a hyphen '-' the sorting order will be reversed for that attribute.
-
If
sort_by
is set, and the server does not support sorting the search will fail. -
If a search returns multiple user objects and
sort_by
is not set, the search will fail.- access_attribute
-
If this is undefined, anyone is authorised.
If it is defined, the contents of this attribute determine whether or not the user is authorised.
- access_positive
-
Control whether the presence of
access_attribute
allows access, or denies access.-
If
yes
, and theaccess_attribute
is present, orno
and theaccess_attribute
is absent then access will be allowed. -
If
yes
, and theaccess_attribute
is absent, orno
and theaccess_attribute
is present, then access will not be allowed. -
If the value of the retrieved
access_attribute
isfalse
, it will negate the result.
-
e.g:
access_positive = yes access_attribute = userAccessAllowed
With an LDAP object containing:
userAccessAllowed: false
Will result in the user being locked out.
- access_value_negate
-
Which value we look for in access_attribute to indicate that we should negate the result.
- access_value_suspend
-
Which value we look for in access_attribute to indicate that the user should be suspended.
- expect_password
-
When set to no, disable warnings for missing password attributes in user objects returned from LDAP. This is useful for ISP environments where some subscribers have passwords set, and others do not (e.g. mixed IPoE and PPPoE).
User membership checking
- base_dn
-
Where to start searching in the tree for groups.
- filter
-
Filter for group objects, should match all available group objects a user might be a member of.
If using Active Directory you are likely to need group
instead of posixGroup
.
- scope
-
Search scope, may be
base
,one
,sub
orchildren
. - name_attribute
-
Attribute that uniquely identifies a group.
Is used when converting group DNs to group names.
- membership_filter
-
Filter to find all group objects a user is a member of.
That is, group objects with attributes that identify
members (the inverse of membership_attribute
).
- membership_attribute
-
The attribute, in user objects, which contain the names or DNs of groups a user is a member of.
Unless a conversion between group name and group DN is needed, there’s no requirement for the group objects referenced to actually exist.
If the LDAP server does not support the |
- cacheable_name
-
If
cacheable_name
orcacheable_dn
are enabled, all group information for the user will be retrieved from the directory and written toLDAP-Group
attributes appropriate for the instance of rlm_ldap.
For group comparisons these attributes will be checked instead of querying the LDAP directory directly.
This feature is intended to be used with rlm_cache
, but may also be useful
if all group values need to be processed using unlang
policies.
If you wish to use this feature, you should enable the type that matches the format of your check items.
i.e. if your groups are specified as DNs then enable cacheable_dn
else enable cacheable_name
.
- cacheable_dn
-
See
cacheable_name
for more details. - cache_attribute
-
Override the normal cache attribute (
<inst>-LDAP-Group
orLDAP-Group
if using the default instance) and create a custom attribute.
This can help if multiple module instances are used in fail-over.
- allow_dangling_group_ref
-
If the group being checked is specified as a name, but the user’s groups are referenced by DN, and one of those group DNs is invalid, the whole group check is treated as invalid, and a negative result will be returned.
When set to yes
, this option ignores invalid DN references.
- group_attribute
-
Override the normal group comparison attribute name
(<inst>-Group
orLDAP-Group
if using the default instance). - skip_on_suspend
-
Don’t process user groups if the user has been suspended. If set to 'no', groups will still be processed.
Groups are never processed for disabled users.
Defaults to 'yes'.
User profiles
RADIUS profile objects contain sets of attributes to insert into the request. These attributes are mapped using the same mapping scheme applied to user objects (the update section above).
- filter
-
Filter for RADIUS profile objects.
- scope
-
Search scope, may be
base
,one
,sub
orchildren
.
Should usually be left as "base", to retrieve the specific profile specified by 'default' or in the user or group objects.
- default
-
The default profile. This may be a DN or an attribute reference.
To get old v2.2.x style behaviour, or to use the &User-Profile attribute
to specify the default profile, set this to &control.User-Profile .
|
- attribute
-
The LDAP attribute containing profile DNs to apply in addition to the default profile above.
These are retrieved from the user object, at the same time as the attributes from the update section, are are applied if authorization is successful.
attribute_suspend: The LDAP attribute containing profile DNs to apply in addition to the default profile above, when the user account is in the suspended state
These are retrieved from the user object, at the same time as the attributes from the update section, are are applied if authorization is successful.
Modify user object on receiving Accounting-Request
Useful for recording things like the last time the user logged
in, or the Acct-Session-ID
for CoA/DM.
LDAP modification items are in the format:
<ldap attr> <op> <value>
Where:
Parameter | Description |
---|---|
<ldap attr> |
The LDAP attribute to add modify or delete. |
<op> |
One of the assignment operators: ( |
<value> |
The value to add modify or delete. |
If using the := operator with a multi-valued LDAP
attribute, all instances of the attribute will be removed and
replaced with a single attribute.
|
LDAP connection-specific options
These options set timeouts, keep-alives, etc. for the connections.
- dereference
-
Control under which situations aliases are followed.
May be one of 'never', 'searching', 'finding' or 'always'
default: libldap’s default which is usually 'never'.
LDAP_OPT_DEREF is set to this value.
|
- chase_referrals
-
controls whether the server follows references returned by the LDAP directory.
They are mostly for Active Directory compatibility.
If you set this to no
, then searches will likely return 'operations error',
instead of a useful result.
- rebind
-
If
chase_referrals
isyes
then, when a referral is followed havingrebind
set tono
will cause the server to do an anonymous bind when making any additional connections. Setting this toyes
will either bind with the admin credentials or the credentials from the rebind url depending onuse_referral_credentials
. - use_referral_credentials
-
On
rebind
, use the credentials from the rebind url instead of admin credentials used during the initial bind.
Default no
- session_tracking
-
If
yes
, then includedraft-wahl-ldap-session
tracking controls.
If yes, encodes NAS-IP-Address
, NAS-IPv6-Address
, User-Name
, Acct-Session-Id
,
Acct-Multi-Session-Id
as session tracking controls in applicable LDAP operations.
Default no
- sasl_secprops
-
SASL Security Properties (see SASL_SECPROPS in ldap.conf man page).
uncomment when using GSS-API sasl mechanism along with TLS encryption against Active-Directory LDAP servers (this disables sealing and signing at the GSS level as required by AD). |
- res_timeout
-
Seconds to wait for LDAP query to finish.
Default: 20
- srv_timelimit
-
Seconds LDAP server has to process the query (server-side time limit).
Default: 20
LDAP_OPT_TIMELIMIT is set to this value.
|
- idle
-
Set the number of seconds a connection needs to remain idle before TCP starts sending keepalive probes.
LDAP_OPT_X_KEEPALIVE_IDLE is set to this value.
|
- probes
-
Set the maximum number of keepalive probes TCP should send before dropping the connection.
LDAP_OPT_X_KEEPALIVE_PROBES is set to this value.
|
- interval
-
Set the interval in seconds between individual keepalive probes.
LDAP_OPT_X_KEEPALIVE_INTERVAL is set to this value.
|
- net_timeout
-
Sets the timeout for establishing connections.
LDAP_OPT_NETWORK_TIMEOUT is set to this value.
|
- reconnection_delay
-
Sets the time in seconds before a failed connection will attempt reconnection. This includes failures to bind as the admin user due to incorrect credentials.
TLS encrypted connections
This subsection configures the tls
related items that control how FreeRADIUS
connects to an LDAP server. It contains all of the tls_*
configuration entries
used in older versions of FreeRADIUS.
Those configuration entries can still be used, but we recommend using these.
- start_tls
-
Set this to
yes
to use TLS encrypted connections to the LDAP database by using the StartTLS extended operation.
The StartTLS operation is supposed to be used with normal ldap connections instead of using ldaps (port 636) connections
If start_tls = yes , then fill up those such options with the certificate information.
|
- require_cert
-
Certificate Verification requirements.
May be one of:
Option | Description |
---|---|
'never' |
do not even bother trying. |
'allow' |
try, but don’t fail if the certificate cannot be verified. |
'demand' |
fail if the certificate does not verify. |
'hard' |
similar to 'demand' but fails if TLS cannot negotiate. |
The default is libldap’s default, which varies based on the contents of ldap.conf .
|
Minimum TLS version to accept. We STRONGLY recommend setting this to "1.2"
Connection Pool
The connection pool is a set of per-thread parameters for connections to the LDAP server.
This connection pool is used for LDAP queries run as the administrative user.
All LDAP operations are performed asynchronously, meaning that many queries can be active on a single connection simultaneously.
- start
-
Connections to create during module instantiation.
If the server cannot create specified number of connections
during instantiation it will exit.
Set to 0
to allow the server to start without the directory
being available.
- min
-
Minimum number of connections to keep open.
- max
-
Maximum number of connections.
If these connections are all fully in use (refer to per_connection_max below) and a new one is requested, the request will NOT get a connection.
- connecting
-
Number of connections which can be starting at once
Used to throttle connection spawning.
- uses
-
Number of uses before the connection is closed.
A setting of 0 means infinite (no limit).
|
- lifetime
-
The lifetime (in seconds) of the connection.
- open_delay
-
Open delay (in seconds).
How long must we be above the target utilisation for connections to be opened.
- close_delay
-
Close delay (in seconds).
How long we must be below the target utilisation for connections to be closed
- manage_interval
-
How often to manage the connection pool.
- request
-
Options specific to requests handled by this connection pool
- per_connection_max
-
Maximum number of active queries there can be on a single connection.
- per_connection_target
-
Target number of active queries on a single connection.
- free_delay
-
How long must a request in the unassigned (free) list not have been used for before it’s cleaned up and actually freed.
Unassigned requests can be re-used, multiple times, reducing memory allocation and freeing overheads.
Bind Connection Pool
This connection pool is used for LDAP binds used to authenticate requests when calling the ldap module in authenticate context. If passwords are retrieved from the ldap directory and FreeRADIUS performs the authentication then this is not used.
The options are essentially identical to the pool section above with certain
limitations. Since only one bind operation can be in progress on a connection at
a time, per_connection_max
and per_connection_target
are always set to 1.
This limitation means that max
represents the maximum number of in progress
binds which there can be on a single thread.
Expansions
The rlm_ldap provides the below xlat’s functions.
%ldap.uri.escape(…}
Escape a string for use in an LDAP filter or DN. The value will then be marked as safe for use in LDAP URIs and DNs, and will not be escaped or modified.
&my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
&reply.Reply-Message := "The LDAP url is %ldap.uri.escape(%{my-string}}"
"The LDAP url is ldap:///ou=profiles,dc=example,dc=com??sub?\28objectClass=radiusprofile\29"
%ldap.uri.safe(…}
Mark a string as safe for use in an LDAP filter or DN. Values marked as safe for use in LDAP URIs will not be escaped or modified, and will be allowed in places where dynamic values are usually prohibited.
&my-int := "%ldap.profile(ldap://%ldap.uri.safe(%{LDAP-Host}):%ldap.uri.safe(%{LDAP-Port})/ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
%ldap.uri.unescape(…)
Unescape a string for use in an LDAP filter or DN.
&my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?\28objectClass=radiusprofile\29"
&reply.Reply-Message := "The LDAP url is %ldap.uri.unescape(%{my-string})"
"The LDAP url is ldap:///ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
Default Configuration
ldap {
server = 'localhost'
# server = 'ldap.rrdns.example.org'
# server = 'ldap.rrdns.example.org'
# port = 389
# identity = 'cn=admin,dc=example,dc=org'
# password = mypass
base_dn = 'dc=example,dc=org'
sasl {
# mech = 'PLAIN'
# proxy = 'autz_id'
# realm = 'example.org'
}
# valuepair_attribute = 'radiusAttribute'
update {
&control.Password.With-Header += 'userPassword'
# &control.Password.NT := 'ntPassword'
# &reply.Reply-Message := 'radiusReplyMessage'
# &reply.Tunnel-Type := 'radiusTunnelType'
# &reply.Tunnel-Medium-Type := 'radiusTunnelMediumType'
# &reply.Tunnel-Private-Group-ID := 'radiusTunnelPrivategroupId'
&control += 'radiusControlAttribute'
&request += 'radiusRequestAttribute'
&reply += 'radiusReplyAttribute'
}
# edir = no
# edir_autz = no
user {
base_dn = "${..base_dn}"
filter = "(uid=%{&Stripped-User-Name || &User-Name})"
# filter = "(&(objectClass=user)(sAMAccountName=%{&Stripped-User-Name || &User-Name})(memberOf:1.2.840.113556.1.4.1941:=cn=group,${..base_dn}))"
sasl {
# mech = 'PLAIN'
# authname = &User-Name
# proxy = &User-Name
# realm = 'example.org'
}
# password_attribute = &User-Password
# scope = 'sub'
# sort_by = '-uid'
# access_attribute = 'dialupAccess'
# access_positive = yes
# access_value_negate = 'false'
# access_value_suspend = 'suspended'
# expect_password = no
}
group {
base_dn = "${..base_dn}"
filter = '(objectClass=posixGroup)'
# scope = 'sub'
# name_attribute = cn
# membership_filter = "(|(member=%{control.Ldap-UserDn})(memberUid=%{&Stripped-User-Name || &User-Name}))"
membership_attribute = 'memberOf'
# cacheable_name = 'no'
# cacheable_dn = 'no'
# cache_attribute = 'LDAP-Cached-Membership'
# allow_dangling_group_ref = 'no'
group_attribute = "${..:instance}-Group"
skip_on_suspend = 'yes'
}
profile {
# filter = '(objectclass=radiusprofile)'
# scope = 'base'
# default = 'cn=radprofile,dc=example,dc=org'
# attribute = 'radiusProfileDn'
# attribute_suspend = 'radiusProfileDn'
}
accounting {
reference = "%tolower(type.%{Acct-Status-Type})"
type {
start {
update {
description := "Online at %S"
}
}
interim-update {
update {
description := "Last seen at %S"
}
}
stop {
update {
description := "Offline at %S"
}
}
}
}
post-auth {
update {
description := "Authenticated at %S"
}
}
options {
# dereference = 'always'
chase_referrals = yes
rebind = yes
use_referral_credentials = no
# session_tracking = yes
# sasl_secprops = 'noanonymous,noplain,maxssf=0'
res_timeout = 10
srv_timelimit = 3
idle = 60
probes = 3
interval = 3
net_timeout = 10
reconnection_delay = 10
}
tls {
# start_tls = yes
# ca_file = ${certdir}/cacert.pem
# ca_path = ${certdir}
# certificate_file = /path/to/radius.crt
# private_key_file = /path/to/radius.key
# random_file = /dev/urandom
# require_cert = 'demand'
# tls_min_version = "1.2"
}
pool {
start = 0
min = 1
max = 5
connecting = 2
uses = 0
lifetime = 0
# open_delay = 0.2
# close_delay = 10
# manage_interval = 0.2
request {
# per_connection_max = 2000
# per_connection_target = 1000
# free_delay = 10
}
}
bind_pool {
start = 0
min = 1
max = 1000
}
}