I have an MVC3 app and the user needs to be authenticated before they can access the site. I was logged in and was on a screen showing data, then i left. I came back an hour later, and by now the user has been automatically logged off. But when i clicked on a button to get data, without logging back in, I got the yellow screen of death cause my object was null. This is my Action:
[Authorize]
public ActionResult Index(string id)
I thought the [Authorize] attribute made sure to not execute this action unless they are authenticated, but apparently it doesnt or im not using it properly. So how do i use the [Authorize] or any other attribute to make sure the user is always authenticated and if they're not, take them to the login screen? Thanks
P.S. This only happens when a timeout has occurred. If i just try to access a view by typing in the URL and not logging in, i get the login screen as expected
I came back an hour later, and by now the user has been automatically logged off
If the action is executed, this means that the user is not logged off. The [Authorize] attribute works as expected.
I suspect that your problem has nothing to do with authentication. It has to do with ASP.NET Session that you are using. Please bear in mind that Forms Authentication cookie and ASP.NET Session are 2 completely different notions. So I guess that you have stored something into the ASP.NET Session when the user logged in. Except that the ASP.NET Session by default expires in 20 minutes and is configured independently of the forms authentication cookie timeout. So while the user authentication cookie is still valid and the user is authenticated it has lost its session because either the session expired or the web server simply recycled your application and everything you stored into the Session is of course lost.
This being said let's see the different possibilities that you have to workaround this problem:
My recommended approach is to get rid of the Session. Simply put <sessionState mode="Off" /> in your web.config and forget about the statefulness that the ASP.NET Session introduces in stateless applications.
Write a custom Authorize attribute which in addition to checking whether the authentication cookie is valid it will check if the Session still contains values:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var authorized = base.AuthorizeCore(httpContext);
if (!authorized)
{
return false;
}
return httpContext.Session["someKeyThatYouHaveStored"] != null;
}
}
and then use this custom attribute:
[MyAuthorize]
public ActionResult Index(string id)
Related
Hi we're having an issue with ASP.NET Identity.
We have an admin page that allows us to affect users to roles. (Admin etc).
The issue is when we affect a role to someone it doesn't apply for him until he logs out/logs back in.
We tried putting
services.Configure<SecurityStampValidatorOptions>(options =>
{
options.ValidationInterval = TimeSpan.Zero;
});
But it causes too many issues with cookies being passed at each request etc.
Is there any way to either :
Force logout another user
Refresh his claims without relogging?
The only solution I have in mind atm is to use something like a list of users to be updated somewhere (redis for exemple) and check this list in a middleware and refreshSigninAsync() if the user is in the list.
You were close, but I'd recommend you change the configuration.
I've added additional explanation on why you want to do this, in case someone wants to understand the thought process.
The problem:
When your user signs into the app they receive a cookie, but when an account is logged out, the user still has the valid cookie, so they aren't really signed out.
How to force sign-out:
Since a cookie gets re-used for as long as it's valid, you need a way to invalidate a cookie. You invalidate a cookie through a security stamp.
Configure Identity so that it periodically re-validates the cookie. It compares the security stamp in the cookie to the database version, and, if it fails, your user needs to reauthenticate.
Add the following configuration to your services:
services.Configure<SecurityStampValidatorOptions(opts => opts.ValidationInterval = System.TimeSpan.FromMinutes(1));
Now, you simply have to use the UserManager to find the user in the userstore, update the roles (or do whatever), then call the UpdateSecurityStampAsync(user) method. For example:
public async Task<IActionResult> OnPostUpdateRolesAsync(string userId)
{
var user = await _userManager.FindByIdAsync(userId);
// do stuff
await _userManager.UpdateSecurityStampAsync(user);
return RedirectToAction(nameof(SomePage));
}
Now that causes the user to be signed out the next time the cookie is revalidated and is forced to re-authenticate.
Notes:
This is certainly a destructive method in terms of user experience, since any HTTP request that the user does will get terminated afterwards.
Also, it's not really an immediate sign-out, only from the perspective of the application is it immediate. The user does not know when he has been signed out, that will only be apparent when he makes an http-request.
Currently upgrading a legacy MVC.NET v3 application to v5 while changing over from Forms Authentication to Microsoft's SSO solution. The requirement we would like to carry over is to force a logout if the user is idle for 30 minutes much like a banking application does due to the confidential information displayed within the application. We've implemented this successfully in the legacy application but I'm having trouble with the signout mechanism.
public void SignOut()
{
HttpContext.GetOwinContext().Authentication.SignOut(
OpenIdConnectAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType);
}
Without changing a thing when a user clicks the signout button - it'll redirect them to Microsoft's account selector to choose which account to log out - even if there's only one choice. But if the user clicks the back button then they are back in the application which lets an authorized user see confidential information. I need to force a logout on the current account to prevent that but I'm not able to figure out how.
I tried:
Clearing cookies. Failed because if the bad actor clicks login again the current session remembers him and automatically logs them back in.
Overwriting the HttpContext.User - looks like it works. But again clicking on login will automatically refresh the old session because the Token Provider remembers the state.
How do I accomplish this?
Thanks,
I found this link to allow session variables with OWIN:
Can OWIN middleware use the http session?
You'll need to review this link to allow system web cookies working with OWIN:
ASP.NET_SessionId + OWIN Cookies do not send to browser
I created another method that signs the user out and creates a session variable.
public void ForceSignOut()
{
SignOut();
HttpContext.Session.Add("IsSignoutRequested", true);
}
If the user clicks the back button and comes back to the application, I force redirect them back into a challenge.
In my startup class I have set the PostLogoutRedirectUri which lets me create another method on a successful logout which abandons the session.
public ActionResult CompleteSignOut()
{
Session.Abandon();
Request.GetOwinContext().Authentication.SignOut();
Request.GetOwinContext().Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
this.HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return new RedirectToRouteResult(new RouteValueDictionary(new
{
controller = "User",
action = "Index"
}));
}
We would like to implement functionality where user should be logged silently over Single sign-on. The user go to the application A and log into. Now he goes to the application B, which is using the same tenant as application A. At this moment to log into the application B, it is necessary by user to click on Login button to start the Challenge which handle the whole OpenID Connect protocol exchange.
[HttpGet]
public IActionResult SignIn()
{
var redirectUrl = Url.Action(nameof(HomeContrsioller.Index), "Home");
return Challenge(new AuthenticationProperties { RedirectUri = redirectUrl },
OpenIdConnectDefaults.AuthenticationScheme);
}
The idea here was to utilize Authorize attribute.
[Authorize]
public IActionResult Index()
{
return View();
}
The problem with this attribute is that per default the attribute redirects to the login UI when the user isn't logged in. The desired behavior here is to try to silently authenticate user, when the authentication isn't possible, ignore it.
I tried to disable to automatic challenge like described here but without success.
You can try embedding an iframe on an anonymous page that has the src set to the signin route. Make sure when your challenge fires you set prompt=none
You can squash any errors that come back from the signin request like interaction_required and acheive a silent single sign on when it works
We developing web application using MVC4 and Jquery Mobile. Recently we found one major issue which is "User using another account in same browser" so its overiding the existing account current browser. So we decided not to allow user to use two different account in one browser. We searched lot but unable to find perfect solution. So we tryed below code before login page load.
[AllowAnonymous]
public ActionResult Index()
{
if (!Request.IsAuthenticated)
{
return View("mLogin");
}
else
{
return View("UserAlready");
}
}
In login controller we written this code. The login page will be shown only when user is not registered. Once he Authenticated we restrict him from loading login page again.
My question.
Is this correct method ? Is it have any drawback? Or any other better approach is there?
Use a cookie with session id in it. In Authorize Action Filter check cookie for the session value with user session value if two match well and good otherwise you can take the necessary action
I am creating a web application that is hosted under a web site with forms authentication enabled. I have a role in my authentication database "Admins". Here is my controller code:
[RequireHttps]
[Authorize(Roles = "Admins")]
public ActionResult Index()
{
return this.View();
}
When I go to the Index page, if I'm not authenticated, it redirects me to the login page where I enter my credentials. The login page then redirects back to Index page of the new app, but the controller doesn't recognize that the user is authenticated.
I have taken the Authorize attribute off and looked at the request as it went out in the Chrome developer console and confirmed that the cookie is indeed being sent. But if I leave the Authorize attribute as is, and go to the Index page, the cookie collection on the request in my controller is empty. The headers collection contains a header entitled "Cookie", and the value of the header contains the .ASPXAUTH cookie.
The login page calls logs in with this code:
FormsAuthentication.SetAuthCookie(userName, remember, "/");
This behavior is reproducible in all major browsers.
What can I do to cause the Cookies collection of the request to be populated?
What do I need to do to make the application realize that the user really is authenticated?
Edit:
I still don't have it working, but I'm pretty sure it's something to do with the ASPXAUTH cookie being filtered.
I'm sure there are multiple causes of this problem. In my case, the problem was that the version of MVC I was using to write the cookie was different from the version that was decrypting it. I changed my sites to all be running MVC 4, and the cookie that was created by one site was consumable by the other site.
Is the .ASPXAUTH cookie generated a secure cookie, i.e. SSL? If so and your Index.aspx is only over HTTP not HTTPS, you will not see the cookie in the collection.