Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Impersonate a user in a standard ASP.NET MVC installation template

I have setup a standard ASP.NET MVC site with normal authentication. I have added roles, so new users get a specific role.

Now, I want to be able to impersonate a user.

Impersonating advice

Impersonating, when I search around, comes the following way:

     FormsAuthentication.SetAuthCookie(user.UserName, false);

This doesn't work by default, as you have to do two things:

1:

Enable forms authentication:

 <system.web>
    <authentication mode="Forms" />
  </system.web>

2:

Disable the module:

<system.webServer>
    <modules>
      <!--<remove name="FormsAuthentication" />-->
    </modules>
    <staticContent>

The challenge

However, doing this leaves a couple of challenges.

  1. When you impersonate, you cannot log out. This is easily fixed by adding the following in LogOut: FormsAuthentication.SignOut();
  2. The User.IsInRole(Constants.Roles.Creditor); stops working, so we cannot check if user in a role

What to do?

This COULD boil down to me - apparently - not fully understanding the membership framework despite trying. However, how do you get impersonate to work here?

I have no explicit reason to use "Forms" authentication, and the only reason I started on this path is Impersonating. So I see I have two obvious directions:

  • A) Implement impersonation in a different way, so I don't touch my web.config to use forms
  • B) Fix the role problem in forms

Any help here? :-)

like image 270
Lars Holdgaard Avatar asked Dec 14 '17 14:12

Lars Holdgaard


2 Answers

There are quite a few ways to accomplish this all you really need to do is get both the Id's to your controller and decide how you want it persisted (Cookie, Cache, Db , etc.).

An easy way to do this is to create a claim for the impersonation and add a policy for those kind of claims. Here is a link for adding claim based policies.

Here is some code to get you started :

In your controllers you will want an end point that does something like this

        var claims = await UserManager.GetClaimsAsync(CurrentUserId);
        var claim = claims.FirstOrDefault(c => c.Type == "Impersonate");
        if (claim!=null)
        {
            //You may forget to remove it or the user could end there session before you are able to
            var r = await UserManager.RemoveClaimAsync(CurrentUserId, claim);
        }
        var result = await UserManager.AddClaimAsync(CurrentUserId, new Claim("Impersonate", userId));

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

Now with the code above we wanted the users ID, but we could have just as easily gotten there role and saved that with the claim. From here you just need to decide how you want to use this claim. The link below will show you how you can do that.

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims

Just remember to remove the claim after you are done.

This one works nice when you may have to impersonate a user for sometime. One project I worked on the clients the needed to be able to impersonate users for weeks at a time to complete work for other clients.

like image 168
rahicks Avatar answered Oct 24 '22 16:10

rahicks


If we need to implement the IsInRole() method in basic forms principal, we need to customize the principal.

User is a principal object, which contains list of Identities. Default identity does not contain role property, so we need to create custom identity object.

For e.g:

public class CustomPricipal : IPrincipal
{        
    public CustomPricipal(string username)
    {
        this.Identity = new CustomIdentity(username);
    }

    public IIdentity Identity
    {
        get;
        private set;
    }

    public bool IsInRole(string role)
    {
        return this.Identity != null && ((CustomIdentity)this.Identity).Roles.Any(x => x.ToLower() == role.ToLower());
    }
}

public class CustomIdentity : IIdentity
{
    public CustomIdentity(string name)
    {
        // We can fetch the user information from database and create custom properties
        this.Name = name;
        this.IsAuthenticated = true;
        this.AuthenticationType = "Forms";
        this.Roles = new List<string>() { "Admin", "SuperAdmin" };
    }
    public string AuthenticationType
    {
        get;
        private set;
    }

    public bool IsAuthenticated
    {
        get;
        private set;
    }

    public string Name
    {
        get;
        private set;
    }
    public List<string> Roles
    {
        get;
        private set;
    }
}

In global.asax.cs

    public override void Init()
    {
        this.PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
        base.Init();
    }

    void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
    {
        if (Request.IsAuthenticated)
        {
            HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
            if (authCookie != null)
            {
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);                    
                Context.User = Thread.CurrentPrincipal = new CustomPricipal(authTicket.Name);
            }
        }
    }

Now we can use the User.IsInRole("")

like image 25
Antony Samy Joseph Avatar answered Oct 24 '22 14:10

Antony Samy Joseph