Search code examples
c#asp.net-web-apicrystal-reportsasp.net-web-api2

How to use impersonation to access a network resource from IIS?


I have a WebApi app that needs to access a network share on a different machine and open Crystal Reports files.

I'm using LogonUser and WindowsIdentity.Impersonate to impersonate a user that has rights to the network share using this code (not complete):

SafeTokenHandle safeTokenHandle;

const int LOGON32_PROVIDER_DEFAULT = 0;
const int LOGON32_LOGON_INTERACTIVE = 2;

bool returnValue = LogonUser(userName, domainName, userPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);

if (returnValue == false)
{
    int ret = Marshal.GetLastWin32Error();
    throw new System.ComponentModel.Win32Exception(ret);
}

using (safeTokenHandle)
using (var newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
using (var impersonatedUser = newId.Impersonate())
{ 
    actionToExecute();
}

This works fine when, for example, listing folders or deleting files using managed code (System.IO). However I need to open Crystal Reports files (I have the latest version), and when doing so, I get an exception:

Access denied

I am assuming that CR is trying to load the file within the context of the Application Pool user.

I would probably get this working if I change the Application Pool user to a domain user with enough rights on the network share. But I want to avoid this solution.

Would using the new WindowsIdentity.RunImpersonated for .NET4.6 help or will it have the same outcome. If yes, is there a way to get CR to run within the supplied user context instead of the Application Pool / AppDomain user?

UPDATE

I've had partial success by changing the LogonUser parameters to LOGON32_LOGON_NEW_CREDENTIALS and LOGON32_PROVIDER_WINNT50. Then I tested the following:

  1. Started the project locally from within VS2017 (so that the WebApi project runs within the local IIS Express context) and accessed the network resource using the client app on my machine. This test was a success.

  2. Published the WebApi project on IIS on a separate machine. Started the client (ClickOnce) project on my machine and accessed the same network resource. This test fails.

  3. Same as (2) but the client is published and installed on another machine, and accessing it using terminal server. This test fails.

Why does the first test succeeds but tests 2 and 3 fail? What should the correct logon parameters be if the supplied ones won't always work?


Solution

  • The problem is that ReportDocument doesn't have something like LoadImpersonate, so, it will always try to open the .rpt file using the app-pool permissions.

    What you need is delegation, not impersonation, if you are using windows authentication and active directory you need to authorize your server and/or your app-pool account for delegation...

    https://support.microsoft.com/en-us/help/810572/how-to-configure-an-asp-net-application-for-a-delegation-scenario

    That way the app-pool account will use the user's privileges to access the resources

    If that is not posible, as a workaround you can use impersonation to copy the .rpt file to an accessible location for your app-pool account and delete it after use it...