-1

I have a website that is attempting to retrieve documents from a folder that's restricted to specific AD groups/users. Given a user that's authenticated using Windows Authentication, I wish to attempt to check if they have access to a specific location and display/hide documents as needed. I was under the impression that using Windows Authentication and ASP.NET Impersonation would use the current user's credentials when executing a request, rather than the Application Pool's credentials, but this doesn't seem to be the case because I'm an admin capable of opening the restricted folders in Windows Explorer, but I can't read them from my application.

Is there any way to use the current requesting user's credentials to access files on the local filesystem?

In my web.config:

<appSettings>
    <add key="documentFolder" value="C:\Users\auser\source\repos\myapp\myapp\docs\folder1,C:\Users\auser\source\repos\myapp\myapp\docs\folder2,C:\Users\auser\source\repos\myapp\myapp\docs\secured" />
    <add key="securityFolder" value="C:\Users\auser\source\repos\myapp\myapp\docs\secured"/>
</appSettings>
<system.web>
  <authentication mode="Windows" />
  <identity impersonate="true"/>
  <authorization>
    <deny users="?" />
  </authorization>
</system.web>

I'm attempting to access files in two places. First, I index them (for now this runs from Application_Start):

var dirs = ConfigurationManager.AppSettings["documentFolder"].ToString().Split(',');

foreach (var dir in dirs)
{
    foreach (var file in Directory.GetFiles(dir, "*.pdf", SearchOption.TopDirectoryOnly))
    {
        try
        {
            FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read); // <-- Fails with "Access to the path 'C:\Users\auser\source\repos\myapp\myapp\docs\secured' is denied."
        }
        catch (Exception ex)
        {
            logger.Error("Failed to read file.", ex);
        }
    }
}

At a later point I attempt to check if the user has access:

protected void Button1_Click(object sender, EventArgs e)
{
    bool canSeeSecurityDocuments;
    try
    {
        System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(ConfigurationManager.AppSettings["securityFolder"].ToString()); <-- Fails with "Attempted to perform an unauthorized operation."
        canSeeSecurityDocuments = true;
    }
    catch (Exception ex)
    {
        canSeeSecurityDocuments = false;
    }
}

From procmon:

Desired Access: Read Attributes, Read Control

Disposition: Open

Options: Open Reparse Point

Attributes: n/a

ShareMode: Read, Write, Delete

AllocationSize: n/a

Impersonating: mydomain\myuserid <- redacted, but correct.

Based off research about integrated vs classic pipelines, I moved the GetFiles call to a different location and wrapped it in a WindowsImpersonationContext to see if that'd force impersonation, which it didn't. (From this SO answer):

var current = System.Security.Principal.WindowsIdentity.GetCurrent();
logger.Debug(current.Name); <-- This is my identity

WindowsIdentity clientId = (WindowsIdentity)User.Identity;

using (WindowsImpersonationContext wic = clientId.Impersonate())
{
    current = System.Security.Principal.WindowsIdentity.GetCurrent();
    logger.Debug(current.Name); <-- This is still my identity

    // call to GetFiles, as above. Still fails.
}

current = System.Security.Principal.WindowsIdentity.GetCurrent();
logger.Debug(current.Name); <-- still me. Nothing seems to change.

Procmon Event tab Procmon Process tab

Community
  • 1
  • 1
Nielsvh
  • 1,151
  • 1
  • 18
  • 31
  • Do you have details about the specific exception that is thrown? I did notice that you're using "documentFolder" in one example and "securityFolder" in the other. Are you certain is a permission Access Denied issue? – Rich-Lang Apr 10 '19 at 18:49
  • 1
    Application_Start won't run under the context of a user. Impersonation will cause requests to run under the logged in user, but not Application_Start – Rich-Lang Apr 10 '19 at 18:59
  • @Rich-Lang, I added the exception messages inline. "securityFolder" is a subfolder of "documentFolder". I do have access to files in "documentFolder", but not "securityFolder". – Nielsvh Apr 10 '19 at 19:26
  • I just reread your post and you say: "At a later point..." Is that to say that is also performed in your Application_Start? If so, that's 100% your problem. – Rich-Lang Apr 10 '19 at 19:34
  • @Rich-Lang, no, the "at a later point" is from a click event handler. Code updated again. – Nielsvh Apr 10 '19 at 19:40
  • The error message you are showing is what I get when I disable Impersonation. I would recommend getting a ProcMon trace (https://learn.microsoft.com/en-us/sysinternals/downloads/procmon) and examine the entries where W3WP.exe tries to connect to your folder. I'd expect you'd get an Access Denied, but take a look at the Properties to see if it is impersonating a user or not. – Rich-Lang Apr 10 '19 at 19:46
  • @Rich-Lang, updated question with procmon results. Is there a chance that GetAccessControl would fail for a directory I actually have access to? – Nielsvh Apr 10 '19 at 23:12
  • Give a thorough read thru https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.getaccesscontrol?view=netframework-4.7.2 and see if anything stands out. I notice the ProcMon entry is looking for ReadAttributes Access. From the above link: > In NTFS environments, ReadAttributes and ReadExtendedAttributes are granted to the user if the user has ListDirectory rights on the parent folder. To deny ReadAttributes and ReadExtendedAttributes, deny ListDirectory on the parent directory. – Rich-Lang Apr 11 '19 at 05:23

1 Answers1

0

The issue was that I was using the threadpool in order to do some background work (indexing files). It appears, according to this SO answer, that the threadpool doesn't carry over the credentials that were used to create it. I should have checked within the actual thread to see what the context was...

Nielsvh
  • 1,151
  • 1
  • 18
  • 31