2

I have a .net/c# web app (web api) with windows authentication. The service is hosted on my local computer, IIS 10. Application pool identity set to me, currently logged in windows user. Computer is in active directory domain.

I want to access shared file using account, currently logged in to the app. File has appropriate permissions. For this purposes I use impersonation like this:

    if (HttpContext.Current.User.Identity is WindowsIdentity windowsIdentity)
       {
           using (windowsIdentity.Impersonate())
           {
                FileStream stream = new FileStream(@"\\server\share\file.ext", FileMode.Open, FileAccess.Read);
           }
       }

I logging in with current windows account, the same as set in app pool identity. This works fine with a shared file on a local computer, where the app is hosted. But does not work with a remote shared file, located on another computer. The other computer is in active directory domain too.

From a hosting computer I can access shared file using windows explorer or my browser. Also if I do not impersonate user, .net trying to access shared file with application pool identity account(set to the same user, me) and it succeeded for both, local and remote files.

It also works with impersonated identity got from LogonUser method from advapi32.dll. But it requires user password and I do not want to request password from user, already logged in to app.

What am i doing wrong?

Update: If a shared file located on hosting machine, then logon event generated by windows (security tab in event viewer) shows the right user. If a shared file located on another machine, then logon event generated by windows on this machine shows the anonymous user. So, account somehow lost.

Update 2: Impersonation works if I run site on IIS like localhost(localhost in url). But if I run it using ip or site name it stops working.

Update 3: Wireshark shows the request for getting ticket(to access shared file server) for delegation fails with error "KRB5KDC_ERR_BADOPTION NT Status: STATUS_NOT_FOUND". Delegation for application pool user allowed in AD. The same ticket(for cifs/fileshareservername) without delegation can be successfully retrieved(wireshark shows) when doing Dir command in cmd. Seems like problem in AD.

DominGez
  • 21
  • 5
  • Have just found exactly the same problem here: https://stackoverflow.com/questions/49988874/impersonate-user-to-access-file-on-remote-server-access-denied But there is no working answer. – DominGez Jan 03 '19 at 16:55
  • Does your .net site use AD for authentication, you calling WindowsLogin, or do you have your own set of userid's to login to your site? I think your "with Windows Authentication" means its going to your local Windows, just making sure – Brent Jan 03 '19 at 17:27
  • @Brent It is standard .net Windows Authentication, you can see it in IIS section "Authentication" for example. And yes, it uses AD users, I do not have my own db users set. – DominGez Jan 04 '19 at 13:53

2 Answers2

1

Can't for sure if what you're doing is wrong, but I can tell you what I've done to do a very similar thing. My .Net site doesn't have WindowsLogin normally, so I had to make an extra jump that I think you could do to facilitate the same thing, just perhaps not the best answer.

At login ( in my membershipProvider ) I run this code:

try
{
    if (LogonUser(user,domain,password, [AD_LOGIN], 
                   LOGON32_PROVIDER_DEFAULT, ref handle))
    {
        IntPtr tokenDuplicate = IntPtr.Zero;

       if (DuplicateToken(handle, SecurityImpersonation,
             ref tokenDuplicate) != 0)
       {
          // store off duplicate token here
       }
    }
}
finally
{
    if (handle != IntPtr.Zero)
    {
        CloseHandle(handle);
    }
}

then when you need to impersonate, do this:

var context = WindowsIdentity.Impersonate(tokenDuplicate);
try
{
    // do your file access here
}
finally
{
    context.Dispose();
}

I had to do some funny conversion of that tokenDuplicate variable. It's an integer value but pointing at a specific memory address where the token information is stored. It stays good as long as your logged in.

Why you can't do the impersonate directly on your identity, don't know. I just know it worked for me with a token, and that was my method to get a token I could use for impersonation.

Rubens Farias
  • 57,174
  • 8
  • 131
  • 162
Brent
  • 109
  • 7
  • I cannot use LogonUser actually, because login process is happening earlier. But I have tried to call DuplicateToken using token I already have and impersonate with new one, doesn't help. – DominGez Jan 04 '19 at 13:58
  • If you already have the token from your login, try to pass that into the Impersonate() call as the argument. – Brent Jan 04 '19 at 22:53
  • I tried it earlier, before posting this question, it does not work too. – DominGez Jan 08 '19 at 09:39
0

It started working for me with the following settings.

IIS:

  1. Application pool identity set to a specific user(let's say IISUser).
  2. Windows authentication enabled for IIS site. Kernel mode enabled (important!).

All other magic is happening in Active directory:

  1. Computer with shared files has an SPN: cifs/%computer_name%.
  2. Hosting computer(where IIS installed) is trusted for delegation. Delegation tab -> Trust this computer for delegation to specified services only -> Use any authentication protocol. Then select SPN from item 1. Important: you should select computer SPN, not IISUser SPN.
  3. IISUser is trusted for delegation for SPN from item 1.
DominGez
  • 21
  • 5