Request admin credentials for part of a project - vb.net

I have a fairly basic VB.NET project that allows users to restore certain parts of their profiles, should it ever need to be recreated (IE Favourites, Quick Launch, that sort of thing).
I have added to the project the ability to restore these profile parts on behalf of other users, but for this you should have Administrator privileges for our Domain, and I wish the project to prompt for appropriate credentials.
Is this possible for only part of a project? I've looked in to manifests, but from my (limited) understanding it seems that they are only appropriate for for projects as a whole, as opposed to components of a project. Thanks.
If Username = "" Then
Return False
ElseIf Not Username = CurrentUsername Then
'** Require admin privilages *'
Else
Return True
End If

Answering your comment i got this:
If My.User.IsInRole(ApplicationServices.BuiltInRole.Administrator) Then
MessageBox.Show("Yes")
Else
MessageBox.Show("No")
End If
It tells if your application is being runned as admin or not.

I figured this out in the end (almost). The code below uses a Username and Password supplied in an optional 'Settings' form to check whether the current user is a member of the built-in Administrators group in our Domain.
Public Function IsAuthenticatedUser(ByVal Username As String,
Optional ByVal Group As String = "Administrators") As Boolean
Dim IsAuthenticated As Boolean = False
Try
Using RootContext2 As New PrincipalContext(ContextType.Domain,
"dynedrewett.com",
"DC=dynedrewett,DC=com",
Me.formSettings.txtUsername.Text,
Me.formSettings.txtPassword.Text & "XXX"), _
TheGroup As GroupPrincipal = GroupPrincipal.FindByIdentity(RootContext2, IdentityType.Name, Group), _
TheUser As UserPrincipal = UserPrincipal.FindByIdentity(RootContext2, IdentityType.SamAccountName, Username)
If TheGroup IsNot Nothing AndAlso TheUser IsNot Nothing Then
For Each SingleGroup As Principal In TheGroup.GetMembers(True)
If SingleGroup.Name = TheUser.DisplayName Then
IsAuthenticated = True
Exit For
End If
Next
Else
IsMember = False
End If
TheGroup.Dispose()
TheUser.Dispose()
End Using
Catch Ex As Exception
Dim ErrorForm As New formError(Ex, "Ensure that valid Administrator Credentials are specified in the application Settings.")
End Try
Return IsAuthenticated
End Function

Related

Using Impersonation for VB.NET WinForm Application, Can Save File, Can't Open File

I'm working on adding a document upload function to an application I've written. I want the user to be able to upload, open, and delete a document on a network drive that they cannot access normally. With this in mind, I stumbled upon Impersonation, where the user can impersonate a user account that has full rights to the drive, then dispose of that after the code has been executed.
I've never used impersonation before, so during my research I found this thread:
Impersonate a Windows or Active Directory user from a different, untrusted domain
I created and copied the class that user Max Vernon had posted as follows:
Option Explicit On
Option Infer Off
Imports System
Imports System.Runtime.InteropServices ' DLL Import
Imports System.Security.Principal ' WindowsImpersonationContext
Imports System.ComponentModel
Public Class Impersonation
'Group Type Enum
Enum SECURITY_IMPERSONATION_LEVEL As Int32
SecurityAnonymous = 0
SecurityIdentification = 1
SecurityImpersonation = 2
SecurityDelegation = 3
End Enum
Public Enum LogonType As Integer
'This logon type is intended for users who will be interactively using the computer, such as a user being logged on
'by a terminal server, remote shell, or similar process.
'This logon type has the additional expense of caching logon information for disconnected operations,
'therefore, it is inappropriate for some client/server applications, such as a mail server.
LOGON32_LOGON_INTERACTIVE = 2
'This logon type is intended for high performance servers to authenticate plaintext passwords.
'The LogonUser function does not cache credentials for this logon type.
LOGON32_LOGON_NETWORK = 3
'This logon type is intended for batch servers, where processes may be executing on behalf of a user without
'their direct intervention. This type is also for higher performance servers that process many plaintext
'authentication attempts at a time, such as mail or Web servers.
'The LogonUser function does not cache credentials for this logon type.
LOGON32_LOGON_BATCH = 4
'Indicates a service-type logon. The account provided must have the service privilege enabled.
LOGON32_LOGON_SERVICE = 5
'This logon type is for GINA DLLs that log on users who will be interactively using the computer.
'This logon type can generate a unique audit record that shows when the workstation was unlocked.
LOGON32_LOGON_UNLOCK = 7
'This logon type preserves the name and password in the authentication package, which allows the server to make
'connections to other network servers while impersonating the client. A server can accept plaintext credentials
'from a client, call LogonUser, verify that the user can access the system across the network, and still
'communicate with other servers.
'NOTE: Windows NT: This value is not supported.
LOGON32_LOGON_NETWORK_CLEARTEXT = 8
'This logon type allows the caller to clone its current token and specify new credentials for outbound connections.
'The new logon session has the same local identifier but uses different credentials for other network connections.
'NOTE: This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
'NOTE: Windows NT: This value is not supported.
LOGON32_LOGON_NEW_CREDENTIALS = 9
End Enum
Public Enum LogonProvider As Integer
'Use the standard logon provider for the system.
'The default security provider is negotiate, unless you pass NULL for the domain name and the user name
'is not in UPN format. In this case, the default provider is NTLM.
'NOTE: Windows 2000/NT: The default security provider is NTLM.
LOGON32_PROVIDER_DEFAULT = 0
LOGON32_PROVIDER_WINNT35 = 1
LOGON32_PROVIDER_WINNT40 = 2
LOGON32_PROVIDER_WINNT50 = 3
End Enum
'Obtains user token.
Declare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As String, ByVal lpszDomain As String, ByVal lpszPassword As String, ByVal dwLogonType As LogonType, ByVal dwLogonProvider As LogonProvider, ByRef phToken As IntPtr) As Integer
'Closes open handles returned by LogonUser.
Declare Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
'Creates duplicate token handle.
Declare Auto Function DuplicateToken Lib "advapi32.dll" (ExistingTokenHandle As IntPtr, SECURITY_IMPERSONATION_LEVEL As Int16, ByRef DuplicateTokenHandle As IntPtr) As Boolean
'WindowsImpersonationContext newUser.
Private newUser As WindowsImpersonationContext
'Attempts to impersonate a user. If successful, returns
'a WindowsImpersonationContext of the new user's identity.
'
'Username that you want to impersonate.
'Logon domain.
'User's password to logon with.
Public Sub Impersonator(ByVal sDomain As String, ByVal sUsername As String, ByVal sPassword As String)
'Initialize tokens
Dim pExistingTokenHandle As New IntPtr(0)
Dim pDuplicateTokenHandle As New IntPtr(0)
If sDomain = "" Then
sDomain = System.Environment.MachineName
End If
Try
Const LOGON32_PROVIDER_DEFAULT As Int32 = 0
Const LOGON32_LOGON_NEW_CREDENTIALS = 9
Dim bImpersonated As Boolean = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, pExistingTokenHandle)
If bImpersonated = False Then
Dim nErrorCode As Int32 = Marshal.GetLastWin32Error()
Throw New ApplicationException("LogonUser() failed with error code: " & nErrorCode.ToString)
End If
Dim bRetVal As Boolean = DuplicateToken(pExistingTokenHandle, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, pDuplicateTokenHandle)
If bRetVal = False Then
Dim nErrorCode As Int32 = Marshal.GetLastWin32Error
CloseHandle(pExistingTokenHandle)
Throw New ApplicationException("DuplicateToken() failed with error code: " & nErrorCode)
Else
Dim newId As New WindowsIdentity(pDuplicateTokenHandle)
Dim impersonatedUser As WindowsImpersonationContext = newId.Impersonate
newUser = impersonatedUser
End If
Catch ex As Exception
MessageBox.Show("An error has occurred. Please contact Technical Support. " & vbCrLf & ex.Message, "Application Title", MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
If pExistingTokenHandle <> IntPtr.Zero Then
CloseHandle(pExistingTokenHandle)
End If
If pDuplicateTokenHandle <> IntPtr.Zero Then
CloseHandle(pDuplicateTokenHandle)
End If
End Try
End Sub
Public Sub Undo()
newUser.Undo()
End Sub
End Class
The impersonation works great for "uploading" (actually just copying a file over from the users local files to the network drive, creating a specific file path if it doesn't exist) but doesn't seem to work when trying to open the file back up, or delete said file.
I get an access denied error like this:
Error Message When Trying to Open File
The Open File Click Event and Class Call Looks Like This:
Private Sub btnOpenDoc_Click(sender As Object, e As EventArgs) Handles btnOpenDoc.Click
Dim Impersonator As New Impersonation
Dim sUser As String = "UserNameGoesHere"
Dim sPass As String = "PasswordGoesHere"
Dim sDomain As String = "DomainGoesHere"
Try
If sActionID <> "" And iDocument = 1 Then
'Starts impersonation
Impersonator.Impersonator(sDomain, sUser, sPass)
Process.Start(RetrieveFilePath())
'Ends Impersonation
Impersonator.Undo()
End If
Catch ex As Exception
MessageBox.Show("An error has occurred. Please contact Technical Support. " & vbCrLf & ex.Message, "Application Title", MessageBoxButtons.OK, MessageBoxIcon.Error)
modGlobal.WriteToErrorLog(ex.Message, "frmActionEntry", modGlobal.GetExceptionInfo(ex), "frmActionEntry->btnOpenDoc_Click", currentUser.getEmployeeName())
End Try
End Sub
Here's Document Delete Function:
Private Function DeleteFile() As Boolean
Dim Impersonator As New Impersonation
Dim sUser As String = "UsernameGoesHere"
Dim sPass As String = "PasswordGoesHere"
Dim sDomain As String = "DomainGoesHere"
Try
'Starts impersonation
Impersonator.Impersonator(sDomain, sUser, sPass)
File.Delete(RetrieveFilePath())
Return True
'Ends Impersonation
Impersonator.Undo()
Catch ex As Exception
MessageBox.Show("An error has occurred. Please contact Technical Support. " & vbCrLf & ex.Message, "Application Title", MessageBoxButtons.OK, MessageBoxIcon.Error)
modGlobal.WriteToErrorLog(ex.Message, "frmActionEntry", modGlobal.GetExceptionInfo(ex), "frmActionEntry->DeleteFile", currentUser.getEmployeeName())
Return False
End Try
End Function
It's used in basically the same way in the FileSave function. Like I said I'm new to impersonation, and feel like I've hit a wall, having researched and tried various things all morning. Any advice is much appreciated!
-Levi
So after much research and trial and error I have an answer to this.
The short answer:
There is not a clean, elegant way to use impersonation to open a file on a network drive because you either butt heads with Windows Security or run into problems with Windows Shell. I decided to go another route.
The long answer:
I believe I was correct in that the Access was Denied error was due to trying to open a file as the impersonated user on the local user's computer. To get around this I decided to try and use ProcessStartInfo() to pass in the correct credentials (while also using impersonation to access the drive) like this:
'Opens the document associated with this action
Private Sub btnOpenDoc_Click(sender As Object, e As EventArgs) Handles btnOpenDoc.Click
'Initializes an impersonation object
Dim Impersonator As New Impersonation
'Strings with login credentials
Dim sUser As String = "UsernameGoesHere"
Dim sPass As String = "PasswordGoesHere"
Dim sDomain As String = "DomainGoesHere"
'Used to load file path in from RetrieveFilePath()
Dim sPath As String = ""
Try
If sActionID <> "" And iDocument = 1 Then
'Starts impersonation
Impersonator.Impersonator(sDomain, sUser, sPass)
'Initializes a ProcessStartInfo Object to use with impersonation
'as Process.Start class always inherits the security context of
'the parent process i.e. the local user
Dim startInfo As New ProcessStartInfo()
'Creates a secure string as the startInfo.Password parameter only accepts SecureStrings
Dim securePass As New Security.SecureString()
'You can't put a full string into a SecureString, so appending char by char
For Each c As Char In sPass
securePass.AppendChar(c)
Next
'Grab the file path
sPath = RetrieveFilePath()
'Load in the parameters for startInfo
startInfo.FileName = sPath
startInfo.UserName = sUser
startInfo.Password = securePass
startInfo.Domain = sDomain
startInfo.UseShellExecute = False
startInfo.WorkingDirectory = "\\Directory\Goes Here"
If File.Exists(sPath) Then
'Execute the process using startInfo
Process.Start(startInfo)
Else
MsgBox("File Not Found!")
End If
'Dispose of securePass
securePass.Dispose()
'Ends Impersonation
Impersonator.Undo()
End If
Catch ex As Exception
MessageBox.Show("An error has occurred. Please contact Technical Support. " & vbCrLf & ex.Message, "Application Title", MessageBoxButtons.OK, MessageBoxIcon.Error)
modGlobal.WriteToErrorLog(ex.Message, "frmActionEntry", modGlobal.GetExceptionInfo(ex), "frmActionEntry->btnOpenDoc_Click", currentUser.getEmployeeName())
End Try
End Sub
There are some interesting aspects to note here. You have to use a SecureString for the password when using ProcessStartInfo, and can only be assigned per character, and more importantly, I had to set UseShellExecute property to False.
I was hopeful that this would work, but after some iterations I got stuck on this error message:
Error Message Example
I figured out that this was due to being unable to access Windows Shell to find the default program to open the corresponding file type with, so it just expected an executable. After more research I was unable to find a clean way to get around this so I've decided to go about addressing this file upload a different way.
I know this is an old question, but maybe it can help someone else, I had the same problem and finally, realized that it's not enough to grant access to the impersonate user to read and write on the folder but also modify, if you don't, the user can not delete the file.

Active Directory: Add New User C# / VB

I browsed other questions and couldn't find the answer.
What is the appropriate way to add a new user to a active directory specific group when the "current user" running the application does not have access rights to add new users?
I am currently authenticating as the domain Administrator to do it, but obviously that is a security no-no and I don't want the Administrator user's credentials hard-codeded in my code.
I assume the answers is not in my code itself but that I have to create a user in the Active Directory that has privileges to add users.
So my question is a combination of a AD and a Coding question:
1) How do I create a AD user that ONLY has access rights to add users to specific OU and CN security group?
2) Is their any way possible to not hard-code the password for this user?
Or... am I going about this entirely wrong?
Here is my current VB.NET code:
Public Function CreateUser(ByVal UserName As String, ByVal Password As String, ByVal DisplayName As String) As Boolean
Try
'Dim catalog As Catalog = New Catalog()
Dim de As DirectoryEntry = New DirectoryEntry()
de.Path = "LDAP://OU=TS2xUsers,DC=dc,DC=example,DC=com"
de.AuthenticationType = AuthenticationTypes.Secure
de.Username = "Administrator"
de.Password = "foopassword"
'1. Create user accountd
Dim users As DirectoryEntries = de.Children
Dim newuser As DirectoryEntry = users.Add("CN=" & DisplayName, "user")
newuser.Properties("givenname").Value = DisplayName
newuser.Properties("name").Value = DisplayName
newuser.Properties("displayName").Value = DisplayName
newuser.Properties("SAMAccountName").Value = UserName
newuser.Properties("userPrincipalName").Value = UserName & "#dc.example.com"
'newuser.Properties("OU").Value = "TS2xUsers"
newuser.CommitChanges()
Dim ret As Object = newuser.Invoke("SetPassword", Password)
newuser.CommitChanges()
Dim exp As Integer = CInt(newuser.Properties("userAccountControl").Value)
exp = exp And Not &H2 'enable acccount
exp = exp Or &H10000 'dont expire password
newuser.Properties("userAccountControl").Value = exp
newuser.CommitChanges()
''' 5. Add user account to groups
If MakeTSUser(newuser) = False Then
Return False
newuser.Close()
de.Close()
End If
newuser.Close()
de.Close()
Return True
Catch ex As Exception
MsgBox("Failed to create user due to the following reason: " & ex.Message, MsgBoxStyle.Critical)
Return False
End Try
End Function
Private Function MakeTSUser(ByVal deUser As DirectoryEntry) As Boolean
Try
Dim deRBGroup As New DirectoryEntry
deRBGroup.Path = "LDAP://CN=TSUsers,CN=Builtin,DC=dc,DC=example,DC=com"
deRBGroup.AuthenticationType = AuthenticationTypes.Secure
deRBGroup.Username = "Administrator"
deRBGroup.Password = "foopassword"
Dim deDomainUsers As New DirectoryEntry
deDomainUsers.Path = "LDAP://CN=Domain Users,CN=Users,DC=dc,DC=example,DC=com"
deDomainUsers.AuthenticationType = AuthenticationTypes.Secure
deDomainUsers.Username = "Administrator"
deDomainUsers.Password = "foopassword"
Dim primaryGroupToken As Object = Nothing
deRBGroup.Invoke("Add", New Object() {deUser.Path.ToString()})
deRBGroup.CommitChanges()
'Get Primary Group Token of MYGROUP
deRBGroup.Invoke("GetInfoEx", New Object() {New Object() {"primaryGroupToken"}, 0})
primaryGroupToken = deRBGroup.Properties("primaryGroupToken").Value
'Assign Primary Group Token value of MYROUP to the User's PrimaryGroupID
deUser.Properties("primaryGroupID").Value = primaryGroupToken
deUser.CommitChanges()
'Remove the User from "Domain Users" group
deDomainUsers.Invoke("Remove", New Object() {deUser.Path.ToString()})
deDomainUsers.CommitChanges()
Return True
Catch ex As Exception
Return False
End Try
End Function
What is the appropriate way to add a new user to a active directory specific group when the "current user" running the application does not have access rights to add new users?
Run the app as a user that does have those permissions... but you already know this:
I assume the answers is ... to create a user in the Active Directory that has privileges to add users.
Is their any way possible to not hard-code the password for this user?
Good question. One way to do this by setting up a Windows Scheduled Task. You can setup a task to run on demand, with no actual schedule, and to run as any user you want, including your new service account. You will have to put in the password for that user when you setup the task, but only when you first setup the task, and the actual password won't be stored... only the authentication token, which is not transferable. Then your desktop application can trigger the task to start.
Another way to do this is to grant the unprivileged HR or helpdesk users who run your app permissions to create new users just within your specific OU. In the case of a web app, you can also do this for the user account that runs the web site, as long as you have appropriate logging and auditing in place.
The other option is to create a separate service to create the users, which runs as the appropriate user. This could be a web service, where less-privileged authenticated users can post the new account information, or it could be a Windows service doing something like watching a file share, where your unprivileged users then have the ability or write to the file share. Then your program can know how to call the service or write the correct file formats into the share.

check that a specific user has specific permission in lightswitch

I'm using lightswitch in VB , i need to check is a given user has specific permission ("User") or not
I've tried the below code:
Dim myper = Me.DataWorkspace.SecurityData.Permissions.Where(Function(p) p.Id.Equals("LightSwitchApplication:User", StringComparison.OrdinalIgnoreCase)).SingleOrDefault
If Not myper Is Nothing Then
Dim myu = myper.RolePermissions.SelectMany(Function(u) u.Role.RoleAssignments).Select(Function(us) us.UserName = UserName)
If Not myu Is Nothing Then
' this mean no user has the user permission!
results.AddPropertyError("found")
Else
'user has been found for this permission
results.AddPropertyError("not found")
End If
Else
'this mean no roles has this permission !
End If
but unfortunately the myu object always return nothing i don't know why, sorry for that but I'm new in LINQ.
You should use the Application.User object for this.
In csharp:
if(this.Application.User.HasPermission(Permissions.PermXYZ))
{
//permitted
}

Using DirectoryEntry.Invoke("SetPassword", ...) to set initial AD account password, I get "RPC server is unavailable" error

The company I'm working in has a web service that can create new Active Directory accounts based on information that is typed in e.g. username, firstname, lastname, OU1, OU2, etc.
This web service has been working fine on Windows Server 2003. Now I'm working on moving the web service to 2008 R2 servers. However a certain functionality doesn't work anymore, which is when it tries to set a random initial password to the newly created account.
The exception that is thrown is a TargetInvocationException containing an inner exception of COMException with a message of "The RPC Server is unavailable".
Imports System.DirectoryServices
Dim ldapPath As String = "..." 'assume valid LDAP path
Dim objContainer As DirectoryEntry = New DirectoryEntry(ldapPath, vbNullString, vbNullString, AuthenticationTypes.Secure)
objUser = objContainer.Children.Add("cn=" & Username.Trim, "user")
'sets objUser.Properties e.g. givenName, displayName, userPrincipalName, samAccountName, etc. Not important...
objUser.CommitChanges()
strPassword = RandomPassword() 'function that generates random password
objUser.Invoke("SetPassword", New Object() {strPassword})
objUser.Properties("useraccountcontrol").Value = "512" ' set as normal account
objUser.CommitChanges()
'and so on...
The error happens on the line that says:
objUser.Invoke("SetPassword", New Object() {strPassword})
Strangely the account creation itself works and I can see the new user from Active Directory Users and Computers.
I have consulted a few different people who manage the security of the DCs and the web servers, they don't really know why...
In the end I figured out a different way of setting the password, which is using the System.DirectoryServices.AccountManagement library.
So the code becomes something like this:
Imports System.DirectoryServices
Imports System.DirectoryServices.AccountManagement
Dim ldapPath As String = "..." 'assume valid LDAP path
Dim objContainer As DirectoryEntry = New DirectoryEntry(ldapPath, vbNullString, vbNullString, AuthenticationTypes.Secure)
Dim objUser As DirectoryEntry = objContainer.Children.Add("cn=" & Username.Trim, "user")
'sets objUser.Properties e.g. givenName, displayName, userPrincipalName, samAccountName, etc. Not important...
objUser.CommitChanges()
Dim domainContext As PrincipalContext = New PrincipalContext(ContextType.Domain, ...)
Dim user As UserPrincipal = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, Trim(Username))
strPassword = RandomPassword() 'function that generates random password
user.SetPassword(strPassword)
user.Enabled = True 'setting these two properties
user.PasswordNotRequired = False 'result in useraccountcontrol value = 512 (normal account)
user.Save()
'and so on...
I'm mixing old code with new code in this one, but it appears to be working really well on the new servers. One thing to note is that sometimes the UserPrincipal.FindByIdentity call initially returns Nothing, I believe due to delay in the account creation or with the replication. So I have to make sure that the user object is not Nothing by trying FindByIdentity multiple times until I get the object.
Despite finding a solution (more like a way around) to the problem, still I'm confused as to why the old code does not work on the new servers, but the new one does. The error is very generic and searching the internet for clues have resulted in nothing but more confusion.
Would really appreciate if experts out there can shed some lights or even comment on the way my new code looks, any problems?
Thanks in advance.

Is it possible to authenticate an Active Directory User with an Expired password?

I have a web form that uses AD to authenticate users. I want to be able to authenticate users with expired password, and redirect them to the password change page after authentication.
if for instance, a site admin reset a users password, I use the method below, to make the user reset their password on next logon.
Public Shared Sub ForceUserToResetPassword(ByVal LDAP_URI As String, ByVal UserName As String, ByVal Auth_UserName As String, ByVal Auth_Password As String)
Dim LDAPEntry As DirectoryEntry = Nothing
Try
LDAPEntry = New DirectoryEntry(LDAP_URI, Auth_UserName, Auth_Password, AuthenticationTypes.Secure)
Dim LDAPSearch As New DirectorySearcher()
LDAPSearch.SearchRoot = LDAPEntry
LDAPSearch.Filter = "(&(objectClass=user)(sAMAccountName=" & UserName & "))"
LDAPSearch.SearchScope = SearchScope.Subtree
Dim results As SearchResult = LDAPSearch.FindOne()
If Not (results Is Nothing) Then
LDAPEntry = New DirectoryEntry(results.Path, Auth_UserName, Auth_Password, AuthenticationTypes.Secure)
End If
LDAPAccess.SetProperty(LDAPEntry, "pwdLastSet", 0)
LDAPEntry.CommitChanges()
Catch ex As Exception
End Try
End Sub
Doing this makes the user's password expire. If the user try to logon with their new password the authentication fails with "Logon failure: unknown username or bad password".
This is my auth. method:
Public Shared Function AuthADuser(ByVal LDAP_URI As String, ByVal UserName As String, ByVal password As String, ByVal Auth_UserName As String, ByVal Auth_Password As String) As Boolean
Dim IsAuth As Boolean = False
Dim LDAPEntry As DirectoryEntry = Nothing
Try
LDAPEntry = New DirectoryEntry(LDAP_URI, UserName, password, AuthenticationTypes.Secure)
Dim tmp As [Object] = LDAPEntry.NativeObject
IsAuth = True
Catch ex As Exception
LDAPEntry.Dispose()
If ex.Message.StartsWith("The server is not operational") Then
IsAuth = False
ElseIf ex.Message.StartsWith("Logon failure:") Then
Throw New ApplicationException("The Username and password combination are not valid to enter the system.")
End If
Finally
LDAPEntry.Close()
End Try
Return IsAuth
End Function
Is there a way around this?
Thanks for your help.
In my understanding, if a user is required to Change his Password at Next Logon (User's password has expired) Active-Directory will not allow us to use LDAP to determine if his password is invalid or not. This is due to the fact that a user must change password. I found here the following solution :
To determine if password is expired, you may call Win32:LogonUser(), and check the windows error code for the following 2 constants:
ERROR_PASSWORD_MUST_CHANGE = 1907
ERROR_PASSWORD_EXPIRED = 1330
I have a non official answer. As administrator you put pwdLastSet to -1 for the user where pwdLastSet is set to 0. The effect of this is to make Active-Directory believe that the password has just been changed. Then, you check the password with your AuthADuser method. Then you put back pwdLastSet to 0. I do not test it, but just imagine it, it's not so clean on the security point of view (in France we call that "bricolage").
Just tell me if it works ?
I hope it helps;
JP