WCF:Relationship between NetworkCredential and Impersonation - wcf

I have a WCF service hosted in IIS 7 in the default app pool in Integrated mode with anonymous access disabled and windows Authentication enabled.
I have put the following attribute on the method implementation for my interface.
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
If I do not supply network credentials in the call to my service I get the expected behavior in that the following are true:
ServiceSecurityContext.Current.WindowsIdentity.Name = myDomain\myUser
ServiceSecurityContext.Current.PrimaryIdentity.Name = myDomain\myUser
Thread.CurrentPrincipal.Identity.Name = myDomain\myUser
I can connect to a database on a remote system using SSPI and myDomain\myUser authentication.
WindowsIdentity.GetCurrent().Name = myDomain\myUser
I can use Thread.CurrentPrincipal.IsInRole() to verify the user is in a role.
I can use WindowsIdentity.GetCurrent().Groups to retrieve a list of groups for the user.
But if I supply network credentials using the following:
var networkCredential = new NetworkCredential(user, pwd, dom);
base.ClientCredentials.Windows.ClientCredential = networkCredential;
base.ClientCredentials.Windows.AllowNtlm = true;
base.ClientCredentials.Windows.AllowedImpersonationLevel
= System.Security.Principal.TokenImpersonationLevel.Delegation;
Then all of the above is the same EXCEPT the database connection and two of the groups listed are different. The connection to the database is being made using the NT Authority\Anonymous login user. Using the NetworkCredentials puts the user in the NT Authority\Network group rather than NT Authority\Interactive and additionally the LOCAL group is removed.
My goal is to make the connection to the database using the credentials passed by NetworkCredential, any advice would be appreciated.
Shane Holder

Sounds like typical double-hop issues.
I am guessing in your working scenario that Kerberos is getting used by default which will get you a Delegation token on the remote server.
In the second scenario it is not using Kerberos because of the supplied user/pass and that does not support getting a Delegation token.
The only other way to get a Delegation token on the remote server that I am aware of is to use Basic Authentication (with SSL), a complete pain.
Concerning the credentials double hop issue

Related

WCF Changing credentials

I have a web app that calls a WCF web application with several services, all using basicHttBinding, on different servers (web server, app server and database server). One of the services has to connect to a database that must be called using an active directory account. Coming in from the web site the user is anonymous.
I have been given credentials to set this user to but I cannot get it to work. I create my channel on the web server like this:
ChannelFactory<T> channelFactory = GetChannelFactoryFromPool<T>(enpointAddress);
channelFactory.Credentials.Windows.ClientCredential.UserName = username;
channelFactory.Credentials.Windows.ClientCredential.Password = password;
channelFactory.Credentials.Windows.ClientCredential.Domain = domain;
proxy = channelFactory.CreateChannel();
In the service on the app server I am trying to determine if the credentials are correct by doing this:
var ssc = ServiceSecurityContext.Current;
but ssc is always null. Can this be done with basicHttpBinding?
Thanks,
Paul
The basicHttpBinding does support Windows authentication as documented in this good MSDN article. You also need to ensure the service operations are configured to allow impersonation of the client credentials to have the security context populated as expected.

Authenticate a call to a WCF service

I am trying to call a Sharepoint Web Service via WCF from inside a .ASHX on a different server. My code works if I run inside of Visual Studio's debug web server, but not from IIS. The working server works in various authentication modes (Kerberos, NTLM), and the non-working one doesn't work in any. I am impersonating the same user in both cases.
Using NTLM, I recorded a working session and non-working session in Wireshark. In the working one, Wireshark parses the NTLM data and reports a DOMAIN and USER NAME that I expect. In the non-working one, it shows
DOMAIN: NULL
USER NAME: NULL
I have debugged in IIS and impersonation is definitely working at the point of the service call. If I check WindowsIdentity.GetCurrent(), it's the user I expect.
If I inspect the WCF service proxy on the working and non-working servers, they look identical -- the part that deals with ClientCredentials is set to "" for Username and Password for both versions.
Any ideas on what else to check? Why would the NTLM data have DOMAIN and USER NAME set to NULL -- where does it pick that up from?
According to this:
http://support.microsoft.com/kb/207671
When IIS services an HTTP request, IIS performs impersonation so that access to resources to handle the request is limited appropriately. The impersonated security context is based on the kind of authentication performed for the request. The five different types of authentication available from IIS 4.0 are:
Authentication Type Impersonation Type
------------------------------------ ---------------------
Anonymous Access (no authentication) Network
Auto Password Synchronization is
ON (ON=default)
Anonymous Access (no authentication) IIS Clear Text
Auto Password Synchronization is OFF
Basic Authentication IIS Clear Text
NT Challenge/Response Authentication Network
Client SSL Certificate Mapping Interactive
In my case, I have a Network Token, but
Network tokens are "NOT" permitted to access network resources. (Network tokens are named so because this kind of token is traditionally created by a server when a user is authenticated across the network. To allow the server to use a network token to act as a network client and access another server is called "delegation" and is considered a possible security hole.)
The KB has many possible ways to avoid the problem

Does this require windows delegation to be enabled for server service account?

I have a client console application which has got some user credentials - domain\user and plain-text password. The client app obtains windowsidentity object for that user by invoking LogonUser (dwLogonType:LOGON32_LOGON_NETWORK) win32 API. I use windowsidentity to impersonate and make WCF Service call (hosted on different machine). The WCF Service is configured to use TCP protocol with windows integrated security. The call fails with SecurityNegotiation exception with error: The remote server did not satisfy the mutual authentication requirement.
My assumption here is that the server sees anonymous client identity which it rejects because the endpoint is configured to use windows integrated authentication. My guess is that the server account needs to be set for windows delegation. Is my guess correct?
Also,
Is my choice of dwLogonType = LOGON32_LOGON_NETWORK correct?
Can the token returned by LogOnUser (dwLogonType = LOGON32_LOGON_NETWORK) be used for making remote WCF calls?
The one who is impersonating should have delegation right if it wants to access network resources under user's identity. In the mentioned scenario client account (under which the client is running) should have delegation right since it is is impersonating some user and wants to propogate the user identity to a remote WCF Service.
Is my choice of dwLogonType = LOGON32_LOGON_NETWORK correct?
No.
Can the token returned by LogOnUser (dwLogonType = LOGON32_LOGON_NETWORK) be used for making remote WCF calls?
With dwLogonType = LOGON32_LOGON_NETWORK option, LogonUser returns a token that cannot be used for propogating user identity to network resources.
The option dwLogonType = LOGON32_LOGON_NETWORK_CLEARTEXT with LogonUser fixed the issue. With that option LogonUser generated a token that is capable of accessing network resources under user's identity.
I give complete credit to arx for my solution. It is only with his comment I could solve the problem.

Can WCF do WindowsAuthentication with username password?

I'm building an wcf service that is meant to run in an intranet environment using Windows Authentication. I have been merrily working along with some kind of default settings on the local computer.
Problem now is that I need to test it installed to an off site demo computer. I just need to get it running with username password used against the wcf service computer's user accounts.
This is my client code:
using (ImportServiceClient client = new ImportServiceClient("ImportServiceSoap12", REMOTE_ADDRESS))
{
client.ClientCredentials.Windows.AllowNtlm = true;
client.ClientCredentials.Windows.ClientCredential =
new NetworkCredential(userName, password, computerName);
result = client.Sync(items.ToArray());
}
Is it possible to configure the wcf service such that it translates the credential to a windows account on it's machine?
I've been reading contradicting posts here and there, but I feel rather sure IIS shouldn't be part of the authentication. I'm unsure wether ASP.Net authentication node applies or if it's all binding configuration.
Ideally I'd like it to be an NTLM type authentication so that I wouldn't need to set up https.
Is it possible to configure the wcf service such that it translates the credential to a windows account on its machine?
No. Integrated Windows Authentication requires that both the server and the client are part of the same domain (or domains with a trust relationship, in any case). You can't usefully run IWA against local computer accounts on the server.
You will have to use some other (potentially custom) form of authentication and then impersonate to the user you want to run as in the server code.

Restricted Remote WCF Service: Windows Authentication Prompt

I want to let remote administrators (with local or domain credentials) control my Windows service via a WCF TCP binding. To do this, I need to authenticate the remote user as an administrator. I can check the principal user/roles, but I don't know how to prompt the remote user for the correct user details/token.
This is related to my previous question on Restricting WCF TCP endpoint to Administrators. Instead of adding [PrincipalPermission(SecurityAction.Demand, Role = "Administrator")] to my restricted service method and catching a SecurityException, it seems I can check for it with:
if (!System.Threading.Thread.CurrentPrincipal.IsInRole("Administrators"))
return MethodResult.AccessDenied;
// haven't tested if it's the service thread or the remote user yet.
How do I prompt the remote user for Windows authentication if a Access Denied result was returned so I can reinitiate the connection as a different principal?
Of course, the change would need to be effected on the remote user's client application. Perhaps there is a cleaner WCF way to do it?
Edit: Searching for ".net impersonation" led me to this on CodeProject. Haven't had a chance to look, but this may be the way to go.
You need to pass in the user's credentials with your WCF call. Normally the client application just "captures" the currently running user's credentials. Alternatively you can specify a username and password explicitly. So you could prompt the user for an alternative set of credentials if you wish.
Either way, the client app needs to prompt the user. Your WCF call should return an error (code or exception) upon authorization failure and your client should capture that return and display a prompt to the user and retry with the new credentials. WCF by itself cannot handle prompting the user.
Here is an article on various means of passing credentials:
http://blogs.msdn.com/b/sonuarora/archive/2007/04/21/setting-client-credentials.aspx
Assuming this is hosted in IIS you need to turn off anonymouse authentication in the IIS Manager. This should force the user to login to the machine using a Windows account. You may also need to enable ASP.NET Impersonation.
Here is how you can prompt the user using the standard windows dialog using pInvoke How to show authentication dialog in C# .Net 3.5 SP1