How to Use ASP.NET Identity 2.0 to Allow a User to Impersonate Another User

How do I use ASP.NET Identity 2.0 to allow a user to impersonate another user?

I've found a solution to this problem.

Basically I add claim with admin username, if this claim exists, I know that impersonation is happening. When admin wants to stop impersonation, system retrieves original username for the claims, deletes old impersonated-cookie and creates a new cookie for the admin:

[AuthenticateAdmin] // <- make sure this endpoint is only available to admins
public async Task ImpersonateUserAsync(string userName)
{
var context = HttpContext.Current;

var originalUsername = context.User.Identity.Name;

var impersonatedUser = await userManager.FindByNameAsync(userName);

var impersonatedIdentity = await userManager.CreateIdentityAsync(impersonatedUser, DefaultAuthenticationTypes.ApplicationCookie);
impersonatedIdentity.AddClaim(new Claim("UserImpersonation", "true"));
impersonatedIdentity.AddClaim(new Claim("OriginalUsername", originalUsername));

var authenticationManager = context.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, impersonatedIdentity);
}

More information is in my blog-post: User impersonation with ASP.Net Identity 2.

User Impersonation in Asp.Net Core

Upd July 2017: this topic is quite popular, so I've looked into user impersonation in Core and principles are very similar with updated API. Here is how to impersonate:

    [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();

// If you use asp.net core 1.0
await HttpContext.Authentication.SignInAsync(cookieOptions.ApplicationCookieAuthenticationScheme, userPrincipal);
// If you use asp.net core 2.0 (the line above is deprecated)
await HttpContext.SignInAsync(cookieOptions.ApplicationCookieAuthenticationScheme, userPrincipal);

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

This is how to stop impersonation:

    [Authorize(Roles = "Admin")] // <-- Make sure only admins can access this 
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");
}

Full explanation in my blog: http://tech.trailmax.info/2017/07/user-impersonation-in-asp-net-core/
Full code sample on GitHub: https://github.com/trailmax/AspNetCoreImpersonation

ASP.NET Core Identity impersonate specific user

There is a blog post about impersonation in Asp.Net Core HERE. I am just searching for such a solution, so I have not tried implementing it yet. However it seems you are on the right track. There are only slight differences between your code and Max's.

Basically you need to replace the cookie at the browser side. So, for the next request the server "thinks" its someone else logged in. At least that's what I understood so far. This is why you better save the original identity in the cookie as well, thus you could switch back to the original user when needed.

I get back when I have a working solutions anyway.

ASP .NET Core - sign in as other user / impersonate user and way back

I solved it with the following code.

In AccountController:

    [Authorize(Roles="Administrators")]
public async Task<IActionResult> ImpersonateUser(string id)
{
var appUser = await _userManager.FindByIdAsync(id);
var userPrincipal = await _signInManager.CreateUserPrincipalAsync(appUser);
userPrincipal.Identities.First().AddClaim(new Claim("OriginalUserId", User.FindFirst(x=>x.Type == ClaimTypes.NameIdentifier).Value));

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

//https://github.com/aspnet/Identity/blob/dev/src/Microsoft.AspNetCore.Identity/IdentityCookieOptions.cs
await HttpContext.Authentication.SignInAsync("Identity.Application", userPrincipal); //impersonate the new user

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

public async Task<IActionResult> StopImpersonation()
{
var originalUserId = User.Claims.First(x => x.Type == "OriginalUserId").Value;
var appUser = await _userManager.FindByIdAsync(originalUserId);
await _signInManager.SignInAsync(appUser, false);

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

Basically this adds the claim OriginalUserId to the impersonated user. By checking if this claim exists I know I'm currently impersonating and can provide a way back to the original account using the code in StopImpersonation.

The authentication scheme Identity.Application is the default.



Related Topics



Leave a reply



Submit