I'm using the Windows Identity Foundation (WIF) Security Token Service (STS) to handle authentication for my application which is working all well and good. However I can't seem to get any long running login with the STS.
From my understanding I shouldn't care about the client tokens at the application level since they can expire all they want to and it should redirect me to the STS and as long as they're still logged in on the STS it should refresh their application token. Yet it doesn't seem to want to keep them signed in.
Here's what occurs in my login.aspx on the STS
var cookie = FormsAuthentication.GetAuthCookie(userName, persistTicket);
if (persistTicket)
cookie.Expires = DateTime.Now.AddDays(14);
Response.Cookies.Add(cookie);
var returnUrl = Request.QueryString["ReturnUrl"];
Response.Redirect(returnUrl ?? "default.aspx");
Which was taken almost directly from existing application using normal Forms Auth.
From my web.config
<authentication mode="Forms">
<forms loginUrl="Login.aspx" protection="All" timeout="2880"
name=".STS" path="/" requireSSL="false" slidingExpiration="true"
defaultUrl="default.aspx" cookieless="UseDeviceProfile"
enableCrossAppRedirects="false" />
</authentication>
Looking at the cookie after I sign in I can see the expires time on the cookie is set for 14 days in the future and that the cookie is NOT a session cookie.
When I'm required to log back into the STS I can see that my original cookie is still there.
Is there some kind of time stamp functionality that the STS embeds into the cookie that is invalidating my cookie even though as far as I know it should still be valid?
After reading the suggestion from #uosel this lead me down the path of doing more indepth analysis on what exactly is occurring here. Whereas my goal is to create a persistent cookie only for the STS itself and not for the STS consuming sites. This way I can always validate the user at the STS level at any expiration of a STS consuming site.
With more locomotion in this train of thought it dawned on me that the STS starter site uses forms auth to secure the actual WIF authorization that occurs in the index.aspx. That the issue was I had no logic that would use an existing forms auth ticket to process the transfer to the forms auth secured index page.
This lead me to a solution similar to
if(User.Identity.IsAuthenticated)
{
if(IsValidUserCredentials())
{
var returnUrl = Request.QueryString["ReturnUrl"];
Response.Redirect(returnUrl ?? "default.aspx");
}
}
else
{
DisplayLoginForm()
}
If you are using passive redirects, do you have persistentCookiesOnPassiveRedirects set to true?
<wsFederation passiveRedirectEnabled="true"
persistentCookiesOnPassiveRedirects="true" />
Related
I've implemented the Login button as following:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(u.UserID.ToString(), true, 2880);
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Expires = DateTime.Now.AddMinutes(2880);
Response.Cookies.Add(cookie);
Response.Redirect("/index.aspx");
And this is my web config:
<authentication mode="Forms">
<forms loginUrl="Login.aspx" defaultUrl="Index.aspx" slidingExpiration="true" timeout="2880" />
</authentication>
My question is: when I deploy my web application to the hosting, once I'm logged in, I scrool around few pages in users directory, and almost immediately after 30 secs - 1 min I get logged out and redirected to the login page so that I can relog again. Why is this happening ??? I've tested it on my local machine and it works just fine?!?!
Can someone help me out with this ??
Are you hosting on a web farm?
If so, you are logging into one server and when you are redirected to a different server it can't decrypt your authentication ticket. All of the machine keys have to be the same across each of your web servers. See How To: Configure MachineKey in ASP.NET 2.0
Is it possible to determine the date & time when an ASP.NET session will expire when using Forms Authentication?
I would like to warn users when their sessions are about to expire. There is no session state & sliding expiration is disabled. Here are some of the system.web settings:
<authentication mode="Forms">
<forms defaultUrl="Default.aspx" loginUrl="Login.aspx" requireSSL="false" enableCrossAppRedirects="true" cookieless="AutoDetect" timeout="2" slidingExpiration="false"/>
</authentication>
<sessionState mode="Off"/>
The timeout / lifetime of a session is easy to determine, but should the user refresh the page within the session windows, adding the lifetime value to the date-time at reload will not be accurate.
Using an authentication cookie with FormsAuthenticationTicket ticket encrypted as its value, one can decrypt it to get the expiration date-time.
Although some AJAX calls may be made, the user might interact with the UI without any post back or request to the webserver.
Any ideas on how I can achieve this type of behavior without the use of cookies?
I have a similar problem. In my case given the low number of users, im opting for a better user experience with a polling ajax call on the page to call back into the server and check the expiration ticket. You may be able to get away with tweaking the below code and including expiration info in the page via http and keeping track of time in client javascript if you dont want to go the ajax route.
if (User.Identity.IsAuthenticated)
{
var identity = (FormsIdentity)User.Identity;
viewModel.UtcInactivityExpiryDate = identity.Ticket.Expiration.ToUniversalTime();
}
If you go the ajax route, there is another gotcha. You have to stop the ajax call itself from renewing the inactivity timeout if you are using one. You can do that by overwriting the new authentication cookie with the original one. at the end of your ajax request.
var requestCookie = HttpContext.Current.Request.Cookies[".ASPXAUTH"];
if (requestCookie != null)
{
HttpContext.Current.Response.Cookies.Add(requestCookie);
}
I am implementing C# authorization using jquery cookies for my page. I set/encrypt username and password in the cookie and in my admin page, if I recognize cookie, then the user is authorized. If not, he gets redirected to the login page. The problem is, that cookie is read after page is loaded, so I can manually hit admin page and only in couple seconds it will get redirected. How do I prevent loading admin page for visitors, who have no cookie yet? What is a correct architecture for cookie based authorization?
Note: I am not using ASP.NET roles or User tables. I implemented my own tables for users.
I suspect that you're re-inventing the wheel. You don't have to use the Membership Provider and ASP.Net membership schema in order to take advantage of forms authentication. When the user logs in, simply drop the Auth Ticket (cookie) on them and you're done. You can then simply do the admin check on the admin page.
Some suggestions below...
Edit: I originally posted a means of storing roles in the Auth Ticket via UserData, but I think it's overkill for this situation.
Web.config:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="30" slidingExpiration="true" />
</authentication>
. . .
<membership>
<providers>
<clear />
</providers>
</membership>
Post login:
When the user submits their username and password, validate them and check to see if they are an admin:
if (UserIsValid(username, pwd)) // some validation call
{
FormsAuthentication.SetAuthCookie(username, true);
}
Admin.aspx:
Finally, a quick hack to restrict access to an admin page. When the page loads, check that the user is / is not an admin:
if (!IsAdmin(User.Identity.Name)) // some admin call
Response.Redirect("Default.aspx");
The problem is, that you use client side code for your security check. If someone would disable JavaScript completely, he would never be redirected. Move the check to your server side code.
I've got an issue with my cookies. I'm authenticating users through LDAP and as long as the browser remains open users don't have to log back into the tool. They can even close the tab that's fine so long as the browser is open.
But the cookie gets removed the moment the user closes the browser. I've searched google a lot for this and I can't get any of the solutions to work such as this one or that one for example.
Here's my setup once they authenticate on my logon page:
String encryptedTicket = FormsAuthentication.Encrypt(authTicket);
//Create a cookie, and then add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
//Add expiration date to the cookie
authCookie.Expires = DateTime.Now.AddMonths(1);
//Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
//You can redirect now.
FormsAuthentication.RedirectFromLoginPage(txtUsername.Text, false);
My Web.Config looks like this:
<authentication mode="Forms">
<forms loginUrl="Logon.aspx" timeout="43200" name="adAuthCookie" path="/" slidingExpiration="true" />
</authentication>
Whatever I do the ASP.NET_SessionId and adAuthCookie cookies are always set to expire "When I close my browser".
I want to avoid my users to always have to login when they close their browser and instead just do it once a month.
Sounds like you need to set a machineKey in your web.config.
If one is not specified either there or machine.config, it will be generated on start up and reset everytime the website is restarted, invalidating the encryption in the cookie.
machineKey element
Make sure browser is not set to delete cookies on close. There is such paranoid setting somewher in security options (I think in IE it is Advanced -> Security ->Empty temporary folders...)
Use Fiddler or other tool to make sure you send cookies with correct expiration to the browser. This way you verify where error is server or client side.
Is it possible to authenticate users across sub-domains when the authentication takes place at a sub-domain instead of the parent domain?
For example:
User logs into site1.parent.com, and then we need to send them to reporting.parent.com.
Can I authenticate them to the reporting site even though the log-in occured at a sub-domain?
So far all of the research I have done has users logging into the parent domain first and then each sub-domain has access to the authentication cookie.
When you authenticate the user, set the authentication cookie's domain to the second-level domain, i.e. parent.com. Each sub-domain will receive the parent domain's cookies on request, so authentication over each is possible since you will have a shared authentication cookie to work with.
Authentication code:
System.Web.HttpCookie authcookie = System.Web.Security.FormsAuthentication.GetAuthCookie(UserName, False);
authcookie.Domain = "parent.com";
HttpResponse.AppendCookie(authcookie);
HttpResponse.Redirect(System.Web.Security.FormsAuthentication.GetRedirectUrl(UserName,
False));
You can set the cookie to be the parent domain at authentication time but you have to explicitly set it, it will default to the full domain that you are on.
Once the auth cookie is correctly set to the parent domain, then all sub-domains should be able to read it.
As a side note, I found that after using jro's method which worked well +1, the FormsAuthenication.SignOut() method didn't work when called from a subdomain other than www/. (I'm guessing because the .Domain property doesn't match) - To get around this I used:
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
HttpCookie myCookie = new HttpCookie(FormsAuthentication.FormsCookieName);
myCookie.Domain = "parent.com";
myCookie.Expires = DateTime.Now.AddDays(-1d);
Response.Cookies.Add(myCookie);
}
In addition to setting a cookie to parent domain also need to make sure that all sites (apps) have same validationKey and decryptionKey () so they all recognise each other's authentication ticket and cookie. Pretty good article here http://www.codeproject.com/KB/aspnet/SingleSignon.aspx
Jro's answer works fine. But make sure to update the webconfig forms authentication setting "domain"
, otherwise forms authentication signout will not work properly. Here is the signout issue I came across. Trick here is to have a '.' as the prefix as the domain is set for the cookie as ".parent.com" (use a cookie inspector).
<authentication mode="Forms">
<forms cookieless="UseCookies" defaultUrl="~/Default" loginUrl="~/user/signin" domain=".parent.com" name="FormAuthentication" path="/"/>
</authentication>
Yes, sure. You may need to roll your own at some stages, but it should be doable.
One idea: as you redirect them across the boundary, give them a one-time pass token and then tell the receiving sub-domain to expect them (this user, from this IP, with this token).
2 things to be done:
MachineKey should be same in all web.config (main domain and sub domain(s))
AuthenticationCookie domain name should be same.
Follow the following article for more depth.