Problems connecting to an authenticated downstream netTcp endpoint - wcf

In a related post, I am having trouble connecting to a basicHttp endpoint and it seems that it is due to WCF impersonation issues when connecting to a downstream service. The funny thing is that it works fine when I replace the basicHttp WCF service with an ASMX web service. Both services use <identity impersonate="true" userName=".." password=".." /> from ASP.NET web.config file, but the ASMX service works while the basicHttp WCF service doesn't.
Does this seem likely to be some sort if Kerberos delegation issue between ASP.NET and WCF?
Or is there something that I can add to my WCF configuration to pass this impersonated user (note I am using framework 4, so I currently have almost no configurtation)?

Finally worked out that I needed to add <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> to the WCF part of the web.config file, and an AspNetCompatibilityRequirementsMode attribute to the implementation of the basicHttp endpoint. This will then call the downstream netTcp endpoint using the credentials defined in <identity impersonate="true" userName=".." password=".." />.

Related

WCF Double Hop Localhost Losing Impersonation on Second Hop

I've seen a lot of posts about the WCF double-hop issue with impersonation, but none of them have specifically helped me resolve my problem.
What am I missing? What else do I need to do in order to retain my Impersonated User (DOMAIN\UserName) over on Service 2? I'm looking at ServiceSecurityContext.Current.WindowsIdentity.Name to confirm - maybe that's wrong.
The Setup:
Client App hosted in localhost IIS with Service Reference to Service 1 - Impersonating WindowsIdentity (DOMAIN\UserName)
Service 1 - WCF Service hosted in localhost IIS with Service Reference to Service 2
Service 2 - WCF Service hosted in localhost IIS
I'm using ALL basicHttpBindings to keep things simple. I've set up SPNs on both service endpoints.
I can successfully MAKE the double-hop and the code executes just fine
In Service 1 (hop 1) my ServiceSecurityContext.Current.WindowsIdentity is the person that I impersonated (DOMAIN\UserName)
In Service 2 (hop 2), my ServiceSecurityContext.Current.WindowsIdentity is the IIS App Pool user
ImpersonationLevel = "Delegation"
Both WCF Services have Windows Authentication Enabled and Anonymous Disabled
** Note: I'm running this all locally on my dev box. Even so, I've had my delegation level set to allow delegation from myself to myself. Maybe overkill.
Binding (similar for both services):
<binding name="...">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
I've set the impersonationLevel = "Delegation" on both the WCF service client and the service endpoint behavior configuration. My service methods are specifically decorated with impersonationOption="Allowed" (hop 1) and impersonationOption"Required" (hop 2).
As it turns out, the critical piece in my case was ensuring the following behavior attribute was set:
<serviceAuthorization impersonateCallerForAllOperations="true" />
Previously, when I set this value, I was receiving errors in Entity Framework, so I undid the setting. It appears that somewhere along the line of aligning my setup to the standard implementation (as described in other varios posts) that I was able to eventually set this attribute and have it work as expected.
Edit:
If this all works locally, but doesn't work in a distributed environment, check out this post: How can I fix the Kerberos double-hop issue?. You probably need to set the machines to trust delegation between each other.

Are requests to a WCF service hosted by WAS authenticated by IIS processing pipeline or ...?

Following questions assume we're hosting in WAS a WCF service side by side with Asp.Net:
"When hosting WCF side by side with Asp.Net - The WCF hosting
infrastructure intercepts WCF requests when the
PostAuthenticateRequest event is raised and does not return processing
to the ASP.NET HTTP pipeline. Modules that are coded to intercept
requests at later stages of the pipeline do not intercept WCF
requests."
"With side-by-side configuration, the WCF hosting infrastructure
intercepts WCF messages and routes them out of the HTTP pipeline"
a) Assuming WAS receives a request for a WCF service, will WCF's authentication mechanism ( Windows, MembershipProvider or Custom authentication ) be invoked when PostAuthenticateRequest event is raised, or will WCF authenticate a request only after it routes the request out of the HTTP pipeline? In other words, is WCF's authentication mechanism working outside of IIS's processing pipeline?
b) If WCF's authentication mechanism is working outside the IIS processing pipeline, then I assume FormsAuthenticationModule isn't involved with authenticating the WCF client ( assuming service is using forms authentication )?
c) Also, if WCF's authentication mechanism is working outside the IIS processing pipeline, then I assume IIS/WAS must be configured for anonymous authentication, even if service is authenticationg clients using windows authentication?
d) Would answers to my above question be any different if WCF service was hosted by IIS7 ( besides the fact that service must only use endpoints that communicate over HTTP protocol )?
Thank you
I would recommend implementing a technical spike project.
At the core you can always implement a codeaccessattribute to secure your operationcontracts.
You can start by applying PrincipalPermission (built in) where you set IPrincipal on Thread.CurrentPrincipal (constructor of your wcf service)
when hosted in IIS you can set HttpContext.Current.User however HttpContext will be null in your case. To use PrincipalPermission you will need to have your own ability to create/implement IPrincipal.
I can only answer part D and part of B, but this may be enough to address the problem you are trying to solve: if you host the WCF service inside an ASP.Net application, then Forms Authentication is supported IF you enable ASP.Net compatibility in the WCF service. We use this method extensively with our Silverlight applets.
This is a two-step process:
1) Decorate your WCF service implementing class with the AspNetCompatibilityRequirements attribute (vb.net code below):
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
2) Add the following entry to your <system.servicemodel> section in web.config:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

How to access HttpContext.Current.User.Username in WCF service

How can I access HttpContext.Current.User.Username from a web application in a WCF service?
Generally you don't - HttpContext is an ASP.NET concept and doesn't apply to WCF unless you run it with ASP.NET Compatibility turned on.
If you want the current user in WCF then use ServiceSecurityContext.Current.PrimaryIdentity or get the security context via the OperationContext.
Actually, with Asp.Net Compatibility mode on, you can access HttpContext.Current.User from a WCF service hosted in the site. See Microsoft's site for details: https://msdn.microsoft.com/en-us/library/aa702682(v=vs.110).aspx
If your service is hosted in an Asp.net site you just need to update your web.config to set aspNetCompatibilityEnabled="true" on the serviceHostingEnvironment element:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>

Problems connecting to a basicHttpBinding endpoint with security mode="None"

Trying to create an framework 4.0 WCF basicHttp service hosted by IIS (6) that is completely unauthenticated. Once deployed, I can successfully retrive the WSDL via a browser.
However whenever I try and connect to it via WCF Test Client or via a visual studio generated proxy, I'm getting "The server has rejected the client credentials.".
This still occurs when I add <security mode="None"/>, but my understanding is that this is the default anyway ...
In the IIS virtual directory properties I only have anonymous ticked, and in the web.config file <authentication mode="None"/> is set as well.
Any ideas?
Seems like the IIS site has anonymous authentication disabled. Check out this article on IIS 6 anonymous access configuration.
Turns out that the source of the exception was from an immediate attempt to connect to a downstream tcp service. As a workaround I ended up creating a plain jane webservice wrapper which successfully connects to the downstream service fine using a domain account specified in the <identity impersonate="true" userName=".." password=".." />.
Note, I've added a related question asking why one works and the other doesn't.

404 BadRequest exposing WCF service through external IP using IIS host headers

We host a WCF webservice on Windows Server 2003. This server only has 2 internal IP's. We want to expose the service externally. This is done through the firewall that maps an external IP to the service.
So, I would need to modify the service to display that external IP for the internal links. This is not an issue since it should only be used externally.
Changing the Host Header value in IIS gives a 'Bad Request (Invalid Hostname)' response from IIS. I also added an 'address' value to the endpoint entry in the web.config ... but it sill just points to the internal machine name. Any ideas?
edit: I can verify that IIS7 has the exact same behaviour. Address didn't work. Different hostname gave Invalid Hostname error. Is there seriously no way to present a different (fictive) IP? :/
edit2:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicAnonymous">
<security mode="None"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Extended">
<serviceMetadata httpGetEnabled="true"/>
<dataContractSerializer maxItemsInObjectGraph="2147483646"/>
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="false" logMessagesAtServiceLevel="false" logMessagesAtTransportLevel="true" maxMessagesToLog="3000"/>
</diagnostics>
<services>
<service behaviorConfiguration="Extended" name="AnCWCFWebService.ProductInfoProvider">
<endpoint address="" binding="basicHttpBinding" name="ASMX" bindingConfiguration="BasicAnonymous" contract="AnCWCFWebService.Interfaces.IProductInfoProvider"/>
</service>
</services>
</system.serviceModel>
404 BadRequest Due to IIS Configuration...
If you are receiving a 404 BadRequest error from IIS after attempting to modify host headers in IIS, this is common, but there is a fix!
Fix By Making IIS Configuration Changes
How can WCF support multiple IIS Binding specified per site?
Fix By Making WCF Code Modifications
Alternatively, the following article explains how one developer solved this issue with a combination of configuration and code:
Well, that was fun! An adventure in WCF, SSL, and Host Headers
http://geekswithblogs.net/rakker/archive/2008/07/03/123562.aspx
The article references two important links...
The first one explains how to properly set the host headers in IIS:
Configuring Server Bindings for SSL Host Headers (IIS 6.0): http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/8d9f2a8f-cd23-448c-b2c7-f4e87b9e2d2c.mspx?mfr=true
After getting host headers working, you'll find that...
"you can't have more than one host
header for IIS or wcf will break"
The solution to working around this limitation is found within this article, and there is also a comment on the GeeksWithBlogs.net article above that provides an enhanced variation:
WCF: This collection already contains
an address with scheme http
If you are still experiencing trouble, let us know in the comments below...
If the Service is Not Working...
My experience with WCF is that it is very tricky at times, especially with configuration. If one is following best practices and not doing anything non-standard, the great majority of deployment problems are the result of a botched configuration file.
In theory (not so much in practice, due to architectural differences), setting up a WCF service on IIS should be no different than setting up a typical virtual directory and corresponding application for web application or for an ASMX web service.
Therefore, I recommend that if this is the first WCF service you are exposing to the Internet, follow the same simple approach you would take when exposing your first website. Basically, create a new sample "WCF Service Application" (this is available in the Add New Project dialog, under the Web section of C# or VB).
Once you have it working, follow your deployment practices to move it into a production sandbox and test it locally. This sandbox would preferably already have some web sites or web services installed and known to be accessible from the Internet, in order to eliminate any doubt about the typical network configuration issues. If you have a sample ASMX web service that is already successfully exposed on the Internet from that server, that would be best.
Next, try testing the the ASMX and the WCF services from web browser, both locally on the server, internally on other desktops and then finally externally.
Testing URLs
We want to test accessing the standard SVC and ASMX file from the web browser in all the varieties of URL flavors that are available and relevant. The results should be similar, with summary page about he service rendering in the window. The difference will be that the ASMX web service's summary will likely allow you to execute the web methods on the service if that feature has not been disabled in the web.config file.
Compare the results of browser fetches of the following styles of URLs...
http://localhost/WcfService1/Service1.svc
http://localhost/WcfService1/Service1.asmx
http://MachineName or MachineFQN/WcfService1/Service1.svc
http://MachineName or MachineFQN/WcfService1/Service1.asmx
http://MachineLocalIP#1/WcfService1/Service1.svc
http://MachineLocalIP#1/WcfService1/Service1.asmx
http://MachineLocalIP#2/WcfService1/Service1.svc
http://MachineLocalIP#2/WcfService1/Service1.asmx
http://ExternalIP/WcfService1/Service1.svc
http://ExternalIP/WcfService1/Service1.asmx
All of these tests should return similar results.
Testing Service Methods
If you feel like it, go head and test some web methods on the ASMX web service for any of the tested URLs, from the web browser. You'll soon see that we can test ASMX web services a different way also...
Next we'll test web methods on both the WCF service and the ASMX web service by using the WcfTestClient.exe application that is found in the Visual Studio 2008 distribution (C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE).
You will need to add the services through the File->Add Service menu item, typing in the URL above for each service URL that you wish to test. Make sure to include the filename of the SVC and ASMX files. If all is well, the MEX endpoint that is enabled by the "httpGetEnabled" attribute of the <serviceMetadata/> element in the web.config file will return the data that is necessary for the utility to operate, thereby populating the tree with the inventory of our service methods like this:
From this point, it will be useful to refer to the following to resources:
WCFTestClient: http://msdn.microsoft.com/en-us/library/bb552364.aspx
What's New for WCF in Visual Studio 2008: http://msdn.microsoft.com/en-us/magazine/cc163289.aspx
Conclusion
If you make it this far, then I do not expect any other issues and you should now attempt to compare the setup of the samples to the WCF service that you are attempting to publish to the Internet, and hopefully the differences will be obvious.
Remember to treat the WCF service like an ASMX web service during you diagnostics, assuming that the web.config is known to be set up correctly.
If you are still unable to make things work, check this guide for further technical advice:
Deploying an IIS-hosted WCF service: http://msdn.microsoft.com/en-us/library/aa751792.aspx
Finally, if all else fails, just wrap your WCF service in an ASMX web service:
How to: Expose WCF service also as ASMX web-service: http://kjellsj.blogspot.com/2006/12/how-to-expose-wcf-service-also-as-asmx.html
You just need to configure your host header in the IIS so that the links in the WSDL references will use the donmain name rather local machine name.
Check out
Steps to configure IIS host header so that WCF will use domain name in WSDL references.
Why not just assign a new IP address to the server instead of messing around with hostnames? A Windows Server can have multiple IP addresses for the same NIC.
Here is an article that talks about it.