Categories
Uncategorized

ASP.NET Identity – invalidate all sessions on SecurityStamp update

I develop the account system for my upcoming game Battlefall with ASP.NET Identity and ASP.NET MVC 5.
I came across the problem, that ASP.NET Identity will not invalidate sessions if the SecurityStamp has changed. This behavior is very important. Let’s say you are logged in from two different browsers with the same user. If you change the password in one browser, the same user in the other browser won’t be logged out!

To add the described behavior, you must modify the following code from a new generated ASP.NET MVC 5 project.
I basically added the SecurityStamp as a Claim to the user session. Every time a user requests a page, I will compare the SecurityStamp from the Claim with the current value from the Database.

AccountController
[code language=”csharp” highlight=”1-11,17,18, 38,39″]
private async Task SignInAsync(ApplicationUser user)
{
Claim rememberMeClaim = AuthenticationManager.User.FindFirst("RememberMe");
if (rememberMeClaim != null)
{
bool rememberMe;
bool.TryParse(rememberMeClaim.Value, out rememberMe);
await SignInAsync(user, rememberMe);
}
await SignInAsync(user, false);
}

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim("SecurityStamp", user.SecurityStamp));
identity.AddClaim(new Claim("RememberMe", isPersistent.ToString()));
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

//
// POST: /Account/Manage
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(ManageViewModel model)
{
bool hasPassword = HasPassword();
ViewBag.HasLocalPassword = hasPassword;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword)
{
if (ModelState.IsValid)
{
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword, model.NewPassword);
if (result.Succeeded)
{
// update SecurityStamp to prevent logout of this user
await SignInAsync(IdentityManager.User);

return RedirectToAction("Manage", new { Message = ManageMessageId.ManageSuccess });
}
else
{
AddErrors(result);
}
}
}
else
{
// User does not have a password so remove any validation errors caused by a missing OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}

if (ModelState.IsValid)
{
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
else
{
AddErrors(result);
}
}
}

// If we got this far, something failed, redisplay form
return View(model);
}
[/code]

Startup
[code language=”csharp” highlight=”8-29,”]
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = ctx =>
{
var ret = Task.Run(() =>
{
Claim claim = ctx.Identity.FindFirst("SecurityStamp");
if (claim != null)
{
UserManager<ApplicationUser> userManager = new UserManager<Models.ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = userManager.FindById(ctx.Identity.GetUserId());

// invalidate session, if SecurityStamp has changed
if (user != null && user.SecurityStamp != null && user.SecurityStamp != claim.Value)
{
ctx.RejectIdentity();
}
}
});
return ret;
}
}
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
[/code]

Fortunately, the Katana Project is open source. It helped a lot to solve this issue.

Categories
Uncategorized

Unity3D Introduction – 3D Ping Pong

I made a Unity3D introduction screencast. We create a 3D Ping Pong in less than 40 minutes.

Play the game in your browser: http://timmlotter.com/files/Unity3DIntroduction_3DPingPong/WebBuild.html

Browse the source code: https://github.com/timmlotter/Unity3DIntroduction_3DPingPong

Watch the screencast:

 

 

Categories
Uncategorized

Tower Lords

The game has finally a name. It’s now called Tower Lords instead of ActionRPG. That name is easy to recognize and reflects the idea of the game. You play a Lord and you can build Towers. Coincidentally, it also has my initials TL. Here is the logo I made:

TowerLordsLogo_1000

My focus is to improve the 3rd person controller. The old level Town was designed for an isometric camera and I create a new level. It’s called Dawnwood.  I’ve added a Crosshair to improve aiming, smoothed animations and  added sprinting with a nice trail renderer. Multiplayer works with this new level as well.

Tower Lords 3rd Person with Logo