WCF Authenticate Preemptively

Normally when you send a request to a service that uses basic authenication, you will initially send a service request without authorization header. The service will respond with a Http 500 error and will send the client an authentication request. This all happens automatically. The client will send the service request again. This time an authorization header goes with the request. When all things are well, the service responds with a Http 200 Success message.
Below you find the WCF code you will normally use:

string ditnopUrl = “http://dspimportservice.nl/”;
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = “Opdracht_OS_XOPBinding”;
binding.MaxReceivedMessageSize = 2147483647;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

EndpointAddress address = new EndpointAddress(ditnopUrl);
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = “user”;
loginCredentials.UserName.Password = “password”;

factory = new ChannelFactory(binding, address);
var defaultCredentials = factory.Endpoint.Behaviors.Find();
factory.Endpoint.Behaviors.Remove(defaultCredentials); //remove default ones
factory.Endpoint.Behaviors.Add(loginCredentials); //add required ones
channel = factory.CreateChannel();

channel.Open();
Opdracht_OS_XOPRequest request = new Opdracht_OS_XOPRequest();
request.Opdrachtbericht = opdrachtbericht;
Opdracht_OS_XOPResponse responseDSP = channel.Opdracht_OS_XOP(request);

channel.Close();
factory.Close();

Maybe you expect you don’t have to use the code that adds the client credentials to the service behavior, but when you remove that code you will receive an error “The username is not provided. Specify username in ClientCredentials”.

Now suppose you use the same service with basic authentication, but this time you specify ‘authenticate preemptively’. This can happen if you build a non-WCF service that you host on let’s say Tomcat. In this case the service expects an authorization header on the initial request. An authentication request will not be sent. The service simply responds with a Http 500 error. So, what you need to do now, is specifically set the authorization header and send it with the request. The code below shows the code you can use:

string ditnopUrl = “http://dspimportservice.nl/”;
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = “Opdracht_OS_XOPBinding”;
binding.MaxReceivedMessageSize = 2147483647;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

EndpointAddress address = new EndpointAddress(ditnopUrl);
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = “user”;
loginCredentials.UserName.Password = “password”;

factory = new ChannelFactory(binding, address);
var defaultCredentials = factory.Endpoint.Behaviors.Find();
factory.Endpoint.Behaviors.Remove(defaultCredentials); //remove default ones
factory.Endpoint.Behaviors.Add(loginCredentials); //add required ones
channel = factory.CreateChannel();

using (OperationContextScope scope = new OperationContextScope(channel))
{
var httpRequestProperty = new HttpRequestMessageProperty();
httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] = “Basic ” +
Convert.ToBase64String(Encoding.ASCII.GetBytes(“user : password”));
System.ServiceModel.OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

channel.Open();
Opdracht_OS_XOPRequest request = new Opdracht_OS_XOPRequest();
request.Opdrachtbericht = opdrachtbericht;
Opdracht_OS_XOPResponse responseDSP = channel.Opdracht_OS_XOP(request);
}

channel.Close();

Leave a Reply

Your email address will not be published. Required fields are marked *