Reputation: 14996
I was running my Visual Studio 2008 Unit Test C# with a WebService PHP using WCF and I received the following error:
System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM,Basic realm="(null)"'. ---> System.Net.WebException: The remote server returned an error: (401) Unauthorized..
I am using Windows XP SP3 machine, unit test VS 2008 and WCF for connect to PHP WebService.
I have no control about PHP WebService. I cannot modify it (neither configuration security).
Here is my config file for the client that use the webservice PHP:
<system.serviceModel>
<extensions>
<bindingElementExtensions>
<add name="customTextMessageEncoding"
type="COMPANY.IntegracionEasyVista.CustomTextEncoder.CustomTextMessageEncodingElement,COMPANY.IntegracionEasyVista.CustomTextEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9744987c0853bf9e" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="ISO8859Binding">
<customTextMessageEncoding messageVersion="Soap11WSAddressing10"
encoding="ISO-8859-1" />
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://serverphp/webservice/SmoBridge.php"
binding="customBinding" bindingConfiguration="ISO8859Binding"
contract="ServiceEasyVista.WebServicePortType" name="EasyVistaSvcEndPoint" />
</client>
</system.serviceModel>
Really, I use C# code:
var endpointAddress = Config.AppSettings.Settings[EasyVistaSvcEndPointAddress].Value;
var endpoint = new System.ServiceModel.EndpointAddress(endpointAddress);
var endpointBinding = new System.ServiceModel.Channels.CustomBinding();
endpointBinding.Name = "ISO8859Binding";
var bindingElement = new IntegracionEasyVista.CustomTextEncoder.CustomTextMessageBindingElement();
bindingElement.Encoding = "ISO-8859-1";
bindingElement.MessageVersion = System.ServiceModel.Channels.MessageVersion.Soap11WSAddressing10; // "Soap11WSAddressing10"
endpointBinding.Elements.Add(bindingElement);
var transportBinding = new HttpTransportBindingElement();
endpointBinding.Elements.Add(transportBinding);
ConfigurarBinding(endpointBinding);
var svcClient = new WebServicePortTypeClient(endpointBinding, endpoint);
return svcClient;
Update: tests
I add this line:
transportBinding.AuthenticationScheme = System.Net.AuthenticationSchemes.Negotiate;
I get this error: The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'NTLM,Basic realm="(null)"'
I add this line:
transportBinding.AuthenticationScheme = System.Net.AuthenticationSchemes.Basic;
I get thiserror:
System.ServiceModel.CommunicationObjectFaultedException: El objeto de comunicación, System.ServiceModel.Channels.ServiceChannel, no se puede usar para la comunicación porque se encuentra en el estado Faulted.
//Server stack trace: // en System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)
I add this line:
transportBinding.AuthenticationScheme = System.Net.AuthenticationSchemes.Ntlm;
I get thiserror:
/Exception = System.ServiceModel.CommunicationException: Versión de mensaje no reconocida.
//Server stack trace: // en System.ServiceModel.Channels.ReceivedMessage.ReadStartEnvelope(XmlDictionaryReader reader)
// en System.ServiceModel.Channels.StreamedMessage..ctor(XmlDictionaryReader reader, Int32 maxSizeOfHeaders, MessageVersion desiredVersion)
// en System.ServiceModel.Channels.Message.CreateMessage(XmlDictionaryReader envelopeReader, Int32 maxSizeOfHeaders, MessageVersion version)
// en System.ServiceModel.Channels.Message.CreateMessage(XmlReader envelopeReader, Int32 maxSizeOfHeaders, MessageVersion version)
// en CustomTextEncoder.CustomTextMessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType) en E:\TFS\pro\CustomTextEncoder\CustomTextMessageEncoder.cs:línea 66
// en System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders)
// en CustomTextEncoder.CustomTextMessageEncoder.ReadMessage (ArraySegment`1 buffer, BufferManager bufferManager, String contentType) en E:\TFS\pro\CustomTextEncoder\CustomTextMessageEncoder.cs:línea 60
// en System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, BufferManager bufferManager, Int32 maxBufferSize, String contentType)
// en System.ServiceModel.Channels.HttpInput.ReadChunkedBufferedMessage(Stream inputStream)
I think, the following is right configuration (if were basichttpbinding)
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
Web service of WCF in basichttpbinding might not be flexible enough. CustomBinding as the name describes that it alllows users design their own web service binding.
I need use CustomBinding and SecurityMode (like basichttpbinding): WCF BasicHttpBinding equivalent CustomBinding
I need Security Mode: TransportCredentialOnly, Basic, HTTP transport and encoding="ISO-8859-1"
http://www.codemeit.com/security/wcf-basichttpbinding-equivalent-custombinding.html
http://social.msdn.microsoft.com/Forums/en/wcf/thread/6cefadf1-9939-4f3b-a502-2d79a30c7d3a
http://offroadcoder.com/2008/03/23/CallingYourNusoapPHPWebServiceFromWCF.aspx
http://msdn.microsoft.com/en-us/library/ms731092(v=VS.90).aspx
I try again using this configuration, and I get the error:
svcPro.ClientCredentials.UserName.UserName = "MY USER";
svcPro.ClientCredentials.UserName.Password = "XXXX";
Config:
<customBinding>
<binding name="ISO8859Binding">
<customTextMessageEncoding messageVersion="Soap11WSAddressing10" encoding="ISO-8859-1" />
<!--<textMessageEncoding MessageVersion="Soap11" />-->
<!--<httpTransport />-->
<httpTransport authenticationScheme="Basic" />
</binding>
</customBinding>
The error (InnerException is null):
Error: Unrecognized message version
Tipo: System.ServiceModel.CommunicationException Mensaje: Versión de mensaje no reconocida. StackTrace: Server stack trace:
en System.ServiceModel.Channels.ReceivedMessage.ReadStartEnvelope(XmlDictionaryReader reader)
en System.ServiceModel.Channels.StreamedMessage..ctor(XmlDictionaryReader reader, Int32 maxSizeOfHeaders, MessageVersion desiredVersion)
en System.ServiceModel.Channels.Message.CreateMessage(XmlDictionaryReader envelopeReader, Int32 maxSizeOfHeaders, MessageVersion version)
en System.ServiceModel.Channels.Message.CreateMessage(XmlReader envelopeReader, Int32 maxSizeOfHeaders, MessageVersion version)
en Reale.IntegracionEasyVista.CustomTextEncoder.CustomTextMessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders, String contentType) en E:\IntegracionEasyVista\CustomTextEncoder\CustomTextMessageEncoder.cs:línea 66
en System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, Int32 maxSizeOfHeaders) en Reale.IntegracionEasyVista.CustomTextEncoder.CustomTextMessageEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType) en E:\IntegracionEasyVista\CustomTextEncoder\CustomTextMessageEncoder.cs:línea 60
en System.ServiceModel.Channels.MessageEncoder.ReadMessage(Stream stream, BufferManager bufferManager, Int32 maxBufferSize, String contentType)
en System.ServiceModel.Channels.HttpInput.ReadChunkedBufferedMessage(Stream inputStream)
en System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(Exception& requestException)
en System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
en System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
en System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
en System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
en System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
en System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
en System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
More info: part of WDSL of Service.php
<?xml version="1.0" encoding="ISO-8859-1" ?>
<definitions
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:si="http://soapinterop.org/xsd"
xmlns:tns="http://192.168.110.50/WebService" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://192.168.110.50/WebService">
<types>
<xsd:schema targetNamespace="http://192.168.110.50/WebService">
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<xsd:import namespace="http://schemas.xmlsoap.org/wsdl/" />
</xsd:schema>
</types>
Upvotes: 1
Views: 21223
Reputation: 364269
Your PHP service requires authentication but your client doesn't send any. Change your custom binding to support authentication. You can set authentication in httpTransport element:
<httpTranposrt authenticationScheme="..." />
Use Basic or Negotiate. Basic will require you to provide client credentials when communicating with the service. Negotiate will require that both service and client are in the same domain.
Upvotes: 1