Accepting both UsernameToken and BinarySecurityToken in WCF customBinding

I create a WCF web service with a custom anchor endpoint and receive a stuck WS-Security header reception that is sent to me by the other side. We both follow the specifications developed by the UK National Health Service, so I cannot make any changes to the requirements.

The basic structure of the <wsse:Security> header should be as follows, according to the specification:

 <wsse:Security> <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd" wsu:Id="6CCF6A2B-11A6-11DF-86D1-236A99759561" > <wsu:Created>2012-06-12T09:00:00Z</wsu:Created> <wsu:Expires>2012-06-12T09:15:00Z</wsu:Expires> </wsu:Timestamp> <wsse:UsernameToken> <wsse:Username>SomeUsername</wsse:Username> </wsse:UsernameToken> <wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wsssoap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis- 200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="30b91ede-35c2-11df-aac9-97f155153931 ">xxx...</wsse:BinarySecurityToken> <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> <SignedInfo> <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#RSA-SHA1" /> <Reference URI="#6CCF6A2B-11A6-11DF-86D1-236A99759561" /> <Transforms> <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </Transforms> <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <DigestValue>xxx...</DigestValue> </SignedInfo> <SignatureValue>xxx...</SignatureValue> <KeyInfo> <wsse:SecurityTokenReference> <wsse:Reference URI="#30b91ede-35c2-11df-aac9-97f155153931 "/> </wsse:SecurityTokenReference> </KeyInfo> </Signature> </wsse:Security> 

In my web service, I tried using the following binding:

 <customBinding> <binding name="wsHttpSoap11" > <textMessageEncoding messageVersion="Soap11WSAddressingAugust2004" /> <security authenticationMode="MutualCertificate"> </security> <httpTransport/> </binding> </customBinding> 

(The reason I use customBinding is because I have to support both WS-Addressing and WS-Security on top of SOAP 1.1 , and got advice from this answer .)

If I run a sample request through Fiddler, I get the following error in my WCF trace:

Cannot find token authenticator for ' System.IdentityModel.Tokens.UserNameSecurityToken '. Tokens of this type cannot be accepted in accordance with the current security settings.

I believe this is because it cannot authenticate <UsernameToken> . If I changed the binding security to:

 <security authenticationMode="UserNameForCertificate"> 

Then I get this error:

Cannot find token authenticator for ' System.IdentityModel.Tokens.X509SecurityToken '. Tokens of this type cannot be accepted in accordance with the current security settings.

I believe this is because now it cannot authenticate <BinarySecurityToken> !

So the question is:

  • Are my assumptions correct regarding the cause of error messages (that it can only process one token in the current configuration)?
  • How to configure it to accept both tokens?

Update

Thanks to @Yaron, a user binding extension has now been added, and UserNameSecurityToken and X509SecurityToken are checked .

However, it now fails at the stage where it validates the XML signature. Exception returned in HTTP response:

Error checking messages.

If I delve into the stack trace in the service trace viewer, I see:

System.Security.Cryptography.CryptographicException ...

Signature Verification Error.

in System.IdentityModel.SignedXml.VerifySignature (HashAlgorithm hash, Asymmetric strain warp matrix) in System.IdentityModel.SignedXml.StartSignatureVerification (Security CheckKey) ...

Can someone help me understand why this is happening? At the moment, I'm a little lost. I tried using some sample code to try to manually verify the signature, but says the signature is not valid. How can I be sure it is or not before I return to the supplier? Is this something that should work? Should we share some certificates somewhere along the line?

+2
source share
1 answer

you will need to create a binding from the code.

  var b = new CustomBinding(); var sec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10); sec.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters()); sec.MessageSecurityVersion = MessageSecurityVersion. WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10; sec.IncludeTimestamp = true; sec.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.EncryptBeforeSign; b.Elements.Add(sec); b.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8)); b.Elements.Add(new HttpTransportBindingElement()); 

(some of the values ​​are evaluated, since I can’t tell in your message which version of soap you are using or using ssl)

another mistake you can start too late is that you need to have ProtectionLevel.SignOnly for ServiceContract attributes, but this is not related to this issue.

+4
source

All Articles