Home > Articles > Web Services > XML

📄 Contents

  1. Configuration Issues
  2. The LdapAuthenticator
  • Print
  • + Share This
Like this article? We recommend

The LdapAuthenticator

A plug-in using LDAP authentication, which can be used to authenticate a user against Active Directory, is the first plug-in added to the solution. It extends the XmlConfiguredPlugin class along with implementing the IAuthenticationPlugin interface. The new project is called AuthenticationPlugin.Plugins.LdapAuthenticator. A project reference to the AuthenticationPlugins.Common project is added right away to allow the project to compile.

In Listing 1-2, you'll see the IsLoginValid method from the newly-created AuthenticationPlugin.Plugins.LdapAuthenticator.Plugin class. The call to the base class' LoadConfiguration method gets the NameValueCollection, which is used later in the IsLoginValid method to find the LDAP server and to get a domain name.

The classes needed for authenticating users with LDAP are in the System.DirectoryServices namespace, so using System.DirectoryServices needs to be added to the Plugin class as well as a reference to the System.DirectoryServices.dll assembly. The LDAP string in the configuration file looks like LDAP://dc=domain,dc=com if your Active Directory domain is called domain.com.

The NativeObject call on the DirectoryEntry object entry is an attempt to bind to the object in the directory. Since this call forces authentication, you will get an error if the user does not exist. If the user is a valid user in the domain, the call will succeed. Unfortunately, since the call throws an exception, there is a bit of a performance hit if the user is not a valid user.

Listing 1-2.

public bool IsLoginValid( string username, string password )
{
   bool isValid = false;

   try
   {
      
      NameValueCollection configuration = 
         LoadConfiguration( ConfigurationRootNodeName );

      /* Get the domain name from the assembly-specific configuration 
       * file
       */
      string domainName = configuration[ "domain" ];
      string ldapPath = configuration[ "ldapPath" ];
      Debug.WriteLine( string.Format( "LDAP path is '{0}'", 
         ldapPath ) );

      /* The full username for LDAP will also have the domain
       * with it
       */
      string fullUsername = string.Format( @"{0}\{1}", 
         domainName, username );
      Debug.WriteLine( string.Format( "Full user name is '{0}'", 
         fullUsername ) );

      DirectoryEntry entry = new DirectoryEntry( ldapPath, 
         fullUsername, password );
      
      /* This will actually force authentication, and will throw an 
       * exception 
       * if the user and password are unknown or invalid
       */
      object obj = entry.NativeObject;

      /* Just making sure at this point */
      DirectorySearcher searcher = new DirectorySearcher( entry );
      searcher.Filter = string.Format( "(samAccountName={0})", 
         username );
      SearchResult result = searcher.FindOne();

      isValid = ( null != result );

   }
   catch
   {
      /* Replace this code with logging, etc. */
   }

   return isValid;
}

Database authentication

I put the second plug-in into a new project called AuthenticationPlugin.Plugins.SqlAuthenticator. This plug-in authenticates a user against values in a database. Similar to the LdapAuthenticator plug-in, it requires some configuration for things like the database connection string. The configuration file is shown here:

<sqlAuthenticator>
  <connectionString>Database=;...</connectionString>
</sqlAuthenticator>

When the LoadConfiguration method is called in the IsLoginValid method, the configuration file loads into the NameValueCollection returned by the LoadConfiguration method. The value of the key is accessed later in the IsLoginValid method:

string connectionString = configuration[ "connectionString"];

That key is used when creating a new instance of the SqlConnection class from the System.Data.SqlClient namespace. For the most part, this is pretty standard database connection code—the only thing that might look odd to you (if you aren't used to seeing it) is the using statement in which the SqlConnection object is created.

The using statement makes sure that any class that implements the IDisposable interface is properly closed and disposed of at the end of the block, regardless of whether an exception occurred. This is the same as building a try...finally block and putting a conn.Close() line inside finally to make sure that even if an exception happens the database connection is closed. The using statement is a little more brief and cleaner than the try...finally block.

The result value of the method, isValid, is finally assigned to true if the string result (retrieved by the ExecuteScalar method which returns the first column of the first row found).

Summary

The key concepts discussed in this article were using inheritance to re-use code. I also showed you how plug-ins can load their own configurations, so applications that use them don't have to worry about whether the plug-in was configured correctly. Finally, I very briefly touched on two concepts: using the classes in the System.DirectoryServices namespace to do LDAP authentication, and using classes in the System.Data.SqlClient namespace to connect to a database and run a stored procedure.

  • + Share This
  • 🔖 Save To Your Account