WSDL Generation for WCF Service Behind Load Balancer - wcf

The Background:
I have a Service hosted on IIS 7.0 behind a Load Balancer which decrypts SSL as traffic passes through it.
The security mode required of the Service is Mixed-Mode ie TransportWithMessageSecurity
To enable the Service to accept HTTP traffic whilst allowing clients to communicate to the Load Balancer over SSL, I have created a User Defined Binding, which adds a custom HttpTransportBindingElement to its Channel Stack.
The custom HttpTransportBindingElement in turn asserts to the framework that it is capable of Encrypting and Signing messages...therefore the Framework won't complain when traffic comes in through it via HTTP because the Transport is claiming that it is signing/encrypting the messages...even though its not.
(For all those concerned, this has been determined to be acceptable security wise because the message orginally should have arrived over SSL to the Load Balancer...)
The Problem:
When we use svcutil.exe to generate the client proxy, the resulting auto-generated app.config file contains an endpoint to the service which is addressed over HTTP. This should be over HTTPS.
Additionally the <transport> element within the <customBinding> node is defined as a <httpTransport> element when it needs to be a <httpsTransport> element.
I suspect this is because the WSDL which is generated by the framework on the server, is being built with HTTP addresses instead of HTTPS > in turn, as a result of using the custom HttpTransportBindingElement (as explained above).
The auto-generated app.config for the client:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="myBindingEndpoint">
<!-- WsdlImporter encountered unrecognized policy assertions in ServiceDescription 'http://tempuri.org/': -->
<!-- <wsdl:binding name='myBindingEndpoint'> -->
<!-- <sp:HttpToken xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">..</sp:HttpToken> -->
<security defaultAlgorithmSuite="Default" authenticationMode="CertificateOverTransport"
requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings cacheCookies="true" detectReplays="false"
replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false" issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true" maxPendingSessions="128"
maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Default" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" decompressionEnabled="true" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://myserver/GAEASSLWcfService/ServiceOverSSL.svc"
binding="customBinding" bindingConfiguration="myBindingEndpoint"
contract="IServiceOverSSL" name="myBindingEndpoint" />
</client>
</system.serviceModel>
</configuration>
The Work-around:
Simply changing the <httpTransport /> to <httpsTransport /> and re-addressing the endpoints to use HTTPS fixes the issue.
But we'd prefer to not have to instruct our service consumers to change their .config files...the use of our service should be as seemless as possible...
The Question:
How can i ensure the client proxies will generate automatically with the correct Addresses and Transport elements???
References:
For those who want to learn about the solution to the 'service behind a load-balancer/ssl decrypter' and the custom HttpTransportBindingElement, see this post XXX by ZZZ regarding building the user defined binding and also this post XXX by ZZZ regarding some of the other issues with exposing Services behind a Load Balancing/SSL accelerator.

I was having the same problem, my WSDL was generated with the http scheme instead of https behind my load balancer.
I've reflected the WCF code and I found a solution that worked, for me though.
In addition to useRequestHeadersForMetadataAddress, you need to turn httpGetEnabled off and httpsGetEnabled on in the serviceMetadata.
Also, if you're using .net 4 like I think you are, instead of adding a custom HttpTransportBindingElement, just use the standard HttpTransportBindingElement and set AllowInsecureTransport on your TransportSecurityBindingElement.

Check out this question. Try to configure:
<serviceBehaviors>
<behavior name="<name>">
<!-- Other options would go here -->
<useRequestHeadersForMetadataAddress>
<defaultPorts> <!-- Use your own port numbers -->
<add scheme="http" port="81" />
<add scheme="https" port="444" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
</serviceBehaviors>

Related

WCF Error A SOAP 1.2 message is not valid when sent to a SOAP 1.1 only using wsHttpBinding

I am trying to consume a service which I have no control over and have been given just the WSDL to consume. The service requires a certificate for authentication. My configuration for the certificate is fine and I get an error when I try and call the service as below:
The content type text/xml;charset=UTF-8 of the response message does
not match the content type of the binding (application/soap+xml;
charset=utf-8). If using a custom encoder, be sure that the
IsContentTypeSupported method is implemented properly. The first 274
bytes of the response were: 'soap:VersionMismatchA SOAP 1.2 message is not valid when sent to a SOAP 1.1 only
endpoint.'.
I have tried different this like using a customBinding but I landed up with a total new number of more errors and feel am not getting anyway. Can you please assist?
Client Config:
<system.serviceModel>
<client>
<endpoint name="IDeliveryServiceImplPort"
address="WebServiceUrl"
binding="wsHttpBinding"
bindingConfiguration="wsHttpBinding"
behaviorConfiguration="wsHttpCertificateBehavior"
contract="IDeliveryService">
<identity>
<dns value="MyIdentity" />
</identity>
</endpoint>
</client>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8"
useDefaultWebProxy="true" allowCookies="false">
<readerQuotas
maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384" maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
<reliableSession enabled="false" ordered="true" inactivityTimeout="00:10:00" />
<security mode="Transport">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
<customBinding>
<binding name="WsHttpSoap11" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00">
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
<security authenticationMode="MutualCertificate" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="wsHttpCertificateBehavior">
<clientCredentials>
<clientCertificate x509FindType="FindBySubjectName" findValue="MyIdentity" storeLocation="LocalMachine" storeName="My" />
<serviceCertificate>
<defaultCertificate x509FindType="FindBySubjectName" findValue="MyIdentity" storeLocation="LocalMachine" storeName="My" />
<authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" trustedStoreLocation="LocalMachine" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
I have managed to figure it out with tweaks and trials. In order to solve is I change to basicHttpsBinding which took me another day or two to figure out the default transport clientCredentialType is None and you need to configure a custom binding as below. I wish WCF would tell you why or give a solution to error you get, because it was such a pain. From one error description to the next nonstop.
<bindings>
<basicHttpsBinding>
<binding name="SecureHubBinding">
<security>
<transport clientCredentialType="Certificate" />
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpsBinding>
</bindings>
Are these configurations automatically generated by adding service reference? We can use the WSDL file of the service to generate the binding information used by the server-side and add the service reference to generate the client proxy class.
In addition, if the service with transport security mode authenticates the client with a certificate, please guarantee that below requirements.
The trusted relationship between the client-side and the server-side
should be established. Install mutual certificates in the Local CA.
These two certificates should be accessed by the WCF application.
Please add the Everyone account (or the account running the WCF
application) to the management group of the certificate private key.
Both two certificates should have the client authentication intended
purpose and the server authentication intended purpose.
Feel free to let me know if there is anything I can help with.

WCF net.tcp issued token

Does anyone have a current example of using net.tcp with message security mode of issued token. I currently have a security token service that issues tokens but not sure how to configure it with net.tcp. I only see examples of using ws2007FederationHttpBinding
<customBinding>
<binding name="wsFed">
<security authenticationMode="SecureConversation" requireSecurityContextCancellation="true">
<secureConversationBootstrap authenticationMode="IssuedToken">
<issuedTokenParameters tokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
<issuer address="http://localhost/STSWebHost/STSService.svc" binding="ws2007HttpBinding" />
</issuedTokenParameters>
</secureConversationBootstrap>
</security>
<tcpTransport />
</binding>
</customBinding>
I keep getting Crypto algorith not supported error? Works fine with ws2007FederationHttpBinding but I am required to use net.tcp. Anyone?
I have a working version by setting allowInsecureTransport=true. I also removed secureconversation since I don't want sessions.
<customBinding>
<binding
name="netTcpFederated">
<security
authenticationMode="IssuedTokenOverTransport"
allowInsecureTransport="true" >
<issuedTokenParameters keyType="BearerKey" />
</security>
<binaryMessageEncoding>
<readerQuotas
maxStringContentLength="1048576"
maxArrayLength="2097152" />
</binaryMessageEncoding>
<tcpTransport
maxReceivedMessageSize="2162688" />
</binding>
</customBinding>`

Manual addressing with secure customBinding on WCF service

I'm developing a web service for a WSDL defined externally. Access is done with HTTP/S (server and client certificates) and both the request and response are signed with the respective certificate. I have imported the WSDL in VS2010 with a service reference and added signing to the MessageContracts, set up the config file to do security and https and setup SSL on the port.
I'm close to getting it working, but I need to enable manual addressing to insert a wsa:To element in the response, but can't figure out how to get that working..
Any help is appreciated.
Here's my current config section:
<bindings>
<customBinding>
<binding name="AfleverServiceSoapBinding_V1_1">
<security defaultAlgorithmSuite="TripleDesRsa15"
authenticationMode="MutualCertificateDuplex"
requireDerivedKeys="false"
securityHeaderLayout="Lax"
includeTimestamp="true"
keyEntropyMode="CombinedEntropy"
messageProtectionOrder="EncryptBeforeSign"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSignatureConfirmation="false"
allowSerializedSigningTokenOnReply="true"
enableUnsecuredResponse="False">
<localClientSettings cacheCookies="true"
detectReplays="true"
replayCacheSize="900000"
maxClockSkew="00:05:00"
maxCookieCachingTime="10:00:00"
replayWindow="00:05:00"
sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true"
timestampValidityDuration="00:05:00"
cookieRenewalThresholdPercentage="60"/>
<localServiceSettings detectReplays="true"
issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128"
replayCacheSize="900000"
maxClockSkew="00:05:00"
negotiationTimeout="00:01:00"
replayWindow="00:05:00"
inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00"
sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true"
maxPendingSessions="128"
maxCachedCookies="1000"
timestampValidityDuration="00:05:00"/>
<secureConversationBootstrap/>
</security>
<mtomMessageEncoding maxReadPoolSize="64"
maxWritePoolSize="16"
messageVersion="Soap11WSAddressing10"
maxBufferSize="65536"
writeEncoding="utf-8">
<readerQuotas maxDepth="32"
maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
</mtomMessageEncoding>
<httpsTransport manualAddressing="false"
maxBufferPoolSize="524288"
maxReceivedMessageSize="65536"
allowCookies="false"
authenticationScheme="Anonymous"
bypassProxyOnLocal="false"
decompressionEnabled="true"
hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true"
maxBufferSize="65536"
proxyAuthenticationScheme="Anonymous"
realm=""
transferMode="Buffered"
unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true"
requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
Most of this was auto-generated.
I know I need to set the manualAddressing attribute on httpsTransport to true, but then I get an exception because this setup is in message-level security.
Would anyone know how to switch to transport-level security whilst keeping the rest the same? Since this is a customBinding, the mode attribute on the security element is not available.
thnx a lot, Gait.
BTW, I know how to set the wsa:To in code, but it get's lost on the encode response unless I can move to manual addressing..
Check out the Nicholas Allen's Indigo Blog on Manual Addressing. Summary; not all of the transports support manual addressing. If the option is available on the transport there are 3 steps to make it work.
First, make sure that the transport that you're using supports some form of manual addressing. If not, then you're out of luck in terms of sending messages to different destinations without creating some new object on a per-destination basis. Second, turn on that manual addressing option to prevent the automatic application of addressing headers during message sends. Third, use whatever method you want to apply your own addressing headers to the outgoing message. If you're just making service calls on a proxy, then you'll want to use something like this:
OperationContext.Current.OutgoingMessageHeaders.To = this.replyTo.Uri;

Caller was not authenticated by the service error - CRM 2011 Deployment wcf service method call over SSL?

I am trying to utilize CRM 2011 deployment service for CRM 2011 management in a custom made vb.net application. Please do not tell me that i should use deployment manager for my operations as i have to develop this custom application tailored to the specific requirements for my organization.
Everything works fine when i use http but when i try to connect call a method of deployment service using SSL (HTTPS is enabled at the server)
Here is my relevant client configurtion for HTTPS/SSL only
<binding name="CustomBinding_IDeploymentServiceHttps">
<security defaultAlgorithmSuite="Default" authenticationMode="SspiNegotiatedOverTransport"
requireDerivedKeys="false" securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy" protectTokens="false" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSecurityContextCancellation="true">
<localClientSettings cacheCookies="true" detectReplays="false"
replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="false" issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true" maxPendingSessions="128"
maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Default" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpsTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" requireClientCertificate="false" />
</binding>
and
<client>
<!-- Deployment Service Endpoints HTTP,HTTPS-->
<endpoint address="http://10.40.30.20:5555/XRMDeployment/2011/Deployment.svc"
binding="customBinding" bindingConfiguration="CustomBinding_IDeploymentService"
contract="CRM2011DeploymentSvc.IDeploymentService" name="CustomBinding_IDeploymentService">
<identity>
<userPrincipalName value="LAB2010\administrator" />
</identity>
</endpoint>
<endpoint address="https://www.mydomain.com/XRMDeployment/2011/Deployment.svc"
binding="customBinding" bindingConfiguration="CustomBinding_IDeploymentServiceHttps"
contract="CRM2011DeploymentSvc.IDeploymentService" name="CustomBinding_IDeploymentServiceHttps" />
</client>
I am using the following code in my asp.net application
Dim DomainCredentials As New NetworkCredential(ADUserName, ADPassword, DomainNETBIOS)
If CRMDeploymentServiceURl.Trim().ToLower().StartsWith("https://") Then
_CrmDeployService = New DepSvc.DeploymentServiceClient("CustomBinding_IDeploymentServiceHttps")
Else
_CrmDeployService = New DepSvc.DeploymentServiceClient("CustomBinding_IDeploymentService")
End If
_CrmDeployService.ClientCredentials.Windows.ClientCredential = DomainCredentials
_CrmDeployService.Endpoint.Address = New EndpointAddress(New Uri(CRMDeploymentServiceURl))
_CrmDeployService.Endpoint.Binding.CloseTimeout = New TimeSpan(0, 30, 0)
_CrmDeployService.Endpoint.Binding.OpenTimeout = New TimeSpan(0, 30, 0)
_CrmDeployService.Endpoint.Binding.ReceiveTimeout = New TimeSpan(0, 30, 0)
_CrmDeployService.Endpoint.Binding.SendTimeout = New TimeSpan(0, 30, 0)
The above code is used just for initialization of the service. Later on when i call a method using
_CrmDeployService object , everything works fine over http but not over https
Please tell what can i do to communicate to the HTTPS secured Deployment service without using any client certificate. (SSL certificate from DigiCert is already installed on the server and website can be browsed over SSL in any web browser. What other certificate do i need and why?)
Also IIS settings have been done as needed. WCf service is browesable over SSL/https via web browser.) I have tried anonymous authentication as well as authentication via a domain user at the server and handled the same in code as well.
Is there any configuration change that i need to make? Is this a WCF specific issue?. I have tried solutions posted on stackoverflow as well as over msdn but to no avail. I cannot change the server's web.config and i must not use a client certificate but i can use any credentials required for authentication and i must achieve it over SSL. Please help. Thanks
SSL means it will gonna need the certificate. First check by making any example app to check if the WCF is working with ssl or not , because only then it can be assured that the CRM servers is the problem (it is looking for certificate) or worse you failed earlier by the WCF before reaching that point . If WCF is failing you then you have to create a temporary certificate for it .There are plenty help code at the internet here is one to get you started.
http://msdn.microsoft.com/en-us/library/ff648498.aspx
and in your application, use the following binding (play around with the different transport/message security modes if you like):
<basicHttpBinding>
<binding name="basicHttp">
<security mode="TransportWithMessageCredential" >
<transport/>
<message clientCredentialType=”UserName”/>
</security>
</binding>
</basicHttpBinding>
also you have to configure iis. You have to enable https in iis and also assign the certificate i think it is in Directory Security | Server Certificate.
and if it is a silverlight application then it will need some more extra development.
Happy coding Machpanel:)

Silverlight - WCF Enable Binary Encoding

I have a WCF service that is returning a lot of data. I want to compress that information so I thought that using BinaryEncoding would be appropriate.
Currently, I have a binding setup in my web.config as follows:
<binding name="myCustomBinding" closeTimeout="00:05:00" openTimeout="00:05:00"
receiveTimeout="00:05:00" sendTimeout="00:05:00">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="8388608" maxBufferSize="8388608">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
In my ServiceReferences.clientconfig file, I have the following binding settings:
<binding name="CustomBinding_MyService">
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
Oddly, this configuration will not work. As soon as I remove the <binaryMessageEncoding /> line from the web.config, everything works fine.
My question is, how do I use binary message encoding? Is there something I need to configure in my ServiceReferences.clientconfig?
Thank you
Can you define "will not work"?
Note that the client and server must agree; Silverlight has only a limited subset of extension points, but it seems that <binaryMessageEncoding/> is supported (source and more info) - so perhaps add it to the client?