wsHttpBinding Message Security Problem

Topics: Technical Questions
Developer
Dec 6, 2007 at 12:47 AM
I've copied the WsHttp (Soap12) Binding to a new Binding and set security mode to "Message". I've hosted a new endpoint that uses this new Binding and have the endpoint exposing the operations of the Basic Calculator service in the samples. When I use the MSE Tester (and copy the binding xml from the MSE snap-in) I get the following error "The message could not be processed because the action "AddIntegers" is invalid or unrecognized.
When I enable WCF tracing, I see that there is a more detailed exception being thrown. "No signature message parts were specified for messages with the 'AddIntegers' action." Note that if I modify the binding to set security mode to "None" it works.

I've copied this binding as-is into my own WCF client/service and it works fine. But when the binding is used within the MSE Runtime it doesn't seem to work.

Has anyone experienced this issue?
Developer
May 20, 2008 at 9:37 PM
Edited Jun 10, 2008 at 10:52 PM
I wanted to close the loop on this item.  To use message security on an MSE endpoint, you need to add a service behavior to the MSE hosted endpoint.  This behavior (IServiceBehavior) should implement the ApplyBindingParameters() method and do the following:
1) Add a service certificate
2) Add channel protection requirements for messages with the specified action.

The second item is needed because the Soap Actions the MSE projects in the wsdl are intended to be virtual.  For example, the action can include an explicit version indicator that allows a specific version of an operation to be invoked if it is active for the endpoint rather than relying on the default resolution mechanism.  Because of this, the wsHttpBinding doesn't automatically know how to setup the encryption and signing protection for messages.  The following code snippet when added to the ApplyBindingParameters method will setup encryption & signing for messages with any action.

 

bindingParameters.Remove<ServiceCredentials>();

ServiceCredentials cr = new ServiceCredentials();

bindingParameters.Add(cr);

//add your appropriate certificate here
cr.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "localhost");

 

//add channel protection requirements for messages with any action
ChannelProtectionRequirements cpr = bindingParameters.Find<ChannelProtectionRequirements>(); 

if (cpr == null)
{
    
cpr = new ChannelProtectionRequirements();
    bindingParameters.Add(cpr);
}

ChannelProtectionRequirements
protection = new ChannelProtectionRequirements();
MessagePartSpecification body = new MessagePartSpecification(true);
body.MakeReadOnly();
protection.OutgoingEncryptionParts.AddParts(body,
"*");
protection.OutgoingSignatureParts.AddParts(body,
"*");
protection.IncomingEncryptionParts.AddParts(body,
"*");
protection.IncomingSignatureParts.AddParts(body,
"*");
protection.MakeReadOnly();
cpr.Add(protection);




botto wrote:
I've copied the WsHttp (Soap12) Binding to a new Binding and set security mode to "Message". I've hosted a new endpoint that uses this new Binding and have the endpoint exposing the operations of the Basic Calculator service in the samples. When I use the MSE Tester (and copy the binding xml from the MSE snap-in) I get the following error "The message could not be processed because the action "AddIntegers" is invalid or unrecognized.
When I enable WCF tracing, I see that there is a more detailed exception being thrown. "No signature message parts were specified for messages with the 'AddIntegers' action." Note that if I modify the binding to set security mode to "None" it works.

I've copied this binding as-is into my own WCF client/service and it works fine. But when the binding is used within the MSE Runtime it doesn't seem to work.

Has anyone experienced this issue?



Jun 12, 2008 at 2:41 PM
I have copied in an email exchange between botto, co-worker, and i on getting security setup: 

BOTTO

 

Can you post a follow up to your posting on codeplex?  The last entry indicates you were having problems establishing the service certificate… it sounds like you are past this and an update would be nice for everyone else to know what you did.  (or is this still an open item?)

 

When working with a distributed deployment where the broker is separated from the messenger, the binding used between them must either be NetTcp or WsHttp(Soap12).  If not you will get an exception like I saw in the log file you sent indicating the message version was incorrect (Outgoing message is Soap12, encoder is Soap11, make sure binding is configured with same version).  Verify this configuration and then let’s see what errors remain.

 

As for your credential challenge, we typically try to handle it one of a couple ways (listed in order of preference with most preferred option first).

1)      Authenticate at the messenger and add a custom message header that contains the original caller identity (just username) that will later be used for authorization (an even better option is to add an appropriate claimset once the user is authenticated).

a.       Perform authorization either as part of the Messenger Endpoint Policy or Policy attached to the Channel used to call the service implementation.

b.      Use Trusted Subsystem pattern for communication between broker and service implementation (which can leverage kerberos, or other mechanism).

c.       If necessary, pass through the custom header/claimset to the service implementation so it can perform authorization based on the identity/claimset of the original caller. This usually helps for auditing requirements that may be needed at the service implementation. (the pass through logic would be in a Channel Policy)

2)      Store usename/password in custom message header.  In your Channel policy for the service implementation, extract the header and use it to supply the UserNameToken required for the service implementation.

 

Although option 1 is preferred (since we aren’t pushing passwords around) it likely requires changes to the service implementation to support which may not be an option.

 

Ideally, authentication/authorization should be managed within the MSE layer.  This puts all security logic in WCF behaviors that allows them to be applied to any endpoint and dynamically changed w/o ever having to touch service logic.  This has implications on what credentials are then used to invoke service implementations.  This can be a pure trusted subsystem where the service implementation fully trusts the identity the MSE Runtime runs under, or the variation specified in option 1 above.

 

Finally, I see your office is in Dallas.  As part of the Microsoft consulting services organization it is very easy for us to work with you directly (a few of the MSE developers are even in Dallas).  If you are interested, let me know and I will have someone contact you to establish a services agreement for our time.  We would be able to do a much better review with your team and provide more complete recommendations that address your scenarios.

 

Either way, let’s get this discussion back on CodePlex so others can start to benefit from the challenges you are running into. J  When it comes to security, we haven’t done much in the way of public documentation/guidance.  I’ve been working on another sample/lab to help out, but this won’t be available on CodePlex for a while.

---------------------------------------------------------------------------------------------------

KDSTOCK

 

Thanks for following up with us.  This did resolve our issue and we were able to move forward, but we did run into two additional  problems.

 

First, we are using UserName credentials instead of Windows authentication as in your example.  But, we need to do our authentication on our app server where our TCP service is hosted.  So, I created a dummy membership provider in our Service Behavior that always authenticates.  I then created a new Endpoint Behavior that I attached to the channel for our TCP service to inject a username and password.  What I can’t figure out is how I can retrieve the credentials from the original call so that they can be passed in to our TCP service.  If we were doing Windows authentication, I assume I could just use impersonation, but that doesn’t seem to be an option right now.  Is this possible?

 

Second, we managed to get this much working when the messenger and broker are on a single instance of the runtime server.  When we tried to distribute the messenger and broker to different machines, we began running into problems.  Are there any examples available of how to configuration MSE in a distributed architecture?  I’ve attached the trace log in case it’s helpful.  Rama may be able to elaborate on the issues we’re encountering.

 

Thanks again for your help so far.

-------------------------------------------------------------------------------------

BOTTO

 

I was able to repro the issue.  For the sample, the following needs to be added at the beginning of the AddBindingParameters method:

 

            bindingParameters.Remove<ServiceCredentials>();

            ServiceCredentials cr = new ServiceCredentials();

            bindingParameters.Add(cr);

            cr.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "localhost");

//Remove since set by the above statement

            //serviceHostBase.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "localhost");

 

I had the above in my original work, but removed it for my posting which ended up not being a good thing… J

 

Please let me know if this does in fact resolve your issue as well.  I’ll update the CodePlex posting accordingly.

 

------------------------------------------------------------------------------------

ramav

 

Thanks for your help in this matter. We have down loaded the Service Trace Viewer, but are at a loss as to how to determine where our error is (need help interpreting the data). We look forward to any findings you may find in the log and hopefully help us understand how to read it better and of course get Message level security working. In addition, I am attaching our policy, bindings, and the extension element that we are using to see if this will help you help us get this implementation working.

 

Policy:

<PolicyModel xmlns="http://microsoft.com/mse/2007/runtime/policyModel" xmlns:mse="http://services.microsoft.com/MSE" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:wcf="clr-namespace:System.ServiceModel.Configuration;assembly=System.ServiceModel" xmlns:ndex="clr-namespace:DefaultNet.Wcf.Behavior;assembly=DefaultNet.Wcf.Behavior">
  <ndex:ServiceCredentialsBehaviorExtensionElement>
  </ndex:ServiceCredentialsBehaviorExtensionElement>
</PolicyModel>

 

 

Binding:

<bindings xmlns="">
  <wsHttpBinding>
    <binding name="Ndex_WSHttpBinding" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="999999999" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" receiveTimeout="00:15:00">
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647">
      </readerQuotas>
      <reliableSession ordered="true" inactivityTimeout="00:15:00" enabled="false">
      </reliableSession>
      <security mode="Message">
        <message clientCredentialType="UserName">
        </message>
      </security>
    </binding>
  </wsHttpBinding>
</bindings>

 

Extension element:

[assembly: XmlnsDefinition("http://mse.microsoft.com/policy/svccred", "DefaultNet.Wcf.Behavior")] namespace DefaultNet.Wcf.Behavior {

public class ServiceCredentialsBehaviorExtensionElement : BehaviorExtensionElement

    {

          public override Type BehaviorType

          {

               get { return typeof(ServiceCredentialsBehavior); }

          }

          protected override object CreateBehavior()

          {

               return new ServiceCredentialsBehavior();

          }

     }

}

 -------------------------------------------------------------------------

Botto

 

The svclog file is generated by WCF tracing and can be viewed in the Service Trace Viewer that ships with the Windows SDK.

 

I’ll have to take a deeper look at what may be going on.  I’ve used Message level security in the June 2008 CTP without issue so I’m sure we’ll get it working for you.

 

 

 -----------------------------------------------------------------------------------------------------

Ramav

 

Thanks for your quick reply. We do have the last couple of lines from your post in our implementation, and we still get the error as I mentioned below. I went ahead and deleted the logs and started the runtime service back up, so the logs that I have attached are from a clean slate. I do have one question, because I tried deciphering the mse_runtime_svclog but couldn’t make much sense out of it. If you do uncover the issue hindering our implementation can you please also explain how you interpreted the log as well?