Monthly Archives: January 2014

Global Game Jam 2014

I ┬áparticipated at the Global Game Jam this year. It was in Karlsruhe at HfG Karlsruhe. I had a lot fun and met at lot of nice people. The theme this year was “We don’t see things as they are, we see them as we are.” It was quite difficult in my view and we had a lot of ideas. 30 minutes of brainstorming ended with the floor full of post-it.
SAMSUNG

After pitching our ideas, I joined Moritz and Till to develop Will to Survive. The story and idea of the game:

You go through a terrible memory of the past. In order to win, carry your will to survive. A shining orb represents it. Beware of your father who just killed your mother. He will try to stab you.

Till made the design and animation of our main character and the vater. Moritz made art for the background and level design. I programmed the game in Unity and put very thing together. The character was controlled by the 2D physic engine that was added with Unity 4.3. The animations were blended with Mecanim.

WillToSurvive_Mecanim

The AI of the father was quite simple. He run with a predefined speed. In front of each obstacle was a trigger, that forced the father to jump with a predefined force and a maximum speed, while he was in the air. With this is place, we were able to trigger small, high and long jumps.

You can find the game and some more details at the Global Game Jam Site

WillToSurviveDSC01634

DSC01616

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

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);
}     

Startup

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);
}

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