troubleshooting Question

Windows user authentication in VB.NET 3.5SP1

Avatar of wjpoconnor
wjpoconnorFlag for United States of America asked on
.NET ProgrammingVisual Basic.NET
2 Comments1 Solution1196 ViewsLast Modified:
I have a slightly unusual problem. I am writing a VB.NET Windows Forms application that manages Windows Task Scheduler tasks. As part of my requirements, the user must be able to specify the Windows user under whose privileges the task will run. This won't necessarily be the currently connected user.

The user could be an account on the local system, or an account on the local domain. The software will need to run on Windows XP, Server 2003, Vista, Server 2008 and Windows 7.

Initially, I was using a piece of code that used SSPI to authenticate against LDAP, but that won't seem to authenticate a local user when the system is attached to a domain and won't authenticate a domain user (even the currently logged in user) if you're disconnected from the network.

So, I switched to a function which used LogonUser to authenticate the user which worked great until I tried it on Vista and found that the users need a specific permission before they can be authenticated using this method.

I have attached my existing functions which are modifications of code I found on the internet.

I appreciate any help I can get.
''' <summary>
    ''' Validates whether the passed Windows user Id and password are valid.
    ''' </summary>
    ''' <param name="szUserName">The Windows user name with domain prepended if necessary.</param>
    ''' <param name="szPassword">The user's Windows password.</param>
    ''' <param name="szPasswordVerify">The user's Windows password again.</param>
    ''' <returns>True if the user's ID and password are correct.</returns>
    ''' <remarks></remarks>
    Public Function ValidateUserIdPassword(ByVal szUserName As String, ByVal szPassword As String, ByVal szPasswordVerify As String) As Boolean
        Dim bRetVal As Boolean = False
        Console.WriteLine("Validating user {0}", szUserName)
        If szPassword.Equals(szPasswordVerify) Then
            Console.WriteLine("Passwords match.")
            AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal) 
            ' Retrieve the computer name
            Dim machName As String = Environment.MachineName
            Dim MyNamespace As IADsOpenDSObject
            Dim oUserValidation As Object
            Dim DN As String = "LDAP://rootDSE"
            Dim ADS_AUTHENTICATION_SECURE As New ADS_AUTHENTICATION_ENUM
            MyNamespace = GetObject("LDAP:")
            'For authentication, pass in a variable for the user name and password that you wish to use for
            'authentication purposes. It is recommended that you use the ADS_AUTHENTICATION_SECURE flag for
            'security reasons. 
            Try
                oUserValidation = MyNamespace.OpenDSObject(DN, szUserName, szPassword, ADS_AUTHENTICATION_SECURE)
                bRetVal = True
            Catch ex As Exception
                ' Do nothing
                Console.WriteLine("Error {0}", ex.Message)
            End Try
        End If
\        Return bRetVal
    End Function 
    ''' <summary>
    ''' Validates a Windows user Id, domain and password combination.
    ''' </summary>
    ''' <param name="szUserName">The Windows user name. This can be in the form of username, domain\username, or username@domain. If the domain is specified like this, leave the szUserDomain parameter blank.</param>
    ''' <param name="szUserDomain">The Windows machine name or domain. If the domain is specified as part of the user name, pass an empty string in this parameter.</param>
    ''' <param name="szPassword">The user's password.</param>
    ''' <param name="szPasswordVerify">A password validation check.</param>
    ''' <returns>True if all the information is correct. False if one or more items were incorrect.</returns>
    ''' <remarks>Uses the Windows API LogonUser function to check the security context. The context is restore before the function exits.</remarks>
    Public Function ValidateUserIdPassword(ByVal szUserName As String, ByVal szUserDomain As String, ByVal szPassword As String, ByVal szPasswordVerify As String) As Boolean
        ' Set default return value.
        Dim bRetVal As Boolean = False
        ' Compare passwords.
        If szPassword.Equals(szPasswordVerify) Then
            ' Password is same in password and password verify variables.
            If szUserDomain = "" Then
                If szUserName.Contains("\") Then
                    ' Pull the domain out of the user name.
                    szUserDomain = szUserName.Substring(0, szUserName.IndexOf("\"))
                    ' Set user name to just user name.
                    szUserName = szUserName.Substring(szUserName.IndexOf("\") + 1)
                ElseIf szUserName.Contains("@") Then
                    ' User Name is in form of "user@domain"
                    ' Pull the domain out of the user name.
                    szUserDomain = szUserName.Substring(szUserName.IndexOf("@") + 1)
                    ' Set user name to just user name.
                    szUserName = szUserName.Substring(0, szUserName.IndexOf("@"))
                Else
                    ' A "." refers to the local system.
                    szUserDomain = "."
                End If 
            End If
            Console.WriteLine("Validating user {0}, Domain {1}", szUserName, szUserDomain) 
            Dim lphToken As IntPtr = IntPtr.Zero 
            ' Attempt to log in to the machine/domain. Function returns True or False depending on the user Id, password and domain work.
            bRetVal = LogonUser(szUserName, szUserDomain, szPassword, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT, lphToken) 
            ' Close the handle received.
            CloseHandle(lphToken)
            ' Revert security to the currently logged in user.
            RevertToSelf()
        End If 
        Return bRetVal
    End Function
ASKER CERTIFIED SOLUTION
wjpoconnor

Our community of experts have been thoroughly vetted for their expertise and industry experience.

Join our community to see this answer!
Unlock 1 Answer and 2 Comments.
Start Free Trial
Learn from the best

Network and collaborate with thousands of CTOs, CISOs, and IT Pros rooting for you and your success.

Andrew Hancock - VMware vExpert
See if this solution works for you by signing up for a 7 day free trial.
Unlock 1 Answer and 2 Comments.
Try for 7 days

”The time we save is the biggest benefit of E-E to our team. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange.

-Mike Kapnisakis, Warner Bros