Impersonating ASP.NET claims identity to windows i

2019-06-22 09:03发布

问题:

I have an ASP.NET application which uses claims bases authentication against ADFS. I also map it to a WindowsClaimsIdentity by using the Claims to Windows Identity Service. That works fine.

But now I need to impersonate the current request/thread so I can access a service which is not claims aware. How should I do that?

Should I acquired a WindowsImpersonationContext in the Application_PostAuthenticate event and save that in the HttpContext.Items and then in the Application_EndRequest call the Undo method?

Or are there other preferred ways to do this?

Update: As I didn't get any hints on what the preferred way to impersonate I tried my own suggestion. I created this code in the global.asax.cs:

    private static readonly string WICKey = typeof(System.Security.Principal.WindowsImpersonationContext).AssemblyQualifiedName;

    protected void Application_PostAuthenticateRequest()
    {
        var wid = User.Identity as System.Security.Principal.WindowsIdentity;
        if (wid != null)
        {
            HttpContext.Current.Trace.Write("PostAuthenticateRequest PreImpersonate: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
            HttpContext.Current.Items[WICKey] = wid.Impersonate();
            HttpContext.Current.Trace.Write("PostAuthenticateRequest PostImpersonate: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
        }
    }

    protected void Application_EndRequest()
    {
        var wic = HttpContext.Current.Items[WICKey] as System.Security.Principal.WindowsImpersonationContext;
        if (wic != null)
        {
            HttpContext.Current.Trace.Write("EndRequest PreUndoImpersonate: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
            wic.Undo();
            HttpContext.Current.Trace.Write("EndRequest PostUndoImpersonate: " + System.Security.Principal.WindowsIdentity.GetCurrent().Name);
        }
    }

When I look to the trace log I see this

PostAuthenticateRequest PreImpersonate: NT AUTHORITY\NETWORK SERVICE   
PostAuthenticateRequest PostImpersonate: MyDomain\CorrectUser
Home: NT AUTHORITY\NETWORK SERVICE
EndRequest PreUndoImpersonate: NT AUTHORITY\NETWORK SERVICE
EndRequest PostUndoImpersonate: NT AUTHORITY\NETWORK SERVICE 

So in the second line you can see the thread is impersonated correctly. But in the next lines you see that the impersonation is lost. (the third line originates from a controller).

When I use the following code to impersonate locally it works fine:

        var wid = User.Identity as System.Security.Principal.WindowsIdentity;
        if (wid != null)
        {
            using (var ctx = wid.Impersonate())
            {
                //Do something
            }
        }

But I want to impersonate the whole request lifetime. How should I do that?

回答1:

You said the backend service is not claims aware. Can you elaborate on this? Do you mean that the compiled code is not claims aware but you have the ability modify the web.config file? If so then you can try to configure the backend service to use the WIF pipeline for authN by wedging in the WSFederationAuthenticationModule, SessionAuthenticationModule and a custom ClaimsAuthorizationManager if you need to also do authZ. You can then use WIF's ActAs or OnBehalfOf features when your ASP.NET application calls the backend service.



回答2:

Sorry for digging up this old thread, but for your code to work make sure the Managed Pipeline Mode of the Application Pool running your application is set to Classic.