I'm noticing some strange behavior with a shared authentication cookie setup, here's my scenario.
I've got two applications with the domains similar to the following:
login.mydomain.com
system.mydomain.com
I am redirecting the user to login.mydomain.com and dropping a the cookie from there on mydomain.com like so.
system.mydomain.com:
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.User == null || !Request.IsAuthenticated)
{
HttpContext.Current.Response.Redirect("http://login.mydomain.com");
}
}
login.mydomain.com
protected void btnSubmit_Click(object sender, EventArgs e)
{
pnlLoginNotice.Visible = true;
if (Membership.ValidateUser(txtUsername.Text, txtPassword.Text))
{
HttpCookie cookie = FormsAuthentication.GetAuthCookie(txtUsername.Text, chkRememberMe.Checked);
cookie.Domain = "mydomain.com";
Response.Cookies.Set(cookie);
}
}
Web.config:
<authentication mode="Forms" >
<forms timeout="2880" name=".COMMONAUTH" />
</authentication>
Now the behavior I'm seeing is that I'm finding the .COMMONAUTH cookie dropped under system.mydomain.com sometimes, while there's the same cookie under mydomain.com. I've noticed that it shows up after some time of inactivity on the site.
Is it possible that asp.net is dropping the cookie on it's own to keep the forms authentication alive?
UPDATE
I've tried the following approaches
1:
system.mydomain.com Web.config
<authentication mode="Forms" >
<forms timeout="1" name=".COMMONAUTH" />
</authentication>
login.mydomain.com Web.config
<authentication mode="Forms" >
<forms timeout="2" name=".COMMONAUTH"/>
</authentication>
When refreshing a page in system.mydomain.com after one minute has passed, I get the .COMMONAUTH cookie under system.mydomain.com
2:
system.mydomain.com Web.config
<authentication mode="Forms" >
<forms timeout="2" name=".COMMONAUTH" />
</authentication>
login.mydomain.com Web.config
<authentication mode="Forms" >
<forms timeout="1" name=".COMMONAUTH"/>
</authentication>
When refreshing a page in system.mydomain.com after one minute has passed, I get logged out.
3:
system.mydomain.com Web.config
<authentication mode="Forms" >
<forms timeout="1" name=".COMMONAUTH" domain="mydomain.com" />
</authentication>
login.mydomain.com Web.config
<authentication mode="Forms" >
<forms timeout="2" name=".COMMONAUTH" domain="mydomain.com"/>
</authentication>
When refreshing a page in system.mydomain.com after one minute has passed, all remains the same and I'm still authenticated. Not sure what will happen when a 3rd application will be introduced to this setup
Conclusion
I think my issue is comming from not setting the domain in the web.config, so system.mydomain.com is trying to refresh the cookie but is using its own domain since I am not telling it where it should be doing it.
My problem is that these applications will have different domain bindings and they will be hosted once for multiple clients. I cannot set FormsAuthentication.CookieDomain as it is read only.
Should I go with option 2, and give my cookie issuer a lower timeout from the other applications? Will this have any implications?
I ended up doing this, I won't mark this as the answer just yet, jut in case anyone points out any issues with it.
In Global.asax
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.User == null || !Request.IsAuthenticated)
{
HttpContext.Current.Response.Redirect(GetLoginUrl());
}
else if (Context.User.Identity is FormsIdentity)
{
HttpCookie cookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
FormsAuthenticationTicket currentTicket = FormsAuthentication.Decrypt(cookie.Value);
if (currentTicket == null && currentTicket.Expired)
{
return;
}
FormsAuthenticationTicket newTicket = currentTicket;
if (FormsAuthentication.SlidingExpiration)
{
FormsIdentity id = (FormsIdentity)Context.User.Identity;
newTicket = FormsAuthentication.RenewTicketIfOld(id.Ticket);
}
if (currentTicket != newTicket)
{
cookie.Value = FormsAuthentication.Encrypt(newTicket);
cookie.Expires = newTicket.Expiration;
cookie.Domain = WebGlobal.GetCurrentContextDomain();
Response.Cookies.Set(cookie);
}
}
}
}
With the information you provided, you also have the option to modify dynamically your configuration in the Application_Start to set the correct value for the domain attribute if it is not already set :
See :
http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k%28System.Configuration.ConfigurationManager%29;k%28TargetFrameworkMoniker-.NETFramework
Hope this will help
I guess an hint can be found in the timeout attribute description of the forms element:
http://msdn.microsoft.com/en-us/library/1d3t3c61%28v=vs.80%29.aspx
To prevent compromised performance, and to avoid multiple browser
warnings for users who have cookie warnings turned on, the cookie is
updated when more than half of the specified time has elapsed. This
might cause a loss of precision. The default is "30" (30 minutes).
is it also set to 2880 minutes on system.mydomain.com ? or is it the default 30 minutes value ? if so, you should see a cookie change after 15 minutes.
Does the problem still happen if you set up your web.config like this ?
<authentication mode="Forms" >
<forms timeout="2880" name=".COMMONAUTH" domain=".mydomain.com" />
</authentication>
Related
i use this code for login user in my api:
var ticket = new FormsAuthenticationTicket(
1,
CurrentCustommer.PhoneNumber,
DateTime.Now,
DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
false,
"user,user1",
FormsAuthentication.FormsCookiePath
);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
{
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
Path = FormsAuthentication.FormsCookiePath,
Domain = FormsAuthentication.CookieDomain
};
HttpContext.Current.Response.AppendCookie(cookie);
my webconfig code is:
<authentication mode="Forms">
<forms loginUrl="Login.aspx" protection="All" timeout="10080" slidingExpiration="true">
</forms>
</authentication>
<compilation debug="true" targetFramework="4.6.2" />
<httpRuntime targetFramework="4.6.2" />
<pages enableSessionState="true" validateRequest="false"></pages>
<sessionState mode="InProc" cookieless="false" timeout="10080" />
now. user after login and after a few minutes and refresh page or change page in site, Automatically Log outed; I see cookies stored through the "document.cookie" in chrome console. this problem does not exist in local host but when used server this problem showed :/
Also, I add that I use my customized database and don't use sql membership provider asp.net.
Should I apply certain settings when I call the method API for user login? Or I need to apply other configurations?
Really I do not know how to fix this problem.
thanks all.
UPDATE: i check authenticate user by this code:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.User.Identity.IsAuthenticated)
{
//Page.Response.Redirect("/");
MainContainer.Visible = false;
Page.ClientScript.RegisterStartupScript(this.GetType(),
"CallMyFunction", "LoginForm()", true);
}
}
for more info And i now see Page.User.ExpireDate in watch in Page_Load, this time 30 minutes after login user.
cookieless="false" can you just try using cookieless property as default or true
I'm new to ASP.NET and have been trying to solve this for awhile now.
I've came across this blog, and everything looks to be good, except one thing: the below code always evaluates to false in HttpContext.Current.User.Identity is FormsIdentity in this code snippit:
protected void Application_AuthenticateRequest(Object sender,
EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
When I used breakpoints, it turned that my PC name is the current user, which I think is not a FormsIdentity.
Web.config:
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
</configuration>
What am I missing here? and how to tell HttpContext of the current user after a sucessful login?
If you want users to have a FormsIdentity, then you need to turn on FormsAuthentication in your web.config file. In your element, you need to populate the authentication and authorization nodes. (For example, see the section of the blog post you mentioned titled "Securing Directories with Role-based Forms Authentication") Right now these elements are not present in your web.config file, and so Forms Authentication is not happening. A configuration like this is typical:
<system.web>
<authentication mode="Forms">
<forms name=".ASPXFORMSDEMO" loginUrl="logon.aspx" protection="All" path="/" timeout="30" />
</authentication>
<authorization>
<deny users ="?" />
<allow users = "*" />
</authorization>
</system.web>
The node instructs ASP.Net to use forms authentication, while the node denies access to the site for any user who is not authentication.
More information can be found here and here
I'm working to set up/correct my session timeout code, and have consulted numerous articles like this one and this SO post for ideas on how best to do this. The solution to detecting a session timeout that I continue to see over and over is to first check the Session.IsNewSession property for true, and if so, then check to see if a session cookie already exists. I guess the logic here is that the user has ended their last session that timed out, started a new session, but the old cookie wasn't yet removed. The code for those checks looks like this:
if (Context.Session != null)
{
if (Session.IsNewSession)
{
string szCookieHeader = Request.Headers["Cookie"];
if ((null != szCookieHeader) && (szCookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
{
Response.Redirect("sessionTimeout.htm"); // or whatever code to handle timeout
}
}
}
Now I'm currently working with a Session timeout value of 120 minutes, and a Forms timeout value of 60 mins. Those two lines from my web.config file, resepectively, are here:
<sessionState mode="InProc" cookieless="UseDeviceProfile" timeout="120" />
<authentication mode="Forms">
<forms loginUrl="~/Home/Customer" timeout="60" name=".ASPXAUTH" requireSSL="false" slidingExpiration="true" defaultUrl="~/Home/Index" cookieless="UseDeviceProfile" enableCrossAppRedirects="false"/>
</authentication>
So after 60 minutes (I set it to 1 to test), I make a request to the server, and I'm automatically redirected to /Home/Customer, I assume due to the 'loginURL' value in my web.config line.
The problem is that the session does not end, and all of my session timeout checks are in the Home/Customer action (I use MVC). So I'm redirected to Home/Customer, and I run through the checks above, but when I get to Session.IsNewSession, it's false, because the session is still alive (I assume because I'm still within the 120 minutes I have set).
So, finally, my question. Does this whole session-timeout-checking scheme only work when the actual Session times out? Or can I make it work for Forms timeouts as well? Maybe the solution is to set my Session timeout value as the same as the Forms timeout value?
The ASP.NET session cookie and the Forms authentication cookie are actually completely different cookies - if your app pool recycles, for instance, your user will lose their session but not their login identity (assuming you're using in-proc session). The only way your code would be hit, I think, is if your session timeout was less than your forms timeout. Any other way, and you will be redirected to the login page before you hit the session timeout code.
Another option would be to move the session timeout code to your login page.
A third would be to handle the check within your global.asax.
I just did some test of what user John Christensen said about
if your session timeout was less than your forms timeout.
web.config
<system.web>
<sessionState mode="InProc" timeout="1" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" defaultUrl="~/Account/Login" name="MyPortalAuth" timeout="2" />
</authentication>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
And it seems it is working solution.
C# filter attribute
public class SessionExpireFilterAttribute : ActionFilterAttribute
{
public UserManager<ApplicationUser> UserManager { get; private set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var ctx = HttpContext.Current;
// check if session is supported
if (ctx.Session != null)
{
// check if a new session id was generated
if (ctx.Session.IsNewSession)
{
// If it says it is a new session, but an existing cookie exists, then it must
// have timed out
string sessionCookie = ctx.Request.Headers["Cookie"];
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
if (ctx.Request.IsAuthenticated)
{
FormsAuthentication.SignOut();
}
RedirectResult rr = new RedirectResult(loginUrl);
filterContext.Result = rr;
//ctx.Response.Redirect("~/Account/Logon");
}
}
}
base.OnActionExecuting(filterContext);
}
}
Site Details which uses the single sign on,
1. http:\\webgate.abcltd.com
2. http:\\sales.abcltd.com
3. http:\\emp.abcltd.com
webgate application does the authentication and authorization. others(sales,emp) uses the webgate application. when any one access the any page from sales/emp site, they will be redirected to webgate's login page(here i have used form authentication. the configurations are below)
<authentication mode="Forms">
<forms loginUrl="Login.aspx"
protection="All"
name="WebGateSecurity"
path="/"
domain="abcltd.com"
defaultUrl="ApplicationList.aspx"
enableCrossAppRedirects="true"/>
</authentication>
<authorization>
<deny users="?" />
</authorization>
<machineKey validationKey="2C0904BC344116CC6FFD3DD7087C942878C41B7F861555651E69C7B72F9A7DF6BC3B63BFF0F1438DFB863EE3EAC62CBFFECA7482D3758888E7CDACDBBAE136D5" decryptionKey="A60EC9E480CB3BBC48D1D2B7FFF9E945FBA46196AD3029187022ADE8F7B99B25" validation="SHA1" decryption="AES" />
User credentials is validated against the data store and the authentication ticket/cookies are being created as below
var authTicket=FormsAuthenticationTicket(1, username, DateTime.Now, DateTime.Now.AddMinutes(30), false, userActions, FormsAuthentication.FormsCookiePath);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(authCookie);
If the given credentials are correct, i am tring to redirect to requested url as below
if (Request.Params["ReturnURL"] == null || Request.Params["ReturnURL"].EndsWith("/Logout.aspx") || Request.Params["ReturnURL"].EndsWith("/Error.aspx"))
Response.Redirect(FormsAuthentication.DefaultUrl);
else
{
//Response.Redirect(FormsAuthentication.GetRedirectUrl(username, false));
FormsAuthentication.RedirectFromLoginPage(username, false);
}
I have used the LoginStatus Control(placed in master page) which is let the user to perform the sign in/sign out from webgate app. When user sign out, the following code will be executed in order to remove the cookie.
protected void LoginStatus1_LoggingOut(object sender, LoginCancelEventArgs e)
{
FormsAuthentication.SignOut();
HttpCookie httpCookie = Request.Cookies[System.Web.Security.FormsAuthentication.FormsCookieName];
if (httpCookie != null)
{
httpCookie.Domain = "abcltd.com";
httpCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(httpCookie);
}
}
Configuration in other applications(sales and emp) are follows
<authentication mode="Forms">
<forms loginUrl="http://webgate.abcltd.com/Login.aspx" name="WebGateSecurity" protection="All" path="/" domain="abcltd.com" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
<machineKey validationKey="2C0904BC344116CC6FFD3DD7087C942878C41B7F861555651E69C7B72F9A7DF6BC3B63BFF0F1438DFB863EE3EAC62CBFFECA7482D3758888E7CDACDBBAE136D5" decryptionKey="A60EC9E480CB3BBC48D1D2B7FFF9E945FBA46196AD3029187022ADE8F7B99B25" validation="SHA1" decryption="AES" />
My problem is: sign out is not working. In details if i say: after sign out, i able to access the any pages from webgate,sales and emp application.
Please help me.
That's because you are using a different domain name in web.config:
domain="vrxstudios.com"
and
domain="abcltd.com"
so no single sign on possible. In your sign out method you cannot remove a cookie that belongs on abcltd.com from vrxstudios.com:
if (httpCookie != null)
{
httpCookie.Domain = "abcltd.com"; // this is not possible from vrxstudios.com
httpCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(httpCookie);
}
What you could do is redirect to a sign out page on abcltd.com which will do the job.
I am developing an user authentication site.
I have a login page, "Login.aspx" in which i have provided a login control.
In the web.config,
<authentication mode="Forms">
<forms name=".AuthenticationCookie" loginUrl="Login.aspx" protection="All" timeout="60" path="/">
<credentials passwordFormat="Clear">
<user name="Jack" password="Jerry"/>
</credentials>
</forms>
</authentication>
<authorization>
<deny users="*"/>
</authorization>
In the login.aspx.cs page,
I have provided,
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
if (FormsAuthentication.Authenticate(Login1.UserName,Login1.Password))
{
FormsAuthentication.SetAuthCookie(Login1.UserName,true);
Label1.Text = "Login Successful";
Login1.InstructionText = "";
FormsAuthentication.RedirectFromLoginPage(Login1.UserName, true);
Response.Redirect("Success.aspx")
}
else
{
Label1.Text = "You are not an authentic user";
}
}
}
but however, while execution instead of going to success.aspx
with the url http://localhost/Login.aspx?ReturnUrl=%2fSuccess.aspx
Why is this so?
If you want to set the forms auth cookie yourself and redirect correctly based on the ReturnUrl query string parameter, you should look at the FormsAuthentication.RedirectFromLoginPage method. In your example, it would be:
FormsAuthentication.RedirectFromLoginPage(Login1.UserName, true);
That method sets the appropriate Forms auth cookie / ticket and then redirects based on the presence or absence of the ReturnUrl parameter. (If absent, it goes to the configured default page.)
Hope this helps,
Donnie