Mixed WCF endpoint bindings for hosted workflow services
I am working on a project where I have multiple hosted WF services. All the services were secured using federated security with WIF and a custom STS. This has all worked fine until I added a new service workflow that needed to be accessible by anonymous users. This is where things get a little tricky.
The WCF configuration for the hosted services looked a little like this before the anonymous service was added.
<system.serviceModel> <protocolMapping> <add scheme="http" binding="ws2007FederationHttpBinding" /> </protocolMapping> <bindings> <ws2007FederationHttpBinding> <binding> <security mode="TransportWithMessageCredential"> <message establishSecurityContext="false"> <issuerMetadata address="https://localhost/JabiruSts/Service.svc/mex" /> <claimTypeRequirements> <!--Following are the claims offered by STS 'https://localhost/JabiruSts/Service.svc'. Add or uncomment claims that you require by your application and then update the federation metadata of this application.--> <add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" isOptional="true" /> <add claimType="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" isOptional="true" /> </claimTypeRequirements> </message> </security> </binding> </ws2007FederationHttpBinding> </bindings> <behaviors> <serviceBehaviors> <behavior> <federatedServiceHostConfiguration /> <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> <serviceMetadata httpGetEnabled="true" /> <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults="true" /> <serviceCredentials> <serviceCertificate findValue="DefaultApplicationCertificate" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /> </serviceCredentials> <errorHandler type="Neovolve.Jabiru.Server.Services.FaultHandler, Neovolve.Jabiru.Server.Services" /> </behavior> </serviceBehaviors> </behaviors> <extensions> <behaviorExtensions> <add name="errorHandler" type="Neovolve.Toolkit.Communication.ErrorHandlerElement, Neovolve.Toolkit" /> <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=18.104.22.168, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </behaviorExtensions> </extensions> <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> </system.serviceModel>
The key thing to notice is that WCF4 uses default configuration values. These services use ws2007FederationHttpBinding in order to communicate with the STS but this is not the default binding for the HTTP stack. The configuration makes this work by defining the federation binding for HTTP using the protocolMapping/add element. The bindings/ws2007FederationBinding configuration does not specify a name as it represents the default configuration for that type of binding.
I attempted to modify this configuration with an explicit service configuration for my anonymous service that uses an IRegistration contract. There were a few roadblocks along the way, but here are the tips to get you across the line.
The first step is to define a configuration name against the xamlx file. This is accessed by viewing the properties of the workflow (the workflow, not any child activity).
This configuration name needs to match to a WCF service configuration name. This configuration can then define a different binding than the default for the HTTP stack. It can then also define the behaviour to use for that endpoint binding.
The relevant change to the above configuration is to add the following.
<services> <service name="Neovolve.Jabiru.Server.Services.Registration"> <endpoint binding="basicHttpBinding" bindingConfiguration="SecureBasicHttpBindingConfig" contract="IRegistration" /> </service> </services> <bindings> <basicHttpBinding> <binding name="SecureBasicHttpBindingConfig"> <security mode="Transport"></security> </binding> </basicHttpBinding> </bindings>
The second important step is to define the “correct” contract name. Ordinarily the contract name in WCF would be the [Namespace].[TypeName] value of the service contract. For some reason this only worked when I specified just the type name.
My hosted workflow services can now respond to a mix of endpoint bindings for the service.