Recently while working on a project for a large government enterprise, I encountered a problem similar, nay, exactly the same as Scott Hanselman in his post "Breaking All The Rules with WCF." From the malformed WSDL to a custom WS-Security usernameToken without a password, I was dealing with the same issue.
Scott, as always, has done an incredible job highlighting the problem, and providing a solution, so I highly encourage you to read his post. I'm writing this post to cover the one thing he missed, creating a service that can be used to test this binding configuration against.
CREATING THE BINDING
Scott was able to create a Custom WCF binding that emits a username without password using the following code:
WSHttpBinding oldBinding = new WSHttpBinding(); oldBinding.Security.Mode = SecurityMode.TransportWithMessageCredential; //Just the username oldBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName; //And basically nothing else oldBinding.Security.Message.NegotiateServiceCredential = false; oldBinding.Security.Message.EstablishSecurityContext = false; //oldBinding.ProxyAddress = new Uri("http://BIGASSLAPTOP:8888"); //oldBinding.UseDefaultWebProxy = false; //remove the timestamp BindingElementCollection elements = oldBinding.CreateBindingElements(); elements.Find().IncludeTimestamp = false; //sets the content type to application/soap+xml elements.Find ().MessageVersion = MessageVersion.Soap12; CustomBinding newBinding = new CustomBinding(elements); FooPortTypeClient svc = new FooPortTypeClient(newBinding, new EndpointAddress("https://example.com/foo/v1")); FooRequest req = new FooRequest(); //...etc...now it's just request and response.
The same binding can be created in configuration like this:
<bindings> <customBinding> <binding name="WSSecurityBinding"> <security defaultAlgorithmSuite="Default" authenticationMode="UserNameOverTransport" requireDerivedKeys="true" includeTimestamp="false" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"> <localClientSettings detectReplays="false" /> <localServiceSettings detectReplays="false" /> </security> <textMessageEncoding messageVersion="Soap12" /> <httpsTransport /> </binding> </customBinding> </bindings>
This will create the binding, but what about testing it?
TESTING
If you configure a test client and service with this binding you'll find that as soon as the client calls the service, you'll receive the following exception:
This exception is thrown because the default UserNamePasswordValidator expects both a username and a password... and we just removed the password. However, fixing this issue is easy enough... we can create a custom UserNamePasswordValidator that allows us to validate the request according to our custom business logic.
public class NullPasswordValidator : UserNamePasswordValidator { public override void Validate(string userName, string password) { if (string.IsNullOrWhiteSpace(userName)) throw new FaultException("The userName cannot be null or whitespace."); // Allow any password, even null values to pass. } }
Configuring the service to use this new validator is as simple as creating a new service behavior configuration and pointing to the new custom validator:
<serviceBehaviors> <behavior name="NullPasswordValidator"> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Security.WCF.Validators.NullPasswordValidator, Security" /> </serviceCredentials> </behavior> </serviceBehaviors>
FULL CIRCLE
After creating and configuring the new UserNamePasswordValidator, our client will be able to communicate with the service. We can open up Fiddler and prove that everything is working correctly by inspecting the SOAP message:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <s:Header> <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-38dc2ff9-a055-4a66-90e3-3aa0c267c36e-1"> <o:Username>viaMacchina\\dec</o:Username> </o:UsernameToken> </o:Security> </s:Header> <s:Body> ... </s:Body> </s:Envelope>
This brings the custom binding full circle. We're able to create a message request without a password to fulfill the custom WS-Security requirements. We're also able to create a test service that will accept the requests without throwing an exception. Finally, we can use tools like Fiddler to inspect the SOAP messages between the client and service to ensure that the message is formed exactly as it should be.
Amazing site http://spellcaster-reviews.com Greetings.
ReplyDeleteKeep up the good work , I read few posts on this web site and I conceive that your blog is very interesting
ReplyDeletevé máy bay từ mỹ về việt nam hãng ana
ve may bay tu Duc ve Viet Nam
lịch bay từ anh về việt nam hôm nay
lịch bay từ úc về việt nam hôm nay
ve may bay gia re tu Dai Loan ve Viet Nam
đặt vé máy bay từ canada về việt nam