Configure Time-Based One-Time Passwords ((T)OTP)
Learn how to set up and use Time-Based One-Time Passwords (TOTP) to enhance the security of your accounts and protect against unauthorized access.
Table of Contents
Passwords, everyone loves to hate them and still, in the era of digital certificates, fingerprints, and voice recognition, we use them on a daily basis and want users to memorize tens of different complex passwords. So they cheat and passwords get reused, written down on a piece of paper, you name it. Not that producers always get this right either. And any time we use a password, we run the risk of it being intercepted, and at that point it's no longer secret and needs to be changed.
Still, passwords have one important advantage over most other forms of authentication: as a simple string they can be used anywhere. Everyone understands a login prompt and it tends to be rather hard to make anything else work for everyone.
One-time passwords represent a modest improvement being relatively unobtrusive for the user while anyone who sees the password should be unable to do anything with it. The user has little extra work to do, and chances are they already carry a smartphone with them. But how do we get existing applications to support them without extensive modification?
For applications that use OpenLDAP for authentication, the answer is easy: turn on time-based one-time password (TOTP) authentication.
Symas OpenLDAP now includes an overlay that lets any application that authenticates through LDAP to work with time-based one-time passwords (https://tools.ietf.org/html/rfc6238).
How TOTP Works
TOTP uses a secret key that's stored in an LDAP user's entry and is also shared with the user on the client side. When user authentication is needed, an application on the client side combines the secret key with the current time to generate a time-limited code (usually 30 seconds). The code is a number, usually six digits in length. The client appends this code to their regular password when an authentication request is sent to the server. When the server receives the authentication request, it uses the secret key stored on the entry and the current time to try to recreate the provided code. If the server is able to recreate the provided code and the regular password matches, the user is authenticated.
The secret key is a randomly generated 20 byte string. The key is stored in the LDAP user's entry as a base64 encoded string and is shared with the user as a base32 encoded string.
TOTP Configuration
Configuration is handled in three areas:
- The slapd configuration
- Parameter entries
- User entries
The slapd Configuration
Module Loading
If using slapd.conf, add “moduleload otp.la” below the “modulepath” directive:
# Module Configuration
modulepath /opt/symas/lib/slapd
moduleload otp.la
If using cn=config, add an olcModuleLoad for OTP to the “cn=module{0},cn=config” configuration entry:
# cn=config Module Configuration
dn: cn=module{0},cn=config
olcModulePath: /opt/symas/lib/openldap
olcModuleLoad: otp.la
Overlay Configuration
If using slapd.conf, add the overlay to the main mdb database configuration block. Place the configuration AFTER the syncprov overlay if it's in use:
# MDB Database Configuration
database mdb
suffix "dc=example,dc=com"
...
overlay otp
If using cn=config, add the overlay entry as a child of the main database configuration. Place the configuration AFTER the syncprov overlay if it's in use:
# Main database configuration
dn: olcDatabase={1}mdb,cn=config
...
dn: olcOverlay={0}otp,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
olcOverlay: {0}otp
TOTP Parameter Configuration
For the server to successfully reproduce the temporary code provided in an authorization request, three parameters are required:
- oathHMACAlgorithm - This is the hashing algorithm used for generating the one-time password. The value must be OID of a supported hashing algorithm:
1.2.840.113549.2.7 (HMAC-SHA1)
1.2.840.113549.2.8 (HMAC-SHA224)
1.2.840.113549.2.9 (HMAC-SHA226)
1.2.840.113549.2.10 (HMAC-SHA384)
1.2.840.113549.2.11 (HMAC-SHA512)
- oathOTPLength - The length of the one-time password. This is normally 6.
- oathTOTPTimeStepPeriod - The length of time that the one-time password is valid. This is normally 30 seconds
Optional:
- oathTOTPTimeStepWindow - The number of time periods around the current time to try when checking the password provided by the user.
While TOTP parameters may be set on individual user entries, the best practice is to create separate TOTP parameter entries that can be referred to by user entries. Doing this simplifies administration. Multiple TOTP parameter entries may be used for different policies.
The following is an example of a TOTP Parameter entry. The entry must use the oathTOTPParams objectClass and be part of an entry with a structural objectClass (applicationProcess in this example). The example sets the hashing algorithm to HMAC-SHA1, the password length to six digits and the validity to 30 seconds.
# Example TOTP Parameter Entry
dn: cn=totpdefault,ou=policies,dc=example,dc=com
objectClass: top
objectClass: applicationProcess
objectClass: oathTOTPParams
cn: totpdefault
oathOTPLength: 6
oathHMACAlgorithm: 1.2.840.113549.2.7
oathTOTPTimeStepPeriod: 30
oathTOTPTimeStepWindow: 3
TOTP User Configuration
Users that are required to authenticate with TOTP must have the following objectClasses and attributes added:
-
objectClass: oathTOTPUser
- This objectClass tells slapd that the user needs to use one-time passwords for authentication -
objectClass: oathTOTPToken
- This objectClass allows to user entry to store user-specific TOTP attributes -
oathTOTPToken: <DN-of-user-entry>
- This tells slapd where to locate the TOTP token used for the entry. Normally this is the same as the user's entry DN. - oathTOTPParams: <DN-of-TOTP-parameter-entry> - This gives the DN of the entry that contains the TOTP parameters used for authentication
-
oathSecret:: <base64-encoded-secret-key>
- The shared secret used by the client and server for generating one-time passwords
The Secret Key
The secret key is a randomly generated chunk of data, 20 bytes in length. The raw key data isn't human-readable, so for it to be stored in the user entry in LDAP and to be shared with the user for the client-side TOTP generator it must be encoded in plain text. For storing the key in the LDAP entry it must be base64 encoded. For sharing the key with the TOTP generator it must be base32 encoded. The following shows how to generate the key and encode the value:
# Generate the 20 byte value and save to a file:
$ openssl rand 20 > secret-key.key
# Encode the key in base64 format for storing in the LDAP database.
# The value of the oathSecret attribute should be the output of this command.
# Base64 encoded attribute values require two colons between the attribute
# name and the attribute value.
# Example -- "oathSecret:: hLPKCN0xT0E9dggEYKEzkMMADPw="
$ base64 secret-key.key
hLPKCN0xT0E9dggEYKEzkMMADPw=
# Encode the key in base32 format for use in a TOTP-generating application:
$ base32 secret-key.key
QSZ4UCG5GFHUCPLWBACGBIJTSDBQADH4
The following script will generate a new secret key, create an LDIF that will update a user entry to use TOTP with the generated secret key, and give a base32 encoded secret key for sharing with the client TOTP generator:
#!/usr/bin/bash
if [[ $# -ne 2 ]]; then
echo -e "\nUsage: $0 <User-DN> <TOTP-Param-DN>\n"
exit 1
fi
OPENSSL=$(which openssl)
SEC=$($OPENSSL rand 20)
KEY="$(echo -n $SEC | base32)"
cat << EOF
dn: $1
changetype: modify
add: objectClass
objectClass: oathTOTPToken
objectClass: oathTOTPUser
-
add: oathTOTPParams
oathTOTPParams: $2
-
add: oathSecret
oathSecret:: $(echo -n $SEC | base64)
-
add: oathTOTPToken
oathTOTPToken: $1
EOF
echo "# OATH USER KEY: $KEY"
Run the script with the DN of the user to update and the DN of the TOTP parameter entry and direct the output to a file:
./create-totp-user-update.sh \ "cn=ErmengardeSchick,ou=Planning,dc=example,dc=com" \
"cn=default,ou=policies,dc=example,dc=com" > update-user.ldif
Use the ldapmodify command to apply the generated LDIF to the user entry:
ldapmodify -xH ldap:/// -D dc=example,dc=com -w secret -f update-user.ldif
Finally, share the secret key at the end of the file with the user to add to their TOTP generator.
TOTP Generator Configuration
There are many TOTP generator applications available. All require the secret key and some require setting the hashing algorithm, time step period or TOTP length. Consult with the documentation for the TOTP generator application for details.
Authenticating With TOTP
To authenticate with TOTP, simply append the current authenticator code to the normal user password. For example, the TOTP code is “538821”:
ldapwhoami -x -H ldap://localhost -D 'cn=user,dc=example,dc=com' \
-w mypassword538821
dn:cn=user,dc=example,dc=com