I want to make "remember time" on a site something aroun one week. In default mvc 3 application I set this changes:
<forms loginUrl="~/Account/LogOn" timeout="10880" slidingExpiration="true" />
But, it is not enought. After half an hour site forget me. What could be wrong?
Did you set propert timeout for the forms authentication ticket and also the isPersistent parameter should be set as true.
FormsAuthenticationTicket tkt = new FormsAuthenticationTicket
(
1, // version
username, // user name
DateTime.Now, // issue date
expiration, // this should also be set to 10880
rememberMeChecked, // this should be true
null, // additional data
"/" // cookie path
);
For more info see here.
Related
I have a Web API based application currently set up using the amazing Thinktecture IdentityModel 4.5.
It is set up for claims-based authentication, accepting a Basic auth credential sent in on the Authorization header. The javascript client saves the returned session token and uses this for subsequent requests by including it in the Authorization header preceded by Session as the scheme.
The javascript client also saves the token to a cookie, for retrieval if the window is closed and reopened quickly, or when new windows are opened to prevent the user having to re-authenticate. The cookie is named sessionToken and it's value is the actual token.
It all works wonderfully well.
The problem is I have a link on the app page that links to a direct address (/api/controller/id/pdfdocument) and opens it in a new window (target: _blank). Therefore there is no way to include the Authorization header in this request. However, the cookie is transferred over correctly as the session is still active.
I have tried to add a mapping to the AuthenticationConfig.Mappings collection to add support for collecting the token from the cookie, however I just can't get the configuration right to get this working, and havn't been able to find any other resources online. I'm assuming there's something very simple that needs to get fixed.
My code:
private static AuthenticationConfiguration CreateAuthenticationConfiguration()
{
var sessionTokenConfiguration = new SessionTokenConfiguration();
sessionTokenConfiguration.EndpointAddress = "/Authenticate";
sessionTokenConfiguration.DefaultTokenLifetime = new TimeSpan(1, 0, 0);
var authenticationConfig = new AuthenticationConfiguration
{
ClaimsAuthenticationManager = _authenticationManager,
RequireSsl = false,
EnableSessionToken = true,
SessionToken = sessionTokenConfiguration,
SendWwwAuthenticateResponseHeaders = false
};
var securityTokenHandler = new Thinktecture.IdentityModel.Tokens.Http.BasicAuthenticationWithRoleSecurityTokenHandler(_userService.ValidateUser, _userService.GetRolesForUser);
securityTokenHandler.RetainPassword = false;
var realm = "localhost";
var authorizationMapping = new AuthenticationOptionMapping
{
Options = AuthenticationOptions.ForAuthorizationHeader(scheme: "Basic"),
TokenHandler = new System.IdentityModel.Tokens.SecurityTokenHandlerCollection { securityTokenHandler },
Scheme = AuthenticationScheme.SchemeAndRealm("Basic", realm)
};
authenticationConfig.AddMapping(authorizationMapping);
var cookieMapping = new AuthenticationOptionMapping
{
Options = AuthenticationOptions.ForCookie("sessionToken"),
TokenHandler = new System.IdentityModel.Tokens.SecurityTokenHandlerCollection { securityTokenHandler },
Scheme = AuthenticationScheme.SchemeOnly(scheme: "Session")
};
authenticationConfig.AddMapping(cookieMapping);
//authenticationConfig.AddBasicAuthentication(_userService.ValidateUser, _userService.GetRolesForUser);
return authenticationConfig;
}
This configuration is then applied like so:
HttpConfiguration config;
var authenticationConfig = CreateAuthenticationConfiguration();
config.MessageHandlers.Add(new AuthenticationHandler(authenticationConfig));
And this is what the cookie looks like in the request header:
Cookie: sessionToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzNzM2NDA5NjgsImlzcyI6InNlc3Npb24gaXNzdWVyIiwiYXVkIjoiaHR0cDovL3Nlc3Npb24udHQvIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2F1dGhlbnRpY2F0aW9ubWV0aG9kIjoiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2F1dGhlbnRpY2F0aW9ubWV0aG9kL3Bhc3N3b3JkIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9hdXRoZW50aWNhdGlvbmluc3RhbnQiOiIyMDEzLTA3LTEyVDEzOjU2OjA4LjA5N1oiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJBZG1pbmlzdHJhdG9yIiwiSWQiOiIyIn0.UlPeD9HzduQfwHE7NuXi9eMVo40hypi_LBK-f76VYFI; username=a
Any help most appreciated!
So after waiting a few minutes and receiving no replies and desperately needing this functionality I dived into the Thinktecture IdentityModel 4.5 source code to see what was going on and it seems this feature is not actually supported. Not only is it not supported but from the looks of it cookie mapping is not actually implemented.
I forked the repository and made a few small changes to allow for this feature:
https://github.com/ibraheemhlaiyil/Thinktecture.IdentityModel.45
and sent Dominick Baier of Thinktecture this in a pull request:
https://github.com/thinktecture/Thinktecture.IdentityModel.45/pull/95
Cookie usage has it's disadvantages, and it seems Thinktecture are trying to stay away from them as far as possible, however I could not come up with a different solution to my problem - a javascript client web applications that needs to open a new window/tab and maintain the authenticated session in the new window/tab.
If you want to use this feature, you simply set the new CookieName property on the SessionTokenConfiguration object. IdentityModel uses the HeaderName property to determine which header to look up for authentication data. In the same way, if the CookieName property is set this determines which cookie name is looked up for authentication data if no authentication data was found on the header.
In the example below, authentication data is looked for on the cookie named sessionToken if no authentication data is found on the Authorization header.
private static AuthenticationConfiguration CreateAuthenticationConfiguration()
{
var authenticationConfig = new AuthenticationConfiguration
{
ClaimsAuthenticationManager = _authenticationManager,
RequireSsl = false,
SendWwwAuthenticateResponseHeaders = false,
EnableSessionToken = true,
SessionToken = new SessionTokenConfiguration
{
EndpointAddress = "/Authenticate",
DefaultTokenLifetime = new TimeSpan(1, 0, 0),
HeaderName = "Authorization",
CookieName = "sessionToken",
SigningKey = CryptoRandom.CreateRandomKey(32)
}
};
authenticationConfig.AddBasicAuthentication(_userService.ValidateUser, _userService.GetRolesForUser);
return authenticationConfig;
}
As before, this configuration is applied like so during your application start up:
HttpConfiguration config;
var authenticationConfig = CreateAuthenticationConfiguration();
config.MessageHandlers.Add(new AuthenticationHandler(authenticationConfig));
The cookie authentication data has the exact same form as the data sent in the Authorization header, so if sent, the cookie should look like:
Cookie: sessionToken=Session eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjEzNzM2NDA5NjgsImlzcyI6InNlc3Npb24gaXNzdWVyIiwiYXVkIjoiaHR0cDovL3Nlc3Npb24udHQvIiwiaHR0cDovL3NjaGVtYXMueG1sc29hcC5vcmcvd3MvMjAwNS8wNS9pZGVudGl0eS9jbGFpbXMvbmFtZSI6ImEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL2F1dGhlbnRpY2F0aW9ubWV0aG9kIjoiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2F1dGhlbnRpY2F0aW9ubWV0aG9kL3Bhc3N3b3JkIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9hdXRoZW50aWNhdGlvbmluc3RhbnQiOiIyMDEzLTA3LTEyVDEzOjU2OjA4LjA5N1oiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJBZG1pbmlzdHJhdG9yIiwiSWQiOiIyIn0.UlPeD9HzduQfwHE7NuXi9eMVo40hypi_LBK-f76VYFI
Hope someone finds this of some use!
i know there is a lot of questions on this already but I still didn't seem to find a definitive answer. What i'm looking to do is have users be remembered after they login for say 2 weeks or until they log out. Below is what I think should be happening and I was wondering if anyone with a bit more experience could tell me if i'm right or wrong.
User logs in for the first time. An RPC call to the server returns a 'UserInfo' object which includes with it a new sessionID. Aka on the server this happens and user is returned:
user.setSessionId(getThreadLocalRequest().getSession().getId());
Now after user is returned we must create Cookies to store the client side data. Am i correct in saying we need a Cookie to identify the current user and another for the sessionID:
final long DURATION = 1000 * 60 * 60 * 24 * 14; //duration remembering login - 2 weeks
Date expires = new Date(System.currentTimeMillis() + DURATION);
String sessionID = user.getSessionId();
String username = user.getUsername();
Cookies.setCookie("sessionID", sessionID, expires, null, "/", false);
Cookies.setCookie("username", username, expires, null, "/", false);
Now when the user comes back to the app at a later date we check the cookies and (provided they exists and have not been deleted for some reason such as an explicit log out from the user) use their values to check session validity via RPC to the server:
String sessionID = Cookies.getCookie("sessionID");
String username = Cookies.getCookie("username");
if ( sessionID != null && username != null){
AsyncCallback<UserInfo> callBack = new AsyncCallback<UserInfo>(){
#Override
public void onFailure(Throwable caught) {
Window.alert("Error connecting to server.");
}
#Override
public void onSuccess(Boolean sessionValid) {
if (sessionValid)
loadInitialInterfaceForUser("username");
else
loadLoginInterface();
}
};
loginSvc.checkSessionValidity(sessionID,username, callBack);
}
else
loadLoginInterface();
Now, assuming what I have done so far is correct (which is a bit of a long shot :P) my real question is what exactly should I check at the server side checkSessionValidity(sessionID,username)?
Is it simply a case of fetching the user that I have stored serverside and comparing sessionID with the sessionID I have associated with user? Do I also check it hasn't expired?
I know this is a longwinded and perhaps not very well worded question... I'm struggling to get my head round it so any and all help is very welcome!
Cheers, Steve
Yes,that is a key thing to do.
Here is some interesting point discussed on that (Storing session id and username in DB)
Have a look on this (ofcourse you can check them in impl class instead of servlet)
how to check if a sessionId is valid in a servlet (java).
And here is an excellent example of Session Management in GWT
http://varuntayur.wordpress.com/2012/01/25/session-management-in-gwt
Read this also
question on GWT, Cookies and webpage directing
Take a look at the following link.
Cannot use same cookie for multiple GWT applications
This might solve your problem.
I am implementing Anti-Forgery framework as described here:
http://weblogs.asp.net/srkirkland/archive/2010/04/14/guarding-against-csrf-attacks-in-asp-net-mvc2.aspx
Plus, to minimize the coding effort, I did the token insertion part at client side handling form.onsumit and ajaxsend events. Everything works fine – until the session expires.
In my application, I display a popup when the user session gets timed out where the user can re-login and continue without refreshing the current page so that the work-in-progress will be safe. But this doesn't go well with the Anti-CSRF logic. When the user tries to re-login after a timed-out session, this throws a CSRF exception as the cookie (__RequestVerificationToken_Lw__) is already expired and all the future POSTs will be invalid until next page refresh.
Is there any way to set the cookie end time to a future date rather than 'session'? I tried to edit Response.Cookie but that made the cookie invalid.
Any help would be appreciated.
Thanks
At the time of user session out (when displaying a popup) is it possible for you to set the httpcookie with expiry in server side.
I have extracted some code from the microsofts antiforgery token implementation.
internal static string GetAntiForgeryTokenName(string appPath)
{
if (string.IsNullOrEmpty(appPath))
{
return "__RequestVerificationToken";
}
return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath);
}
private static string Base64EncodeForCookieName(string s)
{
byte[] bytes = Encoding.UTF8.GetBytes(s);
string text = Convert.ToBase64String(bytes);
return text.Replace('+', '.').Replace('/', '-').Replace('=', '_');
}
Below code which set the cookie in server side.
string antiForgeryTokenName = GetAntiForgeryTokenName(HttpContext.Request.ApplicationPath);
HttpCookie httpCookie = HttpContext.Request.Cookies[antiForgeryTokenName];
HttpCookie httpCookie2 = new HttpCookie(antiForgeryTokenName, httpCookie.Value)
{
HttpOnly = true
//// your domain Domain = ,
//// path Path = ,
//// set path Expires =
};
HttpContext.Response.Cookies.Set(httpCookie2);
Please note that I haven't tested this code, just give a try if you dont have any other options.
hi i used form authentication and create ticket and add it to Response it works good.
when i look at created cookies by Firefox tools>pageinfo>security>cookies find that the expire time set currently on cookies .
it works good on local but when i upload it on server (server 2008-iis7) ,the expire time
not works but sets on cookie and always my cookie expires about 10 minus and member will
log out.
has it some specially settings,i look at some example on internet but cant not find anythings.
my authentication codes:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
username,//username
DateTime.Now,
DateTime.Now.AddMinutes(120),
true,
rollname,
FormsAuthentication.FormsCookiePath);
string hashCookies = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,hashCookies); // Hashed ticket
cookie.Expires = DateTime.Now.AddMinutes(120);
Response.Cookies.Add(cookie);
i used this method in global.asax to check requests authentication:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
// look if any security information exists for this request
if (System.Web.HttpContext.Current.User != null)
{
// see if this user is authenticated, any authenticated cookie (ticket) exists for this user
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
// see if the authentication is done using FormsAuthentication
if (System.Web.HttpContext.Current.User.Identity is FormsIdentity)
{
// Get the roles stored for this request from the ticket
// get the identity of the user
FormsIdentity identity = (FormsIdentity)System.Web.HttpContext.Current.User.Identity;
// get the forms authetication ticket of the user
FormsAuthenticationTicket ticket = identity.Ticket;
// get the roles stored as UserData into the ticket
string[] roles = ticket.UserData.Split(',');
// create generic principal and assign it to the current request
System.Web.HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(identity, roles);
}
}
}
}
in my web config:
<authentication mode="Forms">
<forms loginUrl="~/Home.aspx" timeout="120" />
</authentication>
I'm using FormsAuthentication, I'm having problems setting the TimeOut value.
I've seen some other posts related to this, but they don't seem to be exactly my problem or the solution suggested doesn't help.
My web.config has the following:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn"
timeout="1"
cookieless="UseCookies" />
</authentication>
I have put an AuthorizeAttribute on the controllers that I want to secure.
I can view the .ASPXAUTH cookie (using FireCookies) and I can see that it is set to expire in 1 minute after a login.
If I debug through my code I can see that FormsAuthentication.Timeout = 1.
However my ticket doesn't seem to timeout in 1 minute. After 1 minute of inactivity I can still browse to controllers with AuthorizeAttribute.
In fact I can actually delete the .ASPXAUTH cookie using FireCookies and I can still browse to controllers with an AuthorizeAttribute.
Bizarrely after being inactive for a long time (sorry don't have an exact time - I was out for lunch!) the TimeOut occurs and I am redirected
to the login screen.
Any ideas?
I too had the same problem. Actually, it came about because I could not read the forms authentication cookie from javascript, it was after a while undefined. I just wanted to know if I was authenticated via javascript.
Later I found that the ticket had expired, but I was not getting logged out (also. so i wanted to solve that too)! I saw your question had not been answered so I kept it open while I worked out my problems for half a day. The following is what I came up with that appears to be working.
My Answer is based on this answer. https://stackoverflow.com/a/454639/511438 by user ScottS
This is in my ASP.NET MVC 3 project.
Here is my login code. Not shown, the custom user authentication logic before it. This just sets the initial ticket.
public class FormsAuthenticationService : IFormsAuthentication
public void SignIn(string userName, bool createPersistentCookie, string role)
{
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1, // version
userName, // user name
DateTime.Now, // created
DateTime.Now.Add(FormsAuthentication.Timeout), // expires
false, // rememberMe?
role // can be used to store roles
);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(authCookie);
}
in the same class but a static method that is accessed from global.asax
//-- this is based on https://stackoverflow.com/questions/454616/asp-net-cookies-authentication-and-session-timeouts
internal static FormsAuthenticationTicket RefreshLoginCookie(bool retainCurrentExpiry)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null || authCookie.Value == null)
return null;
FormsAuthenticationTicket oldTicket = FormsAuthentication.Decrypt(authCookie.Value);
DateTime expiryDate = (retainCurrentExpiry ? oldTicket.Expiration : DateTime.Now.Add(FormsAuthentication.Timeout));
HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
var newTicket = new FormsAuthenticationTicket(oldTicket.Version, oldTicket.Name, oldTicket.IssueDate, expiryDate,
oldTicket.IsPersistent, oldTicket.UserData, oldTicket.CookiePath);
HttpCookie newAuthCookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(newTicket));
HttpContext.Current.Response.Cookies.Add(newAuthCookie);
return newTicket;
}
Global.asax
My customization comes that ajax requests do not refresh the forms authentication ticket. So if you sit there for the timeout period, an ajax request will log you out. Change that if you want ajax requests to keep the ticket alive (addresses my javascript cookie issue, not your logout inactivity issue).
*(tip, if you get logged out, then login, but come back to the login page again, the first login did not specify a returnUrl in the querystring perhaps). *
protected virtual void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null || authCookie.Value == "")
{
return;
}
bool isAjax = new HttpRequestWrapper(System.Web.HttpContext.Current.Request).IsAjaxRequest();
FormsAuthenticationTicket authTicket;
try
{
//-- THIS IS WHAT YOU WANT
authTicket = FormsAuthenticationService.RefreshLoginCookie(isAjax);
}
catch
{
return;
}
string[] roles = authTicket.UserData.Split(';');
if (Context.User != null) Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
Web.config
here is the part where i set session timeout and ticket timeout
<configuration>
<system.web>
<sessionState mode="InProc" timeout="60" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="60" name="ProviderMvcSession" cookieless="UseCookies" />
</authentication>
An obvious solution that could easily be looked over by some people, clearing the browser cookies or logging out should solve the issue. If remember me is checked, the application will keep logging in with the old cookie regardless the changes made to the Web.Config timeout value.
It's about how long is the timeout of your session. Default is 20 minutes and you can change it in web.config like this:
<sessionState mode="InProc" timeout="20"/>