#Region "Imports Statements"
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Imports System.Security.Permissions
#End Region


#Region "Enumerations"
    ''' <summary>
    ''' The type of logon to use for logon.
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum LogonType As Integer
        LOGON32_LOGON_INTERACTIVE = 2
        LOGON32_LOGON_NETWORK = 3
        LOGON32_LOGON_BATCH = 4
        LOGON32_LOGON_SERVICE = 5
        LOGON32_LOGON_UNLOCK = 7
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8     'Only for Win2K or higher
        LOGON32_LOGON_NEW_CREDENTIALS = 9       'Only for Win2K or higher
    End Enum

    ''' <summary>
    ''' The logon provider to use for logon.
    ''' </summary>
    ''' <remarks></remarks>
    Public Enum LogonProvider As Integer
        LOGON32_PROVIDER_DEFAULT = 0
        LOGON32_PROVIDER_WINNT35 = 1
        LOGON32_PROVIDER_WINNT40 = 2
        LOGON32_PROVIDER_WINNT50 = 3
    End Enum
#End Region

#Region "Utility Classes"
    ''' <summary>
    ''' This class wraps several unmanaged Window's security and authentication functions so they can be called from .NET managed code.
    ''' </summary>
    ''' <remarks></remarks>
    Class SecuUtil32

#Region "Methods"
        ''' <summary>
        ''' This function wraps the LogonUser function found in 'advapi32.dll'.  This function
        ''' will attempt to logon the specified user to the specified domain."
        ''' </summary>
        ''' <param name="lpszUserName">The Window's username that will be used to authenticate.</param>
        ''' <param name="lpszDomain">The domain that will be used to authenticate.</param>
        ''' <param name="lpszPassword">The password that will be used to authenticate.</param>
        ''' <param name="dwLogonLype">The type of logon that will be used.</param>
        ''' <param name="dwLogonProvider">The logon provider that will be used.</param>
        ''' <param name="TokenHandle">The token handle that will be used.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <DllImport("advapi32.dll", SetLastError:=True)> _
        Public Shared Function LogonUser(ByVal lpszUserName As String, _
                                         ByVal lpszDomain As String, _
                                         ByVal lpszPassword As String, _
                                         ByVal dwLogonLype As Integer, _
                                         ByVal dwLogonProvider As Integer, _
                                         ByRef TokenHandle As IntPtr) As Boolean
        End Function

        ''' <summary>
        ''' This function wraps the CloseHandle function found in 'kernel32.dll'.  This function will attempt to
        ''' close the token handle used for authentication."
        ''' </summary>
        ''' <param name="handle">The token handle to close.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <DllImport("kernel32.dll", CharSet:=CharSet.Auto)> _
        Public Shared Function CloseHandle(ByVal handle As IntPtr) As Boolean
        End Function

        ''' <summary>
        ''' This function wraps the DuplicateToken function found in 'advapi32.dll'.  This function will
        ''' attempt to duplicate the token handle used for authentication.
        ''' </summary>
        ''' <param name="ExistingTokenHandle">The token handle to be duplicated.</param>
        ''' <param name="SECURITY_IMPERSONATION_LEVEL"></param>
        ''' <param name="DuplicateTokenHandle">The new token created by duplicating the existing token.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
        Public Shared Function DuplicateToken(ByVal ExistingTokenHandle As IntPtr, _
                                              ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
                                              ByRef DuplicateTokenHandle As IntPtr) As Boolean
        End Function
#End Region

    End Class
#End Region

#Region "NetworkSecurity Class"

    ''' <summary>
    ''' This function allows web applications to dynamically impersonate a user by calling the
    ''' 'Impersonate User' function and passing the required information.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class NetworkSecurity

#Region "Constants"
        Const securityImpersonation As Integer = 2
#End Region

#Region "Construction"
        Public Sub New()

        End Sub
#End Region

#Region "Public Methods"

        ''' <summary>
        ''' This function will attempt to impersonate a specified user.
        ''' </summary>
        ''' <param name="domain">The domain to attempt to logon to.</param>
        ''' <param name="login">The username to use for authentication.</param>
        ''' <param name="password">The password to use for authentication.</param>
        ''' <param name="logonType">The type of logon to use.</param>
        ''' <param name="logonProvider">The logon provider to use.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function ImpersonateUser(ByVal domain As String, _
                                        ByVal login As String, _
                                        ByVal password As String, _
                                        ByVal logonType As LogonType, _
                                        ByVal logonProvider As LogonProvider) As WindowsImpersonationContext

            Dim tokenHandle As New IntPtr(0)
            Dim duplicateTokenHandle As New IntPtr(0)

            Try
                tokenHandle = IntPtr.Zero
                duplicateTokenHandle = IntPtr.Zero

                'Call LogonUser to obtain a handle to an access token
                Dim returnValue As Boolean = SecuUtil32.LogonUser(login, domain, password, CInt(logonType), CInt(logonProvider), tokenHandle)

                If (returnValue = False) Then
                    Dim ret As Integer = Marshal.GetLastWin32Error()
                    Dim err As String = String.Format("LogonUser failed with error code: {0}", ret)
                    Throw New ApplicationException(err, Nothing)
                End If

                returnValue = SecuUtil32.DuplicateToken(tokenHandle, securityImpersonation, duplicateTokenHandle)

                If (returnValue = False) Then
                    SecuUtil32.CloseHandle(tokenHandle)
                    Throw New ApplicationException("Failed to duplicate token", Nothing)
                End If

                Dim newID As New WindowsIdentity(duplicateTokenHandle)
                Dim impersonatedUser As WindowsImpersonationContext = newID.Impersonate()

                Return impersonatedUser
            Catch ex As Exception
                Throw New ApplicationException(ex.Message, ex)
            End Try

            Return Nothing
        End Function

#End Region

    End Class

#End Region