Double request when calling POX REST using WCF with WebHttpBinding set to Basic Authentication
Error when calling POX REST using WCF with WebHttpBinding set to Basic Authentication (HttpClientCredentialType.Basic)
Instead of one call from the client with the "Authorization: Basic" parameter specified in the HTTP header, two calls are made. The first unauthenticated challenge on all 401 Unauthorized responses from the service, the second challenge with the appropriate authentication information.
This seems to be handled by the WCF service without any hiccups. Calling third-party services clearly poses a problem as they react immediately to the error.
Service code:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Bare,
RequestFormat = WebMessageFormat.Xml,
UriTemplate = "")]
Message SendData(Message message);
}
public class Service : IService
{
public Message SendData(Message message)
{ return Message.CreateMessage(MessageVersion.None, String.Empty, "test");
}
}
Client code:
public class Client: WebChannelFactory<IService>, IService
{
public Client(Uri baseUri, string userName, string password)
: base(CreateBinding(),
baseUri)
{
Credentials.UserName.UserName = userName;
Credentials.UserName.Password = password;
}
public Message SendData(Message requestMessage)
{
var channel = CreateChannel();
Message responseMessage = channel.SendData(requestMessage);
return responseMessage;
}
private static Binding CreateBinding()
{
var binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
return binding;
}
}
Using TcpTrace Im seeing this on requests back:
POST / HTTP/1.1
Content-Type: application/xml; charset=utf-8
VsDebuggerCausalityData: uIDPo2lH6p+lUOdFmrqDKGWYeQkAAAAA7+Y4QR6wNUWZmwCaasMx7xrfcJZxph9NocstwCh8NQsACQAA
Host: localhost:9090
Content-Length: 89
Expect: 100-continue
Connection: Keep-Alive
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test request</string>
POST / HTTP/1.1
Content-Type: application/xml; charset=utf-8
VsDebuggerCausalityData: uIDPo2lH6p+lUOdFmrqDKGWYeQkAAAAA7+Y4QR6wNUWZmwCaasMx7xrfcJZxph9NocstwCh8NQsACQAA
Authorization: Basic dGVzdDp0ZXN0
Host: localhost:9090
Content-Length: 89
Expect: 100-continue
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">test request</string>
Note: only the second call contains: Authorization: basic dGVzdDp0ZXN0 How to stop the first request (without permission)?
An example of a solution with the TcpTrace utility can be downloaded here:
source to share
So based on Remus answer this is my workaround
public Message SendData(Message requestMessage)
{
var channel = CreateChannel();
Message responseMessage;
using (new OperationContextScope((IClientChannel)channel))
{
WebOperationContext.Current.OutgoingRequest
.Headers[HttpRequestHeader.Authorization] = "Basic "
+ Convert.ToBase64String(Encoding.ASCII.GetBytes(
Credentials.UserName.UserName + ":" + Credentials.UserName.Password));
responseMessage = channel.SendData(requestMessage);
}
return responseMessage;
}
I just force the first request to exit with basic authorization
source to share
The problem actually stems from these third parties. Per RFC 2617 Basic authentication is performed in two calls, similar to Digest. The server should respond on the first call with a call containing a scope:
Upon receiving an unauthorized access request for a URI within the protection space, the originating server MAY respond with a challenge, such as the following:
WWW-Authenticate: Basic realm="WallyWorld"
where "WallyWorld" is a string assigned by the server to identify the Request-URI protection space
The WCF endpoint will pre-authenticate only subsequent calls after the first. The very first call made to appdomain for any resource will not contain the basename and password of the header.
source to share