• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 780
  • Last Modified:

How do I get a password from AD based on displayName

I'm trying to grab the password attribute from Active Directory using the users displayName. When I use the code below, it finds the user but errors out on

Label7.Text = result.Properties("password")(0).ToString

With the following: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index

What am I doing wrong here?
Dim filter As String = String.Format("(&(objectClass=user)(objectCategory=person)(displayName={0}))", DropDownList1.Text & "*")
        Dim entry As New DirectoryServices.DirectoryEntry(ldapPath)
        entry.Username = GetADUser()
        entry.Password = GetADPass()
        Dim searcher As New DirectoryServices.DirectorySearcher(entry, filter, New String() {"displayName"})
        searcher.PropertiesToLoad.Add("displayName")
        Dim result As DirectoryServices.SearchResult = searcher.FindOne()
        If Not IsNothing(result) Then
            If Not IsNothing(result.Properties("password")) Then
                Label7.Text = result.Properties("password")(0).ToString
            Else
                Label7.Text = ""
            End If
        Else
            Label7.Text = ""
        End If

Open in new window

0
Mike Miller
Asked:
Mike Miller
  • 5
  • 3
  • 3
1 Solution
 
TimCotteeCommented:
Hello mwmiller78,

You can't get the password property from AD, if you could then it would be a large security hole!

Regards,

TimCottee
0
 
jmwheelerCommented:
I could be wrong but I don't think the password is accessible.  That would be a pretty major security risk.  You can't even view a user's AD password using the Active Directory tools in Windows, only reset the password.
0
 
jmwheelerCommented:
There are functions available for validating an entered username and password against Active Directory if that is what you are trying to do.
0
Has Powershell sent you back into the Stone Age?

If managing Active Directory using Windows Powershell® is making you feel like you stepped back in time, you are not alone.  For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why.

 
Mike MillerSoftware EngineerAuthor Commented:
So is there anyway to validate a user based on the displayName and an entry by the user?
0
 
jmwheelerCommented:
Yes,

Here is some code for a class that I use.  Create the class then call:

WindowsLogon.LogonUser("username","password","domain")
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
 
namespace AHS.Web.Security
{
    public static class WindowsLogon
    {
 
        public static Int16 LOGON32_LOGON_NETWORK = 3;
        public static Int16 LOGON32_LOGON_INTERACTIVE = 2;
        public static Int16 LOGON32_PROVIDER_DEFAULT = 0;
 
        [DllImport("advapi32.dll")]
        private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
 
        [DllImport("advapi32.dll", SetLastError = true)]
        private static extern bool DuplicateToken(IntPtr ExistingTokenHandle, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern bool CloseHandle(IntPtr handle);
 
        public static void ChangePassword(string userName, string oldPassword, string newPassword)
        {
            DirectoryEntry de = new DirectoryEntry("WinNT://10.1.1.11/" + userName + ",user", userName, oldPassword, AuthenticationTypes.Secure);
            object x = de.Invoke("ChangePassword", new object[] { oldPassword, newPassword });
            de.CommitChanges();
        }
 
        private static void DuplicateToken(IntPtr token, ref IntPtr dupToken)
        {
            if (!WindowsLogon.DuplicateToken(token, WindowsLogon.LOGON32_LOGON_INTERACTIVE, ref dupToken))
            {
                WindowsLogon.CloseHandle(token);
                int closeErrID = Marshal.GetLastWin32Error();
                throw new Win32Exception(closeErrID);
            }
        }
 
        private static WindowsPrincipal CreateWindowsPrincipal(IntPtr winToken)
        {
            WindowsIdentity tempIdentity = new WindowsIdentity(winToken);
            WindowsImpersonationContext impersonationContext = tempIdentity.Impersonate();
 
            return new WindowsPrincipal(tempIdentity);
        }
 
        public static IntPtr GetUserToken(string userName, string password, string domain)
        {
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
 
            if (!WindowsLogon.LogonUser(userName, domain, password, WindowsLogon.LOGON32_LOGON_INTERACTIVE, WindowsLogon.LOGON32_PROVIDER_DEFAULT, ref token))
            {
                int errID = Marshal.GetLastWin32Error();
                throw new Win32Exception(5);
            }
 
            return token;
        }
 
        public static WindowsPrincipal LogonUser(string userName, string password, string domain)
        {
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
 
            if (!WindowsLogon.LogonUser(userName, domain, password, WindowsLogon.LOGON32_LOGON_INTERACTIVE, WindowsLogon.LOGON32_PROVIDER_DEFAULT, ref token))
            {
                int errID = Marshal.GetLastWin32Error();
                throw new Win32Exception(5);
            }
 
            DuplicateToken(token, ref tokenDuplicate);
            return CreateWindowsPrincipal(tokenDuplicate);
        }
 
    }
}

Open in new window

0
 
TimCotteeCommented:
mwmiller78,

Or an ActiveDirectory VB.Net based solution.

TimCottee
Imports System.Data
Imports System.Data.SqlClient
Imports System.DirectoryServices 
Public Class ADUser 
    'This class is used to authenticate a user in active directory and return limited information about that user 
#Region " Declarations" 
    Private _Groups() As String
    Private _SAMAccountName As String
    Private _DisplayName As String
    Private _Path As String = "LDAP://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" '
    Private _Domain As String = "mydomain" '
    Private _SecurityPath As String = "DC"
    Private _GUID As String
    Private _Status As UserStatus
    Private _UserID As Integer
    Private _LoginName As String = "Not Logged In"
    Private GroupBase As String = ""
    Private _LoginStatus As ADUser.LoginResult
    Private _LoggedIn As DateTime 
    Public Enum LoginResult
        OK = 0
        Disabled = 1
        LockedOut = 2
        BadUser = 4
        BadPassword = 8
        PasswordExpired = 16
    End Enum 
    Private Enum AccountStatus
        Active = 0
        Disabled = &H2
        LockedOut = &H16
        PasswordExpired = &H800000
    End Enum 
    Public Structure UserStatus
        Public UserName As String
        Public IsLockedOut As Boolean
        Public IsDisabled As Boolean
        Public IsPasswordExpired As Boolean
        Public GUID As String
        Public IsValid As Boolean
        Public IsActive As Boolean
        Public IsAuthenticated As Boolean
        Public InternalUserID As Integer
        Public Status As LoginResult
    End Structure 
#End Region 
#Region " Public Functions" 
    Public Function GetUserByGuid(ByVal GUID As String) As String
        Dim RealGuid As String = GUIDToString(GUID)
        Dim TheName As String = "Unknown"
        Dim deUser As DirectoryEntry = New DirectoryEntry(_Path) 
        Dim dsSearch As DirectorySearcher
        Dim srUser As SearchResult
        dsSearch = Nothing
        srUser = Nothing 

        Try 
            dsSearch = New DirectorySearcher(deUser)
            dsSearch.Filter = "(objectGUID=" + RealGuid + ")"
            dsSearch.PropertiesToLoad.Add("displayname")
            srUser = dsSearch.FindOne()
            TheName = srUser.Properties.Item("displayname").Item(0)
            srUser = Nothing
            dsSearch = Nothing
        Catch ex As Exception
        End Try
        Return TheName
    End Function 
    Public Function GetEmailFromGUID(ByVal GUID As String) As String
        Dim RealGuid As String = GUIDToString(GUID)
        Dim TheName As String = "Unknown"
        Dim deUser As DirectoryEntry = New DirectoryEntry(_Path) 
        Dim dsSearch As DirectorySearcher
        Dim srUser As SearchResult
        dsSearch = Nothing
        srUser = Nothing 

        Try 
            dsSearch = New DirectorySearcher(deUser)
            dsSearch.Filter = "(objectGUID=" + RealGuid + ")"
            dsSearch.PropertiesToLoad.Add("mail")
            srUser = dsSearch.FindOne()
            TheName = srUser.Properties.Item("mail").Item(0)
            srUser = Nothing
            dsSearch = Nothing
        Catch ex As Exception
        End Try
        Return TheName
    End Function 

    Public Sub Login(ByVal UserName As String, ByVal Password As String, Optional ByVal Authenticate As Boolean = False) 
        If UserName Is Nothing Then Exit Sub ' gets us out if we don't have a current user to check against 
        Dim lResult As LoginResult
        Dim usUser As UserStatus
        Dim deUser As DirectoryEntry = New DirectoryEntry(_Path) 
        Dim objADObject As Object = Nothing
        Dim dsSearch As DirectorySearcher
        Dim srUser As SearchResult
        dsSearch = Nothing
        srUser = Nothing
        usUser = Nothing 
        'Clear the local array of groups so we don't inadvertently return it for the wrong user
        ReDim _Groups(0)
        _Groups(0) = "None" 
        'If we are supplied the domain as part of the username strip it out as this is not relevant
        If UserName.IndexOf("\") > 0 Then
            UserName = Split(UserName, "\")(1)
        End If 
        Try 
            dsSearch = New DirectorySearcher(deUser)
            dsSearch.Filter = "(SAMAccountName=" + UserName + ")"
            dsSearch.PropertiesToLoad.Add("cn")
            dsSearch.PropertiesToLoad.Add("useraccountcontrol")
            dsSearch.PropertiesToLoad.Add("memberof")
            dsSearch.PropertiesToLoad.Add("displayname")
            dsSearch.PropertiesToLoad.Add("objectGUID")
            dsSearch.PropertiesToLoad.Add("lockoutTime")
            srUser = dsSearch.FindOne() 
            If lResult = LoginResult.OK Then 'all went well so far so get the user's displayname
                _DisplayName = srUser.Properties.Item("displayname").Item(0)
                usUser.UserName = _DisplayName
                _LoginName = UserName
                _GUID = GetGUID(srUser.Properties.Item("objectGUID").Item(0))
                usUser.GUID = _GUID
                usUser.IsValid = True
                usUser.IsActive = True
            End If 
            If srUser Is Nothing Then 'We couldn't find it so store this value in the return 
                lResult = LoginResult.BadUser
                usUser.IsValid = False
            End If 
            If lResult = LoginResult.OK Then 'The user exists so lets check their status
                Dim uac As Integer = srUser.Properties("useraccountcontrol").Item(0)
                Dim intLockoutTime As Int64 = 0
                If srUser.Properties("lockoutTime") Is Nothing Then
                    intLockoutTime = 0
                Else
                    If srUser.Properties("lockoutTime").Count > 0 Then
                        intLockoutTime = srUser.Properties("lockoutTime").Item(0)
                    End If
                End If
                If (uac And AccountStatus.LockedOut) <> 0 Or intLockoutTime <> 0 Then  ' The account has been locked out
                    lResult = lResult Or LoginResult.LockedOut
                    usUser.IsLockedOut = True
                End If
                If (uac And AccountStatus.Disabled) <> 0 Then  ' The account is disabled
                    lResult = lResult Or LoginResult.Disabled
                    usUser.IsDisabled = True
                End If
                If (uac And AccountStatus.PasswordExpired) <> 0 Then  ' The account's password has expired
                    lResult = lResult Or LoginResult.PasswordExpired
                    usUser.IsPasswordExpired = True
                End If
            End If 
            deUser.Dispose()
            deUser = Nothing 
            ''Bind to the native AdsObject to force authentication.		
            If lResult = LoginResult.OK And Authenticate Then 'The user is active and we can now authenticate them (perhaps)
                deUser = New DirectoryEntry(_Path, _Domain & "\" & UserName, Password, AuthenticationTypes.Secure)
                objADObject = deUser.NativeObject
                'As they are all ok, store the GUID for the user in AD so we can refer to them
                _GUID = GetGUID(srUser.Properties.Item("objectGUID").Item(0))
                usUser.GUID = _GUID
                usUser.IsAuthenticated = True
            End If 
            If lResult = LoginResult.OK Then 'all went well so far so find the groups that this person belongs to 
                If Not (srUser.Properties.Item("memberof") Is Nothing) Then
                    If srUser.Properties.Item("memberof").Count > 0 Then 'Check to see whether they are actually a member of any groups at all.
                        ReDim _Groups(srUser.Properties.Item("memberof").Count - 1)
                        srUser.Properties.Item("memberof").CopyTo(_Groups, 0)
                    End If
                End If
            End If 
        Catch ex As Exception
            lResult = lResult Or LoginResult.BadPassword
        End Try 
        'Now clean up the objects 
        If Not (objADObject Is Nothing) Then objADObject = Nothing
        If Not (dsSearch Is Nothing) Then dsSearch.Dispose() : dsSearch = Nothing
        If Not (deUser Is Nothing) Then deUser.Dispose() : deUser = Nothing
        If Not (srUser Is Nothing) Then srUser = Nothing 
        'Now check whether that was all good, if so then we can sneak this user into the user's table (or update existing records as appropriate) so that we don't have to rewrite the entire app
        If usUser.IsValid And usUser.IsActive And usUser.IsAuthenticated Then 'all good
            _LoggedIn = Now()
        End If
        'Finally return the result so we can decide what to do next
        _Status = usUser
        _LoginStatus = lResult 
    End Sub 
#End Region 
#Region " Private Functions and Subs" 
    Private Function GetGUID(ByVal GUID As Object) As String 
        Dim intByte As Integer
        Dim strGUID As String = ""
        Dim aryGuid() As Byte 
        aryGuid = GUID
        Try
            For intByte = LBound(aryGuid) To UBound(aryGuid)
                strGUID = strGUID & Right("00" & Hex(aryGuid(intByte)), 2)
            Next
        Catch ex As Exception
            strGUID = "".PadLeft(32, "0")
        End Try
        Return strGUID
    End Function 
    Private Function GUIDToString(ByVal GUID As String) As String
        Dim sbGUID As StringBuilder = New StringBuilder
        Dim intPos As Integer
        For intPos = 0 To GUID.Length - 2 Step 2
            sbGUID.Append("\").Append(GUID.Substring(intPos, 2))
        Next
        Return sbGUID.ToString
    End Function 
#End Region 
#Region " Properties" 
    Public ReadOnly Property LoggedIn() As DateTime
        Get
            Return _LoggedIn
        End Get
    End Property 
    'Converts the array held in the class to an enumerable arraylist object so we can do more with it
    Public ReadOnly Property Groups() As ArrayList
        Get
            If _Groups(0) = "None" Then
                Return Nothing
            Else
                Dim Group As String
                Dim arlGroups As ArrayList = New ArrayList
                For Each Group In _Groups
                    arlGroups.Add(Group)
                Next
                Return arlGroups
            End If
        End Get
    End Property 
    Public ReadOnly Property RolesXML() As String
        Get
            Dim strXML As String = "<ROOT>"
            Dim Group As String
            If Not (_Groups Is Nothing) Then
                For Each Group In _Groups
                    If Group.IndexOf(GroupBase) > 0 And Group.IndexOf(_SecurityPath) > 0 Then
                        strXML = strXML & "<Group GroupName=""" & Group.Substring(3, Group.IndexOf("OU=") - 4) & """></Group>"
                    End If
                Next
            End If
            strXML = strXML & "</ROOT>"
            Return strXML
        End Get
    End Property 
    Public ReadOnly Property DisplayName() As String
        Get
            Return _DisplayName
        End Get
    End Property 
    Public ReadOnly Property GUID() As String
        Get
            Return _GUID
        End Get
    End Property 
    Public ReadOnly Property Status() As UserStatus
        Get
            Return _Status
        End Get
    End Property 
    Public ReadOnly Property IsInGroup(ByVal GroupName As String) As Boolean
        Get
            Dim Group As String
            For Each Group In _Groups
                If Group.ToLower.IndexOf(GroupName.ToLower) > 0 And Group.IndexOf(_SecurityPath) > 0 Then
                    Return True
                End If
            Next
            Return False
        End Get
    End Property 
    Public ReadOnly Property UserID() As Integer
        Get
            Return _UserID
        End Get
    End Property 
    Public ReadOnly Property LoginName() As String
        Get
            Return _LoginName
        End Get
    End Property 
    Public ReadOnly Property LoginStatus() As LoginResult
        Get
            Return _LoginStatus
        End Get
    End Property 
#End Region 
End Class

Open in new window

0
 
Mike MillerSoftware EngineerAuthor Commented:
Tim, Ok I've got the VB example all set up. I'm having some trouble figuring out how/what to call and what is being returned.
0
 
TimCotteeCommented:
There is a whole load in there that you probably don't really need.

The basic method is to instantiate the class then call it's Login method with a username and password as parameters. You can then check the classes properties to see what happened, either it will be authenticated or you will get one of the other properties set:

E.g.,

Dim myClass As ADUser = New ADUser
myClass.Login ("Somebody","Password")
If myClass.Status.IsAuthenticated Then
 'All is well
Else
 'Something went wrong so either .Status.IsDisabled/IsLOckedOut/IsPasswordExpired will be true indicating where the problem lies. If none of these are true then it was a simple password error.

The choice of what to do on IsAuthenticated=False is up to you, you may want to report the more detailed result or simply tell them to try again.
0
 
Mike MillerSoftware EngineerAuthor Commented:
In this code, Authenticate is returning false. I've got _Path set to the root LDAP. Does this need to be the actual OU that the user is located in? It's essentially coming back as...

deUser = New DirectoryEntry(LDAP://000.000.00.000, MY-DOM & "\" & UserName, Password, AuthenticationTypes.Secure)

The root path is correct, as is the domain, user, and pass, but it is not authenticating.
            If lResult = LoginResult.OK And Authenticate Then 'The user is active and we can now authenticate them (perhaps)
                deUser = New DirectoryEntry(_Path, _Domain & "\" & UserName, Password, AuthenticationTypes.Secure)
                objADObject = deUser.NativeObject
                'As they are all ok, store the GUID for the user in AD so we can refer to them
                _GUID = GetGUID(srUser.Properties.Item("objectGUID").Item(0))
                usUser.GUID = _GUID
                usUser.IsAuthenticated = True
            End If

Open in new window

0
 
Mike MillerSoftware EngineerAuthor Commented:
For Grins I took off the "And Authenticate" part of this code and it runs through fine. Obviously it's not valid as Authenticate always comes back true for a valid user. How is it that Authenticate becomes True?
            If lResult = LoginResult.OK Then 'And Authenticate Then 'The user is active and we can now authenticate them (perhaps)
                deUser = New DirectoryEntry(_Path, _Domain & "\" & UserName, Password, AuthenticationTypes.Secure)
                objADObject = deUser.NativeObject
                'As they are all ok, store the GUID for the user in AD so we can refer to them
                _GUID = GetGUID(srUser.Properties.Item("objectGUID").Item(0))
                usUser.GUID = _GUID
                usUser.IsAuthenticated = True
            End If

Open in new window

0
 
Mike MillerSoftware EngineerAuthor Commented:
Using it like this works. When the correct PW was entered it worked and when the wron PW entered it did what it was supposed to do. Am I leaving myself open by doing it this way?
            'If lResult = LoginResult.OK And Authenticate Then 'The user is active and we can now authenticate them (perhaps)
            deUser = New DirectoryEntry(_Path, _Domain & "\" & UserName, Password, AuthenticationTypes.Secure)
            objADObject = deUser.NativeObject
            'As they are all ok, store the GUID for the user in AD so we can refer to them
            _GUID = GetGUID(srUser.Properties.Item("objectGUID").Item(0))
            usUser.GUID = _GUID
            usUser.IsAuthenticated = True
            'End If

Open in new window

0

Featured Post

Problems using Powershell and Active Directory?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

  • 5
  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now