...
On note par contre que la demande de suppression des sessions CAS d'un utilisateur (cf le script en place et partagé sur ce même espace wiki) est maintenant très rapide (était très lent précédemment).
Nettoyage de tickets via DefaultTicketRegistryCleaner
...
CAS positionne donc bien un expireAt (index TTL, lié à un expireAfterSeconds) propre à MongoDB dans les enregistrements, notamment les TGT (collection ticketGrantingTicketsCollection).
...
Aussi, les tickets sont supprimés par CAS lui-même via DefaultTicketRegistryCleaner en fonction de ce expireAt.
Et "au pire", ils sont supprimés par le mécanisme interne de MongoDB via le expireAfterSeconds 15 jours après le expireAt ... soit 15 jours et 8 heures après pour les TGT non remember-me et 29 jours après pour les remember-me.
Cf la documentation MongoDB à ce sujet vis-à-vis de expireAfterSeconds.
Coût du
...
nettoyage de tickets via DefaultTicketRegistryCleaner
Aussi, avec cette configuration ("par défaut"), DefaultTicketRegistryCleaner a la charge de supprimer tous les tickets expirés de la base. En soit, on peut penser que ce type d'opérations n'est pas gourmande : on supprime tous les tickets dont le expireAt est plus vieux que la date actuelle ; on peut penser que cela se fait en une seule requête. Malheureusement l'implémentation proposée ici est réalisée dans une logique de NoSQL générique : DefaultTicketRegistryCleaner récupère tous les tickets, les "lit" (et donc les décode si ils sont encodés, ce qui est le cas normalement si vous suivez les recommandations de CAS), sélectionne les tickets qu'il estime expirés pour enfin les supprimer. Cette implémentation générique est très coûteuse, notez qu'en plus d'autant que par défaut cette procédure de suppression de tickets par le DefaultTicketRegistry est appelé appelée toutes les 2 minutes ( cas.ticket.registry.cleaner.schedule.repeat-interval=PT2M ). Ainsi, lors d'une période creuse sur notre CAS, on note une consommation d'environ 30 secondes de CPU à chaque nettoyage de tickets (toutes les 2 minutes) résultant du déchiffrement de l'ensemble des tickets.
Une "optimisation" élémentaire peut être est simplement d'augmenter le le cas.ticket.registry.cleaner.schedule.repeat-interval à 1 heure par exemple (PT1H).
A l'autre extrême on peut aussi imaginer proposer une autre implémentation du TicketRegistryCleaner, d'autant que son nom de "DefaultTicketRegistryCleaner" nous y incite.
La méthode en cause ici étant DefaultTicketRegistryCleaner.cleanInternal qui est justement protected.Le plus logique semble cependant laisser le soin à MongoDB de s'occuper lui-même de supprimer les tickets expirés, d'autant que c'est tout l'intérêt de ce type de base et de la fonctionnalité d'index avec un expireAfterSeconds (ttl) de positionné et que c'est ce qui pose problème à l'implémentation via Redis avec l'introduction de l'entrée CAS_PRINCIPAL:uid correspondant à plusieurs TGT et ne pouvant de fait pas avoir un TTL propre.
...
| Info |
|---|
| The ticket registry cleaner is generally useful in scenarios where the registry implementation is unable to auto-evict expired tokens and entries on its own via a background task. |
...
Tentative d'optimisation du nettoyage de tickets via MongoDB
Pour laisser MongoDB s'occuper du nettoyage des tickets, on désactive simplement le nettoyage périodique des tickets par CAS ainsi :
...
Cf ci-dessus cependant, le comportement ne sera cependant pas tout à fait adapté à ce qu'on recherche car CAS a positionné les expireAfterSeconds expireAfterSeconds des index expireAt non pas à 0 seconde mais à la valeur donnée par cas.ticket.tgt.primary.max-time-to-live-in-seconds (15 jours).
...
| Bloc de code | ||
|---|---|---|
| ||
### Valeur d'expiration des TGTs # Set to a negative value to never expire tickets # 8 heures au max -> mongodb supprimera lui-même les tickets au bout de 8 heures (sauf remember-me) cas.ticket.tgt.primary.max-time-to-live-in-seconds=28800 # DefaultTicketRegistryCleaner supprimera les tickets non remember-me au bout de 8 heures (non utile - désactivé) cas.ticket.tgt.primary.time-to-kill-in-seconds=28800 ### Valeur expiration tickets service/proxy : 10sec par défaut, on augmente car latence sur les sogo ... cas.ticket.pt.timeToKillInSeconds=60 cas.ticket.st.timeToKillInSeconds=60 # rememberme cas.ticket.tgt.rememberMe.enabled=true # mongodb (et pas DefaultTicketRegistryCleaner via notre config) supprimera les tickets non remember-me au bout de 14 jours cas.ticket.tgt.remember-me.time-to-kill-in-seconds=1209600 # rememberme 2 semaines ok pour le cookie tgc.remember.me.maxAge=1209600 cas.tgc.rememberMeMaxAge=1209600 # pinToSession = false pour que ça fonctionne même si chgt d'IP par exemple. cas.tgc.pinToSession=false ### Pas de Ticket Registry Cleaner -> mongo s'en charge cas.ticket.registry.cleaner.schedule.enabled=false # index expireAt/expireAfterSeconds et plein texte adapté pour optimisation cpu cas.ticket.registry.mongo.update-indexes=false |
Effets de bord d'une telle modification
...
En simplifiant la gestion des expirations des tickets pour faire cette optimisation, on a cependant provoqué au moins un effet de bord dans notre installation qui amène une régression pour les utilisateurs.
Un TGT est expiré si la date de dernier usage additionnée de 8 heures (cas.ticket.tgt.primary.time-to-kill-in-seconds) est dépassé ou si la date de création d'un ticket additionnée de 15 jours (cas.ticket.tgt.primary.time-to-kill-in-seconds) est dépassée.
En positionnant le expireAfterSeconds à 0 seconde pour ne plus utiliser le DefaultTicketRegistryCleaner qui prend en compte le lastTimeUsed du TGT (d'où l'obligation de décoder les tickets), la date de dernier usage n'est plus prise en compte, et le TGT expire systématiquement 8 heures après sa création (même si il est régulièrement utilisé) : la session CAS a donc alors une durée de vie maximale de 8 heures.On
Optimisation supplémentaire des index
...