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_HOSTandMAIL_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/
 - The admin can reset the password of users from this web interface: https://ldap.user1.fs.al/service/
 
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 
-Hspecifies the LDAP host (and protocol: ldap/ldaps). - The option 
-Dis like a username or an app ID (it is called "bind dn"). - The option 
-wis like a password or secret token (called "bind password"). - The option 
-bis 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=*)" "$@"
}
You can download this example with:
wget https://linux-cli.fs.al/apps/part5/user.sh