Retrouver un utilisateur à partir d'un identifiant opaque

Dans une fédération d'identité, l'utilisation d'identifiants opaques permet à un organisme A d'autoriser un organisme B à différencier ses utilisateurs, par exemple pour gérer des profils au sein d'une application, sans qu'il ne puisse pour autant identifier les personnes correspondantes. En diminuant le niveau d'exposition des informations à caractères personnels, cette mesure facilite les interactions entre organismes différents, sans avoir à mettre en place un cadre formel à chaque fois.

L'identifiant persistent persistentID, transmis sous forme d'attribut (eduPersonTargetedID) ou de nameID, remplit parfaitement cette fonction. Et même lorsqu'aucun identifiant explicite n'est demandé par le fournisseur de service, il y a toujours un identifiant temporaire de session qui est utilisé, tout aussi opaque.

Cette opacité peut néanmoins être problématique, lorsqu'il est nécessaire d'identifier une personne à partir de cet identifiant, que ce soit pour des raisons techniques, comme résoudre un dysfonctionnement, ou alors pour des raisons légales, par exemple à la suite d'une réquisition judiciaire. Cette documentation ne s'étend donc pas sur la légitimité du besoin, qui est laissé à la libre appréciation du lecteur, mais uniquement sur les moyens techniques d'y arriver. Seul l'administrateur du fournisseur d'identité est en mesure de le faire, à partir des informations suivantes, qui doivent lui être fournies par l’administrateur du fournisseur de service:

  • l'identifiant SAML (entityID) du fournisseur de service
  • la date et l'heure de connexion de l'utilisateur
  • l'un des deux éléments suivants:
    • la valeur de son identifiant persistentID, généralement la valeur de l'attribut eduPersonTargetedID
    • la valeur de son identifiant de session

Utilisation d'un identifiant persistent stocké

Il s'agit du cas le plus simple, puisque la relation entre un fournisseur de service, un utilisateur, et son identifiant persistentID est stocké dans une base de données dédiée. Il suffit donc d'une simple recherche à partir de l'identifiant du fournisseur de service et de la valeur fournie par celui-ci pour l'identifiant persistentID pour obtenir l'identifiant local de l'utilisateur.

Dans le schéma classique, tel que présenté dans notre guide d'installation, cette information est constituée des colonnes suivantes de la table shibpid:

  • peerEntity contient l'identifiant d'un fournisseur de service
  • localId contient l'identifiant local de l'utilisateur
  • persistentId contient la valeur de l'identifiant opaque

Utilisation d'un identifiant persistent généré

Le cas est plus complexe, mais pas impossible à résoudre, à conditions de disposer des journaux d'activités du fournisseur d'identité, et plus particulièrement les traces d'audit, contenues par défaut dans le fichier idp-audit.log.

Dans le cas d'un fournisseur d'identité dont l'activité est faible, la simple concordance des estampilles temporelles (timestamps) peut permettre d'identifier l'utilisateur. En effet, chaque authentification réussie génére un événement de ce type:

20201027T095510Z                                                  |
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect                |
_096c214f4787c5918d7a84b1e9371801                                 |
https://preprod-test-sp.federation.renater.fr                     | <- identifiant SAML du SP
http://shibboleth.net/ns/profiles/saml2/sso/browser               |
https://preprod-idp.renater.fr/idp/shibboleth                     | <- identifiant SAML de l'IdP
urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST                    |
_ee6ec0ecde0f75d68de4854d91d8e482                                 |
prenom.nom@renater.fr                                             | <- identifiant local de l'utilisateur 
urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport | 
commonName,surName,mail,...                                       | <- liste des attributs transmis
AAdzZWNyZXQxTmIcgMoO7lHaugvutthMt7DMNL+fTDs+o5geubTc2UD4NW8zYm... |
_4ce039d3462e20b94402ca3197d195c5                                 | <- identifiant de session
true

S'il n'y a qu'un seul utilisateur à s'être connecté au service adéquat dans le créneau correspondant, le problème est résolu, sans même avoir à se pencher sur la valeur de son identifiant persistentID.

S'il y a plusieurs utilisateurs, en revanche, il est nécessaire de calculer pour chacun d'eux la valeur de cet identifiant, et comparer avec la valeur transmise par le service. Avec les paramètres par défaut de l'IdP (définies dans le fichier saml-nameid.properties), l'algorithme utilisé pour calculer cette valeur correspond à ceci:

ComputedID = base64 ( SHA1 ( EntityID_du_SP . "!" . ID_utilisateur . "!" . salt_IDP ) )

Il est relativement simple de produire le même résultat, avec le langage de son choix. Voici un exemple en Perl, fourni par Benoit Branciard, Université de Paris1 Panthéon-Sorbonne:

use Digest::SHA qw(sha1_base64);
 
sub computedid {
    my ($uid,$sp,$salt) = @_;
    my $cid = sha1_base64($sp."!".$uid."!".$salt);
    while (length($cid) % 4) { $cid .= '=' }
    return $cid;
}

Utilisation d'un identifiant de session

En désespoir de cause, il reste possible d'utiliser l'identifiant de session, généré automatiquement par l'IdP. Cet identifiant temporaire se trouve dans les journaux d'activité du fournisseur de service, dans le fichier transaction.log avec une configuration par défaut.

Chaque ouverture de session se traduit par la génération d'un événement de ce type (le format exact dépend de la configuration du SP):

Oct 27 10:55:11 hostname shibd: INFO Shibboleth-TRANSACTION.Login [3] [default]: <- entête syslog
u:prenom.nom@renater.fr                                                 ,
s:_694da99a4bc53a591fed9bdd8899bfa4                                     ,
IDP:https://preprod-idp.renater.fr/idp/shibboleth                       ,
i:_4ce039d3462e20b94402ca3197d195c5                                     , <- identifiant de session
ac:urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport    ,
t:2020-10-27T10:55:01                                                   ,
attr:cn(1),givenName(1),mail(1),...                                     ,
n:AAdzZWNyZXQxTmIcgMoO7lHaugvutthMt7DMNL+fTDs+o5geubTc2UD4NW8zYm...     ,
b:urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST                        ,
E:                                                                      ,
S:urn:oasis:names:tc:SAML:2.0:status:Success                            ,
SS:                                                                     ,
L:                                                                      ,
UA:Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 ,
a:10.45.80.4