OUR SITES NetworkRADIUS FreeRADIUS

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 command line tool using the parameters from this module’s configuration.

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 xlat expanded.

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 the Password.Cleartext. This will consume the login grace, and verify user authorization.

  • The option set_auth_type was removed in v3.x.x.

  • Equivalent functionality can be achieved by adding the following stanza to the recv Access-Request {} section of your virtual server.

e.g:

ldap
if ((ok || updated) && &User-Password) {
	&control.Auth-Type := ldap
}

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 the access_attribute is present, or no and the access_attribute is absent then access will be allowed.

  • If yes, and the access_attribute is absent, or no and the access_attribute is present, then access will not be allowed.

  • If the value of the retrieved access_attribute is false, 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 or children.

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 memberOf attribute (or equivalent), then you will need to use the membership_filter option above instead. If you can’t see the memberOf attribute then it is also possible that the LDAP bind user does not have the correct permissions to view it.

cacheable_name

If cacheable_name or cacheable_dn are enabled, all group information for the user will be retrieved from the directory and written to LDAP-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 or LDAP-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 or LDAP-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 or children.

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: (:=, =`, `-=`, `+). Note: = is not supported.

<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.

Post-Auth can modify LDAP objects too

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 is yes then, when a referral is followed having rebind set to no will cause the server to do an anonymous bind when making any additional connections. Setting this to yes will either bind with the admin credentials or the credentials from the rebind url depending on use_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 include draft-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.

Example
&my-string := "ldap:///ou=profiles,dc=example,dc=com??sub?(objectClass=radiusprofile)"
&reply.Reply-Message := "The LDAP url is %ldap.uri.escape(%{my-string}}"
Output
"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.

Example
&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.

Example
&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})"
Output
"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
	}
}