= Using OpenLDAP in a docker container

== Bootstrap

https://github.com/osixia[Osixia!] provides a
https://github.com/osixia/docker-openldap[fully functionally OpenLDAP container]
which can be instantiated using the docker invocation below.

This docker invocation also sets up a readonly user, and loads the custom
FreeRADIUS schemas required for RADIUS to LDAP attribute mapping, dynamic client
definitions, and attribute profiles.

=== Define site specific variables
Change the values here to match local paths and your site specific
configuration.

[source,shell]
----
# Where to store a temporary shallow clone of the FreeRADIUS source
# Or the path to an existing copy of the FreeRADIUS source
FREERADIUS_SRC="/tmp/freeradius-src"

# Base DN
LDAP_BASE_DN="dc=example,dc=com"

# Domain
LDAP_DOMAIN="example.com"

# DN Suffix
LDAP_BASE_DN="dc=example,dc=com"

# Password for the administrative user
LDAP_ADMIN_PASSWORD="secret"

# Password for the read only user
LDAP_READONLY_PASSWORD="readonly"
----

=== Instantiate an OpenLDAP docker container

[source,shell]
----
if [ ! -d "${FREERADIUS_SRC}" ]; then
	git clone --depth 1 https://github.com/FreeRADIUS/freeradius-server.git "${FREERADIUS_SRC}"
fi
docker run -it --rm -p 389:389 \
	--env LDAP_DOMAIN=${LDAP_DOMAIN} \
	--env LDAP_ADMIN_PASSWORD=${LDAP_ADMIN_PASSWORD} \
	--env LDAP_READONLY_USER=true \
	--env LDAP_READONLY_USER_PASSWORD=${LDAP_READONLY_PASSWORD} \
	--volume "${FREERADIUS_SRC}/doc/schemas/ldap/openldap/freeradius-policy.schema:/container/service/slapd/assets/config/bootstrap/schema/mmc/freeradius-policy.schema:ro" \
	--volume "${FREERADIUS_SRC}/doc/schemas/ldap/openldap/freeradius-radius.schema:/container/service/slapd/assets/config/bootstrap/schema/mmc/freeradius-radius.schema:ro" \
	--volume "${FREERADIUS_SRC}/doc/schemas/ldap/openldap/freeradius-clients.schema:/container/service/slapd/assets/config/bootstrap/schema/mmc/freeradius-clients.schema:ro" \
	osixia/openldap:1.2.5 --copy-service
----

== Populate with test data
Once docker is running, there should now be an LDAP server running on
`localhost`, it can now be populated with test data.

For test data we will be using the object definitions from the LDAP
module's CIT (Continuous Integration Testing) script.

These object definitions have been designed to exercise all features
of the FreeRADIUS LDAP module.

[source,shell]
----
sed -e '1,/^description:/ d' "${FREERADIUS_SRC}/src/tests/modules/ldap/example.com.ldif" \
    | ldapadd -H ldap://localhost -x -D cn=admin,${LDAP_BASE_DN} -w admin
----

There should be no errors, and the console with the running LDAP
server should show requests being handled.

If the LDAP server server is stopped, as with `CTRL-C`, then the database
contents will be lost.  All of the steps above will have to be re-done the next
time the server is started.

In order to make the LDAP database persistent, see the
https://github.com/osixia/docker-openldap[osixia/openldap
instructions].

== Check it works

As a final step you should verify that test data has been loaded correctly.
This can be done using the `ldapsearch` utility using the LDAP read only user.

The command below will retrieve the entry for one of the test `freeradiusClient`
entries. You should see a single search result returned if everything worked
correctly.

[source,shell]
----
ldapsearch -LLL -H ldap://localhost -x -D cn=readonly,<base_dn> -w <readonly_password> -b <base_dn> '(&(objectClass=freeradiusClient)(freeradiusClientShortname=client2))'
----

.Searching for a RADIUS Client
====
[source,shell]
----
ldapsearch -LLL -H ldap://localhost -x -D cn=readonly,dc=example,dc=com -w readonly -b dc=example,dc=com '(&(objectClass=freeradiusClient)(freeradiusClientShortname=client2))'
----

.Expected output
[source,ldif]
----
dn: freeradiusClientIdentifier=2.2.2.2,ou=clients,dc=example,dc=com
objectClass: freeradiusClient
objectClass: radiusClient
freeradiusClientIdentifier: 2.2.2.2
freeradiusClientShortname: client2
freeradiusClientType: cisco
freeradiusClientComment: Another test client
radiusClientSecret: 123secret
radiusClientRequireMa: TRUE
----
====
