9

I have 2 questions related to that:

1) I need to invalidate.AspNet.ApplicationCookie after Adding / Removing some remote user to Role using Asp.Net Identity 2. I Tried to use UpdateSecurityStamp, but since no password or username is changed, SecurityStamp remains same. When I use ApplicationRoleManger I can see that User roles are updated but in User.Identity Claims they stay unchanged.

2) How does .AspNet.ApplicationCookie Validation work and how can I access it?

I was trying to use this code, but with no effect

What is ASP.NET Identity's IUserSecurityStampStore<TUser> interface?

Update: This is my Cookie Auth setting:

 app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromSeconds(0),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
                OnApplyRedirect = ctx =>
                {
                    if (!IsApiRequest(ctx.Request))
                    {
                        ctx.Response.Redirect(ctx.RedirectUri);
                    }
                }
            }
        });

I can see that user.GenerateUserIdentityAsync(manager) is hitted only on login.

Community
  • 1
  • 1
Tonda Krist
  • 209
  • 2
  • 12

2 Answers2

8

Setting CookieAuthenticationOptions is not enough. When I created new ASP.NET MVC project in VS everything is working good and GenerateUserIdentityAsync() is hitted by each request (if validateInterval is 0). The only problem was that you have to register context per request:

app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

As I am using Winsdor Castle to create context per request, I deleted these lines from template. In injected method in ApplicationUserManager.Create is set UserTokenProvider, which does the magic perharps.

Nowhere in documentation is anything about that, but finally it solves the problem.

If you are using your own IoC, you can resolve dependency this way (eg. using Castle Winsdor)

app.CreatePerOwinContext(() => IoCContainerManager.Container.Resolve<ApplicationDBContext>());
app.CreatePerOwinContext(() => IoCContainerManager.Container.Resolve<ApplicationUserManager>());

and register types this way:

container.Register(Component.For<ApplicationDBContext>().LifestylePerWebRequest());
container.Register(Component.For<ApplicationUserManager>().LifestylePerWebRequest());
Chris Moschini
  • 36,764
  • 19
  • 160
  • 190
Tonda Krist
  • 209
  • 2
  • 12
5

If you want to change the security stamp after adding to a role use this:

UserManager.UpdateSecurityStampAsync(User.Id)

And don't set validateInterval to TimeSpan.FromSeconds(0) - this basically means database will be hit every on request. Set it to something like 10 minutes.

Just last night I've blogged about CookieAuthenticationProvider and how it invalidates the cookie. Basically the cookie contains information about time it was created. If it is older than validateInterval, then reach to database, get user record and compare security stamps in cookie and in the DB. If stamp not changed, issue a new cookie with new issue date. If stamps don't match, invalidate the cookie and log-out user.

trailmax
  • 34,305
  • 22
  • 140
  • 234
  • Thanks for your blog link! Seems, that I am still missing something, because as I said, GenerateUserIdentityAsync method is triggered only on login - so as OnValidateIdentity. And cookie remains same even if I call UpdateSecurityStampAsync(User.Id). Btw I have zero Timespan just for testing. Is there anything else what am I missing in Authentication config? – Tonda Krist Aug 28 '14 at 11:22
  • try killing all the cookies and re-login again – trailmax Aug 28 '14 at 11:28
  • I did it many times. Isn't the problem that SecurityStampValidator.OnValidateIdentity checks SecurityStamp and UserId - and they remains same? So no change is detected? – Tonda Krist Aug 28 '14 at 11:36
  • `UserId` always stay the same - this is a primary key for the user. if your `SecurityStamp` is not changed, the cookie will not be invalidated. So update the `SecurityStamp` for the user and try again. – trailmax Aug 28 '14 at 11:49
  • UserManager.UpdateSecurityStampAsync(User.Id) returns Succeeded true, but still not regenerating identity even validate interval set to 1 second in AuthProvider. Really dont understand. Last think - isnt it possible that SecurityStamp remains same if UserId and Password remains same? – Tonda Krist Aug 28 '14 at 12:00
  • Check in your DB then - `SecurityStamp` is a field in users table. – trailmax Aug 28 '14 at 12:08
  • @trailmax: did you validate that solution? I found that while updating the security stamp does update the DB, the old security stamp (and thus authentication cookies) still remain viable until such point as the validationInterval has elapsed. And the more you increase this, the more does the Identity pipeline have to re-extract users from the database in order to regenerate the identity. – user3566056 Dec 12 '17 at 17:54
  • @user3566056 validated multiple times. After you update the security stamp in the DB you indeed need to wait for the `SecurityStampValidator.OnValidateIdentity` to run on certain time. That's why I usually set the expiry time in that section to be something reasonably small like 5-10 minutes. – trailmax Dec 12 '17 at 18:56
  • So you've come to the same conclusion as I have - it works, but it only works once the security stamp has been regenerated. And since you don't want to hit the DB for every request, you'll set an expiry time (I have 5 minutes as well). But that means the session can still be replayed during those 5 minutes. Better than nothing, but worse than what you'd expect (an immediate cutoff would be nice - that's what the guys doing the pentest on my site were looking for) – user3566056 Dec 13 '17 at 13:48
  • @user3566056 Correct - it works as intended. This is a trade-off between speed of cut-off or database load. If you set the time-out to be 0, cookie will be regenerated on every request, but you'll be doing an extra request (or two) to your DB on every request. That can quickly kill your DB perf if your site is busy. – trailmax Dec 13 '17 at 14:15