Link to home
Start Free TrialLog in
Avatar of Allan
AllanFlag for United States of America

asked on

AD Connectivity (LDAP)

Hi Experts !

I need help with AD connectivity. I followed the instruction from this link:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/active_directory_authentication_from_asp__net.asp

The only difference in my code is that I converted it to VB.NET and use code-behind when possible.

I'm able to compile and run the web app, but when I tried to 'login' (using correct credential) it returns with this error:

A referral was returned from the server

If I use the wrong credential it returns:

Logon failure: unknown user name or bad password

And it occurred on this line (when it tries to bind):
      Dim obj As Object = entry.NativeObject

I have double and tripled checked with the link above in case I have missed something.

My guess is that I don’t have the proper LDAP syntax?

If my domain name is golucky, here’s what I have for LDAP:

Dim adPath As String = "LDAP://DC=golucky,DC=com"

Domain Controller is on a Win 2003, and web app is on a different dev workstation (XP Pro).

Public Function IsAuthenticated(domain As String, username As String, pwd As String) As Boolean
      Dim domainAndUsername as String  = domain + "\" + username
      Dim entry As New DirectoryEntry(_path, domainAndUsername, pwd)

      Try
          'Bind to the native AdsObject to force authentication.                  
          Dim obj As Object = entry.NativeObject   '<-- Error Here
         
          Dim search As New DirectorySearcher(entry)
         
          search.Filter = "(SAMAccountName=" + username + ")"
          search.PropertiesToLoad.Add("cn")
          Dim result As SearchResult = search.FindOne()
         
          If result Is Nothing Then
            Return False
          End If
         
          'Update the new path to the user in the directory.
          _path = result.Path
          _filterAttribute = CType(result.Properties("cn")(0), String)
      Catch ex As Exception
          Throw New Exception("Error authenticating user. " + ex.Message)
      End Try
       
      Return True

End Function 'IsAuthenticated

Any help or guidance you can provide is really appreciated !


Avatar of Joeisanerd
Joeisanerd

Sorry this is C# code, but it works for show users in either a domain or on the local machine
textBox1 is the username and textBox2 is the password. The radioButton1.Checked indicates to connect to the domain that the computer is part of.

Happens in this code is that if the user name and password are correct for the domain or the local machine depending on which is chosen, then a listbox will be filled with all of the account names for the local machine or the domain. If authentication fails the error message will be displayed in the listBox indicate an error.

DirectoryEntry entry = null;
string type;
string userprefix = "";
if( radioButton1.Checked )
      type = "LDAP://RootDSE";
else
{
      type = "WinNT://"+Environment.MachineName+",computer";
      userprefix = Environment.MachineName +"\\";
}
try
{
      entry = new DirectoryEntry(type,
      userprefix+textBox1.Text, textBox2.Text);
            
      if( radioButton1.Checked )
      {
            type = "LDAP://"+entry.Properties["defaultNamingContext"][0].ToString();
            entry = new DirectoryEntry(type,
                  userprefix+textBox1.Text, textBox2.Text);
      }
      foreach( DirectoryEntry en in entry.Children)
      {
            textBox3.Text += en.Name.ToString()+"\r\n";
      }
      textBox3.Text += "Valid\r\n";
                        
}
catch(Exception ex)
{
      textBox3.Text+=ex.Message+"\r\n";
}
finally
{
      entry.Close();
}

If you want I can convert it to VB and test it
Here is a Web Version, I haven't tested the AD part, but the local machine part works

Imports System.DirectoryServices
Public Class WebForm1
    Inherits System.Web.UI.Page


#Region " Web Form Designer Generated Code "

    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub
    Protected WithEvents Button2 As System.Web.UI.WebControls.Button
    Protected WithEvents TextBox1 As System.Web.UI.WebControls.TextBox
    Protected WithEvents TextBox2 As System.Web.UI.WebControls.TextBox
    Protected WithEvents ListBox1 As System.Web.UI.WebControls.ListBox
    Protected WithEvents CheckBox1 As System.Web.UI.WebControls.CheckBox

    'NOTE: The following placeholder declaration is required by the Web Form Designer.
    'Do not delete or move it.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
        InitializeComponent()
    End Sub

#End Region

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here

    End Sub

   
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click


        Dim entry As DirectoryEntry

        Dim userprefix As String = ""
        Dim type As String = "WinNT://" + Environment.MachineName + ",computer"

        ListBox1.Items.Clear()

        Try
            entry = New DirectoryEntry(type, userprefix & TextBox1.Text, TextBox2.Text)

            If CheckBox1.Checked Then
                type = "LDAP://" & entry.Properties("defaultNamingContext")(0).ToString()
                entry = New DirectoryEntry(type, userprefix & TextBox1.Text, TextBox2.Text)
            End If

            For Each en As DirectoryEntry In entry.Children
                ListBox1.Items.Add(en.Name.ToString())
            Next en

        Catch ex As Exception
            ListBox1.Items.Add(ex.Message)
        Finally
            entry.Close()
        End Try

    End Sub
End Class

Your code looks fine to me, did you follow exactly what the article said about the IIS settings required ? If "Integrated Windows Authentication" set to enabled it's very likely a double hop issue.
SOLUTION
Avatar of Joeisanerd
Joeisanerd

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Allan

ASKER

Thanks joeisanerd, I'll try it when on Monday.

ihenry, I had a feeling you would reply since I think you're really good with AD. I read your 'double loop' before on exchange when you're were helping someone else. Too bad I didn't same the link, but I'll search for it.

Thanks for your replies, and I'll try it on Monday. Have a good weekend !



Just an FYI, the code I posted was converted from C# and I know it work for windows apps, but there may need to be something done for it work with Web Apps and since I am not at work I can't fully test it without being in a domain environment
After looked a little deeper to sample code provided in the link, I started thinking a couple things. First, your problem doesn't seem to be a double hop issue. Secondly, I don't really the code.

Authentication to AD tends to fail for a myriads of reasons, I can't be sure what's exactly the problem just from the error message. But the following checks might be able to help you.

1. Are you sure you are not passing a null password to the function? because when a null password is used, AD proceeds with current context credentials of running process which is anonymous user account.

2. Are you sure the user account which is being authenticated has no password problem. You'll get the same error message when the user account's password expired or "User must change password" is checked.

3. Since what the code does is just a simple binding which means the password is sent in a clear text, if your AD server has SSL enabled or uses Kerberos protocol enabled then code simply won't work. Try different combination of AuthenticationTypes.Secure, Sealing, Signing and Delegation might solve your problem.

Finally, as far as authentication process goes your code should do some checking before the actual authentication takes place. Such as password expiration, "user must change password" flag and some other factors and so that you can handle it correctly and display proper error message to your user.

PS: I'll explain why I don't like the sample code after you solve this problem :o)
Avatar of Allan

ASKER

Hi ihenry,

Thank you for all your help so far.

On the IIS for the web app under 'Directory Security' -> 'Anonymous access and authentication control'
I have 'Anonymous access' checked with a domain account that's part of the 'domain admin' group.
'Allow IIS to control password' is not checked.
I also have 'Integrated Windows' checked. If it's not checked, then I can't view the page, and get this error:
   You are not authorized to view this page
   HTTP 401.1 - Unauthorized: Logon Failed

If it's a double hop - do you have any suggestions? In the meantime, I'll look into the article:

"Troubleshooting Authentication Problems on ASP Pages"

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/active_directory_authentication_from_asp__net.asp

As for your pointers:

1. I've debug into the function and the password is not null.

2. There's no problem with the account being use for aunthentication. It's a normal account to logon into the
    network.

3. I'm checking with the sys guys if SSL or anything else is enabled.

Basically, I just want to pull all users on the domain and store into them into a db table. From there, when someone
visits the site I can use Context.User.Identity.Name and then match up with what I have in db and go from there.

Again, thanks for all your help !



Avatar of Allan

ASKER

Thanks Joeisanerd, but I need one that works with AD :(
Avatar of Allan

ASKER

Joeisanerd, I tried your code, and I get the same error. I think it has to do with the configuration .. not sure. Keep searching..
If you are using Intergrated Authentication and Impersonation, then you can just use WindowsIdentity and WindowsPrincipal objects to deal with users.
Avatar of Allan

ASKER

What I need is to grab all the users from our network. I checked MSDN. I don't think WindowsIdentity and WindowsPrincipal will do that right?
Hi allanau20

In the code you explicitly use a user account to bind to AD therefore double hop should be a problem. I'm still thinking that the problem isn't a double hop issue.  That's pretty much described in the following KB.

http://support.microsoft.com/default.aspx?scid=kb;en-us;329986

I think the problem has got to do with delegation, SSL or Kerberos encryption so that binding with AuthenticationTypes Delegation, Sealing, Secure or SSL might be necessary.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdirectoryservicesauthenticationtypesclasstopic.asp

Or better yet, before you continue coding use ldp.exe utility, which comes with Windows support tools, to bind to your AD using the same user account and try different set combination set of AuthenticationTypes and also port number. For example, to test whether your AD has SSL enable, bind to your DC via port 636.
Haha..my previous comment sounds funny! sorry about that, I was rushing typing into the texbox. What I wanted to say was double hop issue shouldn't be a problem.
Avatar of Allan

ASKER

Thanks ihenry. Sys ppl says that there's no SSL enabled. Just to be sure I'll try your suggestions. Will keep you posted !
Avatar of Allan

ASKER

Hi ihenry,

I have tried all the different AuthenticationTypes and still not working. I'll look into the ldp.exe utility, but I have a question. Using LDAP, do I need to install 'it' on the domain controller or IIS to get LDAP working? Thanks again.

I'm not very sure can understand your question. When you say "do you need to install 'it' on the domain controller or IIS to get LDAP working". do you mean ldp.exe utility?
Ok, a small testing to whether you can bind to your AD server in the first place. Create a simple console program and paste the following code into the main function and run it, what do you get?

Dim de As DirectoryEntry
Try
      de = new DirectoryEntry()
      de.Path = yourAdsPath
      de.Username = theUserName
      de.Password = thePassword

      '--first run without this line then second run try with this
      'de.AuthenticationType = AuthenticationTypes.Secure Or AuthenticationTypes.Sealing
      '--

      de.RefreshCache()
Catch
      Throw
Finally
      de.Close()
      de.Dispose()
End Try
Avatar of Allan

ASKER

Sorry about the confusion. What I meant was that the LDAP provider that DirectoryServices uses, do I need to install it somehow on the IIS or DC? I read here that you need to 'integrate LDAP' to AD. Just a thought:

https://www.experts-exchange.com/questions/21333064/Authenticating-WebApp-with-LDAP.html

Running the console gives me this error w/ or w/o the AuthenticationTypes line:

'System.Runtime.InteropServices.COMException' occurred in ConsoleApplication1.exe

Additional information: A referral was returned from the server

Avatar of Allan

ASKER

Oh, Thanks ihenry for all your help so far.
LDAP or WinNT provider is supported by AD on Win2K (or higher)  and if your web server is also running on Win2K or higher, I don't think you need to install anything. As long you're able to login to your web server using your domain account, everything should be set correctly.

About the error, did you use the same ADsPath? after login with domain account run again the code without using user name and password.

And can you post the exception stack trace here?
And by the way, have you tried using ldp.exe utility?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Allan

ASKER

Thanks for your replies ihenry - you're right that I don't need to install anything else if I have Win2k or higher.
I'm still waiting from Sys admin for the ldp.exe -- arrrgghhh.

Yes, I did use the same ADsPath and I tried w/o the passwords.

I'll look into your suggestion of RootDSE and FQDN.

In the meantime, here's my stack trace:

[COMException (0x8007202b): A referral was returned from the server]
   System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   System.DirectoryServices.DirectoryEntry.Bind()
   System.DirectoryServices.DirectoryEntry.get_NativeObject()
   ADSample.LdapAuthentication.IsAuthenticated(String domain, String username, String pwd) in c:\web\ADSample\LdapAuthentication.vb:21
   ADSample.grabusers.Login_Click(Object sender, EventArgs e) in c:\web\ADSample\grabusers.aspx.vb:50
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +108
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +57
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +18
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +33
   System.Web.UI.Page.ProcessRequestMain() +1277

Thanks for all your help -- really appreciate it !!!
 
Avatar of Allan

ASKER

HA AH HA HA HA HA HA HAH HA !

I figured it out. You're right the problem was in the adPath. What I did was ping dc for an ip and used that instead:

"LDAP://xxx.x.x.10"

I got the idea by reading one of your post:

https://www.experts-exchange.com/questions/21248005/Active-Directory-Search-Filter-Issue.html

Now, I just got figure out how to pull all users from the domain.

I can stop pulling my hair, and all thanks to you !!!