Par défaut, il n'est pas possible de déterminer la date de dernière connexion réussie sur un annuaire LDAP (last login time). Seules les erreurs de connexion peuvent être détectées dans les politiques de mots de passe.
Parfois cependant, il est intéressant de connaître la date de dernière connexion, afin de pouvoir supprimer - ou bloquer - des comptes inutilisés depuis plusieurs mois.
Certains annuaire permettent de modifier les politiques de mots de passe pour tracer les connexions réussies, mais ceci a un impact sur les authentifications. En effet, à chaque authentification réussie, l'annuaire doit écrire la date de connexion sur l'objet utilisateur. On passe donc d'une suite d'opérations search and bind à une suite search and bind and mod.
Quel est donc l'impact de ce suivi sur les performances d'un annuaire ? C'est l'objet de ce test, réalisé sur un annuaire LDAP Forgerock Opendj (DS 5.5).
Configuration utilisée
La configuration utilisée est la suivante :
- 2 vCPU Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz
- 16 Go de RAM
Le jeu de test est constitué d'un fichier LDIF de 481 Mo, comprenant 220 000 entrées utilisateur.
Parmi ces 220 000 entrées, 50 000 sont situées dans une OU (organizational unit) spécifique : ou=People,ou=FR,o=example.
Politique de mots de passe par défaut
La politique de mot de passe par défaut est utilisée, avec le chargement des entrées.
Property : Value(s)
------------------------------------------:------------------------------------
account-status-notification-handler : -
allow-expired-password-changes : false
allow-multiple-password-values : false
allow-pre-encoded-passwords : false
allow-user-password-changes : true
default-password-storage-scheme : Salted SHA-512
deprecated-password-storage-scheme : -
expire-passwords-without-warning : false
force-change-on-add : false
force-change-on-reset : false
grace-login-count : 0
idle-lockout-interval : 0 s
java-class : org.opends.server.core.PasswordPolicyFactory
last-login-time-attribute : -
last-login-time-format : -
lockout-duration : 0 s
lockout-failure-count : 0
lockout-failure-expiration-interval : 0 s
max-password-age : 25 w 5 d
max-password-reset-age : 0 s
min-password-age : 0 s
password-attribute : userPassword
password-change-requires-current-password : false
password-expiration-warning-interval : 5 d
password-generator : Random Password Generator
password-history-count : 5
password-history-duration : 0 s
password-validator : Length-Based Password Validator
previous-last-login-time-format : -
require-change-by-time : -
require-secure-authentication : false
require-secure-password-changes : false
skip-validation-for-administrators : false
state-update-failure-policy : reactive
Outils de benchmark
Les tests sont lancés avec les utilitaires authrate et searchrate, qui sont intégrés aux binaires de l'annuaire.
Pour la recherche :
/opt/opendj/bin/searchrate -h 10.150.29.161 -p 1389 -D 'uid=user.1,ou=people,ou=fr,o=example' -w password -F -c 10 -b o=example -m 300000 -g 'rand(100,49000)' '(uid=user.%d)'
Pour les authentifications, en mode search + bind :
/opt/opendj/bin/authrate -h 10.150.29.161 -p 1389 -D '%2$s' -w password -f -c 10 -b ou=people,ou=fr,o=example -s sub -m 300000 -g 'rand(100,49000)' '(uid=user.%d)'
Procédure de tests
La procédure de tests est la suivante :
- démarrage de l'annuaire
- lancement d'un premier test de type searchrate, qui permet de cacher les entrées en RAM
- lancement d'un test d'authentification avec authrate en mode search + bind
Mesures sans suivi de la date de dernière connexion
Avec le paramétrage par défaut, on obtient un débit moyen de 4283 authentifications par seconde, avec un temps de réponse moyen de 2.131 millisecondes.
------------------------------------------------------------------------------
Throughput Response Time
(ops/second) (milliseconds)
recent average recent average 99.9% 99.99% 99.999% err/sec bind time %
------------------------------------------------------------------------------
3901.6 3907.1 2.573 2.573 25.304 162.729 167.620 0.0 44.4
4186.4 4047.8 2.372 2.469 26.546 166.949 195.819 0.0 46.6
4540.4 4212.9 2.183 2.365 23.388 166.223 195.819 0.0 44.2
4624.0 4315.7 2.147 2.307 22.435 162.729 195.819 0.0 42.6
4609.7 4374.6 2.156 2.275 22.083 160.540 172.100 0.0 43.0
4663.1 4422.7 2.130 2.250 21.634 158.399 172.100 0.0 42.5
4765.9 4471.7 2.088 2.225 21.431 154.617 172.100 0.0 42.8
4764.9 4508.4 2.089 2.207 20.982 141.395 172.100 0.0 42.0
4864.1 4547.9 2.050 2.188 21.024 39.778 169.393 0.0 42.2
4811.6 4574.2 2.077 2.177 20.934 34.832 169.393 0.0 42.0
4777.0 4592.6 2.091 2.169 20.525 32.932 169.393 0.0 41.8
4825.5 4611.9 2.072 2.160 20.090 32.724 169.393 0.0 41.9
4101.4 4572.6 1.898 2.142 19.807 32.213 169.393 0.0 41.7
530.8 4283.0 0.869 2.131 19.703 32.118 167.620 0.0 41.0
La CPU est utilisée à 90 % environ sur le serveur cible (qui dispose de 2 vCPU).
Mise en place du suivi du last login time
Création d'un attribut spécifique
La mise en place du suivi demande tout d'abord de créer un attribut qui sera utilisé pour stocker la date de dernière connexion. La documentation donne justement un exemple de politique de mots de passe qui met en oeuvre le suivi.
dn: cn=schema
changetype: modify
add: attributeTypes
attributeTypes: ( lastLoginTime-oid
NAME 'lastLoginTime'
DESC 'Last time the user logged in'
EQUALITY generalizedTimeMatch
ORDERING generalizedTimeOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
SINGLE-VALUE
NO-USER-MODIFICATION
USAGE directoryOperation
X-ORIGIN 'OpenDJ example documentation' )
On ajoute l'attribut au schéma via la commande ldapmodify :
ldapmodify \
--hostname localhost \
--port 1389 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
lastLoginTime.ldif
Création d'une politique de mots de passe spécifique
Si on veut cibler certains comptes utilisateurs, on peut créer une politique de mots de passe spécifiquement pour cet usage :
/opt/opendj/bin/dsconfig \
create-password-policy \
--hostname localhost --port 4444 \
--bindDN "cn=Directory Manager" \
--bindPassword password \
--policy-name "Track Last Login Time" \
--type password-policy \
--set default-password-storage-scheme:"Salted SHA-512" \
--set password-attribute:userPassword \
--set last-login-time-attribute:lastLoginTime \
--set last-login-time-format:"yyyyMMddHH'Z'" \
--trustAll \
--no-prompt
Modification de la politique de mots de passe
On peut créer une nouvelle politique de mots de passe, ou modifier la politique existante. Dans ce cas, la commande à utiliser est la suivante :
/opt/opendj/bin/dsconfig set-password-policy-prop \
--policy-name Default\ Password\ Policy \
--set last-login-time-attribute:lastLoginTime \
--set last-login-time-format:"yyyyMMddHH'Z'" \
--hostname localhost \
--port 4444 \
--bindDn cn=Directory\ Manager \
--bindPassword password \
--trustAll \
--no-prompt
Test sur une entrée
Si on fait une requête avec un utilisateur en se connectant, on peut ensuite récupérer la date de dernière connexion sur son entrée, à condition de disposer des droits adéquats.
Par exemple :
ldapsearch -x -h localhost -p 1389 -D 'cn=Directory Manager' -w password -b o=example '(uid=user.2)' lastLoginTime
dn: uid=user.2,ou=People,ou=FR,o=example
lastLoginTime: 2017121909Z
On constate que la date est bien au format déclaré, c'est à dire comprenant l'année, le mois, le jour et l'heure. En effet, il n'est pas nécessaire de suivre les connexions à la minute près.
Mesures AVEC suivi de la date de dernière connexion
Avec le nouveau paramétrage, incluant la mise à jour de la dernière date de connexion, on obtient un débit maximum de 2860 authentifications par seconde en moyenne, avec un temps de réponse moyen de 3.382 millisecondes.
La charge CPU sur le serveur d'annuaire oscille entre 50 et 95%, avec des I/O wait.
On a bien un impact assez fort, avec notamment des phases pendant laquelle l'annuaire est en I/O wait, révélateur des mises à jour effectuées sur les entrées.
------------------------------------------------------------------------------
Throughput Response Time
(ops/second) (milliseconds)
recent average recent average 99.9% 99.99% 99.999% err/sec bind time %
------------------------------------------------------------------------------
1570.3 1573.1 6.421 6.421 152.833 177.026 177.026 0.0 63.6
2308.4 1942.2 4.325 5.170 53.701 176.974 177.026 0.0 57.0
2479.4 2122.0 4.023 4.722 49.889 165.267 177.026 0.0 53.3
1025.2 1847.4 3.712 4.581 48.670 165.267 177.026 0.0 51.6
0.0 1477.0 - 4.581 48.670 165.267 177.026 0.0 NaN
1013.4 1399.8 25.871 7.149 50.589 11195.648 11204.023 0.0 93.5
2996.8 1627.5 3.332 6.147 46.142 11193.992 11204.023 0.0 49.8
3301.1 1836.1 3.028 5.447 44.262 11187.622 11204.023 0.0 48.4
3329.9 2001.8 2.737 4.948 41.735 11165.580 11204.023 0.0 47.0
0.0 1800.9 - 4.948 41.735 11165.580 11204.023 0.0 NaN
92.4 1645.4 226.166 6.078 43.042 11156.315 11204.023 0.0 99.2
4024.9 1843.1 2.485 5.426 39.488 10339.090 11203.705 0.0 45.4
4193.7 2023.6 2.382 4.942 38.478 10328.566 11203.705 0.0 44.3
4487.2 2199.3 2.227 4.547 36.814 10316.059 11203.705 0.0 43.1
4496.0 2352.3 2.222 4.251 35.540 10313.618 11203.705 0.0 43.3
4530.5 2488.3 2.207 4.018 34.530 10213.330 11203.705 0.0 43.0
4535.5 2608.8 2.204 3.833 33.649 168.792 11202.112 0.0 43.3
4479.8 2712.7 2.230 3.686 33.112 163.941 11202.112 0.0 42.7
4722.0 2818.5 2.116 3.547 32.285 160.038 11202.112 0.0 42.6
4710.9 2913.1 2.108 3.431 31.666 79.285 11202.112 0.0 42.5
1816.5 2860.5 1.834 3.382 31.418 75.221 11195.866 0.0 42.9
Note : ceci est cependant à modérer, puisque notre première campagne de tir va déclencher une écriture pour chaque utilisateur qui s'authentifie. Si on relance un deuxième tir dans l'heure (qui est l'unité minimale de suivi de la date de connexion), on retrouve des résultats quasiment identiques au premier cas : un débit de 4291 authentifications par seconde, et un temps de réponse de 2.195 ms. Si on regarde la charge sur le serveur d'annuaire, on ne constate plus d'écritures sur disque.
------------------------------------------------------------------------------
Throughput Response Time
(ops/second) (milliseconds)
recent average recent average 99.9% 99.99% 99.999% err/sec bind time %
------------------------------------------------------------------------------
3988.3 3994.8 2.514 2.514 23.066 163.522 167.640 0.0 42.6
.../...
4628.0 4525.7 2.159 2.206 18.978 28.433 158.819 0.0 42.9
4327.2 4510.4 2.219 2.207 19.051 28.221 158.819 0.0 43.0
1450.9 4291.0 1.721 2.195 18.968 28.071 158.406 0.0 42.1
Conclusion
Si l'impact du suivi de la date de dernière connexion n'est pas anodin, surtout dans le cas d'un test, en situation réelle, l'impact peut être relativement négligeable, notamment si les authentifications se font au fil de l'eau.