5 novembre 2008

Droits insuffisants, pensez Impersonation !

Bien souvent, lorsque l'on développe une application web ou même parfois une application Windows (Winforms, WPF, ...), le compte Windows utilisé par l'application ne possède pas les droits suffisants pour effectuer des actions sur le système de fichier, le domaine, la base de données ou sur tout autre système.

Vous avez toujours la possibilité de modifier le compte utilisé. Par exemple, pour une application ASP.Net hébergé dans IIS, il est possible de changer le compte dans les paramètres du pool d'application. Cependant, ce n'est pas forcément une bonne solution. Cela peut même casser votre système d'authentification si celui-ci est de type Windows.

Il est aussi possible d'ajouter les droits nécessaires au compte utilisé par l'application. Mais cela est bien souvent maladroit. Le compte utilisé pour une application ASP.Net est par défaut "Service réseau". Il peut paraître indélicat d'ajouter des droits de d'ajout ou de suppression de dossier à ce compte. Une autre application web utilisant ce compte pourrait être détournée intentionnellement pour supprimer, modifier ou récupérer des données importantes ...

Une bonne solution est d'utiliser l'impersonation. Cela consiste à changer le compte utilisé pour exécuter la logique de votre application par un compte qui possède les droits nécessaires, c'est à dire un compte de service. Pour réaliser ceci, voici une petite classe utilitaire :


using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

public class Impersonation
{
[DllImport("advapi32", SetLastError = true)]
private static extern bool LogonUser(string pUserName, string pDomaine, string pMotDePasse,
int pLogonType, int pLogonProvider, out IntPtr pJeton);
[DllImport("advapi32", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr pHandle);
private string _identifiant;
private string _motDePasse;
private string _domaine;
private WindowsImpersonationContext _impContext;

public Impersonation(string pIdentifiant, string pMotDePasse, string pDomaine )
{
_identifiant = pIdentifiant;
_motDePasse = pMotDePasse;
_domaine = pDomaine;
}

public void Impersonifier()
{
IntPtr handle = new IntPtr(0);
if (!LogonUser(_identifiant, _domaine, _motDePasse, 3, 0, out handle))
throw new Exception("Erreur d'authentification");
_impContext = new WindowsIdentity(handle).Impersonate();
CloseHandle(handle);
}

public void Fermer()
{
_impContext.Undo();
}
}


Tout est articulé autour de la fonction LogonUser qui permet de récupérer un jeton d'authentification. Elle prend entre en paramètre l'identifiant, le mot de passe et le domaine d'un compte de domaine ou local (SAM).

Voici maintenant un petit exemple d'utilisation :


try
{
Impersonation imp = new Impersonation("identifiant", "domaine.fr", "motdepasse}");
imp.Impersonifier();
try
{
// Votre code ncessitant des droits suprieurs
}
catch { }
finally
{
imp.Fermer();
}
}
catch { }

1 commentaire:

Guillaume a dit…

Bonjour,
merci pour ce code qui m'a bien aidé sur une problématique de manque de droits.

Juste 2 petites remarques qui pourraient servir à d'autres :
1°) l'ordre des paramètres lors de l'appel du constructeur n'est pas conforme à celui de la définition (inversion domaine/mot de passe)
2°) dans votre exemple le 4 paramètre de logonuser est 3. Cela ne semble fonctionner que sur une machine distante. Pour pouvoir utiliser le nom de machine locale en tant que domaine, il faut passer cet argument à 9.

Encore une fois merci