ASP.NET authentication with SSL and http to https, https to http problems

So you read the available documentation an put together the basic Forms authentication framework for an ASP.NET application (for which there’s a good article by Abel Banda on O’Reilly) and you say to yourself, boy it really sucks that these passwords are being sent over the internet unencrypted; which leads to the next logical step of using SSL for the login.aspx page.
The steps to follow are these:
1.      Add a server certificate to the web site root folder (Internet Information ServicesàDefault Web SiteàPropertiesàDirectory SecurityàServer Certificate…)
2.      Create folder in your web app for which you will require SSL access. Call it “ssl”.
3.      Move your login.aspx file to ssl/login.aspx.
4.      Make sure the NTFS security settings on the web application folder includes the anonymous IIS user account (IUSR_machine typically).
5.      Disable Integrated Windows authentication and make sure Anonymous access is enabled for the web app (Internet Information Servicesàweb app folderàPropertiesàDirectory SecurityàAnonymous access and authentication controlàEdit…)
6.      Require SSL for your ssl folder (Internet Information Servicesàssl folderàPropertiesàDirectory SecurityàServer Certificate…àcheck the “Require Secure Channel” box.)
7.      Modify the loginURL attribute of the Forms element in your web.config file to reference the new login.aspx location with an absolute url beginning with “https://”.
8.      Test your application.
At this point if you’re like me, a few things will begin to annoy you. First you’ll be reminded that you can’t debug under Visual Studio 2003 without Integrated Windows authentication. That’s okay. Leave it off for now. Just open a browser and manually try to hit your test page.
Again, if you’re like me, you should be getting a 401.2 error attempting to get the login.aspx page.
You might even try directly accessing the login page from the browser with https – no good. And you might try changing the loginUrl back to a relative url (“ssl/login.aspx”) and requesting your test page with https. Wow! That works!?! Hmm… You might also test what happens if you change the “deny users=”?”” to “deny users=”bob””. Again it works accessing each page with https, but you’ve given up forcing the redirect to the login page. If you actually tried any of these things, put things back the way they were and move on to the solution.
Add this in front of your existing element in the web.config file:
<location path="ssl/login.aspx">
     <system.web>
         <authorization>
             <allow users="?" />
         authorization>
     system.web>
 location>
This block tells the authorization logic to explicitly allow the anonymous user to access the ssl/login.aspx page and overrides the blanket deny element that comes later. There seems to be some special case code that handles relative login URLs but fails on absolute login URLs.
Change your loginUrl attribute back to an absolute “https://”  url and the authentication should work.
One annoyance remains: The ReturnUrl passed to the login page doesn’t include the request scheme (the “http://” part) so you end up stuck in SSL after you login.
So I tried taking charge of the redirect URL with the following code. Thanks to Scott Hanselman for the xml timeout hack, and yes, it needs better packaging for production:
System.Xml.XmlDocument x =new System.Xml.XmlDocument();
x.Load(Request.PhysicalApplicationPath + "web.config");
System.Xml.XmlNode node = x.SelectSingleNode("/configuration/system.web/authentication/forms");
int timeout = int.Parse(node.Attributes["timeout"].Value, System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
string userData = "Place application specific data for this user here.";
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
      1,
      UserName.Value,
      System.DateTime.Now,
      System.DateTime.Now.AddMinutes(timeout), // Should be timout from web.config
      PersistCookie.Checked,
      userData,
      FormsAuthentication.FormsCookiePath);
string encTicket = FormsAuthentication.Encrypt(ticket);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket));
string url = FormsAuthentication.GetRedirectUrl(UserName.Value, PersistCookie.Checked);
Uri uri = Request.Url;
url = uri.Scheme.Replace("https", "http") + "://" + uri.Host + url;
Response.Redirect(url, true);
That does the trick but generates a very annoying Security Alert dialog (“You are about to be redirected to a connection that is not secure.”).
To avoid this warning which is intended to remind naïve users that they are being taken away from the protection of https by the never-to-be-trusted server you must arrange for the client to request the shift back to non-SSL traffic.
Instead of the “Response.Redirect(url, true)” at the end of the previous block of code, replace it with:
(FindControl("RedirectUrl") as System.Web.UI.HtmlControls.HtmlInputHidden).Value = url;
And merge the following bit of code into the login.aspx file:
           
     
     
           
                 
That should do it. Nothing could be simpler…. J
The following notes are from Jason Loader,
2005-04-08
Hi Tone,
You know, you're the only person whose posted a solution to this problem I could find. Anyway, I was getting a windows login prompt/401.2 error (I was using Anonymous/Integrated Authentication on IIS), which was odd, as my application uses role-based security, but I'd already given anonymous/all users access to the login page via a location element. I tried what you suggested, but it still didn't work (it did get rid of the windows login prompt though), I couldn't find an explicit solution to the problem, but it would appear that the answer is actually in the Duwamish 7.0 sample.
You need to give the login page subdirectory it's own web config file that gives access to it for all users (that's all that needs to be in there) if you want to hard code the absolute url in the forms loginurl e.g.
In the application web.config file, you'd put -


In the Secure subdirectory web.config file, you'd put -

 
   
 

then remove the location section for the login page from the main app config file (the bit below) -

 
   
     
   
 

From what I can tell, it's probably something to do with ASP.NET not picking up the authentication from the config file for the sub directories correctly when using absolute urls, as it works when you use relative urls and SSL for the whole site.
However, you still had to change the config file if you moved the directories, changed the server name etc. With a bit of playing about, I found that you can force Forms Authentication to use SSL without hard-coding HTTPS in the loginURL by using the following code in globals.aspx -
Sub Application_EndRequest(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.EndRequest
Dim responseURI As System.Uri
Dim responseURIBuilder As System.UriBuilder
Dim pageName As String
' check to see if we're being redirected to the login page
If Not Response.RedirectLocation Is Nothing AndAlso Response.RedirectLocation.Length > 0 Then
' load the redirect into the uri
responseURI = New System.Uri(Request.Url,
Response.RedirectLocation)
pageName = GetPageFromURL(responseURI.AbsolutePath).ToLower()
If pageName = "login.aspx" AndAlso responseURI.Scheme <> "https"
Then
' force it to be HTTPS
responseURIBuilder = New System.UriBuilder(responseURI)
responseURIBuilder.Scheme = "https"
' remove the port number from the url and write it back
Response.RedirectLocation = Replace(responseURIBuilder.ToString(), ":" & responseURIBuilder.Port & "/",
"/")
ElseIf pageName <> "login.aspx" AndAlso responseURI.Scheme = "https" Then
' force it to be HTTP
responseURIBuilder = New System.UriBuilder(responseURI)
responseURIBuilder.Scheme = "http"
' remove the port number from the url and write it back
Response.RedirectLocation = Replace(responseURIBuilder.ToString(), ":" & responseURIBuilder.Port & "/",
"/")
End If
End If
End Sub
GetPageFromURL is a function which gets the page from a URL string, there's plenty of examples out there if you need to do the same.
What Duwamish does is automatically prefix absolute urls in the aspx files so you can turn SSL on and off through web.config, but I prefer to do that in the vb code so I can use relative links. One thing I haven't done is check that the login page is always being requested over secure sockets and if not force it to be, but you can get round that through IIS configuration (just in case you don't configure IIS and someone tries to access the login page directly). The next step is to make this configurable, like Duwamish is, and possibly picking up the HTTP/HTTPS ports if you've changed them (I've only tried it on default ports with IE).
Cheers,
Jason Loader
Software Developer, GVAS
Wealth Management Software PLC
E-mail: jason.loader@wms-plc.com

0 nhận xét:

 

Coding experience share Copyright © 2010 | Designed by Ipietoon for Free Blogger Template