Adding WS-Security Credentials to SOAP headers using WCF - wcf

I am trying to communicate with a Java web service that I have no control over, and I'm trying to create a binding that'll work.
Timestamp is not allowed in the header, so in order to use the includeTimestamp="false" attribute, I have to use a <customBinding>.
They are using MTOM, so I have to use the <mtomMessagingEncoding> element.
Here is my <bindings> element:
<bindings>
<customBinding >
<binding name="MyBindingName" >
<mtomMessageEncoding />
<transactionFlow />
<security authenticationMode="UserNameOverTransport"
includeTimestamp="false">
</security>
</binding>
</customBinding>
</bindings>
The SOAP web service requires that the message header be in the following format:
<soap:Envelope ... >
<soap:Header ... >
<wsse:UsernameToken>
<wsse:Username>doo</wsse:Username>
<wsse:Password Type="wsse:PasswordText">fuss</wsse:Password>
</...>
</...>
</...>
The closest I have come is:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1"></a:Action>
<a:MessageID>urn:uuid:a368e205-a14d-4955-bf75-049cdd3a78c0</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">https://blablabla</a:To>
<o:Security s:mustUnderstand="1"
xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:UsernameToken u:Id="uuid-0f1e399b-31a8-4e00-a57f-277c21e94879-1">
<o:Username><!-- Removed--></o:Username>
<o:Password><!-- Removed--></o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
I am sure I'm missing something trivial and stupid here, but for the life of me i can't figure out what it might be.

You must also configure message version because by default it uses WS-Addressing:
<bindings>
<customBinding >
<binding name="MyBindingName" >
<mtomMessageEncoding messageVersion="Soap11" /> <!-- or Soap12 -->
<security authenticationMode="UserNameOverTransport"
includeTimestamp="false">
</security>
</binding>
</customBinding>
</bindings>
TransactionFlow element is not needed at all.
Btw. message you showed is not valid usage of WS-Security token because it must be inside Security element so if it is really what Java service expects it doesn't conform to WS-Security specification and you will have to use custom message header instead.

Related

Stuck connecting to remote SOAP service with credentials

I need to connect to a remote SOAP service. For several days that I have been trying all the many configurations without success.
Connection is OK when using SoapUI.
Connection is KO when calling from my .net application.
Errors : The username is not provided. Specify username in ClientCredentials.
My application and the remote application are both running on IIS.
Here is the remote binding :
<bindings>
<wsHttpBinding>
<binding name="WsHttpBinding_Default" maxReceivedMessageSize="524288000" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
SoapUI works with the following configuration :
Authorization : Basic
Username: DOMAIN\username
Password : pwd
Pre-Emptive authentication
When I check the raw request from SoapUI, it's sending this :
POST https://domain.name/TestNode/V_ServicePartenaireDS/v5.svc HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="http://URI/getUser"
Authorization: Basic UEFSVFxzdmMtaWlzYmsdfsdfsdfphZG1pbjEyMy0t
Content-Length: 1371
Host: proxy-int.part.lan.net
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:v2="http://cnc.fr/Circe/Partenaires/v2.7">
<soap:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Timestamp wsu:Id="TS-268FDC1861EA4F5F3C154297086643492">
<wsu:Created>2018-11-23T11:01:06Z</wsu:Created>
<wsu:Expires>2018-11-23T16:34:26Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken wsu:Id="UsernameToken-268FDC1861EA4F5F3C154297086643491">
<wsse:Username>PART\svc-iisbackend</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pwd</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">yi71/jQzUJw/lzReixSgOA==</wsse:Nonce>
<wsu:Created>2018-11-23T11:01:06.434Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
<wsa:Action>http://UIR/getUser</wsa:Action>
</soap:Header>
<soap:Body>
<v2:getUser>
<!--Optional:-->
<v2:id>200785</v2:id>
</v2:getUser>
</soap:Body>
</soap:Envelope>
Everything above is working.
Now, what am I doing in my .net 4.6.1 application ? I am trying to send the same request that SoapUI is sending.
Here is how I do : web.config with endpoints, bindings and behaviour extension. The extended behaviour implements an EndPoint Behaviour that calls an Inspector (from ApplyClientBehavior) from which I use the BeforeSendRequest to add two things :
a SOAP header <wsse:Security />
a Authorization: Basic http header.
Here are the details of the implementation.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WsHttpBinding_Default" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
<binding name="WsHttpBinding_Authentication" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
<security mode="Transport">
<transport clientCredentialType="Basic" />
<message clientCredentialType="UserName" />
</security>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</wsHttpBinding>
<basicHttpBinding>
<binding name="BasicHttp_Default" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00" />
</basicHttpBinding>
</bindings>
<extensions>
<behaviorExtensions>
<add name="localSecurity" type="Users.UsersImplementation.Service.ImplementationCommon.BehaviorExtensionBasicAuthent, Users.UsersImplementation"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="LocalWsBehavior">
<callbackDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<localSecurity/>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="https://domain/TestNode/V_ServiceUser/v5.svc" behaviorConfiguration="LocalWsBehavior" binding="wsHttpBinding" bindingConfiguration="WsHttpBinding_Authentication" contract="App.UserDSContract.IServiceUserDS" name="" />
<!--<headers>
<wsse:Security xmlns:soap="schemas.xmlsoap.org/soap/envelope" soap:mustUnderstand="true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Timestamp wsu:Id="TS-268FDC1861EA4F5F3C154289160250080">
<wsu:Created>2018-11-22T15:15:02Z</wsu:Created>
<wsu:Expires>2018-11-22T18:33:22Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken wsu:Id="UsernameToken-268FDC1861EA4F5F3C154289160250079">
<wsse:Username>PART\svc-iisbackend</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pws</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">NcDsjgc1/cRNuHVMR7kJBw==</wsse:Nonce>
<wsu:Created>2018-11-22T15:15:02.499Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</headers>
</endpoint>-->
</client>
</system.serviceModel>
Down the chain of c# class, we find this code :
void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
{
// nothing to do here
}
object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
SoapSecurityHeader header = new SoapSecurityHeader("PART\\svc-iisbackend", "pwd");
request.Headers.Add(header);
HttpRequestMessageProperty httpRequestMessage;
object httpRequestMessageObject;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
{
httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
if (string.IsNullOrEmpty(httpRequestMessage.Headers[HttpRequestHeader.Authorization]))
{
httpRequestMessage.Headers[HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("PART\\svc-iisbackend-sagre" + ":" + "admin123--"));
}
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
}
else
{
httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("PART\\svc-iisbackend-sagre" + ":" + "admin123--")));
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
}
return header.Id;
}
The resulting SOAP envelope at the remote server side* is this :
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://UIR/getUser</a:Action>
<a:MessageID>urn:uuid:2b66b328-778f-4967-925a-01b75d9ab607</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<wsse:Security s:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Timestamp wsu:Id="TS-f7abfe27c28e4209b8c028ef78bdf739">
<wsu:Created>2018-11-23T14:37:46.59Z</wsu:Created>
<wsu:Expires>2018-11-23T16:37:46.59Z</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken wsu:Id="UsernameToken-aff0ea1c178c4843babf4afa5cd280f6">
<wsse:Username>PART\svc-iisbackend</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">pwd</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">qdiFSufkRLuPRHTwDYPzBDTu1/o=</wsse:Nonce>
<wsu:Created>2018-11-23T14:37:46.593Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
<a:To s:mustUnderstand="1">https://domain.url/V_ServiceUser/v5.svc</a:To>
</s:Header>
<s:Body>
<getUser xmlns="http://url">
<id>200472</id>
</getUser>
</s:Body>
</s:Envelope>
I have followed many blog and documentation to make it until this point and I am still stuck :D
*To get the message to hit the server I need to use the default binding configuration WsHttpBinding_Default. When I am using the WsHttpBinding_Authentication the request does not seem to be processed by the remote server.
I tried to play with the bindings configuration but no luck so far.
What is wrong with my current configuration ?
With WsHttpBinding_Authentication I got the said error (edited : wrong error copied pasted)The username is not provided. Specify username in ClientCredentials. An error occurred when verifying security for the message.
With WsHttpBinding_Default, the remote server processed a bit of the request and reject it with the following error :
the error :
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
<a:RelatesTo>urn:uuid:2b66b328-778f-4967-925a-01b75d9ab607</a:RelatesTo>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Sender</s:Value>
<s:Subcode>
<s:Value xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:InvalidSecurity</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="fr-FR">Une erreur s'est produite lors de la vérification de la sécurité du message.</s:Text>
</s:Reason>
</s:Fault>
</s:Body>
</s:Envelope>
Sorry for the wall of text, I hope everything needed to get a clear view of my issue is here.
Many thanks for having read so far :)
Edit : as you can see I also tried to put the header directly in the xml endpoint but no success so far.
Edit : The calling binding was wrong, it is now :
<binding name="WsHttpBinding_Authentication" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" openTimeout="00:10:00" closeTimeout="00:10:00" sendTimeout="00:10:00" receiveTimeout="00:10:00">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" />
<message clientCredentialType="UserName" />
</security>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
With that new binding my error is now :
{"globalErrors":["Message with Action 'http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT' is unknown and cannot be forwarded to the recipient. This may happen if message Action was changed, or if operation was disabled or deleted from the service contract."]}
I find no content about this error, what is happening :/
Edit : Solved the error by re-adding establishSecurityContext="false" in the binding.
Edit : To add credentials I am using that post answers : Set WCF ClientCredentials in App.config
It seems to work, I am making progress toward an old error : An error occurred when verifying security for the message.
To add a username and password to the Service, you would need to do the following when setting up the service
// Instantiate the proxy
Service1Client proxy = new Service1Client();
// Set the user’s credentials on the proxy
proxy.ClientCredentials.UserName.UserName = username;
proxy.ClientCredentials.UserName.Password = password;
This is when you are using standard WS username and password, I have added an answer to my own question after experiencing the exact same thing as well, The link is WCF Service inside aspnet webforms throwing 302
You can read up more on from Microsoft
Solved !!!
So much frustration, but writing a SO post and keeping it updated helped a lot.
I go celebrated and I will come back to detail the solution.
In short, use the implementation from the link I add in my edits, not my previous way.

WCF Custom binding - service responds, client doesn't

I have a WCF service that's been working with a wsDualHttpBinding but I'm rewriting it to use a customBinding for greater configurability. Here's my service binding:
<customBinding>
<binding name="CodeServiceBinding" openTimeout="00:01:00">
<transactionFlow transactionProtocol="WSAtomicTransactionOctober2004"/>
<reliableSession acknowledgementInterval="00:00:00.2" flowControlEnabled="true"
inactivityTimeout="00:05:00" maxPendingChannels="4" maxRetryCount="8"
maxTransferWindowSize="8" ordered="true" reliableMessagingVersion="Default" />
<compositeDuplex/>
<oneWay maxAcceptedChannels="10">
<channelPoolSettings idleTimeout="00:02:00" leaseTimeout="00:10:00" maxOutboundChannelsPerEndpoint="10" />
</oneWay>
<textMessageEncoding messageVersion="Soap12WSAddressing10"/>
<httpTransport allowCookies="false" authenticationScheme="Anonymous" bypassProxyOnLocal="false"
decompressionEnabled="true" keepAliveEnabled="true" manualAddressing="false"
maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxPendingAccepts="0"
maxReceivedMessageSize="2147483647" proxyAuthenticationScheme="Anonymous"
transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
And client binding:
<system.serviceModel xdt:Transform="Replace">
<bindings>
<customBinding>
<binding name="Code.DualEndPoint" openTimeout="00:00:10" sendTimeout="00:00:10">
<transactionFlow transactionProtocol="WSAtomicTransactionOctober2004"/>
<reliableSession inactivityTimeout="00:05:00" />
<compositeDuplex />
<oneWay />
<textMessageEncoding messageVersion="Soap12WSAddressing10" />
<httpTransport authenticationScheme="Anonymous" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://1.2.3.4/Code/Code.svc"
binding="customBinding" bindingConfiguration="Code.DualEndPoint"
contract="CodeProxy.ICode" name="Code.DualEndPoint" />
</client>
</system.serviceModel>
Everything works great when I run it against http://localhost/Code/Code.svc but, as soon as I put the client somewhere else, it doesn't work. I don't think it's firewall issues because the old version using the wsDualHttpBinding works ok. Also because I wiresharked it.
Both versions send their CreateSequence request
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</a:Action>
<a:MessageID>urn:uuid:222d5f6a-cca4-4a4b-b8bc-3347b81b425a</a:MessageID>
<a:ReplyTo>
<a:Address>http://1.2.3.4:1234/CodeClient/8f191330-523a-4820-a784-46fe364aebcc</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://hostname.com/Code/Code.svc</a:To>
</s:Header>
<s:Body>
<CreateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">
<AcksTo>
<a:Address>http://1.2.3.4:1234/CodeClient/8f191330-523a-4820-a784-46fe364aebcc</a:Address>
</AcksTo>
<Offer>
<Identifier>urn:uuid:f7a18edc-e79f-4d96-a90d-696d1055b592</Identifier>
</Offer>
</CreateSequence>
</s:Body>
</s:Envelope>
and receive an HTTP 202 accepted from the service, but the new client never goes to send the actual function call request. The old one starts it right away but the new binding hangs until the SendTimeout is met and it throws an exception. What is my new binding waiting for that causes it not to send the function call request and how can I make it stop waiting? Thanks!
By omitting clientBaseAddress from my <compositeDuplex/> element in my client binding, I guess I was confusing the service about where to direct its response? I don't know. Either way, it is now working with this updated node:
<compositeDuplex clientBaseAddress="http://1.2.3.4:1234/CodeClient"/>
<compositeDuplex/> is still attributeless in my service web.config. However, now I'm facing a different problem. Programmatically updating the clientBaseAddress for a custom binding is proving to be quite difficult.

The security protocol cannot secure the outgoing message

I am trying to return a custom fault exception using unity
but I get the following error during Rst\Issue action:
[Service Trace Viewer exceptions][1]
Image: [1]: http://i.stack.imgur.com/oAxGT.png
No signature message parts were specified for messages with the 'http://tempuri.org/IWcfServiceLayer/GetFirstOrder' action.
The security protocol cannot secure the outgoing message
RequestContext aborted
I am using a custmBinding which actually resembles wsHttpBinding.
Here I manually throw an exception in the wcf method, in order to test the behaviour.
When I comment out the throw new exception statement, the service works fine and returns the expected results. But the service cannot handle exceptions currently.
So why can't the service secure the outgoing message when an exception occurs?
EDIT (BindingConfig):
<customBinding>
<binding name="MyServiceBinding" closeTimeout="00:05:00" openTimeout="00:05:00"
receiveTimeout="00:05:00" sendTimeout="00:05:00">
<transactionFlow />
<reliableSession maxPendingChannels="4000" maxRetryCount="20"
maxTransferWindowSize="4000" ordered="false" />
<security enableUnsecuredResponse="false" authenticationMode="SecureConversation"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<secureConversationBootstrap authenticationMode="SspiNegotiated"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
<localServiceSettings maxStatefulNegotiations="500" maxPendingSessions="500" />
</security>
<textMessageEncoding maxReadPoolSize="100" maxWritePoolSize="50" />
<httpTransport maxReceivedMessageSize="2000000" allowCookies="true"
maxBufferSize="2000000" />
</binding>
</customBinding>

wsdl with no serialization info

I am trying to send a request to a web service. The wsdl can be seen here
https://amsel.dpwn.net/abholportal/gw/lp/schema/1.0/var3ws.wsdl
Creating a request is straight forward
BookLabelRequest request = new BookLabelRequest();
RpPartnerType rpt = new RpPartnerTypeClient();
dhlService.BookLabelResponse response = rpt.BookLabel(new dhlService.BookLabelRequest());
but how do i pass the required parameters to it when there is no serializable BookLabelRequest exposed? and how do i pass the username/password in the header?
Sample SOAP request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:var="https://amsel.dpwn.net/abholportal/gw/lp/schema/1.0/var3bl">
<soapenv:Header>
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<var:BookLabelRequest portalId ="OnlineRetoure" deliveryName="Deutschland_Var3"
shipmentReference="notreturnedonlabel" customerReference="CustomerRef1234567890"
labelFormat="PDF" senderName1="Markus" senderName2="Beck"
senderCareOfName="actualnotinuse" senderContactPhone=""
senderStreet="Buschmühlenstraße" senderStreetNumber="40"
senderBoxNumber="" senderPostalCode="58093" senderCity="Hagen"/>
</soapenv:Body>
The wsdl file isn't mine so i can't edit it. Is there any other way to import this. I tried to create a data contract from the xsd using svcutil but i got the error message:
The input read from "https://amsel.dpwn.net/abholportal/gw/lp/schema/1.0/
var3bl.xsd" is inconsistent with other options
I tried passing the username and password to the proxy as well
RpPartnerType test = new RpPartnerTypeClient();
((RpPartnerTypeClient)test).ClientCredentials.UserName.UserName = "username";
((RpPartnerTypeClient)test).ClientCredentials.UserName.Password = "password";
dhlService.BookLabelResponse response = test.BookLabel(new dhlService.BookLabelRequest());
but got the error: Authentication failed: No username given
The binding security is:
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Your WSDL is importing XSD with serialization info from other path:
https://amsel.dpwn.net/abholportal/gw/lp/schema/1.0/var3bl.xsd
but location in WSDL should specify full this path.
If you need to use UserNameToken profile you must first specify binding for your your client:
<bindings>
<basicHttpBinding>
<binding name="secured">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
And use this binding in your client endpoint:
<client>
<endpoint address="..." name="..." contract="..." binding="basicHttpBining"
bindingConfiguration="secured" />
</client>
Once you have your client configured you need to create proxy of the service ans set credentials"
proxy.ClientCredentials.UserName.UserName = ...;
proxy.ClientCredentials.UserName.Password = ...;
Create a HttpWebRequest according to Mike Hadlow's blog and sent that.
http://mikehadlow.blogspot.com/2006/05/making-raw-web-service-calls-with.html
May be better ways to achieve this but it worked.

Configuring a WCF Client to Use UserName Credentials On the Request and Check Certificate Credentials On the Response

I'm trying to use WCF to consume a web service provided by a third-party's Oracle Application Server. I pass a username and password in a UsernameToken as part of the request and as part of the response the web service returns a standard security tag in the header which includes a digest and signature.
With my current setup, I successfully send a request to the server and the web service sends the expected response data back. However, when parsing the response WCF throws a MessageSecurityException, with an InnerException.Message of "Supporting token signatures not expected."
My guess is that WCF wants me to configure it to handle the signature and verify it. I have a certificate from the third party that hosts the web service that I should be able to use to verify the signature, although I'm not sure if I'll need it.
Here's a sample header from a response that makes WCF throw the exception:
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<dsig:Signature xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<dsig:Reference URI="#_51IUwNWRVvPOcz12pZHLNQ22">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>
[DigestValue here]
</dsig:DigestValue>
</dsig:Reference>
<dsig:Reference URI="#_dI5j0EqxrVsj0e62J6vd6w22">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>
[DigestValue here]
</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>
[Signature Value Here]
</dsig:SignatureValue>
<dsig:KeyInfo>
<wsse:SecurityTokenReference xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Reference URI="#BST-9nKWbrE4LRv6maqstrGuUQ22" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</dsig:KeyInfo>
</dsig:Signature>
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" wsu:Id="BST-9nKWbrE4LRv6maqstrGuUQ22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
[Security Token Here]
</wsse:BinarySecurityToken>
<wsu:Timestamp wsu:Id="_dI5j0EqxrVsj0e62J6vd6w22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2010-05-26T18:46:30Z</wsu:Created>
</wsu:Timestamp>
</wsse:Security>
</soap:Header>
<soap:Body wsu:Id="_51IUwNWRVvPOcz12pZHLNQ22" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
[Body content here]
</soap:Body>
</soap:Envelope>
My binding configuration looks like:
<basicHttpBinding>
<binding name="myBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
I think that basically what I have to do is configure WCF to use UserName client credentials in the request and Certificate client credentials in the response. I don't know how to do this though.
I'm new at WCF, so I'm sorry if this is a bit of a dumb question. I've been trying to Google solutions, but there seem to be so many different ways to configure WCF that I'm getting overwhelmed.
Thanks in advance!
For anyone who is interested, I was able to work around this problem by creating a CustomMessageEncoder (with help from this MSDN article) to intercept the response message before WCF was able to handle it. There, I removed the BinarySecurityToken and Signature elements from the response before handing it off to WCF. I used the following method to remove the offending elements from the stream:
private Stream RemoveSignatures(Stream stream)
{
XmlDocument doc = new XmlDocument();
doc.Load(stream);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);
nsMgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
nsMgr.AddNamespace("dsig", "http://www.w3.org/2000/09/xmldsig#");
nsMgr.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XmlNode signatureNode = doc.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security/dsig:Signature", nsMgr);
XmlNode binarySecurityTokenNode = doc.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security/wsse:BinarySecurityToken", nsMgr);
XmlNode headerNode = doc.SelectSingleNode("/soap:Envelope/soap:Header/wsse:Security", nsMgr);
headerNode.RemoveChild(signatureNode);
headerNode.RemoveChild(binarySecurityTokenNode);
return new MemoryStream(new UTF8Encoding().GetBytes(doc.OuterXml));
}
Obviously this is not the greatest solution. It's very 'hacky'. But it works and if need be I can continue using it because the message security is already being taken care of by HTTPS transport.
If anyone can tell me a better way to solve this, I'm open.
Seems like service isn't waiting for credentials at a place you providing them. Try to specify username and password for transport level instead.