Exécuter du code .NET sous un autre nom d'utilisateur

.NET dispose d'une fonctionnalité qui permet d'exécuter du code sous un autre nom d'utilisateur que celui qui a lancé le programme à l'origine (une sorte de RUNAS). C'est un peu compliqué à utiliser car il faut notamment P/Invoker des fonctions de l'API Windows.

Voici un portage du code C# originellement publié par Michiel van Otegem en VB.NET. Cette classe permet de simplifier le basculement de contexte.

Imports System
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Imports System.Security.Permissions
Imports Microsoft.VisualBasic
Imports System.ComponentModel
Imports System.Diagnostics
 
' Classe qui permet d'exécuter du code sous un autre nom d'utilisateur
Public Class WrapperImpersonationContext
    Private Declare Auto Function LogonUser Lib "advapi32.dll" ( _
            ByVal lpszUsername As [String], _
            ByVal lpszDomain As [String], ByVal lpszPassword As [String], _
            ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, _
            ByRef phToken As IntPtr) As Boolean
 
    Public Declare Auto Function CloseHandle Lib "kernel32.dll" ( _
            ByVal handle As IntPtr) As Boolean
 
    Private Const LOGON32_PROVIDER_DEFAULT As Integer = 0
    Private Const LOGON32_LOGON_INTERACTIVE As Integer = 2
 
    Private _domain As String
    Private _username As String
    Private _password As String
    Private _token As IntPtr
    Private _context As WindowsImpersonationContext
 
    Protected ReadOnly Property InContext() As Boolean
        Get
            Return Not _context Is Nothing
        End Get
    End Property
 
    ' Constructeur
    ' Le nom de domaine peut être laissé vide et on peut passer 
    ' le nom d'utilisateur sous la forme utilisateur@domain
    Public Sub New(ByVal domain As String, ByVal username As String, _
                   ByVal password As String)
        Dim pos As Integer = username.IndexOf("@")
        If pos <> -1 Then
            _username = username.Substring(0, pos)
            _domain = username.Substring(pos + 1)
        Else
            _domain = domain
            _username = username
        End If
 
        _password = password
    End Sub
 
    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
    Public Sub Enter()
        If Me.InContext Then Return
 
        _token = IntPtr.Zero
        Try
            Dim logonSuccessFull As Boolean = LogonUser(_username, _domain, _
                _password, LOGON32_LOGON_INTERACTIVE, LOGON32_LOGON_INTERACTIVE, _
                _token)
            If Not logonSuccessFull Then
                Dim err As Integer = Marshal.GetLastWin32Error()
                Throw New Win32Exception(err)
            End If
            Dim identity As WindowsIdentity = New WindowsIdentity(_token)
            _context = identity.Impersonate()
        Catch ex As Exception
            Trace.WriteLine(ex)
        End Try
    End Sub
 
    <PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
    Public Sub Leave()
        If Not Me.InContext Then Return
 
        _context.Undo()
 
        If _token <> IntPtr.Zero Then CloseHandle(_token)
        _context = Nothing
    End Sub
End Class

Pour l'utiliser, il suffit d'appeler Enter au début de la section de code qui doit être exécutée sous un autre nom d'utilisateur et d'appeler Leave à la fin :

Dim ctx As New WrapperImpersonationContext(domain, user, password)
ctx.Enter()
' Le code s'exécute sous le nom de user
ctx.Leave()
' On revient avec le nom de l'utilisateur qui a lancé le programme

Etiquettes:

Add new comment