Introduction
A question was posed in the C# forum today about logging in to an application using the user's Windows account. In essence, if the user is logged into his account, and he tries to run an application, it's kind of pointless (and annoying) to re-request his login info. However, making a user login to an application does allow the programmer to dictate the terms, specifically, what roles the user has on the computer in question. This article demonstrates not only this aspect of application access, but also allows the program to have its own xml-based database of users.
The Windows Authentication Problem
Since we don't have to worry about the user's name and/or password, this process is reduced to a much easier task - determining if the user is in an acceptable group/role. With the .Net framework, this is easy as pie, involving just three lines of code:
using System.Security.Principal;
public bool UserInSystemRole(WindowsBuiltInRole role)
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(role);
}
The function above is from the supplied sample application, and is called by passing the desired WindowsBuiltInRole
ordinal (like WindowsBuiltInRole.Administrator
). You can also check for custom roles such as "MySuperRole". Below is the function from the sample application:
using System.Security.Principal;
public bool UserInCustomRole(string role)
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(role);
}
Sometimes, .Net really does make things too easy on us. :)
The Application Authentication Problem
When you want something application-specific, this is probably the best way to go. The data file can be stored on any network share (for easy administration), and you can go as far as you want or need regarding security. For this sample application, I chose not to implement any kind of encryption or hashing of passwords because that's not what this article is about (and I pretty much didn't feel like doing it). Here's the function used to authenticate via the application's XML-based user database:
public bool ValidateApplicationUser(string userName, string password)
{
bool validUser = false;
try
{
string fileName = System.IO.Path.Combine(Application.StartupPath, "users.xml");
XDocument users = XDocument.Load(fileName);
XElement userElement = (from subitem in
(from item in users.Descendants("user") select item)
where subitem.Element("name").Value.ToLower() == userName.ToLower()
&& subitem.Element("password").Value == password
select subitem).SingleOrDefault();
validUser = (userElement != null);
}
catch (Exception ex)
{
if (ex != null) {}
}
return validUser;
}
Notice that we used our new friend, LINQ, again. LINQ is just too handy to ignore. While I wouldn't use it all the time, it's great for dealing with XML files like our user database.
Notes
You can easily combine the application-specific authentication with the role validation to further control access to your applications.
The provided sample application has NOT been thoroughly tested (I simply don't have the time right now), so run your login code through the debugger a couple of times to make sure it's going to do what you want it to do.
History
10/03/2008: Changed the LINQ statement that retrieves the userElement in the ValidateApplicationUser()
method to return null instead of waiting for an exception in the event that the user isn't found. I did not change the code in the download file, so remember to make the same change in your own code.
10/02/2008: Original article posted.