# VBForums CodeBank > CodeBank - Visual Basic .NET >  Validate Login against Active Directory

## Wokawidget

The following function validates a username and password against an active directory.

VB Code:
Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
        Dim Success As Boolean = False
        Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
        Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
        Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
        Try
            Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
            Success = Not (Results Is Nothing)
        Catch
            Success = False
        End Try
        Return Success
    End Function
This would be used like:

VB Code:
If ValidateActiveDirectoryLogin("VBForums", "Woof", "Mouse") Then
   'do something
End If
Woka

----------


## RuaanD

Hallo,

Is it possible to use this code in the Login Form of vb .net?

Where must I place it?

Also, can it be used in the Custom Login Authentication ASP code that you have written?

Apreciate the help.

Ruaan

----------


## Wokawidget

Yes to both answers.
Place the code where it can be called. It's just a simple normal bog standard function after all.
Yes it can be directly used with my auth code.

Woka

----------


## RuaanD

Hi, I'm busy taking a look at the login.aspx code and can you tell me where must I place this code


VB Code:
Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
            Dim Success As Boolean = False
            Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
            Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
            Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
            Try
                Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
                Success = Not (Results Is Nothing)
            Catch
                Success = False
            End Try
            Return Success
        End Function

Thanks,

R

----------


## RuaanD

> Hi, I'm busy taking a look at the login.aspx code and can you tell me where must I place this code
> 
> 
> VB Code:
> Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
>             Dim Success As Boolean = False
>             Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
>             Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
>             Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
> ...


Sorry my ASP is very bad

----------


## Wokawidget

U put that code in the login function ub the auth demo.

Woka

----------


## michaelrawi

Hi Wokawidget,

Your code doesn't work in my project. It always return false. It generate error (the server is not operational) if I remove try-catch and search it directly with this:


VB Code:
Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
        Dim Success As Boolean = False
        Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
        Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
        Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
        'Try
        '    Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
        '    Success = Not (Results Is Nothing)
        'Catch
        '    Success = False
        'End Try
         Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
        Success = Not (Results Is Nothing)
        Return Success
    End Function

My domain server still use WinNT4.0, maybe that happened because WinNT4.0 doesn't support it?

Thanks

Michael

----------


## Wokawidget

What is the value of "LDAP://" & Domain???

Woka

----------


## michaelrawi

"LDAP://skb_ii"

skb_ii is the name of my domain.

----------


## Wokawidget

Hmmmm try modifying the code so the domain passed to the DirectoryEntry object is like:

LDAP://skb_ii.com/DC=skb_ii,DC=com

What happens now?

Woka

----------


## michaelrawi

> Hmmmm try modifying the code so the domain passed to the DirectoryEntry object is like:
> 
> LDAP://skb_ii.com/DC=skb_ii,DC=com
> 
> What happens now?
> 
> Woka



It still not work. Weren't it supposed to be LDAP://skb_ii.com/D*N*=skb_ii,DC=com ? I've tried this either, but still no luck. It gives the same error mistake:




> The server is not operational


at this line :

VB Code:
Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne

And for .com, maybe NT4 didn't support DNS ? (don't have experience in legacy system  :Frown:  )

There's a win2000 server in my company. Maybe I should try join it to test my code.

----------


## wrecklesswun

If this is an NT4 domain, this may not work. NT4 does not understand this provider

----------


## Wokawidget

Hmmmm...are ppl still running NT4  :Wink: 

Woof

----------


## cjwallace

Hi guys.

Does anyone have any ideas or can help me. I have a windows application that i would like to have a login to. I would like the login to check if you are a member of a certain group and then authenticate you to Active Directory by supplying a valid user name and password.

Maybe i am reading this post wrong but it looks like you are hard coding the user name and password into the code???

What if my password changes or i want to give more than one person access to use my application?

Thanks to anyone who can help me

Cheers

----------


## Wokawidget

lol. No, nothing is hard coded.
The function validates a username and password for a domain, and you can pass in all 3 params.
I added a demo call, which does have the params "hard coded", but you would just take these values from a UI input...which is simple to do.

Once you have the user in the search results, you can then browse through it's children and check for the group you want.

Woka

----------


## cjwallace

Hi mate and thanks for the reply.

Ok i am new to vb.net biiiiiiiiiiiiiig time, got kind of comfy with vbscript but realise how lazy a coder it makes you.

Anyway i am using vb.net 2005 and i have used the built in login form that i would like to use. The code for the form is below, Can you help me blend your code into the code below and to check for AD membership. What i would like to achive is if User Craig Wallace is not a member of say AD Security Group called User Creation then dont let him in, if he is and he supplies the correct login and password then let him in

Thanks for your help so far.

Public Class LoginForm

    ' TODO: Insert code to perform custom authentication using the provided username and password 
    ' (See http://go.microsoft.com/fwlink/?LinkId=35339).  
    ' The custom principal can then be attached to the current thread's principal as follows: 
    '     My.User.CurrentPrincipal = CustomPrincipal
    ' where CustomPrincipal is the IPrincipal implementation used to perform authentication. 
    ' Subsequently, My.User will return identity information encapsulated in the CustomPrincipal object
    ' such as the username, display name, etc.

    Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
        Me.Close()
    End Sub

    Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click
        Me.Close()
    End Sub

End Class

----------


## Wokawidget

Well in the OK_Click event you need to call my function with the username and password, and pass in the domain info.
But before you do that you much loop through the search results...the user object can be found in the results object.
Once you have this then you need to loop through it's children and find the group.
Sorry, I don't have time to write it for you as I am pushed with deadlines  :Frown: 

See what you can find on VBF or google regarding AD search results.

Woka

----------


## cjwallace

Hi mate. Thanks very much for the reply. I am soooooooooooooooooo new to vb.net , whats the best way of calling your function. there is no big rush to reply as i know your busy, just when you have a minute

I am going to do this bit by bit.

First get it working with just a user name and password then move on to more advanced stuff like AD group

Thanks again

----------


## Wokawidget

Ok. np  :Smilie: 
Lets do this in stages.
So to use the code as it stands now, just validating the user (no group code yet), we would use something like:


```
Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
   Dim authenticated As Boolean = AuthenticateUser()
   If isAuthenticated Then
      'some code here to open app
      Me.Close()
   Else
      'code here to display incorrect login details
   End If
End Sub

Private Function AuthenticateUser() As Boolean
   Dim username As String = txtUsername.Text
   Dim password As String = txtPassword.Text
   Dim domain As String = 'this can be in a config file, hard coded (I wouldnt do that), or inputed from the UI

   Dim isAuthenticated As Boolean = ValidateActiveDirectoryLogin(username, password, domain)

   Return isAuthenticated
End Function
```

Hope this helps.

Woka

----------


## cjwallace

Hi mate. Thanks for your time tonight.

Ok so i have copied your code into the form.

It may just be a typo but is Dim authenticated not supposed to be Dim isauthenticated 



```
Dim authenticated As Boolean = AuthenticateUser()
   If isAuthenticated Then
```

Other small issues that vb.net is throwing up are

txtUserNames is not declared
txtPasswords is not declared

on line

Dim domain As String = 'this can be in a config file, hard coded (I wouldnt do that), or inputed from the UI

it is moaning about the = saying expression expected.

Also it is moaning about Name 'ValidateActiveDirectoryLogin' is not declared.



```
Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
   Dim authenticated As Boolean = AuthenticateUser()
   If isAuthenticated Then
      'some code here to open app
      Me.Close()
   Else
      'code here to display incorrect login details
   End If
End Sub

Private Function AuthenticateUser() As Boolean
   Dim username As String = txtUsername.Text
   Dim password As String = txtPassword.Text
   Dim domain As String = 'this can be in a config file, hard coded (I wouldnt do that), or inputed from the UI

   Dim isAuthenticated As Boolean = ValidateActiveDirectoryLogin(username, password, domain)

   Return isAuthenticated
End Function
```

----------


## Wokawidget

txtUsername is the name of the text box on screen, as is txtPassword. In your app I don't know what they are called. Replace txtUsername and txtPassword with the name of the controls on your form.

ValidateActiveDirectoryLogin is the function originally posted in this thread....did you not copy that also?

The comain name is giving that error because ' means a remark, ie you must replace this bit of code with something.
Use something like:

Dim domain As String = "MyDomain.com"

Bearing in mind your domain is NOT MyDomain.com...it's soemthing else, so replace that with your domain.

Yea, sorry about typos' Am tired and typed straight into VBF and not a VB.NET editor.

I may suggest you get a Learn VB.NET in 21 days kind of book...this will seriously benefit you, and you'll be up and running in no tiem at all.

WOka

----------


## cjwallace

Thanks for the reply. i am also very tired and going to bed now. i will pick this up tomorrow. thanks for the pointers i will put them right tomorrow.

Thanks again for your help, it really is helping me learn big time.

Cheers

----------


## cjwallace

Hi mate.

Ok picking this back up tonight. I have copied your code as per your posts and have put it into my login form. I am hard coding the domain for the time being. Now when the form loads i am putting the correct login details as thats what i used to login to my laptop but the code always returns in correct login details. I have put a couple of msgbox's in as you will see.

Any ideas as to why it does not think i am using the right details?

Thanks for your help.



```
Public Class AuthenticateWithAD

    Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
        Dim isauthenticated As Boolean = AuthenticateUser()
        If isauthenticated Then
            MsgBox("YOU HAVE BEEN AUTHENTICATED")
            Me.Close()
        Else
            MsgBox("YOU HAVE NOT BEEN AUTHENTICATED")
        End If
    End Sub

    Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
        Dim Success As Boolean = False
        Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
        Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
        Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
        Try
            Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
            Success = Not (Results Is Nothing)
        Catch
            Success = False
        End Try
        Return Success
    End Function

    Private Function AuthenticateUser() As Boolean
        Dim username As String = UsernameTextBox.Text
        Dim password As String = PasswordTextBox.Text
        'Dim domain As String = 'this can be in a config file, hard coded (I wouldnt do that), or inputed from the UI
        Dim domain As String = "WALLACE-UK.COM"

        Dim isAuthenticated As Boolean = ValidateActiveDirectoryLogin(username, password, domain)

        Return isAuthenticated
    End Function

    Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click
        Me.Close()
    End Sub

End Class
```

----------


## Wokawidget

ValidateActiveDirectoryLogin(username, password, domain)

should be

ValidateActiveDirectoryLogin(domain, username, password)

----------


## cjwallace

Hi mate. Thanks very much for the update. i have changed my code as per your last post. YAY all is working i can now see it is checking with AD for my login which is cool, so thanks very much.

Ok so on to Part 2. What i now need to work out is that ok so you have the right user name and password but if you are not a member of a Active Directory user group the dont allow login , but if you are and you supply the right user name and password then login.

Any ideas?

Thanks in advance

----------


## cjwallace

Hi guys. Ok thought i would share back this code with others. Ok the code is the original code in that it will authenticate a user againt Active Directory.

The will now also check to see if the user is a member of a certain Active Directory Group. So you now have Group Check and User Name and Password Check.

Also and it may no use to others but i hve put a bit in here to check if the screen res is 1024 x 768 or above. also it has a progress bar. 

Afew people on here have helped me along the way so cant take full credit for it.

Anyway here is the code. I hope someone finds it usefull



```
Imports System.DirectoryServices
Imports System.Net.Mail

Public Class Authenticate_With_Active_Directory

    Private Sub OK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK.Click
        Dim isauthenticated As Boolean = AuthenticateUser()

        If isauthenticated Then

            ProgressBar1.Value = 1

            Timer1.Enabled = True



            'MsgBox("YOU HAVE BEEN AUTHENTICATED")

            Dim frm As New Main_Menu
            frm.Show()

            Me.Close()

        Else

            ProgressBar1.Value = 1

            Timer1.Enabled = True

            MessageBox.Show("YOU HAVE NOT BEEN AUTHENTICATED" & _
                Environment.NewLine & Environment.NewLine & "PLEASE CONTACT THE LONDON SYSTEMS TEAM. THIS LOGON ATTEMPT HAS BEEN RECORDED", "Alert - PLEASE READ , PLEASE READ", MessageBoxButtons.OK, MessageBoxIcon.Information)

        End If


    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        ProgressBar1.Value = ProgressBar1.Value + 1
        If ProgressBar1.Value = 50 Then
            Timer1.Enabled = False
            'MsgBox(" progressbar at the end")
        End If
    End Sub


    Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean
        Dim Success As Boolean = False
        Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)
        Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)
        Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel
        Try
            Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne
            Success = Not (Results Is Nothing)
        Catch
            Success = False
        End Try
        Return Success
    End Function

    Private Function AuthenticateUser() As Boolean
        Dim username As String = UsernameTextBox.Text
        Dim password As String = PasswordTextBox.Text
        'Dim domain As String = 'this can be in a config file, hard coded (I wouldnt do that), or inputed from the UI
        Dim domain As String = "WITHERS.NET"

        Dim isAuthenticated As Boolean = ValidateActiveDirectoryLogin(domain, username, password)

        Return isAuthenticated
    End Function

    Private Sub Cancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel.Click
        Me.Close()
    End Sub

    Private Sub AuthenticateWithAD_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim screenSize As Rectangle = Screen.PrimaryScreen.Bounds
        If screenSize.Width < 1024 Or screenSize.Height < 768 Then
            MessageBox.Show("Incorrect Screen Size" & _
            Environment.NewLine & Environment.NewLine & "This Application requires a Screen Resolution of 1024 x 768 and above. Please change", "Alert - PLEASE READ , PLEASE READ", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Me.Close()
        Else

        End If

        'You grab the current logon username from environment object
        Dim userID As String = Environment.UserName
        'Then pass it into the function like this
        If IsMemberOf(userID, "GROUP NAME YOU WANT TO CHECK") Then
            'MessageBox.Show("Yes")
        Else
            MessageBox.Show("Unauthorised Access, You do not have permission to use this application" & _
                                    Environment.NewLine & Environment.NewLine & "Please contact the London Systems Team", "Alert - UNAUTHORISED ACCESS , UNAUTHORISED ACCESS", MessageBoxButtons.OK, MessageBoxIcon.Information)

            Me.Close()
        End If

    End Sub

    Public Shared Function IsMemberOf(ByVal userName As String, ByVal groupName As String) As Boolean


        ' Uncomment if using at Withers

        Dim answer As Boolean = False
        Dim dirEntry As DirectoryEntry = Nothing
        Dim serverName As String = "SERVER NAME"         'example "server1"
        Dim domainName As String = "DOMAIN NAME"  'example "yahoo", "msn", "google"...
        Dim domain As String = "NET"              'example "com", "org", "net"...
        Dim ldapPath As String = "LDAP://" & serverName & "/DC=" & domainName & ",DC=" & domain
        Dim dirSearcher As DirectorySearcher = Nothing
        Dim result As SearchResult = Nothing
        Try
            'dirEntry = New DirectoryEntry(ldapPath)
            'If you run into security permission issue, try this overload with supplied credentials
            dirEntry = New DirectoryEntry(ldapPath, "USERNAME", "PASSWORD", AuthenticationTypes.Secure)


            dirSearcher = New DirectorySearcher(dirEntry)
            With dirSearcher
                .Filter = "(SAMAccountName=" & userName & ")"
                .PropertiesToLoad.Add("memberOf")
                result = .FindOne()
            End With
            If Not result Is Nothing Then
                Dim propertyCount As Integer = result.Properties("memberOf").Count
                Dim dn As String = String.Empty
                Dim group As String = String.Empty
                Dim equalsIndex, commaIndex As Integer
                Dim propertyCounter As Integer = 0
                While propertyCounter < propertyCount
                    dn = CType(result.Properties("memberOf").Item(propertyCounter), String)
                    equalsIndex = dn.IndexOf("=", 1)
                    commaIndex = dn.IndexOf(",", 1)
                    If -1 = equalsIndex Then
                        Return False
                    End If
                    group = dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1).ToUpper
                    If group = groupName.ToUpper Then
                        answer = True
                        Exit While
                    End If
                    propertyCounter += 1
                End While
            End If
        Catch ex As Exception
            Throw New Exception(ex.Message)
        Finally
            'Release unmanaged COM objects
            dirEntry = Nothing
            dirSearcher = Nothing
        End Try
        Return answer

    End Function

End Class
```

----------


## Wokawidget

Cool. Thanks for the code  :Big Grin: 

Woka

----------


## Wokawidget

Hi.

I have cleaned the code up slightly for you. I hope you don't mind.
I have also combined the Validate and the Check group functions into one function.

You seemed to be doing something funny with the ldap path, so I simplified this also.

If you pass a groupname to the function then it validates this and checks if the user is a member, if no groupname is passed then the user is validated for a normal login.

Hope this helps, and thanks again for posting the code.


```
Private Function AuthenticateUser() As Boolean
        Dim username As String = "TestUser11@WokasCustomer.com"
        Dim password As String = "Woof123"
        Dim domain As String = "eQuest.local"

        Dim isAuthenticated As Boolean = ValidateActiveDirectoryLogin(domain, username, password, "Admins@WokasCustomer.com")

        Return isAuthenticated
    End Function




    Public Function ValidateActiveDirectoryLogin(ByVal domainName As String, ByVal userName As String, ByVal userPassword As String, ByVal groupName As String) As Boolean
        Dim isValidated As Boolean = False

        Try

            Dim ldapPath As String = "LDAP://" & domainName
            Dim dirEntry As New DirectoryEntry(ldapPath, userName, userPassword, AuthenticationTypes.Secure)
            Dim dirSearcher As New DirectorySearcher(dirEntry)

            dirSearcher.Filter = "(userPrincipalName=" & userName & ")"
            dirSearcher.PropertiesToLoad.Add("memberOf")

            Dim result As SearchResult = dirSearcher.FindOne()

            If Not result Is Nothing Then

                If groupName.Length = 0 Then
                    isValidated = True
                Else
                    Dim groupCount As Integer = result.Properties("memberOf").Count
                    Dim isInGroup As Boolean = False

                    For index As Integer = 0 To groupCount - 1
                        Dim groupDN As String = result.Properties("memberOf").Item(index)

                        Dim equalsIndex As Integer = groupDN.IndexOf("=")
                        Dim commaIndex As Integer = groupDN.IndexOf(",")

                        Dim group As String = groupDN.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1).ToLower
                        If group.Equals(groupName.ToLower) Then
                            isInGroup = True
                            Exit For
                        End If
                    Next index

                    isValidated = isInGroup
                End If
            End If
        Catch ex As Exception
            Throw New Exception(ex.Message)
        End Try

        Return isValidated

    End Function
```

Woka

----------


## cjwallace

Hi mate. No of course i dont mind and its great to see another way of doing it. All about learning

Thanks again.

----------


## Wokawidget

np  :Smilie: 

Also, I changed it to search for sAMAccountName to userPrincipalName.

sAMAccountNames are like eQuest\Wokawidget
userPrincipalNames are like Wokawidget@eQuest.com

Most MS apps now use the UPN and not SAMAccountName...except some of thier hosting software, with exchange, as that requires the sAMAccountName to validate a mobile device.

Woka

----------


## sherwin

hi there.

not that into development, but i find the code very helpful.

is there a way for the code to be modified and also check for "Bad Login Count"?

regards.

----------


## sherwin

no suggestion? can someone suggest how to get badlogoncount?regards

----------


## Wokawidget

Well if badlogin account is an AD property, then just retrieve this property from the users AD object, which is got during validation process.

ie


```
int loginCount = Convert.ToInt32(userADobject.properties["badLogin"].Value.ToString())
```

But off the top of my head I dont know what the bad login count ad property is.

Woka

----------


## sherwin

thanks for the reply. i'll try that suggestion.

we used this:


```
    IntAttempts = objUser.BadLoginCount
```

but it's not working as expected.

regards.

----------


## xion.truth

The code works great.  Thank you very much.   

is there a way in this function to check the manager property within active directory.  for instance:

Johns manager is Sam

When John logs in it runs 

```
messagebox.show("Your manager is " &  somthing here)
```

thanks again

----------


## Wokawidget

Yes.
From Post 28, the user object is stored in a variable called "result".
So to get the manager you would use the following:



```
Dim managerPath As String.Empty;
if (result.Properties("managedBy").Count == 1) Then
   Dim managerDN As String = result.Properties("managedBy").Value.ToString()
   managerPath = string.Format("LDAP://{0}", managerDN); 
End If
if (managerPath.length > 0) Then
   DirectoryEntry managerObject = new DirectoryEntry(managerPath)
   string managerUPN = managerObject.Properties("userprincipalName").value.ToString()
   string managerDisplayName = managerUPN;
   if (managerObject.Properties("displayName").Count == 1) Then
      managerDisplayName = managerObject.Properties("displayName").value.ToString()
   End If
End if
```

Hope that helps.

Woka

----------


## xion.truth

Is that vb.net code or C# I have not been able to get it to work here is a screen shot of the errors:

----------


## Wokawidget

yes u are right...its a mix of them both  :Big Grin: 

Doh

I have been coding in both a lot recently.
try this:


```
Dim managerPath As String = String.Empty
if (result.Properties("managedBy").Count = 1) Then
   Dim managerDN As String = result.Properties("managedBy").Value.ToString()
   managerPath = string.Format("LDAP://{0}", managerDN)
End If
if (managerPath.length > 0) Then
   Dim managerObject As DirectoryEntry = new DirectoryEntry(managerPath)
   Dim managerUPN As String= managerObject.Properties("userPrincipalName").value.ToString()
   Dim managerDisplayName As String = managerUPN
   if (managerObject.Properties("displayName").Count = 1) Then
      managerDisplayName = managerObject.Properties("displayName").value.ToString()
   End If
End if
```

Also u need to add:


```
dirSearcher.PropertiesToLoad.Add("managedBy")
```

----------


## xion.truth

Thank you so much for you time and help.  I am a noob at active directory.

I also still have one error when i get to the 



```
If (result.Properties("managedBy").Count = 1) Then
```

the system says "Object referance not set to an instace of an object"

also the code still shows the following error.  If i remove the .value.toString  and replace it with .toString it will take the error away but i dont know if it will work here is a picture.  thanks again for your help!

----------


## Wokawidget

yea, sorry.Was on my mobile fone in town when I posted  :Big Grin: 
instead of

.Value.ToString()

use

.Item(0).ToString();

Woka

----------


## Wokawidget

Oh, and after checking by AD...the field is "manager", and not "managedBy"...How wrong could I have been. doh!
Sorry about that.
the AD property "managedBy" is on a group object, and not a user one.

Woka

----------


## sghazagh

Hello guys,
I don't know if this post still is live but first of all I would like to thank you all as I didn't know this is simple to use LDAP like this.

My code working great but my problem is that if I use a wrong password for existing username the user get locked.

How can I prevent this then I can just validate the username and password in the Active Directory.

Is there any way?

Cheers,
 :Thumb:

----------


## sghazagh

Just to let you know that I have used the first posted function in this section

cheers

----------


## RBC827

Thanks for this code.  It got me pass the first part of my little app, but now I need to know how to pass the AD credentials to another form.  My app simply allows an Admin to login to the app and then run programs as an Admin like "RunAs" for common apps.  Any advice on how to achieve this would be helpful.

thanks!

----------


## CXXXV

I am trying to use the OP code to find AD username. However, the only info available to me is Domain and ComputerName.

I've been searching for hours. Any ideas.

----------


## maikeru-sama

I have a few questions regarding the code the Original Poster provided.

1) Will the code work for Framework 2.0 and 3.5?

2) Is this the best code to use if one just wants to verify that the user does exist in Active Directory?  The App that I am making will have its own security but at the least, they must be valid Domain Users.

3) My app will be an ASP.net app so would I be correct in assuming that I can use the same code?

----------


## Wokawidget

Good morning,

1) Yes, the DirectoryServices code has not changed through the frameworks...each Framework does however add more functionality to DirectoryService.
2) Hmmmmm...not 100% sure. You could use The directory Searcher and just check if there is 1 result returned...or you can look into the DirectoryServices.AccountManagement namespace and play with the user object. http://msdn.microsoft.com/en-us/libr...anagement.aspx
3) This shouldn't be an issue...most of the AD coding I have done has been from an ASP.NET application.

Cheers,

Woka

----------


## Wokawidget

> I am trying to use the OP code to find AD username. However, the only info available to me is Domain and ComputerName.
> 
> I've been searching for hours. Any ideas.


I am not sure I follow. How can you search for a username that you don't know? :s

Woka

----------


## maikeru-sama

Woka thanks for responding. 

I get an invalid login and password each time even when I modify some of the code.

I don't have access to the Active Directory Server but I bet I have to drill down more than just one level as I bet they have everyone in groups and then in the group you can access the username.

That is just a guess but I have decided to go ahead and have my application have its own security and forget about AD.

If I am not mistaken, it sends the Username and Password in clear text over the Internet as well.

Thanks for the code.

----------


## CXXXV

> I am not sure I follow. How can you search for a username that you don't know? :s
> 
> Woka


I am able to obtain the computer name of the users of an .mdb via the JETSCHEMA built in to VB. However, what I need is to then search the AD using the computer name and return who is logged in to that computer.

----------


## chris128

> I am able to obtain the computer name of the users of an .mdb via the JETSCHEMA built in to VB. However, what I need is to then search the AD using the computer name and return who is logged in to that computer.


AD cannot tell you who is logged on to a computer. WMI can however  :Smilie: 
Here's an example vbscript**:



```
strRemoteComputer = inputbox("Remote computer name:","Enter PC Name...")

if strRemoteComputer = "" then
wscript.echo "Click OK to close."
	wscript.quit
end if

set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!//" & strRemoteComputer & "")
set colWin32 = objWMI.ExecQuery("Select * from Win32_ComputerSystem")

For Each objItem In colWin32
	if strUsers <> "" then
		strUser = strUser & ", " & objItem.UserName
	else
		strUser = objItem.UserName
	End If
Next

if strUser = "" then
wscript.echo "Could not retrieve users from " & strRemoteComputer & ". Check that the machine is powered on and can access the network"
Else
wscript.echo strUser & " is logged on to " & strRemoteComputer
end if
```

Hope that helps





> If I am not mistaken, it sends the Username and Password in clear text over the Internet as well.
> 
> Thanks for the code.


Not if you use the Secure authentication type it doesnt (DirectoryServices.AuthenticationTypes.Secure)

----------


## simplyrichard

This post has been great! Thank you all for your time. I have a small issue. Here is my code:

This is my Auth.vb:


```
Imports System.DirectoryServices
Imports System.Net.Mail

Public Class Auth
    Public Function AuthNow(ByVal userName As String, ByVal userPassword As String, ByVal groupname As String) As Boolean
        Dim isValidated As Boolean = False
        Dim domainName As String = "XXX.org"

        Try

            Dim ldapPath As String = "LDAP://" & domainName
            Dim dirEntry As New DirectoryEntry(ldapPath, userName, userPassword, AuthenticationTypes.Secure)
            Dim dirSearcher As New DirectorySearcher(dirEntry)

            dirSearcher.Filter = "(SAMAccountName=" & userName & ")"
            dirSearcher.PropertiesToLoad.Add("memberOf")
            dirSearcher.PropertiesToLoad.Add("givenname")
            dirSearcher.PropertiesToLoad.Add("managedBy")
            Dim result As SearchResult = dirSearcher.FindOne()

            Dim managerPath As String = String.Empty
            If (result.Properties("managedBy").Count = 1) Then
                Dim managerDN As String = result.Properties("managedBy").Item(0).ToString
                managerPath = String.Format("LDAP://{0}", managerDN)
            End If
            If (managerPath.Length > 0) Then
                Dim managerObject As DirectoryEntry = New DirectoryEntry(managerPath)
                Dim managerUPN As String = managerObject.Properties("userPrincipalName").Value.ToString()
                Dim managerDisplayName As String = managerUPN
                If (managerObject.Properties("displayName").Count = 1) Then
                    managerDisplayName = managerObject.Properties("displayName").Value.ToString()
                End If

            End If
            If Not result Is Nothing Then

                If groupname.Length = 0 Then
                    isValidated = True
                Else
                    Dim groupCount As Integer = result.Properties("memberOf").Count
                    Dim isInGroup As Boolean = False

                    For index As Integer = 0 To groupCount - 1
                        Dim groupDN As String = result.Properties("memberOf").Item(index)

                        Dim equalsIndex As Integer = groupDN.IndexOf("=")
                        Dim commaIndex As Integer = groupDN.IndexOf(",")

                        Dim group As String = groupDN.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1).ToLower
                        If group.Equals(groupname.ToLower) Then
                            isInGroup = True
                            Exit For
                        End If
                    Next index

                    isValidated = isInGroup
                End If
            End If
        Catch ex As Exception
            MsgBox("Bad Username or Password")
        End Try

        Return isValidated


    End Function
End Class
```

Here is my default.vb:



```
Imports Auth
Partial Class _Default
    Inherits System.Web.UI.Page

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim isauthenticated As Boolean = AuthenticateUser()
        Dim managerDisplayName As String = 
        If isauthenticated Then
            MsgBox("You have logged In!")
        Else
            MsgBox("You have not yet logged in!")
        End If

    End Sub

    Private Function AuthenticateUser() As Boolean

        Dim username As String = txtUsername.Text
        Dim password As String = txtPassword.Text
        Dim groupname As String = "IS"
        Dim AuthSend As New Auth

        Dim isAuthenticated As Boolean = AuthSend.AuthNow(username, password, groupname)
        Return isAuthenticated

    End Function
End Class
```

My question is ... how do I get the manager's name to appear on default.vb?

Thanks,

Richard

----------


## chris128

Well if you want to use the user object that you got from the manager part of the AuthNow function then you would have to return that user object (or just the name if thats all you are after) instead of just returning a boolean. Alternatively, you could just use a separate function to return the manager's name but only if the AuthNow function returns true.

If you want any further help then the best thing to do would be to create a new thread in the VB.NET part of these forums and put all the details in there, as the codebank threads such as this one arent really meant to be used for people just asking questions like yours  :Smilie:

----------


## Wokawidget

Chris is right. That question is not really related to AD code at all, and more geared towards general .NET code design. 
Your AuthNow function needs to return the users AD object.
So in your code you would do:


```
DirectoryEntry authUser = AuthSend.AuthNow(username, password, groupname);
if(authUser != null)
{
   //Authenticated
   string managedBy = string.empty;
   if(authUser.Properties["managedBy"].Value != null)
   {
      managedBy = authUser.Properties["managedBy"].Value.ToString();
   }
}
else
{
   //user failed authentication, do something here
}
```

You may want to create your own user class to return from this function, which holds properties of a user, instead of throwing AD DirectoryEntry objects around, that will lead to "cleaner" code.

Woka

----------


## randygodwin

Can this code be used in classic ASP?  I've been asked to authenticate against AD in a classic ASP-coded page.

----------


## jinx101

Just a note on the original code.  If you use that code in any kind of loop the AD objects need to be disposed of because you'll leak lots of memory otherwise (speaking from personal experience):



```

        Public Shared Function ValidateLogin(ByVal domain As String, ByVal username As String, ByVal password As String) As Boolean
            Dim success As Boolean = False
            Dim entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & domain, username, password)
            Dim searcher As New System.DirectoryServices.DirectorySearcher(entry)
            searcher.SearchScope = DirectoryServices.SearchScope.OneLevel

            Try
                Dim results As System.DirectoryServices.SearchResult = searcher.FindOne
                success = Not (results Is Nothing)
            Catch ex As Exception
                success = False
            Finally
                entry.Close() : entry.Dispose()
                searcher.Dispose()
            End Try

            Return success

        End Function
```

----------


## chris128

> Just a note on the original code.  If you use that code in any kind of loop the AD objects need to be disposed of because you'll leak lots of memory otherwise (speaking from personal experience):
> 
> 
> 
> ```
> 
>         Public Shared Function ValidateLogin(ByVal domain As String, ByVal username As String, ByVal password As String) As Boolean
>             Dim success As Boolean = False
>             Dim entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & domain, username, password)
> ...


That is a good point  :Smilie:  but one minor comment - you don't need to call Close *and* Dispose on the DirectoryEntry object because they both do pretty much exactly the same thing. The Close method just calls an internal method named Unbind (which frees up the resources that were used) and the Dispose method calls the same Unbind method but then also calls MyBase.Dispose. So I would just go with Dispose on its own and not bother with Close  :Smilie:

----------


## iZeR

Hi guys. sorry to reawaken the thread...im using vb.net 2010 and i could really have good use for this code. im making an local domain chat application and the users should login with there domain acc/pw stored in the AD. so if someone could convert this code it would be appreciated.

----------


## chris128

There is no conversion required - this code works in .NET 2.0 so it will work in .NET 4.0 (which is what VS 2010 will target by default but you can just set it to target 2.0 if you want anyway).

Also, for anyone using .NET 3.5 or 4.0, you might want to look at the AccountManagement namespace which is new in .NET 3.5 - see here for more info and examples: http://msdn.microsoft.com/en-us/maga...135979.aspx#S9

----------


## iZeR

this code:

vb Code:
Private Function ValidateActiveDirectoryLogin(ByVal Domain As String, ByVal Username As String, ByVal Password As String) As Boolean        Dim Success As Boolean = False        Dim Entry As New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password)        Dim Searcher As New System.DirectoryServices.DirectorySearcher(Entry)        Searcher.SearchScope = DirectoryServices.SearchScope.OneLevel        Try            Dim Results As System.DirectoryServices.SearchResult = Searcher.FindOne            Success = Not (Results Is Nothing)        Catch            Success = False        End Try        Return Success    End Function
gives this error list:

Error	1	Type 'System.DirectoryServices.DirectoryEntry' is not defined.	C:\Users\karhol02\AppData\Local\Temporary Projects\IP chat with login\Login.vb	5	26	IP chat with login
Error	2	Type 'System.DirectoryServices.DirectorySearcher' is not defined.	C:\Users\karhol02\AppData\Local\Temporary Projects\IP chat with login\Login.vb	6	29	IP chat with login
Error	3	'DirectoryServices' is not declared. It may be inaccessible due to its protection level.	C:\Users\karhol02\AppData\Local\Temporary Projects\IP chat with login\Login.vb	7	32	IP chat with login
Error	4	Type 'System.DirectoryServices.SearchResult' is not defined.	C:\Users\karhol02\AppData\Local\Temporary Projects\IP chat with login\Login.vb	9	28	IP chat with login

----------


## chris128

You need to add a reference to the System.DirectoryServices assembly

----------


## iZeR

thanks its all working out now.

----------


## Wokawidget

Just thought I'd add the following code change.
The Directory Service objects need to be disposed of:


vb Code:
Private Function ValidateActiveDirectoryLogin(ByVal domain As String, ByVal username As String, ByVal userPassword As String) As Boolean
        Dim success As Boolean = False
        Using rootEntry As New System.DirectoryServices.DirectoryEntry("LDAP://" & domain, username, userPassword)
            Using adSearcher As New System.DirectoryServices.DirectorySearcher(rootEntry)
                adSearcher.SearchScope = DirectoryServices.SearchScope.OneLevel
                Try
                        Dim searchResults As System.DirectoryServices.SearchResult = adSearcher.FindOne
                        success = Not (searchResults Is Nothing)
                Catch
                        success = False
                End Try
        End Using
    End Using
        return success
End Function


c# Code:
private bool ValidateActiveDirectoryLogin(string domain, string username, string userPassword)
{
        bool success = false;
        using(System.DirectoryServices.DirectoryEntry rootEntry = New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password))
    {
            using(System.DirectoryServices.DirectorySearcher adSearcher = New System.DirectoryServices.DirectorySearcher(rootEntry))
        {
                adSearcher.SearchScope = DirectoryServices.SearchScope.OneLevel;
                try
            {
                        System.DirectoryServices.SearchResult searchResults = adSearcher.FindOne;
                        success = (searchResults != null);
            }
                catch
            {
                        success = false;
                }
        }
    }
    return success;
}

Hope that helps.

Cheers, woka

----------


## chris128

There isn't really a need for the Success variable, you could just do this (I would also recommend using the Secure binding as I have done in the code below)


vb Code:
Private Function ValidateActiveDirectoryLogin(ByVal domain As String, ByVal username As String, ByVal userPassword As String) As Boolean
   Using rootEntry As New System.DirectoryServices.DirectoryEntry("LDAP://" & domain, username, userPassword, DirectoryServices.AuthenticationTypes.Secure)
      Using adSearcher As New System.DirectoryServices.DirectorySearcher(rootEntry)
                adSearcher.SearchScope = DirectoryServices.SearchScope.OneLevel
                Try
                       Dim searchResults As System.DirectoryServices.SearchResult = adSearcher.FindOne
                       Return Not searchResults Is Nothing
                Catch
                       Return False
                End Try
        End Using
    End Using
End Function

Again though, anyone using .NET 3.5 or 4.0 should probably just use the built in methods in the Sytem.DirectoryServices.AccountManagement namespace to do this.

----------


## Wokawidget

I agree with the secure binding.

The AccountManagement namespace contains objects like Group and UserPrincipal...these are just wrappers around the DirectoryEntry object.
I prefer having the flexibility of using the DirectoryServices namespace and writing app specific wrappers.

One thing I personally disagree with is multiple return exit points from a function. I would strongly discourage this. This can lead to complex and hard to read code execution and the managability of your code decreases.
You gain no benefit by removing the bool success flag, only negatives, yet if you keep it then you have the flexibility for future code modifications and easy of reading the code.

cheers,

Woka

----------


## Wokawidget

One example of this would be if I wanted to log the failure. 

c# Code:
private bool ValidateActiveDirectoryLogin(string domain, string username, string userPassword)
{
        bool success = false;
        using(System.DirectoryServices.DirectoryEntry rootEntry = New System.DirectoryServices.DirectoryEntry("LDAP://" & Domain, Username, Password))
    {
            using(System.DirectoryServices.DirectorySearcher adSearcher = New System.DirectoryServices.DirectorySearcher(rootEntry))
        {
                adSearcher.SearchScope = DirectoryServices.SearchScope.OneLevel;
                try
            {
                        System.DirectoryServices.SearchResult searchResults = adSearcher.FindOne;
                        success = (searchResults != null);
            }
                catch
            {
                        success = false;
                }
        }
    }
             if(!success)
             {
                          ErrorLogging.LogFailedLogin(username);
             }
    return success;
}

If you had multiple exit points then you would have to write more code, a few lines per exit point, which is why it can become unmanagable very quickly.

Hope that helps.

WOka

----------


## chris128

lol surely if you wanted to log the failure you would log it in the Catch block so that you could actually get the exception details?

Anyway, I definitely agree that you get a lot more power and flexibility if you use the DirectoryEntry class etc but as this thread is purely about authenticating a user against AD I think it makes sense to suggest using classes/methods that are there purely to do this kind of thing.





> One thing I personally disagree with is multiple return exit points from a function. I would strongly discourage this. This can lead to complex and hard to read code execution and the managability of your code decreases.


Fine, this then:

vb Code:
Private Function ValidateActiveDirectoryLogin(ByVal domain As String, ByVal username As String, ByVal userPassword As String) As Boolean
   Using rootEntry As New System.DirectoryServices.DirectoryEntry("LDAP://" & domain, username, userPassword, DirectoryServices.AuthenticationTypes.Secure)
      Using adSearcher As New System.DirectoryServices.DirectorySearcher(rootEntry)
                adSearcher.SearchScope = DirectoryServices.SearchScope.OneLevel
                Dim searchResults As System.DirectoryServices.SearchResult
                Try
                       searchResults = adSearcher.FindOne
                Catch
                       searchResults = Nothing
                End Try
                Return Not searchResults Is Nothing
        End Using
    End Using
End Function
I just dont see the point declaring an extra variable when there is no real need for it  :Smilie:

----------


## Wokawidget

> Anyway, I definitely agree that you get a lot more power and flexibility if you use the DirectoryEntry class etc but as this thread is purely about authenticating a user against AD I think it makes sense to suggest using classes/methods that are there purely to do this kind of thing.


Framework 3.5 wasn't out when I 1st created this thread  :Wink:

----------


## Wokawidget

> I just dont see the point declaring an extra variable when there is no real need for it


Some examples of function that could return success or any other variable will not always have a try catch block.
I refer back to my last post about maintainability of multiple exit points.
I think there is a *definate* need for it.

Anyways, that's symantecs of coding, and should be taken up in another thread. Lets not get off track here  :Smilie: 

Woka

----------


## mcvrba

Sorry if this is a double post 

Hey I would appreciate some help. I have implemented your active directory connect which works perfectly but I am trying to connect to a server and download or open a file for viewing. How can this be completed?

Doman: MyCompany.com
Server: ServerOne.MyCompany.com
path: \home\etc
file: Test.pdf

I have been using things like TransferFile but this option does not work when the site is deployed so I am thinking I am not using System.DirectoryServices correctly. Any tips, pointers, examples would be greatly appreciated.

Many Thanks

----------


## rman13

I have a web app using this Validate Login and it works great on an interal server.  Now I need to move this to an external web server that allows AD authentication.  Both of these servers are on Windows Server 2003 SP 2.

When I try to login to the external server it never authenticates.  Besides changing the ldap domain for the exteranl server do I need to change anything else?

In the web.config on the internal server it has:
<authentication mode="Windows"></authentication>
<authorization>
	<deny users="?"/>
</authorization>

On the external server I changed it to forms mode.  

Thanks in advance.

----------


## Philou75

Hi VbForums,

I am very happy to have found your site and this article dealing with what i am looking for a long time ... but for VBA.
Because I use Excel.

I have tried first to understand and adapt the code of all of your functions ... but without success.

Would it be possible for you to give me instructions to do that.
I need to give access to 10 of my colleagues to a workbook in which i have built one sheet for each of them.
We are ALL Authenticated users against our main AD Domain.
I want to display a userform in which each of them could enter its Username / Current AD Password ...
then ... send query to Validate these credentials and finally activate HIS PRIVATE SHEET ... each sheet name is username of my colleague.

Thanks in advance
Regards from PARIS.
Philou75

----------


## Shaggy Hiker

You need to start a thread on this topic in the Office Development forum. This thread hasn't been active for nine years, and is about working with a language that is radically different from VBA. Nothing in here is likely to be all that meaningful to the problem you have, but there are folks in Office Development who may well be able to answer the question you have.

----------

