Background

Last month I worked on a small assignment to authenticate windows account (Domain or Local) using form authentication. The purpose of this task was to facilitate our application users to login with any valid windows account (instead of automatic authentication of windows logged in user).

As it was an interesting task, I decided to share my experience with you.

Requirement

The application should authenticate windows user using form authentication so that the currently logged in user shouldn't be bound to logged-in in the application only with his windows account. He should be able to log-in with any valid windows account.

Solution

We need to do the following steps to get the desired functionality:

Configure Authorization and Authentication settings in web.config

A login page and execute logic to authenticate provided credential of windows user

If provided credentials are authenticated in step 2, then generate an authentication token so that user should be able to navigate into the authorized pages of your application.

1. Configure Authorization and Authentication Settings in web.config

We need to use Form authentication. The user will enter his windows credential in the form and we will validate provided windows credential using custom logic in step 2.

We need to create a login page (e.g. login.aspx) to get username and password information from user and then validate them. We can have different options to validate windows credentials, the way I chose is LogonUser() method of a win32 API called Advapi32.dll.

The LogonUser function attempts to log a user on to the local computer. This method takes username, password and other information as input and returns a Boolean value to indicate that either user is logged or not. If it returns true, it means the provided username and password are correct. To use this method in our class, we need to include the following namespace:

using System.Runtime.InteropServices;

And the add method declaration with DLLImport attribute (as this is a method of Win32 DLL which is an unmanaged DLL).

A pointer to a null-terminated string that specifies the name of the user. This is the name of the user account to log on to. If you use the user principal name (UPN) format, User@DNSDomainName, the lpszDomain parameter must be NULL.

lpszDomain [in, optional]

A pointer to a null-terminated string that specifies the name of the domain or server whose account database contains the lpszUsername account. If this parameter is NULL, the user name must be specified in UPN format. If this parameter is ".", the function validates the account by using only the local account database.

lpszPassword [in]

A pointer to a null-terminated string that specifies the plaintext password for the user account specified by lpszUsername. When you have finished using the password, clear the password from memory by calling the SecureZeroMemory function. For more information about protecting passwords, see Handling Passwords.

dwLogonType [in]

The type of logon operation to perform.

dwLogonProvider [in]

Specifies the logon provider.

phToken [out]

A pointer to a handle variable that receives a handle to a token that represents the specified user.

3. Generate an Authentication Token, If Provided Credentials are Authenticated in step 2

If provided credentials are authenticated by LogonUser() method, then we need to generate an authentication token so that users should be able to navigate into the authorized pages of the application.

FormsAuthentication.RedirectFromLoginPage()

Or:

FormsAuthentication.SetAuthCookie()

can be used for this purpose.

Here is login button’s Click handler code for authentication and generating authentication token. The comments will help you to understand the code.

protectedvoid btnLogin_Click(object sender, EventArgs e)
{
string domainName = GetDomainName(txtUserName.Text); // Extract domain name
// form provided DomainUsername e.g Domainname\Username
string userName = GetUsername(txtUserName.Text); // Extract user name
// from provided DomainUsername e.g Domainname\Username
IntPtr token = IntPtr.Zero;
//userName, domainName and Password parameters are very obvious.
//dwLogonType (3rd parameter):
// I used LOGON32_LOGON_INTERACTIVE, This logon type
// is intended for users who will be interactively using the computer,
// such as a user being logged on by a terminal server, remote shell,
// or similar process.
// This logon type has the additional expense of caching
// logon information for disconnected operations.
// For more details about this parameter please
// see http://msdn.microsoft.com/en-us/library/aa378184(VS.85).aspx
//dwLogonProvider (4th parameter) :
// I used LOGON32_PROVIDER_DEFAUL, This provider use the standard
// logon provider for the system.
// The default security provider is negotiate, unless you pass
// NULL for the domain name and the user name is not in UPN format.
// In this case, the default provider is NTLM. For more details
// about this parameter please see
// http://msdn.microsoft.com/en-us/library/aa378184(VS.85).aspx
//phToken (5th parameter):
// A pointer to a handle variable that receives a handle to
// a token that represents the specified user.
// We can use this handler for impersonation purpose.
bool result = LogonUser(userName, domainName,
txtPassword.Text, 2, 0, ref token);
if (result)
{
//If Successfully authenticated
//When an unauthenticated user try to visit any page of your
//application that is only allowed to view by authenticated users
//then ASP.NET automatically redirect that user to login form
//and add ReturnUrl query string parameter that contain the URL of
//a page that user want to visit, So that we can redirect the
//user to that page after authenticated.
//FormsAuthentication.RedirectFromLoginPage() method not only
//redirect the user to that page but also generate an authentication
//token for that user.
if (string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
{
FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);
}
//If ReturnUrl query string parameter is not present,
//then we need to generate authentication token and redirect the user
//to any page ( according to your application need).
//FormsAuthentication.SetAuthCookie() method will
//generate Authentication token
else
{
FormsAuthentication.SetAuthCookie(txtUserName.Text, false);
Response.Redirect("default.aspx");
}
}
else
{
//If not authenticated then display an error message
Response.Write("Invalid username or password.");
}
}

Share

About the Author

I am Microsoft Certified Technology Specialist for Web Application Development. I have 4 year experience of Web and Distributed application development.I have considerable experience developing client / server software for major corporate clients using the Windows operating systems and .NET platform ( ASP.NET, C# , VB.NET).I have single and multi-threaded code development experience, as well as experience developing database and enterprise level distributed applications.

Comments and Discussions

dear .. how can i use it for sharepoint..
all what i need is to remove defult windows authentication pop up and make new loging page using windows authentication ... as in your post ..
but when i redirect to sharepoint portal after authentication successfully passed i got sharepoint access denied page ..
do you have any idea why is that happen ..
thanks alot ..

Thanks for your reply but let me write more about my story. I am writing code in my laptop (which is being joined into a domain controller). When debugging in my laptop, the function works fine (with all users in domain controller). When distributing to web server (which is also domain controller), the function always returns false (with no error message) with non-administrator privilege. My web server runs on Windows Server 2003.

I guess the answer for your question is because normal your don't have access to your domain controller to login as Interactive. They should Login using network access, not interactive. Interactive means that the user able to login to the domain controller to use the server, network access means that a user once use the network services provided by the domain controller.

Sorry for the Inconvenience, I have changed download link to correct one,
Or you can directly download from
http://www.codeproject.com/KB/aspnet/WinAuthusingFormAuth/WindowsAuthenticationUsingFormAuthentication.zip