0

Before I start, I've already visited Unknown Error (0x80005000) with LDAPS Connection and changed my code and while it did solve the problem it seems that it has mysteriously come back.

Here's the good stuff:

public static bool Authenticate(string username, string password, string domain)
{
    bool authentic = false;

    try
    {
        LdapConnection con = new LdapConnection(
            new LdapDirectoryIdentifier(Host, Port));
        if (IsSSL)
        {
            con.SessionOptions.SecureSocketLayer = true;
            con.SessionOptions.VerifyServerCertificate = ServerCallback;
        }
        con.Credential = new NetworkCredential(username, password);
        con.AuthType = AuthType.Basic;
        con.Bind();
        authentic = true;
    }
    catch (LdapException)
    {
        return false;
    }
    catch (DirectoryServicesCOMException)
    { }
    return authentic;
}

public static bool IsSSL
{
    get
    {
        return ConnectionString.ToLower().Contains("ldaps");
    }
}

public static string ConnectionString
{
    get
    {
        if (string.IsNullOrEmpty(_connectionString))
            _connectionString = CompleteConfiguration.GetLDAPConnectionString();

        return _connectionString;
    }
    set { _connectionString = value; }
}

public static int Port
{
    get
    {
        var x = new Uri(ConnectionString);
        int port = 0;
        if (x.Port != -1)
        {
            port = x.Port;
        }
        else
        {
            port = x.OriginalString.ToLower().Contains("ldaps")
                       ? 636
                       : 389;
        }
        return port;
    }
}

public static string Host
{
    get
    {
        var x = new Uri(ConnectionString);
        return x.Host;
    }
}

private static bool ServerCallback(LdapConnection connection, X509Certificate certificate)
{
    return true;
}

Here's the bad stuff: When I attempt to authenticate to the application I get the following error, to be precise this is triggered by the con.Bind() line:

[COMException (0x80005000): Unknown error (0x80005000)] System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) +378094 System.DirectoryServices.DirectoryEntry.Bind() +36 System.DirectoryServices.DirectoryEntry.get_NativeObject() +31 Complete.Authentication.GCAuthentication.Authenticate(String username, String password, String domain) in c:\Builds\6\Idealink.Open.Pancanal\Panama Canal\Sources\Idealink.Open\Complete.Authentication\GCAuthentication.cs:27 Complete.Authentication.AuthenticationFactory.ValidateUserLdap(String username, String password, String domain, Boolean isValid, String usernameWithDomain) in c:\Builds\6\Idealink.Open.Pancanal\Panama Canal\Sources\Idealink.Open\Complete.Authentication\AuthenticationFactory.cs:93

It is quite confusing as it seems that some user accounts work and others don't. However when I place the above code in an isolated test environment it does succeed each and every time regardless of which account I use. When I place it back on the Windows 2008 R2 Server with ASP.NET and IIS it fails as stated above. The failures are consistent though - accounts consistently fail or succeed, from that perspective there is no randomness.

The LDAP Server must be accessed using LDAPS and NOT LDAP which is why we cannot use the DirectoryEntry object - the LDAP server is controlled by a client and therefore cannot be reconfigured or altered in any way. We simply want to capture username/password on a web form and then use BIND on the LDAP server to check credentials.

We are using .NET 3.5 and cannot upgrade at this time so I respectfully ask that if your main suggestion and arguments are to upgrade than please hold off on your contribution.

Thanks, hope you can help

Community
  • 1
  • 1
Karell Ste-Marie
  • 1,022
  • 1
  • 10
  • 22
  • Karell, how are you connecting to LDAP, can you show the LDAP Connection String for example LDAP://... – MethodMan Jan 08 '13 at 15:26
  • fore example `using (DirectoryEntry de = new DirectoryEntry()) { de.Path = "LDAP://yourSite/rootDSE"; de.Username = @"domain\Karell"; de.Password = "password";}` – MethodMan Jan 08 '13 at 15:27
  • sure thing: LDAPS://ServerAddress/OU=Users,DC=domain,DC=com - we don't specify the domain on the username (never had a problem with it, works on the "working" accounts). – Karell Ste-Marie Jan 08 '13 at 15:41
  • could it be a character encoding problem, where non working users dn or pwd contain special chars (comma, utf-8, quotes) ? – jbl Jan 08 '13 at 16:08
  • I was able to peek at an account and password it only contained alpha/numeric characters - but thanks for the suggestion – Karell Ste-Marie Jan 08 '13 at 16:37
  • do you have anything set for you DirectoryEntry for example DirectoryEntry entry = new DirectoryEntry(@"LDAPS://:636/CN=LDAP Test ,CN=Users,DC=customer,DC=com"); entry.AuthenticationType = AuthenticationTypes.SecureSocketsLayer; – MethodMan Jan 08 '13 at 18:18
  • I have tried that, I get the same error COMException – Karell Ste-Marie Jan 08 '13 at 19:28
  • The stack trace shows System.DirectoryServices.DirectoryEntry, but your given code is using System.DirectoryServices.Protocols.LdapConnection? Either you posted the wrong stack trace, or you're calling a wrong method. – Sean Hall Jan 08 '13 at 20:27
  • Problem is that I'm the only person that maintains production systems and I'm looking at the source code and it's using LdapConnection. So not saying you're wrong and I'm right but at this moment, the source code says I am. I am redeploying a fresh version and I will know for a fact that it uses the right object/method and I'll see then. I didn't notice that, it's an interesting observation - thanks – Karell Ste-Marie Jan 08 '13 at 21:11

1 Answers1

2

Would something like this work for you..?

const string Domain = "ServerAddress:389";
const string constrParts = @"OU=Users,DC=domain,DC=com";
const string Username = @"karell";
PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, Domain, constrParts);
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext,  username);

Here is a really good site for great references and examples DirectoryServices DirectoryEntry

for Connection over SSL you could do something like the following

const int ldapInvalidCredentialsError = 0x31;
const string server = "your_domain.com:636";
const string domain = "your_domain.com";

try
{
    using (var ldapSSLConn = new LdapConnection(server))
    {
        var networkCredential = new NetworkCredential(username, password, domain);
        ldapSSLConn.SessionOptions.SecureSocketLayer = true;
        ldapSSLConn.AuthType = AuthType.Negotiate;
        ldapSSLConn.Bind(networkCredential);
    }

    // If the bind succeeds, the credentials are valid
    return true;
}
catch (LdapException ldapEx)
{
    // Invalid credentials a specific error code
    if (ldapEx.ErrorCode.Equals(ldapInvalidCredentialsError))
    {
        return false;
    }

    throw;
}

MSDN list of Invalid LDAP Error Codes

MethodMan
  • 18,625
  • 6
  • 34
  • 52
  • Thanks DJ, but it would appear that this technique - even if I specify port 636 (LDAPS) will not actually use SSL over LDAP. Test method Complete.Authentication.Tests.GCAuthenticationTests.Test_AuthenticationSsl threw exception: System.DirectoryServices.AccountManagement.PrincipalServerDownException: The server could not be contacted. ---> System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable. – Karell Ste-Marie Jan 08 '13 at 16:54
  • you have tried this changing the port to 636 I apologize I forgot you're doing this over SSL can you post the exact string of the LDAP://connect alter the IP but put all other relevant stuff with :636 port and stuff. I want to look at something – MethodMan Jan 08 '13 at 18:12
  • I have also tried it by specifying the port, the problem is that this LDAP server is only accessible on SSL/636. If I specify 636, it simply switches the port but doesn't use the correct protocol. – Karell Ste-Marie Jan 08 '13 at 19:25
  • This is rather odd.. can you findout if they have this setup to allow for SSL..? can you findout.. – MethodMan Jan 08 '13 at 20:19
  • This setup has been working for 2 months - then it started to fail for most users while others keep working. – Karell Ste-Marie Jan 08 '13 at 20:25
  • For other users if it's not working..could it be a provisioning problem perhaps..? – MethodMan Jan 08 '13 at 20:27
  • I am not sure, the client guarantees me that nothing has changed on their end either... I've tried your suggested code - I didn't consider the .Negotiate and it did pass unit tests - I'm deploying and I'll see what happens – Karell Ste-Marie Jan 08 '13 at 21:06
  • Sounds like it worked Karell can you confirm..? we had an Issue like this 3 weeks ago in my ActiveDirectory group here at the bank where I work and the problem was a patch / update that was corrupt it took about 3 days for them to rollback and reinstall and haven't had an issue since.. – MethodMan Jan 08 '13 at 21:21
  • It's working with unit tests but those have always worked consistently, i'm deploying to production where the problem manifests. I'll let you know how it goes – Karell Ste-Marie Jan 08 '13 at 21:22
  • sounds like there is something different on that Production Server.. wanted to point out something else as well.. that I do a majority of our code in .NET 3.5 and on one of our stage servers the Architect installed the in correct version of .net frame work.. in regards to AD these type of issues are nerve wrecking especially when it works in a testing environment.. I will cross my fingers for you on this one – MethodMan Jan 08 '13 at 21:25