WCF Service Accounts - vb.net

I have a WCF self-hosted as a Windows Service.
When I start the service (under the NETWORK_SERVICE account), I can consume the service from my ASP.NET application on a different server.
However, the business rules have changed. Now I need to run the service under my own account. I am able to stop the service, and start it again under my account. No problem there.
Until I try to consume the service from my ASP.NET application on the other service. I get:
A call to SSPI failed, see inner exception
I'm relatively certain there's something I need to do security wise to eliminate this error, being new to all this I just don't know what.
Any help is greatly appreciated.
Thanks,
Jason

Usually this is a sign of a missing or misconfigured SPN, which gets in the way when you're using windows authentication (at the transport or message level) and Kerberos is being negotiated.
Notice that how/when the error manifests itself might depend on the way the hostname (or IP address) of the service host is used in the URL used by the client, since WCF will try, by default, to deduce the right SPN to use based on the URL information, unless you explicitly override it by setting the endpoint identity.
So likely all you need to do is register an SPN (using setspn.exe) for your new service and make sure your client uses an appropriate identity.
There's some more extra information on how WCF uses service identities here, here and here.

Related

WCF Client default SPN generation

How does WCF client generates target Service's SPN dynamically to get the kerberos ticket in Spnego Use case?
For example, if the target service is running under domain machine account, SPN associated with the Service would be in the form 'host/machinename'.
If we try to call the service using wcf client, wcf client is able to get the ticket for host/machinename. I initially thought that wcf client might be using hardcoded string host/+domainname by default.
But If I change the target service to run under domain user and associate SPN named "http/machinename" with the domain user, wcf client is still able to generate the ticket for this service successfully.
How does WCF client decides whether to use prefix 'host/' or 'http/' in these scenarios.
I know that there is a way to add custom spn on the client side under endpoint element but I'm interested to know how it works by default.
The default is host/myhostname for Windows credential type. This is also the expected SPN while running the WCF service with a machine account.
Note that the WSDL will include the Identity (e.g. SPN), so the WCF client can use that information while connecting. Check the WCF Test Client Config file to see what is actually generated.

Using WCF's net.pipe in a website with impersonate=true

I'm trying to use WCF named pipes in a web site, and it's failing with errors:
There was no endpoint listening at net.pipe://localhost/mypipename
that could accept the message. This is often caused by an incorrect
address or SOAP action. See InnerException, if present, for more
details.
and the InnerException:
The pipe name could not be obtained for net.pipe://localhost/mypipename.
and there is another inner exception giving an access denied message.
My web site is using impersonation, and looking around the internet, this seems to be relevant, but I don't know how to fix it.
Does anyone have any ideas?
Thanks
Matt
The standard WCF NetNamedPipesBinding creates a randomly-generated pipe name when the service starts up, and also a kernel shared memory object which the WCF client-side channel stack has to consult to find out the name of the pipe.
Using impersonation on your web site means that the security context from which your WCF service is being invoked has a logon token (the impersonation token) which includes membership of the NETWORK USERS group.
When the service listener starts up, the WCF binding creates an Access Control List (ACL) on both the named pipe itself, and on the shared memory object where the pipe name is published. Both of these ACLs deny access to the NETWORK USERS group. Thus your web site, impersonating the remote user, is denied access to the shared memory object before it can even discover the pipe name. Even if it found out the pipe name some other way, it would still be denied access to the pipe.
Everything works when you remove impersonation, because now the service is being invoked in the security context of the web application worker process, whose logon token does not have membership of the NETWORK USERS group - it is a local logon.
More details at http://blogs.charteris.com/blogs/chrisdi if you're interested. I show how the ACLs can be adjusted, and in principle this approach could be used to grant access to remote users, but I don't recommend this.
If you're getting this particular exception, it typically means that your service is not running. I see that you use localhost in the URL. I just want to make sure that the host and the service are running on the same machine. WCF does not allow communication across machines with this binding.
When I get this message, usually I check and see that I forgot to start the service, thus, there is no endpoint listening. Please check that your service is actually still running and hasn't crashed at the time that the exception is thrown. If that doesn't fix the problem, please post your progress and I can make more suggestions.
I worked around the problem by making the IIS endpoint where I ended up calling the net pipe from available to anonymous users, which meant no impersonation.

Identity of thread in self hosted WCF service when called from Web Application

I have a Windows Service that is self hosting a Wcf service, this Wcf service has a tcpBinding with default settings. The Windows service is running as LocalSystem.
The Wcf Service is referenced (default settings) by a Web application that is running in IIS 7.5 integrated pipeline within it's own application pool with its own identity.
Both are running on the same machine.
All is working fine, except that when in the Wcf Service when I check the identity of the current thread with:
Thread.CurrentPrincipal.Identity.Name
It returns the user of the Application Pool of the Web Application.. this is not what I expect. It looks like some sort of impersonation is going on in the Wcf service.
Is this standard behavior? I can't find any documentation on this.
And does it mean that when I try to access a database in the Wcf service i'm introducing a identity hop?
Edit, the config on service side:
Type serviceType = typeof(WcfService);
host = new ServiceHost(serviceType);
Binding tcpBinding = new NetTcpBinding( );
Uri tcpBaseAddress = new Uri("net.tcp://localhost:8001/Test");
host.AddServiceEndpoint(typeof (WcfService), tcpBinding, tcpBaseAddress);
host.Open();
On the client side:
NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.Transport);
windowsService = new WindowsService.WcfServiceClient(tcpBinding, new EndpointAddress("net.tcp://localhost:8001/Test"));
I'm reading from Learning WCF by Michele Bustamante. I have used WCF for an application that I've refactored and we're interested in using WCF in new applications for the flexibility it offers. One of the downsides of WCF is that it can be tricky to use the .net attributes or .config files to get the settings just right. I have spent days tracking down issues with the WCF settings. I've even created automated tests that will check that my service runs the way it's supposed to.
In response to your question, Michele says very specifically in Chapter Seven that NetTcpBinding is secure by default, meaning that callers must provide Windows credentials for authentication. I believe that would explain why the thread appears to be running as the identity of the web service. This is to protect your service from being called by an unauthorized user.
I believe that the following quotation from pp. 419-420 will answer your question concisely. "If you are familiar with traditional .NET role-based security, you know that there is a security principal attached to each executing thread. That security principal holds the caller's identity, which may be tied to a Windows account or a custom database credential, and its roles."
That seems to state plainly that yes, this is standard behavior.
I believe that you can change the behavior through attributes and .config files. I recommend you get a good book on the subject. I spun my wheels in the sand a long time trying to get bits and pieces of information about WCF from the web.
To clearify:
I was checking the wrong property here. Because code would be executed under the WindowsIdentity.GetCurrent() identity.
By default this is NOT the same as the caller (which is in Thread.CurrentPrincipal.Identity). If you want this behaviour you can control this with:
host.Authorization.ImpersonateCallerForAllOperations = true;
and
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
We actually have integrated security set at the website, and then any calls from the website to the WCF service we wrap in:
using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
{
That makes sure the credentials of the logged in user are passed through, rather than the IIS app pool credentials.
Works like magic!
More information is needed, but I'm guessing that it's somewhere in the configuration for the binding on either the server side or the client side that impersonation is enabled. When adding service references, svcutil.exe is VERY aggressive in setting EVERY possible binding property in configuration.
If you could provide more information for the configuration on the server and client side, it would be appreciated.

What are my binding options for a self hosted cross domain WCF service with remote thick clients?

I'm trying to build a WCF self hosted service (eventually in a windows service) that will receive binary and text base messages from remote thick clients that have no accounts on my hosted machine. I'm trying to figure out both my binding options and security options, and in reading the patterns and practices guides, my head has completely spun around at least once.
The clients would be authenticated against a custom SQL based method, so I'd like to be able to pass that info in the initial login request and then set an authorization token of some kind. (This part of the problem is probably outside the scope of the question, but I included it in case it might make a difference.)
Any thoughts at all would be very helpfull.
Ryan
The choice of binding and security option depends on the usage of your WCF service. Is it just for your rich client or are you planning to expose it to the world as API? If it's just for your rich app, does it run on LAN or over untrusted, unreliable Internet?
With WCF you can configure the service to expose multiple endpoints with different bindings, for example both SOAP and REST. In general, I'd start with something stateless and lightweight like basicHttpBinding and webHttpBinding, passing user and password on every request. Once you have that up and running you can optimize cache authentication, provide binary endpoint etc.. only if it actually helps.
There's no need to have just one binding. Having said that if it's self hosted you're "on your own" here. I've never looked at what's involved.

Reading a caller's IP address in WCF (OperationContext is null)?

I am validating users using the UserNamePasswordValidator.Validate(string username, string password) and the service is hosting itself (e.g. no IIS).
The problem I have is that if the user fails the validation I want to track the users IP address. This works fine of the user gets validated, because then the OperationContext has been initialized (it is null inside the validate method and not created until later).
Does anyone know how to get the clients IP address either in the validate method or before the validate method has been executed?
Yes, I know about how to get the IP address using RemoteEndpointMessageProperty but like I said, it never get that far if validation fails :-)
I've researched this to death all week, and I can't come up with a single blog entry or MSDN article that deals with the issue.
As far as I can tell, you cannot log IP address during the Validate stage.
The only workaround I can suggest is to host in IIS and use the weblogs there, which do log IP address. It's painful, unfortunately, but it may be the only way.
If you're hosting in IIS then this becomes much more simple. This chunk of config comes straight from my hosting web project and forces ASP.NET requests to come down the IIS pipeline rather than being dispatched straight to the ASP err bits of IIS.
aspNetCompatibilityEnabled: When this attribute is set to
true, requests to Windows Communication Foundation (WCF) services
flow through the ASP.NET HTTP pipeline, and communication over
non-HTTP protocols is prohibited.
See: http://msdn.microsoft.com/en-us/library/ms731336.aspx
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
I use the AuthenticationService and make use of the HttpContext to get at all the interesting stuff about the client, much of it is useful for things like ensuring a user isn't logging in from six different subnets as well as playing around with cookies.
Although I think this is applied to the MS AuthenticationService, any other services you have will need this attrib:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
If you want to pursue your non-IIS hosted service route, then I'd see what stuff is available inside the MS API using reflection, poking around on a WCF with the debugger while stopped, unfolding all those Non-public members.
I suppose the problem will be getting a reference to a bit of WCF which is initialized from which to start poking. You might have to register some kind of listener to one of the dispatchers when you setup the service host.
http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.channeldispatcher.aspx
Edit:
Adding this link as my thoughts are that you'd need to get at stuff in WCF that's right down the stack before it gets to your code:
http://blogs.msdn.com/sonuarora/archive/2007/06/11/passing-soap-actions-to-adapter-inbound-handler-for-filtering-type-of-listeners.aspx