A Programmer's Dream

Logging In On a Windows Application

Posted by Stephen Wrighton on 08 Aug 2009

Oh the things people will dream up.

Here's the situation: the customer wants the system to easily be able to assign rights as user/administrator to an application, but they do not want the application to automatically assume the identity of the user who is logged into the computer.

Well, after my brain reset at this odd design decision, I got to work, and began thinking.

I knew I had a few things I could take for granted. I knew I had a SQL Server, and I knew that the client had an Active Directory & a Domain Controller. So, far, so good.

The ease of assigning administrators is a blessing with the Active Directory. All I need to do is generate two Global Groups in AD one for users and one for administrators. This makes it easy to pass-through authentication against the SQL Server as well. As all I need to do is create the USER group as a SQL SERVER USER and give it the necessary permissions to run the application.

Additionally, using AD means that there's one less username/password that the user has to commit to memory; and I'm all about having to remember less stuff.

So far, life is good.

Then I stumbled.

And not just any stumble, we're talking an animal into a tar pit level stumbling here.

It was that second part of the requirement, where the user is required to log into the application itself, after they have been logged into the computer.

All right, I thought to myself, that's not a problem. I'll just query AD directly and have it authenticate.

Well, a short discussion with my Sr. Network Engineer/COO corrected that particular opinion. Not only does Microsoft discourage that type of behavior being initiated by an Enterprise-based application, but depending on how AD is configured, it may not even allow an authentication request to be processed.

Additionally, the application itself would need elevated security rights in order to make an authentication request against AD.

He then informed me that SQL Server is the proposed way to utilize AD authentication (not AUTHORIZATION mind you). This goes back to that whole Global Group as a "SQL Server Windows User" thing.

But, after banging my head for a bit, I come to find out that the connection string requires Integrated Security to be TRUE.

Which means it doesn't matter one whit what I put into the username/password textboxes, as authentication occurs based on the Windows Identity Token which is running the application making the request.

Via the Authorization process (where I ask AD if the username provided is in the expected group) would cull the login request if I provided a bad username, but there was no checking at all of the password.

So, I cried.

Like a baby.

Then had lunch.

When I got back, I saw the problem waiting for me, so I once again turned to Google, MSDN and StackOverflow.

Apparently, I'm the only person who has this particular problem.

Enter prodigious amounts of head-banging.

I considered briefly calling the client up, and asking just how certain they are about this whole double log-in scenario. But then remembered that she was on vacation, and thus out-of-contact.

So, as I expanded my searches into wider and wider realms of dealing with C# and impersonation, I found a discussion where one would be able to launch a process as a different user. This was CLOSE to what I was attempting to do. After all, I didn't care what user context the application was running under, just so long as it was running, and whoever logged into the system was authenticated.

So, I delved further into these concepts, diving deeply into the dark nether regions of namespaces such as System.Diagnostics.

And then I started noticing something. All of these designs were accessing a non-managed DLL. A little thing called "advapi32.dll."

Which has this function:
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

Well, at least somewhat.

With this I was able to pass off the authentication of the supplied username/password to Windows itself. It would then provide me a boolean value if the logon process was successful or not, and if I ever NEED it, I also have an authentication token as an IntPtr.

Additionally, according to MSDN this will continue to work in Windows 7--so I have a year or 5 in which to convince them that a single log-on is acceptable.

Tweet me @kidananubix if you like this post.