WCF RequestChannel; What Really Happens? - wcf

What really happens when a person calls the Open method of IRequestChannel? For example, if I have the following code:
ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>();
// using a netTcpBinding to a net.tcp://localhost:9999/Bar
IRequestChannel outchannel = factory.CreateChannel();
outchannel.Open(); // what happens here?
if (outchannel.State == CommunicationState.Opened)
{
success = true;
}
outchannel.Close();
I seem to get "false positives" on some services with accurate failures on others. I would assume I'd always get false positives if this didn't in some way verify that the channel was open.
Any suggestions on improvement? I'd like to avoid sending a message since this is just to test a service's viability for a diagnostic test but I can if that's necessary.
I noticed from our configuration file that the channels that return false positives are using the following behaviorConfiguration:
<binding name="secureNetTcpStream" maxBufferSize="2000000" maxReceivedMessageSize="2000000000" transferMode="Streamed" sendTimeout="00:05:00" receiveTimeout="14:00:00">
<readerQuotas maxStringContentLength="2000000000" maxArrayLength="2000000000" />
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
I wonder if the streamed behavior configuration is what leads to the IRequestChannel showing it is open even when the host and service are unavailable?

Calling the Open function will indeed contact the server side and will open the communication channel.
However, there might be situations when Open will succeed but calling one of the methods of the service will fail.
For example: If the client calls a service method that initiates a session and the server has reached its max sessions number then the function will fail with a server is busy exception. So you might fail creating a session even when you have an open channel.
There are other various failures that may be in a service even though the channel was opened successfully.
Summary:
your check is good but there might be other "obstacles" that will interfere the client-server communication. These are probably your false positives...

Related

Enable WCF replay detection cache with certificate based message security

I have a WCF service that has the following requirements:
Sent over SSL (HTTPS Transport)
Reliable Messaging On
WS-* message security using a X.509 certificate.
Replay Detection On
Here is the binding that I have:
<customBinding>
<binding name="replayDetectionBinding">
<reliableSession />
<security authenticationMode="SecureConversation">
<secureConversationBootstrap authenticationMode="CertificateOverTransport"
protectTokens="true">
<issuedTokenParameters keyType="AsymmetricKey" />
</secureConversationBootstrap>
<localServiceSettings maxClockSkew="00:01:00"
replayWindow="00:01:00" />
</security>
<textMessageEncoding />
<httpsTransport maxReceivedMessageSize="5242880" maxBufferSize="5242880" />
</binding>
</customBinding>
The service is hosted in IIS and I have a test client to make a request to the service. I have Fiddler up and running to catch all messages coming to and from the test client and the WCF service.
Everything is working, including the replay detection outside of the replay window. However, what I need is to have the replay detection use the nonce cache so that an identical message is rejected no matter what (as long as that message signature is in the nonce cache). This part is not happening.
I send a message using the test client, it is received by the WCF service and a response is returned, I do not close the connection. I then use Fiddler to reissue/replay the message that was sent. In this case, it is accepted by fiddler - even if I issue it from another machine.
I've done so much searching and have read just about everything I can find, but cannot get this to work.
Does anyone know how to enable the nonce cache in this case or do you have to code your own?

Looking for WCF Solution to Pass User Credentials in a Load Balanced Environment with Custom Binding

We currently support several WCF services running in a load balanced environment. In the past, we have used wsHttpBinding and set establishSecurityContext to false to allow the service to work properly with our load balancer.
An issue we have ran into is that the wsHttpBinding encrypts the return results by default and, apparently, cannot be turned off. This causes issues with the Riverbed compression appliance we have on our network - i.e. the encrypted data does not compress very well (or at all).
Now we're attempting to make use of the basicHttpBinding since it does not encrypt the data by default. We have two requirements:
Work with the load balancer - this appears to be possibly by using setting the keepAliveEnabled to false. This requires the use of a custom binding. For example:
<customBinding>
<binding name="NewBinding0">
<httpTransport authenticationScheme="Ntlm" **keepAliveEnabled="false"** />
</binding>
</customBinding>
Passes User Credentials - this appears to be possible by setting the security mode to TransportCredentialOnly. This is available with the basicHttpBinding. For example:
<basicHttpBinding>
<binding name="NewBinding1">
<security **mode="TransportCredentialOnly"** />
</binding>
</basicHttpBinding>
So now for my actual question :-)... How/Is it possible to combine the above two requirements into a single custom binding? What is the equivalent of #2 above for a custom binding? How can I get it to pass the user credentials?
Thanks!
It turns out I was able to do what I wanted with the custom binding using the following binding configuration:
<customBinding>
<binding name="NewBinding0">
<httpTransport authenticationScheme="Ntlm" keepAliveEnabled="false" />
</binding>
</customBinding>
Then, on the client side, I could use the following code to get the identity of the application pool the WCF service was running under (in IIS) as well as the identity of the user who actually called the WCF service:
public string GetData(int value)
{
var callingUser = string.Empty;
var appPoolUser = WindowsIdentity.GetCurrent().Name;
var identities =
OperationContext.Current.ServiceSecurityContext.AuthorizationContext.Properties["Identities"] as
IList<IIdentity>;
if (identities != null)
{
var result = from i in identities
where i.AuthenticationType == "NTLM"
select new { i.Name };
if (result.Count() > 0)
{
callingUser = result.First().Name;
}
}
return string.Format("Value Entered: {0}; AppPool User: {1}; Calling User: {2}", value,
appPoolUser, callingUser);
}
I tested the above code in a load balanced environment, for Requirement #1, and everything seemed to run just fine. The tests simulated a 100-user load for 10 minutes in a load balanced environment. We took one of the load balanced servers down during the test and everything continued to run as expected (i.e. no exceptions were thrown during the tests nor did any identities come back incorrectly).
The code above is the key piece, for Requirement #2, that I was missing - i.e. I didn't realize until this research that WCF would give you multiple identities.
Also, using this configuration, the results of the WCF call is not encrypted (which is what we wanted). So, I think this configuration will work for our situation just fine.

Certificate Information from WCF Service using Transport security mode

Is there any way to pull information about which client certificate was used inside of my web service method when using <security mode="Transport>? I sifted through OperationContext.Current but couldn't find anything obvious.
My server configuration is as follows:
<basicHttpBinding>
<binding name="SecuredBasicBindingCert">
<security mode="Transport">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
I'm working with a third party pub/sub system who is unfortunately using DataPower for authentication. It seems like if I'm using WCF with this configuration, then I'm unable to glean any information about the caller (since no credentials are actually sent).
I somehow need to be able to figure out whose making calls to my service without changing my configuration or asking them to change their payload.
Yes, but it's unintuitive.
First, be sure and reference the System.IdentityModel assembly from your service library.
Now, add something similar the following to your service method where you would like to know about the client certificate:
// Find the certificate ClaimSet associated with the client
foreach (ClaimSet claimSet in OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets)
{
X509CertificateClaimSet certificateClaimSet = claimSet as X509CertificateClaimSet;
if (certificateClaimSet != null)
{
// We found the ClaimSet, now extract the certificate
X509Certificate2 certificate = certificateClaimSet.X509Certificate;
// Do something interesting with information contained in the certificate
Debug.Print("Certificate Subject: " + certificate.Subject);
}
}
Hope this helps!

Can IIS-hosted WCF service be configured for BOTH Windows Auth and Anonymous?

I've got a small WCF webservice working with the built-in WCF Service Host and with hosting by the Visual Studio 2008 built-in development webserver.
I these hosting enviroments I have relied on the WCF Test Client for invoking the service methods.
Now I am running into problems with my next phase of testing:
I have it hosted in IIS 5.1 on my WinXP dev machine and I think maybe the problem is I cannot continue to use WCF Test Client anymore. Here is what's happening:
Case 1: "Anonymous Access" is CHECKED (ENABLED)
WCF Test Client UI comes up properly, exposing the WebMethods and the INVOKE button.
Yet when I click INVOKE it fails to connect with a backend data store (a 3rd party product) that requires Windows authentication. I could post the error I get back from the product.DLL but I don't think it is relevant.
Case 2: "Anonymous Access" is un-CHECKED (DISABLED)
WCF Test Client UI fails to even initialize properly. My researching of this tells me that MEX (WS-Metadata Exchange) requires "Anonymous Access" and (apparently) WCF Test Client requires MEX. Here are key snippets of the error being returned:
Error: Cannot obtain Metadata from http://localhost/wcfiishost
The remote server returned an error: (401) Unauthorized.HTTP GET Error
URI: http://localhost/wcfiishost
There was an error downloading 'http://localhost/wcfiishost'.
The request failed with the error message:
Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service
The are lots of explanations of binding options, message security, etc. and stuff I honestly do not understand. Here is my take on where I am but I would love your opinions:
(a) Because I know my WCF webservice MUST be configured to use Windows Authentication, I conclude I cannot continue to use the WCF Test Client when hosting my service in IIS. That it has effectively outlived it's usefulness to me. I will just have to take the time to write a web client because WCFTestClient won't work without Anonymous.
(or)
(b) It is possible to use WCF Test Client if it and the hosted service are configured propertly (I just don't know what the special configuration techniques are for this).
Which is correct? Time to stop using WCFTestClient or is there a way to have it both ways? Thanks in advance for your advice.
EDIT: 11 June 09
Is there anything else I can provide to help someone else help me on this question?
I just tried to have the same setup - but in my case, everything seems to work just fine.
ASP.NET web site
WCF service, using basicHttpBinding without any special settings at all
IIS Application with anonymous = enabled and Windows authentication = enabled (both turned on)
I can easily connect to it with the WcfTestClient and retrieve the metadata, and I can then call it, no problem.
Inside my service function, I check to see whether the current user is a known user or not, it is correctly identified as a Windows authenticated user:
ServiceSecurityContext ssc = ServiceSecurityContext.Current;
if (ssc.IsAnonymous)
{
return "anonymous user";
}
else
{
if(ssc.WindowsIdentity != null)
{
return ssc.WindowsIdentity.Name;
}
if (ssc.PrimaryIdentity != null)
{
return ssc.PrimaryIdentity.Name;
}
}
return "(no known user)";
I don't really know, what more to check for (except I'm on Vista with IIS7). Any chance you could include this code to check for the user in your service code? Just to see....
Marc
Marc, your setup is not even close to Johns.
John uses WSHttpBinding that uses Windows Credentials for Message mode transport. The Windows Authentication isn't being used with BasicHttpBinding. Furthermore, John had AnonymousAuthentication disabled, which is why the Metadata Exchange (mex) is failing.
The call won't even reach inside the service side function, because we get a Error 401 (Unauthorized) when we try to call.
Just know John, I have the same issue, and I'm trying to somehow set up separate bindings per endpoint. Hopefully that will work.
When I set the title/subject of this question and reached a dead end here, I opened up the same issue in the MSDN forum with a different emphasis on the title (content of question essentially the same).
For me, the real issue was how to use WCFTestClient in IIS without Anonymous Authentication being set (because my service needed Integrated Windows Authentication only).
Mex apparently requires Anonymous and by default WCFTestClient seems to need Mex. The key seems to be accomodating both my doctoring up the web.config file carefully.
Anyway, I got it working with this web.config below (the MSDN link is here:
<?xml version="1.0"?>
<configuration>
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="wsBindingConfig"
contract="sdkTrimFileServiceWCF.IFileService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="basic"
binding="basicHttpBinding"
bindingConfiguration="bindingConfig"
contract="sdkTrimFileServiceWCF.IFileService" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="bindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
<wsHttpBinding>
<binding name="wsBindingConfig">
<security mode="Transport">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</serviceBehaviors>
</behaviors>

WCF: The request for security token could not be satisfied because authentication failed

I have written a very simple WCF Service that sends and receives messages. I have tested the app through the VS 2008 default web server host and everything works fine. But when I deploy the WCF service to another computer's IIS I receive the following error:
"The request for security token could not be satisfied because authentication failed."
How can I set the authentication type to use my custom username and password in config file?
If it is not possible, please tell me how I can set its windows credentials because the 2 computers that I'm using, don't share the same users.
You need to turn off security for the binding. Otherwise, I believe that, by default, the wsHttpBinding will try to negotiate a Security Context Token (SCT).
So, modify the endpoint definition to point to a binding configuration section. Here's an example:
<endpoint address=""
binding="wsHttpBinding"
contract="HelloWorldService.IService1"
bindingConfiguration="TheBindingConfig">
And then add something like the following binding configuration right after the <services> section in the web.config's <system.serviceModel> section.
<bindings>
<wsHttpBinding>
<binding name="TheBindingConfig">
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
Setting security to "None" is the key.
Hope this helped!
The above helped me - but what is not immediately obvious is how to add to the service end (its clear once you've done it what's needed, but not until you've done so). The reason its not entirely obvious is because there isn't a bindings section by default whereas there is liable to be one in the client.
So, just to be very clear - at the service end, add the bindings section (as detailed above) and then to the appropriate endpoint add the bindingConfiguration="TheBindingConfig" attribute. Obvious once you've done it once...
You don't actually need to turn off security and in some cases you shouldn't. Within a bindingConfiguration, you can specify message level security that does not establish a security context as follows:
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="false" />
</security>
Note the establishSecurityContext attribute. Both the client and service should have a security configuration with establishSecurityContext set to the same value. A value of true also works fine but false is recommended in an environment where the servers are load balanced.
Be sure to set this bindingConfiguration (specifying security mode 'none') on both client and server or else you will get this message - which is quite a red herring as far as debugging the problem.
The message could not be processed.
This is most likely because the action
'http://tempuri.org/IInterfaceName/OperationName'
is incorrect or because the message
contains an invalid or expired
security context token or because
there is a mismatch between bindings.
The security context token would be
invalid if the service aborted the
channel due to inactivity. To prevent
the service from aborting idle
sessions prematurely increase the
Receive timeout on the service
endpoint's binding.
If you are in debug mode then set the debug attribute as
<serviceDebug includeExceptionDetailInFaults="true"/>
by default it sets as false ..so while you go for debugging it throws that exception .
hope it helps .