I’ve blogged about user impersonation in Asp.Net MVC three years ago and this article has been in top 10 of most visited pages in my blog.

Since Asp.Net Core is out and more or less ready for production, it is time to review the article and give guidance how to do the same thing in Core. Approach have not changed at all, we do same steps as before, only some API been changed and it took me a bit of time to figure out all the updated API parts.

Impersonation Process

Impersonation is when an admin user is logged in with the same privileges as a user, but without knowing their password or other credentials. I’ve used this in couple applications and it was invaluable for support cases and debugging user permissions.

The process of impersonation in Asp.Net core is pretty simple – we create cookie for potential user and give this to the current admin user. Also we need to add some information to the cookie that impersonation is happening and give admin a way to go back to their own account without having to log-in again.

In my previous article I’ve used a service-layer class to do impersonation. This time I’m doing everything in a controller just because it is easier. However please don’t be alarmed by this – I’m still a big believer of thin controllers – they should accept requests and hand-over the control to other layers. So if you feel you need to add an abstraction layer – this should be pretty simple. I’m not doing this here for simplicity sake.

So this is the part that starts the impersonation:

[Authorize(Roles = "Admin")] // <-- Make sure only admins can access this 
public async Task<IActionResult> ImpersonateUser(String userId)
{
    var currentUserId = User.GetUserId();

    var impersonatedUser = await _userManager.FindByIdAsync(userId);

    var userPrincipal = await _signInManager.CreateUserPrincipalAsync(impersonatedUser);

    userPrincipal.Identities.First().AddClaim(new Claim("OriginalUserId", currentUserId));
    userPrincipal.Identities.First().AddClaim(new Claim("IsImpersonating", "true"));

    // sign out the current user
    await _signInManager.SignOutAsync();

    await HttpContext.Authentication.SignInAsync(cookieOptions.ApplicationCookieAuthenticationScheme, userPrincipal);

    return RedirectToAction("Index", "Home");
}

In this snippet you can see that I’m creating a ClaimsPrincipal for impersonation victim and adding extra claims. And then using this claims principal to create auth cookie.

To de-impersonate use this method:

[Authorize]
public async Task<IActionResult> StopImpersonation()
{
    if (!User.IsImpersonating())
    {
        throw new Exception("You are not impersonating now. Can't stop impersonation");
    }

    var originalUserId = User.FindFirst("OriginalUserId").Value;

    var originalUser = await _userManager.FindByIdAsync(originalUserId);

    await _signInManager.SignOutAsync();

    await _signInManager.SignInAsync(originalUser, isPersistent: true);

    return RedirectToAction("Index", "Home");
}

Here we check if impersonation claim is available, then get original user id and login with that user. You will probably ask what is .IsImpersonating() method? Here it is along with GetUserId() method:

public static class ClaimsPrincipalExtensions
{
    //https://stackoverflow.com/a/35577673/809357
    public static string GetUserId(this ClaimsPrincipal principal)
    {
        if (principal == null)
        {
            throw new ArgumentNullException(nameof(principal));
        }
        var claim = principal.FindFirst(ClaimTypes.NameIdentifier);

        return claim?.Value;
    }

    public static bool IsImpersonating(this ClaimsPrincipal principal)
    {
        if (principal == null)
        {
            throw new ArgumentNullException(nameof(principal));
        }

        var isImpersonating = principal.HasClaim("IsImpersonating", "true");

        return isImpersonating;
    }
}

Dealing with Security Stamp Invalidation and cookie refreshing

Now this bit I always forget. When Security Stamp validation and cookie refreshing kicks in, it will erase the custom claims we’ve put into the cookie when started impersonation. This is a subtle bug because this happens only every 30 minutes by default and I’m never using impersonation long enough to experience this bug. However it happens and I better update this post, since I have a solution.

In you Startup class inside ConfigureServices put this block of code:

services.Configure<IdentityOptions>(options =>
{
    // this sets how often the cookie is refreshed. Adjust as needed.
    options.SecurityStampValidationInterval = TimeSpan.FromMinutes(10);
    options.OnSecurityStampRefreshingPrincipal = context =>
    {
        var originalUserIdClaim = context.CurrentPrincipal.FindFirst("OriginalUserId");
        var isImpersonatingClaim = context.CurrentPrincipal.FindFirst("IsImpersonating");
        if (isImpersonatingClaim.Value == "true" && originalUserIdClaim != null)
        {
            context.NewPrincipal.Identities.First().AddClaim(originalUserIdClaim);
            context.NewPrincipal.Identities.First().AddClaim(isImpersonatingClaim);
        }
        return Task.FromResult(0);
    };
});

This fixes the issue by re-adding our custom claims to the new cookie.

And this is pretty much it. You can see the full working sample on GitHub

Impersonation in Asp.Net Core v2.0

Aspnet Core v2 has been out for a while, but I did not get a chance to migrate my projects. Today that happened and I had to work out impersonation for Core v2. Mostly I’ve followed this guide: https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/ and then Identity part: https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x

One important change was in ImpersonationController.

   //[Authorize(Roles = "Admin")] // <-- Make sure only admins can access this 
    public async Task<IActionResult> ImpersonateUser(String userId)
    {
        var currentUserId = User.GetUserId();

        var impersonatedUser = await _userManager.FindByIdAsync(userId);

        var userPrincipal = await _signInManager.CreateUserPrincipalAsync(impersonatedUser);

        userPrincipal.Identities.First().AddClaim(new Claim("OriginalUserId", currentUserId));
        userPrincipal.Identities.First().AddClaim(new Claim("IsImpersonating", "true"));

        // sign out the current user
        await _signInManager.SignOutAsync();

        await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, userPrincipal); // <-- This has changed from the previous version.

        return RedirectToAction("Index", "Home");
    }

Also there was syntax change in Startup when configuring Security Stamp invalidator:

        services.Configure<SecurityStampValidatorOptions>(options => // different class name
        {
            options.ValidationInterval = TimeSpan.FromMinutes(1);  // new property name
            options.OnRefreshingPrincipal = context =>             // new property name
            {
                var originalUserIdClaim = context.CurrentPrincipal.FindFirst("OriginalUserId");
                var isImpersonatingClaim = context.CurrentPrincipal.FindFirst("IsImpersonating");
                if (isImpersonatingClaim.Value == "true" && originalUserIdClaim != null)
                {
                    context.NewPrincipal.Identities.First().AddClaim(originalUserIdClaim);
                    context.NewPrincipal.Identities.First().AddClaim(isImpersonatingClaim);
                }
                return Task.FromResult(0);
            };
        });

Other than that the impersonation is mostly the same. See full working sample in CoreV2 branch on GitHub

UPD There is a part 2 of this blog-post explaining how to do roles and fixing a minor issue with authentication.

UPD If you are on Windows 10 and get “System.IO.FileNotFoundException: The system cannot find the file specified”, have a look on this page. Thanks to David Engel for this link.

A while back I had to implement a login system that relied on in-house Active Directory. I did spend some time on figuring out how to work this in the nicest possible ways.

One of the approaches I used in the past is to slam Windows Authentication on top of the entire site and be done with it. But this is not very user-friendly – before showing anything, you are slammed with a nasty prompt for username/password. And you need to remember to include your domain name in some cases. I totally did not want that on a new green-field project. So here goes the instructions on how to do a nice authentication against your Windows Users or in-house hosted Active Directory.

For this project I’ll use Visual Studio 2015. But steps for VS2013 will be the same. Can’t say anything nice about any earlier versions of Visual Studio – I don’t use them anymore.

Continue reading

I have seen a fair amount of questions on Stackoverflow asking how to prevent users sharing their password. Previously with MembershipProvider framework it was not a simple task. People went into all sorts of crazy procedures. One of the most common was to have a static global list of logged-in users. And if a user already in that list, the system denied their second login. This worked to an extent, until you clean cookies in the browser and try to re-login.

Luckily now Asp.Net Identity framework provides a simple and clean way of preventing users sharing their details or logging-in twice from different computers.

Continue reading

I’m an avid user on StackOverflow in questions about Asp.Net Identity and I attempt to answer most of the interesting questions. And the same question comes up quite often: users try to confirm their email via a confiramtion link or reset their password via reset link and in both cases get “Invalid Token” error.

There are a few possible solutions to this problem.

Continue reading

As far as I know next version of ASP.Net is going to abandon MSBuild and build projects differently. Can’t wait for this to happen!

But for now we are still stuck with horribleness of XML and MSBuild (did I tell you I hate MSBUILD with passion?).

When I start a new MVC project, I add extra bits of MSBuild script into *.csproj file.

Missing Content files

First element is to fail a build if some of *.js or *.css files are missing from the project folder. This happened before – somebody in a team forgets to check-in a new file site.css – build server is silent for this matter. Only until somebody gets latest version of the project, builds, looks on it in a web-browser and notices that styles are not right, then the digging starts happening.

So here is the snippet to add to your project:

<Target Name="ValidateContentFiles">
    <Error Condition="!Exists(%(Content.FullPath))" Text="Missing Content file [%(Content.FullPath)]" />
</Target>

Simples – issue error if some of the “Content” files not on the hard-drive.

*.cshtml files marked as “None” for Build Action

This happened to me a few times now: to create a new view you copy-paste existing file, rename the file and change the internals. This is much faster than having to ask Visual Studio to create a new View file for you. The problem starts that sometimes files created this way are marked as “None” in Build Action (Right click on the file, Properties -> Build Action). This is very subtle change and not discoverable on development stage. But when you deploy the application to a server, files marked as None are not packed into the package. And your server now missing these view files. And only when somebody navigates to that missing page – that’s when you get a nasty exception in your face (hopefully your face, not your customer’s).

To avoid this Stackoverflow actually provided me very good answer (for a change).
So to fail a build on *.cshtml file being marked as None, add this snippet to your .csproj file

<Target Name="EnsureContentOnViews" BeforeTargets="BeforeBuild">
    <ItemGroup>
        <Filtered Include="@(None)" Condition="'%(Extension)' == '.cshtml'" />
    </ItemGroup>
    <Error Condition="'@(Filtered)'!=''" Code="CSHTML" File="$(MSBuildProjectDirectory)\%(Filtered.Identity)" Text="View is not set to [BuildAction:Content]" />
</Target>

I wish these were the default settings in the project template.

The title is quite vague, but this is the best I can call this post. Bear with me, I’ll explain what I mean.

While working with Asp.Net MVC, in Razor views I use Html helpers a lot. My view end up looking like this:

@Html.TextBoxFor(m => m.Title)
@Html.TextAreaFor(m => m.Description)

And later if I write JavaScript and need to reference one of the input fields, I usually do this:

var title = document.getElementById("Title");
var description = document.getElementById("Description");

or if you use jQuery you go like this:

var title = $("#Title");
var description = $("#Description");

This is fine and works. Until you start renaming field names in your model. And then you need to track down where you hard-coded the input id. And many times these references slip away (they do from me!) and remain unchanged.

Would it not be great if these changed could be picked up automatically? or even better, do some sort of strongly-typed reference to the element if it is used in JavaScript?

Just use @Html.IdFor(m => m.Name)

And your JS code would look like this:

var title = document.getElementById("@Html.IdFor(m => m.Title)");
var description = $("#@Html.IdFor(m => m.Description)");

Below I’ve re-invented the wheel. [Facepalm]

So I trolled through MVC source code and figured out how it generates id’s for elements and here are my findings:

using System;
using System.Linq.Expressions;
using System.Web.Mvc;

public static class HtmlHelpers
{
    public static String ElementId<T, TResult>(this HtmlHelper<T> htmlHelper, Expression<Func<T, TResult>> selector)
    {
        var text = System.Web.Mvc.ExpressionHelper.GetExpressionText(selector);
        var fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
        var id = TagBuilder.CreateSanitizedId(fullName);

        return id;
    }
}

As you can see, I have not made any custom code, all components are from MVC and are applied in the same order as MVC does when it generates id for elements when you call for @Html.EditorFor(). So this guarantees the provided id from this function will match the id in your form.

In the view you use it like this:

@Html.ElementId(m => m.Title)

And your JS code would look like this:

var title = document.getElementById("@Html.ElementId(m => m.Title)");
var description = document.getElementById("@Html.ElementId(m => m.Description)");

A bit of mouthful, but gives you the safety net of strong types. I have not actually used it widely, so not sure how it’ll work out in the longer run.

Part 1: AspNet Identity and IoC Container Registration

Sounds like I’m making a series of articles about ASP.Net Identity and how to use it with Depenency Injection. Part 1 have seen a lot of hits from Google in just a few days. I suppose it is worth extending the tutorial.

Building up on Part 1 where I wired all Identity components to be injected by Unity container, now I’m going to add emailing service for email confirmation and password reset.

My plan is to use SendGrid as a email service and email debugging service Mailtrap.IO as a hosted fake SMTP server.

Continue reading

TL;DR: Registration code for Autofac, for SimpleInjector, for Unity, for Castle Windsor.

Tony Mackay has an alternative walk-through of a very similar process but with Autofac

Part 2: Sending Emails in Asp.Net Identity using Dependency Injection, Sendgrid and debugging it with Mailtrap.io

Warning: If you don’t know what Dependency Injection is or you don’t know why you need this, don’t waste your time on this article. This approach is not recommended for cases when you don’t need a IoC container and have only a handful of controllers. Visual Studio template with Identity framework works great out of the box. You don’t need DI to enjoy full power of Asp.Net Identity. This article does not explain what DI is, how it works and why you need it. So proceed with caution and only if you know the difference between constructor injection and lifetime scope.

I regularly monitor StackOverflow for questions related to AspNet Identity framework. And one question keeps popping up over and over again: how do you use Inversion of Control containers with this framework.

If you know the main principles of Dependency Injection, things are very simple. Identity is very DI-friendly and I’ve done a number of projects with Identity and injected all Identity components via Autofac or SimpleInjector. The principles behind DI are applicable to all the containers, despite the differences in API’s for registration.

For the sake of this blog-post I’ll start with the standard VS2013 template and use Unity container, just because I’ve never used Unity before. You can view registrations for SimpleInjector in my test-project.

Projects where I used Autofac are far too complex to show as an example and none of them are open-source, so Autofac fans will have to figure out themselves from my examples.

Continue reading