Impersonation in ASP.NET MVC

Impersonation in ASP.NET MVC

Impersonation allows machine to machine impersonation, so the client browser and the server are on the same page when it comes to the impersonation. When you then attempt to access the network share, the computer doesn't trust the impersonated credentials.

You need to enable delegation for the IIS machine in Active Directory. Go to Active Directory Users and Computers, find the computer, click properties, and 'Trust computer for delegation'. (You might need to restart IIS for this to work, I don't remember).

There is way more theory than this that I don't fully understand, but this should work. Whether it is right or not someone else could comment on!

Also, the reason it works on your development machine is that the development server runs as the developer, not (Local)\Network Service.


A decent link:

http://msdn.microsoft.com/en-us/library/cc949004.aspx

What is the difference between impersonation and delegation?

Impersonation flows the original caller’s identity to back-end resources on the same computer. Delegation flows the original caller’s identity to back-end resources on computers other than the computer running the service.

For example, if a service is running within IIS without impersonation, the service will access resources using the ASP.NET account in IIS 5.0, or the Network Service account in IIS 6.0. With impersonation, if the client is connecting using the original caller’s account, the service will access resources such as a SQL Server database on the same machine using the original caller’s account instead of the system ASP.NET account. Delegation is similar except that the SQL Server database could be on a different machine that is remote to the service.

ASP.NET MVC 5 Membership impersonate specific user

Now if a user from role User has some issues with the application, how
can I allow a user from Admin role to impersonate that specific user,
without that specific user to give the Admin his username and
password? ...Is this possible to achieve in MVC?

This can be accomplished without knowing the password of the user to be impersonated, but you do have to know the username of the user to be impersonated.

You can do this with the following using normal Forms Authentication:

FormsAuthentication.SetAuthCookie("username-to-be-impersonated", false);

Of course you would want to protect the entry to this block of code, so that only admins can do the impersonation. You will probably want to do something else like save the admin user's username in session or cookie to help the system know that an impersonation is in progress, and give the user the ability to reverse it when they are done impersonating.

Bottom line is, all the membership system cares about is the auth cookie, and you can write an auth cookie for any username without knowing the user's password.

The process is the same for ASP.NET Identity 2, the difference is just how you write the auth cookie. Note the code below is a snippet based on the comment that @trailmax left in the OP:

// assume you already have references to a UserManager and HttpContext
var userToImpersonate = await userManager
.FindByNameAsync(userNameToImpersonate);
var identityToImpersonate = await userManager
.CreateIdentityAsync(userToImpersonate,
DefaultAuthenticationTypes.ApplicationCookie);
var authenticationManager = httpContext.GetOwinContext().Authentication;
authenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(new AuthenticationProperties()
{
IsPersistent = false
}, identityToImpersonate);

You should also have a policy that allows you to somehow get the user's permission before having an admin impersonate their account.

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

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://learn.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.

ASP.NET User Impersonation

What you are doing/asked to do is typically frowned upon. When you have Integrated Security=True set in your connection string, the SID/user access the connection is defined by the application pool. This allows SQL Connection Pooling to work very efficiently.

When you try to access the SQL server using Integrated Security with Pass-through authentication or impersonation, you basically lose all value from the connection pool (because now each connection has to be created with the user credentials and cannot be shared across requests).

Normally when I come across this situation, I create a user, grant db access and use that user with the application pool. When a user authenticates on the website (windows or basic auth) I use Active Directory Services or LDAP to verify the user has access to the application.

Impersonate a Active Directory user in MVC application with Windows Authentication

 using (new Impersonation()){
// now working in context of whatever user you want
}

and this is the class

 [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonation : IDisposable
{
private readonly SafeTokenHandle _handle;
private readonly WindowsImpersonationContext _context;

//const int Logon32LogonNewCredentials = 9;
private const int Logon32LogonInteractive = 2;

public Impersonation()
{
var domain = "your domain;
var username = "the user";
var password = "their password";
var ok = LogonUser(username, domain, password, Logon32LogonInteractive, 0, out _handle);
if (!ok)
{
var errorCode = Marshal.GetLastWin32Error();
throw new ApplicationException(string.Format("Could not impersonate the elevated user. LogonUser returned error code {0}.", errorCode));
}
_context = WindowsIdentity.Impersonate(_handle.DangerousGetHandle());
}

public void Dispose()
{
_context.Dispose();
_handle.Dispose();
}

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle()
: base(true) { }

[DllImport("kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr handle);

protected override bool ReleaseHandle()
{
return CloseHandle(handle);
}
}
}

Impersonation in ASP.NET MVC

You may try writing a custom FilePathResult:

public class ImpersonatingFileResult : FilePathResult
{
public ImpersonatingFileResult(string fileName, string contentType)
: base(fileName, contentType)
{ }

protected override void WriteFile(HttpResponseBase response)
{
// TODO : Start impersonation
response.TransmitFile(FileName);
// TODO : Rollback impersonation
}
}

and in your controller:

return new ImpersonatingFileResult(path, "application/octet-stream");

Impersonation issue with ASP.NET MVC

In order to access remote files on behalf of an impersonated client, your server needs to be trusted for delegation. See this KB article for more info, or just google "trusted for delegation".



Related Topics



Leave a reply



Submit