Checking Credentials

Authentication via the CredUIPromptForCredentials API

Don Kiely

October 30, 2009

6 Min Read
ITPro Today logo in a gray background | ITPro Today

SecureASP.NET

LANGUAGES: ALL

ASP.NET VERSIONS: ALL

 

Checking Credentials

Authentication via the CredUIPromptForCredentials API

 

By Don Kiely

 

A post on the http://www.asp.netsupport forums recently asked a question about using Windows authentication inan ASP.NET project. Users get the familiar dialog box in IE that prompts forthe user name and password. Some users would get a dialog that included a Remembermy password checkbox, but others didn t. The author of the post wondered whyit was inconsistent and how to enable the checkbox and feature to rememberpasswords for all users.

 

The variation in dialog boxes, as it turns out, can bebased on the version of Windows the user is running. Windows XP and Windows Server2003 include a CredUIPromptForCredentials API function. In later versions ofWindows, IE uses this API for prompting the user for credentials. A nicebenefit is that then Windows, not IE or your custom apps that use the API,takes care of securely saving the password. You shouldn t need to useCredUIPromptForCredentials directly in your ASP.NET apps because IE can handleit for you. Even if you did, such as to perhaps allow FireFox as the clientbrowser for an app that uses Windows authentication, you d have to install andrun client-side code to make the method call. Nevertheless,CredUIPromptForCredentials is an interesting method that can make clear someauthentication issues for any Windows app. So let s take a look at how itworks, using a WinForms app.

 

I recently used this in a project and so had to do all theresearch to make it work. This application happened to be written in VB.NET,but the ideas are similar for C#. If you re using C++, you ll need the Includeand Lib directories from the Platform SDK (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sdkintro/sdkintro/devdoc_platform_software_development_kit_start_page.asp).Here s the code I used to prompt the user for login credentials:

 

Dim bUseCredUI As Boolean = WindowsVersionForCredentials()

Dim frmLogin As Login

Dim sUser As String

Dim sPwd As String

Dim bSave As Boolean

Dim bAttemptAuth As Boolean

Do While True

 If bUseCredUI Then

      bAttemptAuth =CredUILogin(sUser, sPwd, bSave)

 Else

      'Use a custom loginform

 End If

 If bAttemptAuth Then

      'Do whatever isnecessary to authenticate user

 Else

      DoLogout()

      Exit Do

 End If

Loop

 

The code starts with a call to a customWindowsVersionForCredentials function to determine whether the code is runningon a version of Windows that supports CredUIPromptForCredentials, namelyWindows XP or Windows Server 2003 (more about WindowsVersionForCredentialsbelow). If CredUIPromptForCredentials is available, the code calls the customCredUILogin function, which calls CredUIPromptForCredentials and returns aBoolean indicating whether the user entered any credentials. Here I m passingreference variables to get the user name, password, and whether the userchecked the Remember my password box (see Figure 1).

 


Figure 1: The login box, whichshould look familiar to Windows users. Note that it includes a custom prompt.

 

The rest of the code above uses a custom login form if thecode is running on Windows 2000. Then, if in either case the user enteredcredentials, the code does whatever is necessary to authenticate the user. Thisis commonly a database lookup.

 

CredUILogin Function

Here is the crux code, the call toCredUIPromptForCredentials:

 

Private Function CredUILogin(ByRef sUserName As String,

 ByRef sPassword As String,ByRef bSave As Boolean) As Boolean

 Dim info As NewCredentialManager.CREDUI_INFO

 info.hwndParent =Me.Handle

 info.pszCaptionText =Application.ProductName

 info.pszMessageText ="Please enter " & Application.ProductName & " logininformation"

 Dim result AsCredUIReturnCodes

 Dim flags As CREDUI_FLAGS

 flags =CREDUI_FLAGS.GENERIC_CREDENTIALS Or _

      CREDUI_FLAGS.SHOW_SAVE_CHECK_BOX Or _

      CREDUI_FLAGS.ALWAYS_SHOW_UI Or _

      CREDUI_FLAGS.EXPECT_CONFIRMATION

 Dim sUser As String

 Dim sPwd As String

 result =CredUI.PromptForCredentials(info, _

      Application.ProductName,0, _

      sUser, sPwd, _

      bSave, flags)

 If result =CredUIReturnCodes.NO_ERROR Then

      sUserName = sUser

      sPassword = sPwd

      Return True

 Else

      Return False

 End If

End Function

 

CredUIPromptForCredentials has a boatload of parameters,but here I m using a bare minimum. The trickiest part is setting up theCREDUI_INFO structure with the parent form s window handle, the caption textfor the title bar, and the text for the prompt. The code sets some flags; forinstance, here to:

  • use generic credentials rather than a Windowslogin;

  • show the Save my password box;

  • show the login even if the credentials arecached (used only with generic credentials); and,

  • say whether the code will confirm thecredentials after making use of them.

 

Check the documentation for the several other flags youcan use.

 

Finally, the code calls the CredUIPromptForCredentialsfunction actually the CredUI.PromptForCredentials method passing in theinfo structure; the application name used to store the credentials if the useropts to do that (any string will do, as long as it is unique for this set ofcredentials); 0 for a reserved parameter; reference variables for user name,password and the save flag; and the flags you set.

 

The CredUILogin function then returns True to indicatethat the user entered credentials, or False if not.

 

Astute readers will no doubt notice that there is just notthat much support for calling Win32 APIs as is implied in this code like, oh,say a p/invoke statement. Yes, of course! To do all the heavy lifting I used aCredentialsManager component, CredUI, written by Duncan Mackenzie and publishedon MSDN (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/dpapiusercredentials.asp).

 

Confirming Credentials

The last step in using the CredUIPromptForCredentialsfunction is to optionally confirm the credentials. This uses another API function,CredUIConfirmCredentials, which must be called after you validate thecredentials, if you passed the CREDUI_FLAGS.GENERIC_CREDENTIALS flag, and ifthe prompt function returned NO_ERROR. Duncan sCredentialsManager makes this easy. If the credentials are good:

 

'Credentials are good, so let Windows persist them

CredUI.ConfirmCredentials(Application.ProductName, True)

 

If they are bad:

 

'Credentials failed, so don't let Windows persist them

CredUI.ConfirmCredentials(Application.ProductName, False)

 

Here again I m passing the Application.ProductName as theunique string with which these credentials will be associated. Once thisfunction is called with True for the second parameter, the credentials aresaved for this user.

 

WindowsVersionForCredentials function

The WindowsVersionForCredentials function simply uses theOperatingSystem object to make sure that the code is running on Windows XP orWindows Server 2003. This might not be as robust as you need, because thisparticular application could only be installed on Windows 2000 or later, so Ididn t need to worry about Windows 9x at all. But the docs explain thingspretty thoroughly. This is way better than the old tricks we had to use withWin32 API programming to find out what the app was running on:

 

Public Function WindowsVersionForCredentials() As Boolean

 'Determine if the app isrunning on a version of Windows that can use the CredUI API in Windows,

 'available for WinXP andlater. IOW, not Windows 2000.

 Dim bOkay As Boolean =False

 Dim OS As OperatingSystem= Environment.OSVersion

 If OS.Platform =PlatformID.Win32NT Then

      If OS.Version.Major >=5 Then

           IfOS.Version.Minor > 0 Then

                'Version5.0 is Win2K, 5.1 is WinXP

                bOkay =True

           End If

      End If

 End If

 Return bOkay

End Function

 

Valery Pryamikov, who writes an excellent security blog,talks about the problem of clearing the credential cache (http://www.harper.no/valery/PermaLink,guid,deba3b20-9d29-440f-b7bb-5a61c50bd99d.aspx),and includes a nifty utility to make it easier.

 

Enjoy!

 

Don Kiely, MVP,MCSD, is a senior technology consultant, building custom applications as wellas providing business and technology consulting services. His development workinvolves tools such as SQL Server, Visual Basic, C#, ASP.NET, and MicrosoftOffice. He writes regularly for several trade journals, and trains developersin database and .NET technologies. You can reach Don at mailto:[email protected] and readhis blog at http://www.sqljunkies.com/weblog/donkiely/.

 

 

 

 

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like