Geeks With Blogs

News My Blog has been MOVED to https://mfreidge.wordpress.com
Michael Freidgeim's OLD Blog My Blog has been MOVED to https://mfreidge.wordpress.com

It is quite common request to support both Forms and Windows authentication on the same Web Application.
The best solution that I found is described by  Richard Dudley at posts Using Forms Authentication with Windows Authentication ("Mixed Mode") and How I Made Windows Authentication and Forms Authentication Work Together.

I want to post some details of my implementation of this approach. 

There is a snippet from my WebLogin.ASPX code Page_Load method:

        If Not IsPostBack Then

            Dim bUseWindowsAuthentication As Boolean = Application("UseWindowsAuthentication")

            If bUseWindowsAuthentication Then

                ' Redirect to winlogin to try WindowsAuthentication if possible

                'http://aspadvice.com/blogs/rjdudley/archive/2005/03/10/2561.aspx

                'http://aspadvice.com/blogs/rjdudley/archive/2005/03/10/2562.aspx (How I Made Windows Authentication and Forms Authentication Work Together )

            '//only try to force windows if starting with LAN ip address

                '//change this logic as your like using a Regex

                Dim r As New Regex(ConfigurationSettings.AppSettings("lanIPmask"))

                If r.IsMatch(Me.Request.UserHostAddress) = True Or HttpRequestHelper.IsBrowserOnServer Then

                    If Me.Request.QueryString("WinLoginError") = Nothing Then 'avoid indefinite loop

                        Dim sQueryString As String = Me.Request.QueryString.ToString()

                        DebugHelper.TracedLine("sQueryString =" & sQueryString)

                        Response.Redirect("Authent/WinLogin.aspx?" & sQueryString)

                    Else

                        lblError.Text = Me.Request.QueryString("WinLoginError")

                    End If

 

                End If

            End If

The snippet from Authent/WinLogin.aspx page

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/MixedSecurity.asp

        DebugHelper.PrintAspNetIdentities()

        Dim userName As String = Me.Request.ServerVariables("LOGON_USER") 'usually with domain name

        userName = StringHelper.RightAfter(userName, "\") 'Strip domain if applicable

        CreateFormsAuthenticationTicket(userName)

    End Sub

    Function CreateFormsAuthenticationTicket(ByVal userIdentity As String) As Boolean

        Dim oLogin As New FSWeb.LoginHelper

        Dim bPersistCookie As Boolean = False ' = Persist.Checked

        'Set Current.Session["PatronID"] if successful

        Dim bRet As Boolean = False

        If Not DataHelper.IsNullOrEmpty(userIdentity) Then

            bRet = oLogin.LoadUserFromDatabase(userIdentity)

        End If

        If bRet = True Then

            'Save WindowsIdentity -from http://weblogs.asp.net/pwilson/archive/2004/02/02/66155.aspx

            Dim sUserToken As String = LoginHelper.GetUserTokenAsString(Me.Context)

            Dim userToken As New IntPtr(Integer.Parse(sUserToken))

            Dim identity As New WindowsIdentity(userToken, "NTLM", WindowsAccountType.Normal, True)

            Dim principal1 As New WindowsPrincipal(identity)

            bRet = oLogin.SaveWindowsPrincipalInSession(principal1)

        End If

        If bRet = True Then

            oLogin.CreateTicket()

            If FSWeb.Login.RedirectBack(Me) = True Then Exit Function 'old way of redirect

            ' Redirect back to original URL.

            WebFormsHelper.SmartRedirect(Page, FormsAuthentication.GetRedirectUrl(oLogin.PatronID, bPersistCookie))

        Else 'windows account not found in the database- so use normal forms authentication

            Dim sQueryString As String = HttpHelper.QueryStringCollectionToString(Me.Request.QueryString)

            'Expected that oLogin.ErrorMessage is meaningful, but if not, ensure it's not empty

            sQueryString = HttpHelper.AddQueryStringParameter(sQueryString, "WinLoginError", Nz(oLogin.ErrorMessage, "Error during windows Authentication"))

            Dim sUrl As String = ResolveUrl("~\login.aspx?" & sQueryString)

            WebFormsHelper.SmartRedirect(Page, sUrl)

        End If

        Return bRet

    End Function

 

To setup this functionality it is required to specify lanIPmask in Web.Config and set authentication on Authent\WinLogin.aspx page to be Windows Integrated only.

 

Procedure to specify lanIPmask:

  1. Open file web.config in your web application folder the text editor(e.g. Notepad)
  2. Search for a line
    <add key="lanIPmask" value=""/>
  3. Change the value to appropriate, e.g. "192.168.\d{1,3}\.\d{1,3}" if your LAN IP addresses are in range "192.168.0.0"- "192.168.255.255"
    For details how mask can be specified see

http://www.regular-expressions.info/examples.html

 

  1. Save the changed file.

 

Procedure to set  Authent\WinLogin.aspx page to be Windows Integrated only.  

1.      On the web server right-click the My Computer icon and click Manage.

2.      Expand the Services and Applications node in the MMC.

3.      Select Internet Information Services.

  1. Navigate to YorApplicationVirtualDirectory\Authent Folder(Assume that the application is installed in the default virtual folder).
  2. Right-mouse click WinLogin.aspx, then Click Properties, and then click the File Security tab.
  3. Under Authentication and access control, click Edit.
  4. In the Enable Anonymous Access group, clear the Enable anonymous access check box.
  5. Ensure that Integrated Windows Authentication check box is ticked
  6. Click OK to close the dialog.
    UPDATE- See the post Programmatically set IIS Authentication for a page. to set authentication for WinLogin.aspx automatically from the installer.

 It is also required to  change Internet Explorer clients setting to trust your website  as described at

 http://groups.google.com.au/group/microsoft.public.inetserver.iis/msg/4e6c0dda9313f23a?hl=en&

I want to highlight that site should be added to Local Intranet , not to Trusted Sites.

 

 

UPDATE: Jorge Loco requested to post code of helper classes that are referred by these snippets.

 See My DataHelper class.  (including Nz method), My DebugHelper and TraceHelper classesMy HttpRequestHelper class, My StringHelper class.

 

To resolve 'WindowsIdentity' and  'WindowsPrincipal' add

imports System.Security.Principal.
 

FSWeb.LoginHelper, FSWeb.Login and HttpHelper classes contain propriatary information and can't be published. You should replace them with your own code.

UPDATE: there is excellent Michael Morozov's post Single Sign-On for everyone ,which suggest easier solution for mixed-mode authentication (Forms and Windows).I haven't tried, but it looks promising. 

 
Posted on Thursday, October 27, 2005 8:18 AM | Back to top


Comments on this post: Support Forms and Windows authentication on the same ASP.NET Application.

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
Hello,

I was wondering if you could post the references/code files so I can remove the following errors:

Name 'HttpRequestHelper' is not declared. weblogin.aspx.vb
Name 'DebugHelper' is not declared. weblogin.aspx.vb
Name 'DebugHelper' is not declared. winlogin.aspx.vb
Name 'StringHelper' is not declared. winlogin.aspx.vb
Type 'FSWeb.LoginHelper' is not defined. winlogin.aspx.vb
Name 'DataHelper' is not declared. winlogin.aspx.vb
Name 'LoginHelper' is not declared. winlogin.aspx.vb
Type 'WindowsIdentity' is not defined. winlogin.aspx.vb
Type 'WindowsPrincipal' is not defined. winlogin.aspx.vb
Name 'FSWeb' is not declared. winlogin.aspx.vb
Name 'WebFormsHelper' is not declared. winlogin.aspx.vb
Name 'HttpHelper' is not declared. winlogin.aspx.vb
Name 'HttpHelper' is not declared. winlogin.aspx.vb
Name 'Nz' is not declared. winlogin.aspx.vb
Name 'WebFormsHelper' is not declared. winlogin.aspx.vb

Thank you,

Jorge Loco
Left by Jorge Loco on Jul 13, 2006 2:21 AM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
I've updated the post to include references to some of missing classes.
Left by Michael Freidgeim on Jul 13, 2006 8:47 AM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
Can you please share the code?
Left by Tej on Jul 28, 2006 12:04 AM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
Tej,
I've shared most of the code(see links to My classes in the post) except of some classes that are my application specific.
Left by Michael Freidgeim on Jul 31, 2006 8:08 AM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
Thanks for sharing your code. I see that you store the WindowsPrincipal object for Windows authenticated users in the Session scope. I'm curious why this is and how you are able to make use of it. Especially since Session scope is not available to the Application_AuthenticateRequest event. Also, if your Session expires before your FormsAuthenticationTicket does, you effectively lose that information for users still logged in. I had tried to persist the token via the FormsAuth cookie and then recreate the WindowsPrincipal object on subsequent requests, but I ran into all sorts of token duplication errors and incorrect identities being returned. Was that your reason for using Session scope? Thanks.
Left by Ryan on Nov 18, 2006 2:31 AM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
Ryan,
You've asked a good question. My approach to store the WindowsPrincipal object in Session is based on article "Activate Windows Impersonation Selectively" http://www.ftponline.com/vsm/2004_05/magazine/columns/qa/default_pf.aspx .I am using Windows Impersonation to search LAN files and Exchange MailBox for current user.
In Application_AuthenticateRequest event I am using only FormsAuthentication ticket.
You are right,it is aproblem with this approach that if your Session expires before your FormsAuthenticationTicket does, you effectively lose that information for users still logged in. I've considered to store token in in the UserData section of the FormsAuthenticationTicket, but didn't have a time to try it.
Left by Michael Freidgeim on Nov 21, 2006 8:26 PM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
Ryan,
Paul Wilson in http://weblogs.asp.net/pwilson/archive/2004/02/02/66155.aspx has an example how to store WindowsPrincipal in a separate cookie.
Left by Michael Freidgeim on Nov 21, 2006 8:48 PM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
excelent code, good article, I learned alot to day about authentication and for that I'm greatful to the writer
Left by web development company on Aug 20, 2009 10:39 AM

# re: Support Forms and Windows authentication on the same ASP.NET Application.
Requesting Gravatar...
I get Error message 401.2.: Unauthorized: Logon failed due to server configuration. after 3 prompts for userid/password.
What am I doing wrong?
Left by mani on May 20, 2010 7:44 AM

Your comment:
 (will show your gravatar)


Copyright © Michael Freidgeim | Powered by: GeeksWithBlogs.net