Tuesday, April 20, 2010

Transitioning from non-ssl to ssl and back again for login

Problem
You have a web site that needs to transition from non-ssl, to an ssl login page, back to non-ssl for the rest of the site navigation. This must use forms authentication

Details
Forms authentication has a method FormsAuthentication.RedirectFromLoginPage()
However the url is passed over the querystring as login.aspx?RedirectUrl=somepage.aspx
This is all automatic and you cannot specify an absolute url here. Even if you make it an absolte url such as
login.aspx?RedirectUrl=http://www.mysite.com/somepage.aspx (of course this would need to be url encoded) this wont work.
Also an oddity in my testing if you specify an absolute url for the login page, forms authentication - even with a valid login- redirects you right back to the login page.
For example: If my web.config contains:
<forms loginUrl="http://localhost/secure/Login.aspx"
Or SSL
<forms loginUrl="https://localhost/secure/Login.aspx"

Both of these cause forms authentication to send out a redirect NOT to the RedirectUrl, but right back to the login page!

If you are currently surfing a non-http site and need the login page to go SSL there doesn't seem to be an easy way to do this considering the problem above (at least on my laptop Im using for testing) . Even if you set the flag <forms requireSsl=true it just errors out if you are not using an ssl connection but it does not redirect to ssl.


Solution
1. For your login url in forms authentication you can specify the full https:// url. OR you can use
<forms loginUrl="~/secure/Login.aspx"
On your login.aspx page

if (!Request.IsSecureConnection)
{
Response.Redirect( --form your https url here or read from config);
}


OR you can use
<forms loginUrl="https://localhost/secure/Login.aspx"
and then in your login page, use a login control. Hook into the Logged_In method.


protected void Login1_LoggedIn(object sender, EventArgs e)
{
//see below for code on GetNonSslRedirectUrl
Response.Redirect(GetNonSslRedirectUrl(""));

}


If you are not using a login control, then simply do something like such:

if (Authenticate(userName, password))
{
string redirectUrl = GetNonSslRedirectUrl(userName);
FormsAuthentication.SetAuthCookie(userName, false);
Response.Redirect(redirectUrl);
}




///
/// Returns an http url (not https) to redirecto to a non-secure page
/// after being at a secure login page.
///

/// The username attempting the login.
/// The http://... url
private string GetNonSslRedirectUrl(string userName)
{
string redirectUrl = FormsAuthentication.GetRedirectUrl(userName, false);
//if its ssl, make non ssl.
if (redirectUrl.Contains("https://"))
{
redirectUrl = redirectUrl.Replace("https://", "http://");
}
//if it doesnt contain http:// then its a relative path. append http and the host to it.
if (!redirectUrl.Contains("http://"))
{
if (redirectUrl.StartsWith("/"))
{
redirectUrl = string.Format("http://{0}{1}", Request.Url.Host, redirectUrl);
}
else
{
//it needs a / in it. url is just 'something.aspx' - not sure if this can happen, its a failsafe
redirectUrl = string.Format("http://{0}/{1}", Request.Url.Host, redirectUrl);
}
}
return redirectUrl;
}


No comments:

Post a Comment