Thursday, September 3, 2009

Login control validation by Windows

Let's say that you needed a Login control in a .NET application to use the local Windows login authority to provide authentication. That is, the login control would authenticate using the same accounts and passwords as Windows does itself when a user logs into a session. Here is a scenario where that would happen:

Two users (user1 and user2) are sitting at user1's workstation. User1 is logged in using his domain account. He points IE at an internal IIS server to get to a .NET application. Directory security has been set and IIS allows access to the default page of the application because User1 has been validated. The default page uses User1's username to look at an the application's database to fetch some user-specific settings. The default page then redirects to the home page that is populated based on User1's fetched settings.

But User1 doesn't have as many rights as User2 (who is an application admin for instance). To complete the task at hand, User2 needs to log into the application, but we don't want to force User1 to log out of their Windows session. So User1 clicks on the logout button, and the home page redirects to a login page similar to the default page but with a visable Login control. If the domain\username and pass entered in the Login control by User2 are validated, the login page acts just like the default page and fetches User2's settings and redirects to the home page that is populated based on User2's fetched settings.

To do this, we need to implement a custom Membership Provider. Implemnting a custom Membership provider is well documented on the internet, so I will not detail it here. What is not well documented is how to write the ValidateUser method so that it will use the native Windows authority.

So here it is, the ValidateUser method that expects a username in the typical domain\username format (ex: DNC\bclinton) and vailidates it against the native NT authority.



public override bool ValidateUser(string username, string password)
{
//split the domain and username into an array of strings
string[] userParams = username.Split('\\');

//if there are not 2 elements in the array, it means the user
//forgot to enter their domain name
if (userParams.GetLength(0) < 2) return false;

string serverName = "WinNT://" + userParams[0];
DirectoryEntry entry = new DirectoryEntry(serverName);
entry.AuthenticationType = AuthenticationTypes.Secure;
entry.Username = userParams[1];
entry.Password = password;

// Bind to the native object to force authentication to happen
try { Object obj = entry.NativeObject; return true; }

//If the bind didn't happen, auth fails
catch (Exception ex) { return false; }
}


No comments:

Post a Comment