I have written a very simple WFCSerice that returns the Windows username supplied. Here is the client side code:
public Form1()
{
ServiceReference1.Service1Client s1 = new ServiceReference1.Service1Client();
s1.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
string str = s1.ReturnWindowsUsername();
InitializeComponent();
}
I can see the credentials in the HTTP Header using Fidddler:
I have tried to do the same thing with Basic Authentication (accessing another web service that supports Basic Authentication). Here is the client side code:
public Form1()
{
InitializeComponent();
ServiceReference1.Service1Client s1 = new ServiceReference1.Service1Client();
s1.ClientCredentials.UserName.UserName = "testuser";
s1.ClientCredentials.UserName.Password = "testpassword";
string str = s1.GetData(1);
}
Here is the screenshot from Fiddler when using Basic Authentication:
Why is there nothing in the header when using Basic Authentication. The Basic Authentication service seems to work as expected. Here is the response (interestingly there appear to be two requests and two responses):
Basic authentication works on the HTTP
level. The general flow is that the client requests a resource, then the server issues a challenge, then the client issues a new request with an Authorization
header included. If the username and password in the Authorization
header are accepted by the server, the client will usually then add the header for subsequent request without going through the request - challenge - re-request-with-authorization
steps again.
If you have everything setup correctly, you should expect to see two requests in Fiddler.
Authorization
header included. The response from the server for this request will be a 401
with a WWW-Authenticate: Basic realm="your realm"
header attached. Authorization
header has been sent from the client.Here is a sample from my environment:
If you don't see the 401
challenge from the server, then basic authentication is not correctly set up.
In order for the service proxy to supply the header, you need to configure your client binding to use <transport clientCredentialType="Basic"/>
. Or that's what I did, who knows with WCF with it's myriad of configuration options.
EDIT: I used this on the service side:
<bindings>
<basicHttpBinding>
<binding name="httpTransportCredentialOnlyBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
On the client:
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:53156/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="WcfTest_CBT.IService1"
name="BasicHttpBinding_IService1" />
</client>
I use basicHttpBinding
, TransportCredentialOnly
and Basic
in order to test this easily without SSL hassle etc.