views:

311

answers:

3

I have a WSE 3.0 based web service running in Windows Server 2003 under IIS 6.0. I want the web service process to impersonate the client user that sends the web service request, however the service is not impersonating the client.

The web application has its own app pool, which is currently set to run under the Network Service identity. The Windows Server 2003 machine account has been enabled for delegation in Active Directory (at least according to my IT guy). The service WSE policy (in wse3policyCache.config) looks like this:

<policy name="GeneratedServicesPolicy">
    <kerberosSecurity establishSecurityContext="false" renewExpiredSecurityContext="true" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">
        <protection>
            <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
            <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
            <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
        </protection>
     </kerberosSecurity>
     <requireActionHeader />
</policy>

The service has the following entries (among others) in its web.config:

<identity impersonate="false"/>
<authentication mode="Windows"/>

Anonymous access is enabled for the application (this is required since transport-level security is not used by the service, message-leve is). The machine account has the following SPN's registered:

HOST/RD360-2
HOST/rd360-2.mycompany.com

The client has the following in its wse3policyCache.config:

<policy name="KerbClient">
 <kerberosSecurity establishSecurityContext="false" renewExpiredSecurityContext="true" requireSignatureConfirmation="false" messageProtectionOrder="SignBeforeEncrypt" requireDerivedKeys="true" ttlInSeconds="300">
  <token>
   <kerberos targetPrincipal="HOST/rd360-2.mycompany.com" impersonationLevel="Impersonation" />
  </token>
  <protection>
   <request signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
   <response signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
   <fault signatureOptions="IncludeAddressing, IncludeTimestamp, IncludeSoapBody" encryptBody="false" />
  </protection>
 </kerberosSecurity>
 <requireActionHeader />
</policy>

The client code looks like this:

static void Main(string[] args)
{
 AddFloatsWSWse client = new AddFloatsWSWse();
 client.SetPolicy("KerbClient");

 double result = client.AddFloats(2.3, 3.2);
 Console.WriteLine("Result was: '" + result + "'");
}

The service is not impersonating my client identity, though. I am using log4net in the service, and when I ask it to print out the %username into the ASP.NET trace log, it is always NT AUTHORITY\NETWORK SERVICE and not the client user id. Is there anything I'm doing wrong? Is there somewhere I can look to see if WSE is even trying to perform the impersonation and failing? I do see the following entries in my event log (MYDOMAIN and MYUSER are obscured here):

Event Type: Success Audit
Event Source: Security
Event Category: Privilege Use 
Event ID: 576
Date:  12/9/2009
Time:  11:07:16 AM
User:  MYDOMAIN\MYUSER
Computer: RD360-2
Description:
 Special privileges assigned to new logon:
  User Name: MYUSER
  Domain:  MYDOMAIN
  Logon ID:  (0x0,0x4B410AE)
   Privileges: SeSecurityPrivilege
    SeBackupPrivilege
    SeRestorePrivilege
    SeTakeOwnershipPrivilege
    SeDebugPrivilege
    SeSystemEnvironmentPrivilege
    SeLoadDriverPrivilege
    SeImpersonatePrivilege

----------------------------------------------------------------------------------

Event Type: Success Audit
Event Source: Security
Event Category: Logon/Logoff 
Event ID: 540
Date:  12/9/2009
Time:  11:07:16 AM
User:  MYDOMAIN\MYUSER
Computer: RD360-2
Description:
 Successful Network Logon:
  User Name: MYUSER
  Domain:  MYDOMAIN
  Logon ID: (0x0,0x4B410AE)
  Logon Type: 3
  Logon Process: Kerberos
  Authentication Package: Kerberos
  Workstation Name: 
  Logon GUID: {OBFUSCATED}
  Caller User Name: -
  Caller Domain: -
  Caller Logon ID: -
  Caller Process ID: -
  Transited Services: -
  Source Network Address: -
  Source Port: -

And in my WSE trace file I do see:

<processingStep description="Entering SOAP filter Microsoft.Web.Services3.Design.RequireSoapHeaderAssertion+RequireSoapHeaderFilter" />
<processingStep description="Exited SOAP filter Microsoft.Web.Services3.Design.RequireSoapHeaderAssertion+RequireSoapHeaderFilter" />
<processingStep description="Entering SOAP filter Microsoft.Web.Services3.Design.KerberosAssertion+ServiceInputFilter" />
<processingStep description="Exited SOAP filter Microsoft.Web.Services3.Design.KerberosAssertion+ServiceInputFilter" />

so at least I know the Kerberos extensions are processing my Kerberos headers. Thanks in advance for any help or hints!

Edit: My webservice then uses a proprietary client communication library to call into another server using SSPI/IWA (let's call this third server a foo server). I want it to use the client's identity when it makes this second call into the foo server. This means that this client communication library calls AcquireCredentialsHandle and InitializeSecurityContext using the SPN of the foo server and a different service. In this particular case, the foo server is actually running on the same machine as the WSE web service (so it's using the SPN mycompany/rd260-2). Since this second hop is to the same machine, I would expect this to use NTLM, but it still should impersonate my web service client's user identity, shouldn't it? In the logs of the foo server, I see that it accepts the connection, uses the IWA security context provided and tells me that based on this security context, the connecting user is rd36-2$ which is the machine account since the WSE web service is running in IIS under the Network Service identity (which is in turn associated to the machine account). In the logs of the foo server, after it receives the IWA security context, I ultimately want to see the identity of the user who submitted the web service request. Would it be useful to move the foo server to a different machine to see if that has some bearing on this?

+2  A: 

The Kerberos token used with WSE 3 is a message-level security mechanism and only authenticates the client. It does not actually change the security context as in IWA, so you won't notice anything different in the trace log as such. In order to actually impersonate the client, you have to:

  • Enable impersonation on the security token with impersonationLevel="Impersonation" on the <kerberos> element (which you've already done); and
  • Have your WebMethod create a WindowsImpersonationContext based on the token's identity.

Example:

WindowsIdentity identity =
    (WindowsIdentity)RequestSoapContext.Current.IdentityToken.Identity;
WindowsImpersonationContext impersonationContext = null;
try
{
    impersonationContext = identity.Impersonate();

    // Perform your work here
    // ...
}
finally
{
    if (impersonationContext != null)
    {
        impersonationContext.Undo();
    }
}
Aaronaught
Thanks for your suggestions! I've added some more details to my question outlining the work that the service does perform. In my trace log, I still see the process running as NT Authority\Network Service even after the Kerberos token is processed by the WSE framework. But perhaps, based on your comment, I should never expect to see the user's identity in the log even after a successful impersonation? I thought I recalled that when you do transport-level IWA via IIS in conjunction with impersonation, you see the client's user identity in the trace logs. Is this just different for TLS IWA?
Zach
As far as I know, IWA is not important here. The WSE clients are connecting anonymously and authenticating/encrypting/signing at the message level. If memory serves, you won't see the impersonated user in the trace log, ever. FYI - WCF does WA completely differently, Microsoft changed it because the WSE version was so hackish.
Aaronaught
Also, if the work done involves calling into some proprietary SSPI-enabled library then it's entirely possible that the library tries to get its context from somewhere other than the caller. As I mentioned, try a very simple test first, i.e. set up an ACL on a file somewhere with access rights given to the user you want to impersonate, then try accessing the file in your WebService method.
Aaronaught
I've got it! The key was to actually perform the Impersonate on my own (after obtaining the kerberos token from the current soap context). Apparently the WSE framework doesn't actually perform the impersonation, it is up to the client code to do it. Once I added the code you reference (WindowsIdentity.Impersonate), I do see my real client id in the log, and the 3rd party communication library uses that identity correctly for its call. Aaron, could you add information about the fact that the WSE framework doesn't impersonate, then I will mark your answer as accepted.
Zach
Done. This should be clearer.
Aaronaught
+1  A: 

Have a look here and here

Peter Stuer
It looks like step 4 in the first link (creating the WindowsImpersonationContext) is the important step; the other steps should already be handled by the policy. I guess WSE impersonation isn't transitive.
Aaronaught
A: 

As far I can understand the situation is when you're trying to make the second hop the Kerberos ticket is dropped. In double hop scenario's the Kerberos Ticket will be dropped at the second hop.

Your authentication will fail after that and will not switch to NTLM.

pipelinecache