On the same IIS web site, I have two ASP.NET web applications called /foo and /bar. Both use forms authentication and I want users to be able to log in and out of both sites independently.
With the standard configuration for forms authentication, it seems to send a cookie path of "/" for the forms auth cookie. This means that when a user logs into /bar it logs him out of /foo which is undesirable behaviour for me.
The obvious solution seems to be this:
FormsAuthentication.RedirectFromLoginPage(username, false, Request.ApplicationPath);
This makes the forms auth cookie have the application path which allows the user to log into /foo and /bar independently :-) However there is a further and more nasty problem: If the user tries to log into /Foo (with a capital F), IIS directs them to the web application /foo, but they can never log in because the browser (chrome in this case) is case sensitive when deciding whether to send the cookie based on the cookie path.
This seems to be a common problem which every ASP.NET web app developer will face but I can't see a sensible solution for it. Please tell me i've missed something obvious?
Thanks
Andy
I assume you have already solved this issue somehow, but since I stumbled upon this question I thought I should add my few cents.
To solve the issue use different cookie names in web.config. Something like:
<authentication mode="Forms">
<forms name=".ASPXFORMSAUTH_FOO"
loginUrl="public/login.aspx" cookieless="UseCookies" slidingExpiration="true"/>
</authentication>
and
<authentication mode="Forms">
<forms name=".ASPXFORMSAUTH_BAR"
loginUrl="public/login.aspx" cookieless="UseCookies" slidingExpiration="true"/>
</authentication>
Dim ticket As FormsAuthenticationTicket = New FormsAuthenticationTicket(1, _
pUsernameEntered, _
DateTime.Now, _
DateTime.Now.AddMinutes(60), _
True, _
pOperatorID, _
FormsAuthentication.FormsCookiePath)
' Encrypt the ticket.
Dim encTicket As String = FormsAuthentication.Encrypt(ticket)
'create a cookie with the encrypted ticket
Dim authenticationCookie As New HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
'only create a persistent cookie if ticket persistent is checked
If (ticket.IsPersistent) Then
'give the cookie an expiration date outside of the forms authentication encrypted ticket
authenticationCookie.Expires = ticket.Expiration
End If
'save the cookie
HttpContext.Current.Request.Cookies.Remove(".cookiename")
Response.Cookies.Add(authenticationCookie)
In cookiename you can set you cookie name.
and in AddMinutes you can set your minutes values currently it is 60.
Related
This has been the bane of my existence for the better part of a week.
I have four existing webforms applications that utilize forms authentication. The URL for each is mydomain/app1/, mydomain/app2/, etc. I have been tasked with creating a new application that will function as a single sign-on application with the URL mydomain/ssoapp. Once a user logs in, it basically compiles everything from the pre-existing apps that the user has access to, so our users don't have to go out and log into each of them separately. But the old applications need to function as they currently do.
The important part of my web.config is as follows:
<authentication mode="Forms" >
<forms loginUrl="frmLogin.aspx?Type=login" name="sqlAuthCookie" protection="All" path="/" domain="mydomain"
timeout="60" cookieless="UseCookies" enableCrossAppRedirects="true" />
</authentication>
<machineKey validation="SHA1" decryption="AES" decryptionKey="mykey" validationKey="myvalkey"/>
Simply adding this to the web.config for all of the applications worked like a charm....for three of them.
In the SSO application I'm creating a formsauthenticationticket, cookie, and adding that to the response with the following code. Each of the four pre-existing applications uses this same code as well:
Dim lTicket As New FormsAuthenticationTicket( _
1, _
pstrUserId.ToString, _
System.DateTime.Now, _
System.DateTime.Now.AddMinutes(60), _
True, _
pstrUserId.ToString, _
FormsAuthentication.FormsCookiePath)
' Encrypt the ticket.
Dim lencTicket As String = FormsAuthentication.Encrypt(lTicket)
' Create the cookie and add to response
Dim cookie As HttpCookie = New HttpCookie(FormsAuthentication.FormsCookieName, lencTicket)
cookie.Domain = ".mydomain.gov"
pobjResponse.SetCookie(cookie)
pobjResponse.Cookies.Add(cookie)
'Cleanup
lencTicket = Nothing
lTicket = Nothing
In chrome debugger for the SSO application, I log in and the cookie is created with the correct information.
I can click on my menu list, which uses a response.redirect to go out to the other applications. For the 3 working applications, I bypass the login screen, go directly to the form I need, and the cookie is unchanged
For the problem child application, I can still see the cookie however I am redirected back to the login screen.
If I login from this point, a new cookie is created, with the same name as the preexisting one, however the domain has the "www" prefix on it
Other useful information (maybe):
I've ensured that all machinekey, decryption key, validation method, etc match across applications
My domain is in the format of sub1.mid1.gov . I've tried every combination of the format for this in the cookie assignment and web.config. Both with and without the preceding dot.
I've removed httpRuntime from the web.config as some others had mentioned this causes issues.
There are no errors in the IIS logs
All applications are running under the same apppool currently
Currently I'm contemplating taking some vacation time so I don't feel bad about crying in the corner on my employers dime. I'm sure it's something ridiculously simple, but I appreciate any help in the matter. Thanks!
We are trying to use authentication between two applications on our PC's (Windows 7, IIS 7.5) and eveything goes fine. But the problem is when we try to publish these sites (Windows web server 2008, IIS 7.0) the cross authentication didn't work!!
After long invistigation we found that the error occured in the following code which is on the second site:
Dim formsCookie As HttpCookie = Request.Cookies(FormsAuthentication.FormsCookieName)
If (formsCookie IsNot Nothing) Then
Else
' always null
We tried to check the pathes like this in code behind :
Dim ticket As New FormsAuthenticationTicket(1, smsProfile, DateTime.Now, _
DateTime.Now.AddDays(1), True, AdminSessions.UserObj.Pid, _
FormsAuthentication.FormsCookiePath)
Dim hash As String = FormsAuthentication.Encrypt(ticket)
Dim cookie As New HttpCookie(
FormsAuthentication.FormsCookieName,
hash)
If (ticket.IsPersistent) Then
cookie.Expires = ticket.Expiration
End If
Response.Cookies.Add(cookie)
Response.Redirect(smsPortal)
in the web.config:
<authentication mode="Forms">
<forms name=".ASPXFORMSAUTH" enableCrossAppRedirects="true" domain="mydomain.com.jo" loginUrl="http://..." protection="All" path="/"/>
</authentication>
Kindly advice us what is the difference between IIS in local PC and the Server.
Thanks.
It is highly likely that the browser is not sending the authentication cookie from the first site to the second site. Check the cookie path and the domain. Both sites must be on the same domain, and the cookie path must be set to a common root.
See this link for more details:
Cookie Domains and Paths
To aid in troubleshooting, use a utility such as Fiddler or Firebug to view the cookies being sent in the request, and verify that the authentication cookie set by site 1 (where the user logged in) is also being sent to site 2.
If the sites aren't on the same server, also check if they are using the same machineKey configuration.
I'm using the Membership API for my login system and a wierd thing has been bothering me. I allow user to choose whether to "Remember Me", which means whether to create a persistent cookie with one month expiration period.
In the Web.config, I wrote:
<authentication mode="Forms">
<forms timeout="60" />
</authentication>
This is supposed to be a default session cookie of 60 minutes.
In the code behind of the login page:
if(Membership.ValidateUser(UsernameTextBox.Text, PasswordTextBox.Text))
{
authCookie = FormsAuthentication.GetAuthCookie(UsernameTextBox.Text, RememberMeCheckBox.Checked);
if(RememberMeCheckBox.Checked)
authCookie.Expires = DateTime.Now.AddMonths(1);
Response.Cookies.Add(authCookie);
Response.Redirect(FormsAuthentication.GetRedirectUrl(UsernameTextBox.Text, RememberMeCheckBox.Checked));
}
The result however is strange. I seem to have created a persistent cookie of 60 minutes! How is this possible?
You are setting the cookie expiration time to be be 1 month, but the authentication ticket that it contains has not been modified. It has inherited the default value of 60 minutes from your web config.
You likely want to synchronize cookie expiration with the authentication ticket expiration, or alternatively set the cookie to have a very long expiry date.
What you need to do is
create a FormsAuthenticationTicket instance manually and set the
Expiration property of the instance.
Use FormsAuthentication.Encrypt() to encrypt the ticket
Add a cookie to the Response.Cookies collection containing the ticket, manually. (rather then using get/setAuthCookie(), which uses
the web.config settings).
Some example code is in the documentation for FormsAuthentication.Encrypt().
I want to expire cookie that for FormsAuthentication when browser closed.
(I want to it works like PHP session does)
Here is my Auth code that located in Model (Not controller).
Models/Auth.cs
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
model.UserId,
DateTime.Now,
DateTime.Now.AddDays(1),
true,
model.UserId +" "+reader["lastname"],
FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hash);
if (ticket.IsPersistent)
{
cookie.Expires = ticket.Expiration;
}
HttpContext.Current.Response.Cookies.Add(cookie);
Web.config
<authentication mode="Forms">
<forms name="user" timeout="60" loginUrl="~/Auth/login" path="/"></forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
And one more questions is, there are 2 times setting cookie timeout,
in ticket,
DateTime.Now.AddDays(1),
and in authentication in Web.config file
<forms name="user" timeout="60" loginUrl="~/Auth/login" path="/"></forms>
how different they are, and which one will effect to actual expire cookie?
Anybody know, please advise me.
Thank you!
You can't expire the cookie when the browser is closed. You can, however, make the cookie non-persistent, which means it will not save the cookie and thus when you open a new browser it will have a new cookie (be aware, however, that with the way most browsers cache non-persistent cookies with tabs, the entire browser has to be closed for this to clear it out).
As for your second question, the web.config entry is used if you do not specify a timeout.
jQuery unload event can be used to detect the browser closing.
But this event is also fired when : The user clicked on a link to leave the page, or typed in a new URL in the address bar. The forward and back buttons will trigger the event.Even a page reload will first create an unload event.
Bind an event handler to the "unload" JavaScript event.
Answer the your second question, the timeout that you set in your code with override the web.config entry.
I have a main asp.net app, which is written in asp.net 1.1. Runnning underneath the application are several 2.0 apps. To completely logout a user can I just logout of the 1.1 app with FormsAuthentication.SignOut or is it more complicated than that?
What you are looking to do is called Single Sign On and Single Sign Off. There are differences based on how you have the applications set up. I will try to clarify where those differences come into play.
To implement single sign on and single sign off you need to make the cookie name, protection, and path attributes the same between all the applications.
<authentication mode="Forms">
<forms name=".cookiename"
loginUrl="~/Login.aspx"
timeout="30"
path="/" />
</authentication>
Next you need to add the machine keys and they need to be the same between all your applications.
<machineKey validationKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902"
encryptionKey="F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC"
validation="SHA1" />
Are you using second or third level domains for the applications? If so you will need to do a little bit more by adding the domain to the cookie:
protected void Login(string userName, string password)
{
System.Web.HttpCookie cookie = FormsAuthentication.GetAuthCookie(userName, False);
cookie.Domain = "domain1.com";
cookie.Expires = DateTime.Now.AddDays(30);
Response.AppendCookie(cookie);
}
Now to do single sign off, calling FormsAuthentication.SignOut may not be enough. The next best thing is to set the cookie expiration to a past date. This will ensure that the cookie will not be used again for authentication.
protected void Logout(string userName)
{
System.Web.HttpCookie cookie = FormsAuthentication.GetAuthCookie(userName, False);
cookie.Domain = "domain1.com";
cookie.Expires = DateTime.Now.AddDays(-1);
Response.AppendCookie(cookie);
}
I am taking into consideration you are using the same database for all the applications. If the applications use a separate database for registration and authentication, then we will need to do some more. Just let me know if this is the case. Otherwise this should work for you.
It could be easier if you are having a central session store for all your applications. You can then set the session to null in one place.
This worked for me:
In the Logout event, instead of FormsAuthentication.GetAuthCookie method use Cookies collection in Request object as below:
HttpCookie cookie = Request.Cookies.Get(otherSiteCookieName);
cookie.Expires = DateTime.Now.AddDays(-1);
HttpContext.Current.Response.Cookies.Add(cookie);
Ofcourse, this requires u know the Cookie name of the site(s) you want the user to be logged out - which however won't be a problem if you are using the same cookie across all the web apps.
I prefer to use web.config
<authentication mode="Forms">
<forms domain=".tv.loc" loginUrl="~/signin" timeout="2880" name="auth" />
</authentication>