Implementing a WCF SOAP Client that uses Basic Authentication at first request.
Friday, November 20, 2009 14:52If you have to consume a Web Service that requires Basic Authentication, the normal flow of things is that the first request the client makes is unauthenticated. The server then response with an HTTP 401 response (‘Authentication required’). The client then sends the credentials to the server and the SOAP request goes through.
That is the NORMAL way of things. But there are web services out there that require the credentials to bent sent at the first request. If you use Visual Studio to create a consumer, you will run into problems.
Many have tried to get around this issue by setting the PreAuthenticate property of the WebClientProtocol to ‘true’. This does NOT mean that the credentials are sent at the first request. It merely means that every request after the initial ‘handshake’ has completed will have the authentication header in place. Yet, the FIRST connection will still be tried without any credentials or authentication headers. Hence this does NOT solve the problem.
What you need to do, is, first, add the reference to the service as a Web Reference, not a Service Reference. After Visual Studio creates the proxy class, create another partial class of that proxy class that overrides the GetWebRequest(Uri uri) method.
From within that method, you can then take the HttpWebRequest object and manually add the authentication header.
Here’s an example;
1: public partial class api : System.Web.Services.Protocols.SoapHttpClientProtocol
2: {
3: protected override System.Net.WebRequest GetWebRequest(Uri uri)
4: {
5: HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
6: if (PreAuthenticate)
7: {
8: NetworkCredential networkCredentials = Credentials.GetCredential(uri, "Basic");
9: if (networkCredentials != null)
10: {
11: byte[] credentialBuffer = new UTF8Encoding().GetBytes(networkCredentials.UserName + ":" + networkCredentials.Password);
12: request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(credentialBuffer);
13: }
14: else
15: {
16: throw new ApplicationException("No network credentials");
17: }
18: }
19: return request;
20: }
21: }
Now this is in place, you will send the authentication header at the first request. Since this implementation is using the credentials from the WebClientProtocol, you will be required to set these in advance. But I guess you were doing that anyways. Furthermore, I chose to only do the pre-authentication if the PreAuthenticate property was set to true.
So if you want to consume this service, this is how you would initiate it;
1: api client = new api();
2: client.PreAuthenticate = true;
3: client.Credentials = new NetworkCredential("username", "password");
Good luck!
Leave a Reply
You must be logged in to post a comment.
