Sunday, December 18, 2011

Using LDAP to Authenticate Windows Users

Here are some my programming notes about using LDAP library to authenticate Windows Users.

This request came from my ASP.Net project, which is hosted on intranet IIS server. The first login page is to authenticate Windows users in the company.  I need a library to do the job.  I tried some codes created long time before, but I found that the codes is not completed.  The authentication works only in Visual Studio, but not at an IIS server after deployment. I need to fix the issue.

I found that there are many ways to do that.  One is based on our existing codes with Novel.Directory.Ldap library, another on System.DirectoryServices. I tried both in one test console application.

Here some some references and constants used in the console application:

using System;
using Novell.Directory.Ldap;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
using AD_LdapConnection = System.DirectoryServices.Protocols.LdapConnection;
using ND_LdapConnection = Novell.Directory.Ldap.LdapConnection;
using System.Net;
...
private const string LDAPHOST = "xxxx.yy.zzzz.com";
private const int LDAPPORT = 389;
private const string DOMAINNAME = "yy";
private const string CN_NAME_SUFIX = "@yy.zzzz.com";

Novel.Directory.Ldap


The first one is base on Novel.Directory.Ldap:

private static bool Authenticate(string username, string pwd)
{
  bool bRet = false;
  bool connected = false;

  // connect to LDAP server
  ND_LdapConnection ldapConnLogin = new ND_LdapConnection();
  try
  {
    Console.WriteLine("Start authenticating...\nConnecting to {0}, port: {1}",
      LDAPHOST, LDAPPORT);
    ldapConnLogin.Connect(LDAPHOST, LDAPPORT);
    connected = ldapConnLogin.Connected;
    if (connected)
    {
      Console.WriteLine("Connected: {0}", connected);

      string cn = string.Format(
        "{0}{1}", username, CN_NAME_SUFFIX);
      Console.WriteLine("Binding with {0}", cn);
      ldapConnLogin.Bind(cn, pwd);
      bRet = ldapConnLogin.Bound;
      Console.WriteLine("Bound: {1}", bRet);
    }
  }
  catch (Exception ex)
  {
    string msg = string.Format(" Error message or code: {0}", ex.Message);

    Console.WriteLine(msg);
    bRet = false;
  }
  finally
  {
    if (ldapConnLogin != null && connected)
    {
      ldapConnLogin.Disconnect();
    }
    ldapConnLogin = null;
  }

  return bRet;
}

This methods depends on ldap host name, port number, and cn name(in a format like email address in our company). One thing interesting is that the exception thrown from the binding call are error codes in Message, and no implementation of ToString() method.

System.DirectoryServices


The second method is Microsoft .Net library APIs in System.DirectoryServices. The following codes are much simpler and works in the same way to authenticate a Windows user:

private static bool Authendicate2(string domain, string userName, string password)
{
  bool validation = false;
  try
  {
    Console.WriteLine("Authenticating user by AD library...");
    var ldc = new AD_LdapConnection(
        new LdapDirectoryIdentifier(LDAPHOST, false, false));
    NetworkCredential nc = new NetworkCredential(userName, password, domain);
    Console.WriteLine("Created credencial object.");
    ldc.Credential = nc;
    ldc.AuthType = AuthType.Negotiate;
    Console.WriteLine("Binding credencial...");
    ldc.Bind(nc);
    // user has authenticated at this point, as the credentials were used to login to the dc. 
    Console.WriteLine("Binding credencial is done.");
    validation = true;
  }
  catch (Exception ex)
  {
    Console.WriteLine("Exception: {0}", ex.Message);
    validation = false;
  }
  return validation;
}

References

0 comments: