OpenLDAP
This app provides LDAP authentication for other applications. It also has a web interface that allows users to change or recover their password. For each user it basically keeps a username, password and email address. However it is possible to customize it in order to store other fields as well (for each user), according to the needs of applications.
1. Installation
-
Get the scripts and initialize a directory:
ds pull openldap
ds init openldap @ldap.user1.fs.al
cd /var/ds/ldap.user1.fs.al -
Customize and build the container:
nano settings.sh
ds makeLet's comment out (or delete)
PORTS
, since we don't want it to be accessed from the internet (it will be used only internally). Let's also changeLDAP_ADMIN_PASSWORD
,SMTP_HOST
andMAIL_FROM
. -
Check the container:
ls
ds shell
hostname
ps ax
systemctl status slapd
slapcat
apt install less
slapcat -n0 | less
ds exit
2. Usage
2.1 Organization units (OU)
Organizational units are like subdirectories (or main branches) from the root.
Add organizational units (under the root of DIT):
ds ou
ds ou add users
ds ou add groups
ds ou add apps
ds ou ls
2.2 Manage users
ds user
ds user add \
users \
test1 \
test1@user1.fs.al \
pass123
ds user add \
users \
test2 \
test2@user1.fs.al \
# no password
ds set-passwd \
pass234 \
uid=test2,ou=users,dc=user1,dc=fs,dc=al
ds user ls
ds user del users test1
ds user ls
The users that are created with ds user add
have a minimal data
structure, as seen on the examples above. This is usually sufficient
for authentication purposes. But if we have to customize it, we can
make a local copy of cmd/user.sh
and modify it as needed.
The users can change or recover their password with a web interface: https://ldap.user1.fs.al/
2.3 App credentials
ds app
ds app add test1 pass123
ds app add mail1 pass234
ds app add nc1 pass345
ds app ls
ds app del test1
ds app ls
These app credentials look like
cn=test1,ou=apps,dc=user1,dc=fs,dc=al
and they have read-only access
to the data. On the other hand, the normal users can authenticate with
their own password, and change their own password, and nothing else.
Let's check that we are able to read data from the LDAP server, using
the credetials of cn=mail1,ou=apps,dc=user1,dc=fs,dc=al
:
apt install ldap-utils
ds app ls
ds user ls
ldapsearch -xLLL \
-H ldap://ldap.user1.fs.al/ \
-D cn=mail1,ou=apps,dc=user1,dc=fs,dc=al \
-w pass234 \
-b ou=users,dc=user1,dc=fs,dc=al \
"(uid=test2)"
- The option
-H
specifies the LDAP host (and protocol: ldap/ldaps). - The option
-D
is like a username or an app ID (it is called "bind dn"). - The option
-w
is like a password or secret token (called "bind password"). - The option
-b
is the branch of the directory where the searching starts (called "base dn" or "search base"). - The last argument is the LDAP filter used for searching.
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
If you get an error message like this, then uncomment
PORTS="389:389"
on settings.sh
and remake the container with ds make
.
Try the same command with -D cn=mail2,ou=apps,dc=user1,dc=fs,dc=al
(where app mail2
does not exist), and with a filter "(uid=test1)"
(where uid test1
does not exist).
With the option -ZZ
we can request a TLS connection, which is
better than a plain text connection for security reasons:
ldapsearch -xLLL -ZZ \
-H ldap://ldap.user1.fs.al/ \
-D cn=mail1,ou=apps,dc=user1,dc=fs,dc=al \
-w pass234 \
-b ou=users,dc=user1,dc=fs,dc=al \
"(uid=test2)" \
uid mail
The arguments after the filter (uid
and email
) are the list of
attributes to show.
If there is any problem, add the option -d9
for debugging.
2.4 Modify
Let's say that we want to make some modifications to the data. For
example change the email of a user. There is no special command for
this case (like ds ou
, ds user
and ds app
), but we can use the
generic command cmd/modify.sh
:
ds modify --help
cat <<EOF > modify-test2-email.ldif
dn: uid=test2,ou=users,dc=user1,dc=fs,dc=al
changetype: modify
replace: mail
mail: xyz@user1.fs.al
EOF
nano modify-test2-email.ldif
ds user ls
ds modify modify-test2-email.ldif
ds user ls
Let's restore back the email:
nano modify-test2-email.ldif
cat modify-test2-email.ldif
cat modify-test2-email.ldif | ds modify
cat <<EOF | ds modify
dn: uid=test2,ou=users,dc=user1,dc=fs,dc=al
changetype: modify
replace: mail
mail: test2@user1.fs.al
EOF
ds user ls
The format of input is LDIF, and it can be used for all kinds of modifications in the database.
By the way, the commands ds ou
, ds user
and ds app
, under the
hood use ds modify
.
2.5 Search
ds user add users test1 test1@user1.fs.al pass123
ds user ls
ds search | less
ds search "(uid=test*)"
ds search "(uid=test*)" dn
ds search "(uid=test*)" cn mail
ds search "(mail=*@user1.fs.al)" mail
ds search "(mail=*.fs.al)" mail | grep 'mail:'
ds search "(objectClass=inetOrgPerson)"
ds search "(&(objectClass=inetOrgPerson)(uid=test2))"
ds search "(objectClass=organizationalUnit)"
ds search "(objectClass=organizationalRole)"
The first argument is an LDAP filter.
2.6 Backup and restore
ds backup
tar tvfz backup-*.tgz
ds restore backup-*.tgz
3. Customize
The command ds user add
assumes a very basic (minimalist) data
structure for each user, with a uid
, mail
, and userPassword
,
which looks like this:
dn: uid=test1,ou=users,dc=user1,dc=fs,dc=al
uid: test1
objectClass: top
objectClass: inetOrgPerson
sn: test1
cn: test1
mail: test1@user1.fs.al
userPassword:: e1NTSEF9T2NlUExtSUIvQjF6SE51cVQ3WlFCaTNISFEvanJhUSs=
This is usually sufficient for authentication purposes (for example
using uid
or mail
as username).
Sometimes we may need to store more data for each user. For example,
let's say that we want to store the first name of the user in the
cn:
attribute, and store the last name on the sn:
attribute.
In this case, we can modify the behavior of the command ds user
by
creating a local copy of cmd/user.sh
, which will override the app
copy:
cd /var/ds/ldap.user1.fs.al/
mkdir -p cmd/
cp /opt/docker-scripts/openldap/cmd/user.sh cmd/
nano cmd/user.sh
cmd/user.sh
For storing the first name and last name, the modified local copy of the script might look like this:
cmd_user_help() {
cat <<_EOF
user add <ou> <uid> <mail> <first-name> <last-name> [<passwd>]
user del <ou> <uid>
user (list | ls) [...]
_EOF
}
cmd_user() {
local cmd=$1 ; shift
case $cmd in
add|del)
_user$cmd "$@"
;;
list|ls)
_user_ls "$@"
;;
)
fail "Usage:\n$(cmd_user_help)\n"
;;
esac
}
_user_add() {
local ou=$1 uid=$2 mail=$3 first_name=$4 last_name=$5 passwd=$6
[[ -n $ou && -n $uid && -n $mail && -n $first_name && -n $last_name ]] \
|| fail "Usage:\n$(cmd_user_help)\n"
cat <<EOF | ds modify
dn: uid=$uid,ou=$ou,$(get_root_of_dit)
changetype: add
uid: $uid
objectClass: top
objectClass: inetOrgPerson
sn: $last_name
cn: $first_name
mail: $mail
EOF
[[ -n $passwd ]] && \
ds set-passwd $passwd "uid=$uid,ou=$ou,$(get_root_of_dit)"
}
_user_del() {
local ou=$1 uid=$2
[[ -n $ou && -n $uid ]] \
|| fail "Usage:\n$(cmd_user_help)\n"
cat <<EOF | ds modify
dn: uid=$uid,ou=$ou,$(get_root_of_dit)
changetype: delete
EOF
}
_user_ls() {
ds search "(uid=)" "$@"
}