Identité basée sur les revendications dans ASP.NET
Cet article a pour but de vous donner une idée générale des nouvelles techniques d’autorisation permises par les revendications (Claims) utilisées par la Windows Identity Foundation (WIF) et ASP.NET 4.5. Je vais essayer d’expliquer ce qu’elles sont, comment elles s’importent dans votre application, et comment les réclamations résultantes se traduisent en code utilisable dans une application ASP.NET 4.5.
Pourquoi utiliser les revendications ?
La sécurité basée sur les revendications (Claims-based identity) est un type d’authentification où l’identité de l’utilisateur est vérifiée et confirmée par un tiers, extérieur à votre application. En d’autres termes, votre application, connue sous le nom de partie utilisatrice (Relying party, RP), n’est plus obligée d’avoir une page de connexion, ou tout autre code qui valide les mots de passe, noms d’utilisateur, etc. Il n’y a plus de procédures de création de compte, de réinitialisation de mot de passe, etc. On parle de découplage de la sécurité de votre application.
Qu’est-ce qu’une revendication ?
Les précédents modèles de sécurité exigeaient que le développeur crée des utilisateurs et des rôles, puis qu’il attribue des rôles aux utilisateurs. Une logique d’autorisation devait alors vérifier si un rôle était bien autorisé telle ou telle chose dans |'application. Ce modèle est connu sous l’appellation d’autorisation basée sur les rôles (Role-Based authorization). Et, vu sous un autre angle, il peut aussi se décrire comme une revendication : “L’utilisateur John revendique être dans le rôle appelé Administrateur”. Pensez au rôle comme “type de revendication”.
Cependant, avec la sécurité basée sur les revendications, un utilisateur peut demander bien plus de choses que ce qui est prévu par le ou les rôles qui lui sont attribués. Par exemple, un utilisateur peut revendiquer son âge, ou encore son adresse de courriel. Les possibilités sont infinies, et ne se limitent pas à des rôles.
Plus haut, je vous disais que vous n’avez plus besoin de fournir une page de connexion à votre application si vous utilisez l’authentification basée sur les revendications. En tant que développeur, vous recevrez du tiers ce qu’on appelle un jeton sécurisé, à l’intérieur duquel vous trouverez la liste des revendications de l’utilisateur. Vous utiliserez ces revendications pour cartographier ce que l’utilisateur peut et ne peut pas faire dans votre application. Pensez à ce jeton comme un permis de conduire, le tiers de confiance étant l’autorité délivrant les permis.
Qui est le tiers ?
Ce tiers est connu comme un service de jetons de sécurité (Security Token Service, STS) ou fournisseur d’identité (Identity Provider, IP) et agit comme une autorité d’émission qui accepte les identifiants entrants, les valide, puis crée un jeton sécurisé contenant la liste des revendications. En d’autres termes, le tiers est un autre site web que le vôtre qui va faire le travail pour vous.
Les jetons sont cryptés et envoyés à votre application. Il est important que l’émetteur du jeton soit une entité de confiance, par exemple Microsoft, Facebook ou Google.
Microsoft propose deux services de jeton de sécurité que vous pouvez utiliser :
Comment le processus débute-t-il ?
L’utilisateur utilise un navigateur pour se connecter à votre application. Lors de la première requête, et si Windows Identity Foundation est correctement configuré, l’application se rend compte que l’utilisateur n’est pas authentifié et elle le redirige vers le service de jeton de sécurité (STS). Le STS fournira une page de connexion où l’utilisateur va saisir ses identifiants. En cas de succès, le STS émettra un jeton à l’utilisateur. L’utilisateur est alors redirigé avec son jeton vers votre application.
Votre application est configurée pour faire confiance au STS et aux jetons qu’il émet. Quand elle reçoit le jeton, votre application va l’analyser avec l’API WIF nécessaire. Vous allez utiliser cette API pour personnaliser la sécurité de votre application. Une fois le jeton analysé, vous aurez les informations nécessaires pour autoriser ou interdire l’utilisateur d’effectuer des actions.
Comment mettre en œuvre ?
Quand votre application le reçoit, le jeton de sécurité personnalisé ressemblera à quelque chose comme ci-dessous. C’est fondamentalement un fichier au format XML contenant une liste des revendications incluses dans des éléments
<m:thecustomtoken m:audience="https://yourwebsite/" m:id="”anID”" m:issuer="”urn:AnyIssuer”" m:validfrom="”2016-01-01”" m:validto="”2016-12-31”" xmlns:m="”urn:thecustomtoken”">
<m:claim name="”FirstName”" namespace="”urn:firstname”">Ray</m:claim>
<m:claim name="”LastName”" namespace="”urn:firstname”">Cacciatore</m:claim>
<m:claim name="”Role”" namespace="”urn:firstname”">Administrator</m:claim>
<signature xmlns="”http://www.w3.org/2000/09/xmldsig#">
<signedinfo>
…
</signedinfo>
</signature>
</m:thecustomtoken>
Lorsque l’on travaille avec l’identité d’un utilisateur dans une application ASP.NET, les développeurs mettent d’habitude en œuvre les interfaces IIdentity et IPrincipal. Avec WIF, les revendications sont ajoutées comme une propriété à ces classes, en utilisant des extensions à ces interfaces (IClaimsIdentity et IClaimsPrincipal). IClaimsIdentity dérive de IIdentity et IClaimsPrincipal dérive de IPrincipal. Ainsi, lorsque le jeton est analysé, WIF place automatiquement les revendications dans une instance de ces classes d’identité. Commençons donc en montrant comment implémenter un jeton personnalisé.
La première étape consiste à créer une classe qui représente le jeton :
public class YourCustomToken : SecurityToken
{
public List Claims { get; set; }
public XmlElement Signature { get; set; }
…
}
Comme vous pouvez le voir, votre jeton doit être une sous-classe de la classe SecurityToken. Cette classe conservera les informations du fichier XML (le jeton). Pour que ce jeton soit utilisé dans votre application, vous devez lui créer un handler, dérivé de la classe SecurityTokenHandler. Ce handler sera utilisé pour lire et analyser le fichier XML.
public class YourCustomTokenHandler : SecurityTokenHandler
{
…
public override SecurityToken ReadToken(XmlReader reader)
{
YourCustomToken token = new YourCustomToken(
Claims = from elem in XElement.Load(reader).Elements(Xname.Get(“Claim”, TokenNamespace)) select new Claim(elem.Attribute(“Namespace”).Value, elem.Value)
);
return token;
}
}
Le gestionnaire doit aussi redéfinir une méthode pour valider le jeton, ce qui ressemblera à quelque chose de ce style :
public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
{
ClaimsIdentityCollection claimsColl = new ClaimsIdentityCollection();
if (token is YourCustomToken)
{
IClaimsIdentity id = new ClaimsIdentity((token as YourCustomToken).Claims);
claimsColl.Add(id);
}
return claimsColl;
}
Le handler ci-dessus remplace les méthodes qui lisent et valident le jeton. La classe de base SecurityTokenHandler passera automatiquement cette collection de réclamations au ClaimsAuthenticationManager, et cette classe mettra en retour la propriété IClaimsPrincipal.Claims à la collection. Je laisse de côté de nombreux détails de ces deux classes, mais je vous suggère fortement de vous familiariser avec, car il y a d’autres importantes méthodes que vous devrez remplacer.
Maintenant, vous avez accès aux revendications via le code en utilisant les propriétés Thread.CurrentPrincipal ou HttpContext.Current.User, comme vous le feriez pour toute autre application .NET.
L’une des étapes importantes dans ce processus est d’enregistrer votre handler dans votre fichier de configuration. Parmi les autres configurations, il est important de ne pas l’oublier :
<microsoft.identitymodel>
<service>
…
<securitytokenhandlers>
<add type="”YourCustomTokenHandler”">
</add></securitytokenhandlers>
</service>
</microsoft.identitymodel>
En résumé
La procédure ci-dessus vous donne une idée de ce que WIF peut vous apporter et comment un gestionnaire de jeton peut être utilisé par votre application basée sur les revendications. Mais vous devez vraiment être conscient que WIF fournit de base des classes qui dérivent déjà de SecurityTokenHandler pour tous les formats de jetons standards (par exemple le populaire SAML). Tous les fournisseurs d’identité n’utilisent pas le même format, mais WIF fournit la plupart de ceux qui sont standards.
Ainsi, dans les cas les plus simples, les valeurs par défaut de WIF vous suffiront pour le travail. Tout ce que vous devez faire est de le paramétrer dans les fichiers de configuration. WIF fournit un modèle de configuration étendue qui est trop complexe à expliquer ici, mais un bon point de départ est ici. Un bonne partie de cette configuration vous évite d’avoir à écrire du code et doit être bien comprise avant d’écrire une application basée sur les revendications. Nous espérons que cette introduction vous donne bon aperçu de la façon dont une application WIF utilise une identité basée sur les revendications.