I am trying to create a WCF service that uses certificate authentication over SSL to create a Business to Business gateway. I have created a CA and a client certificate and put them in the Trusted root and personal folders respectively. I have set up the SSL routing but I keep getting the following error ‘The security protocol cannot verify the incoming message.’ And I can’t figure out why.
Below is my service configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<services>
<service name="B2BGateway.SSOBackChannel" behaviorConfiguration="B2B">
<endpoint binding="wsHttpBinding"
bindingConfiguration="WSCertificateSecurity"
contract="B2BGateway.Contracts.ISSOBackChannel"
address="https://blah.com/SSOBackChannel.svc"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="B2B">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<serviceCertificate />
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" />
</clientCertificate>
</serviceCredentials>
<serviceAuthorization principalPermissionMode="None"></serviceAuthorization>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="B2B">
<clientCredentials>
<clientCertificate findValue="2e2ecba0f33265085cc53cb53c0b00977aaa9e9e" storeName="My" storeLocation="LocalMachine" x509FindType="FindByThumbprint" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSCertificateSecurity">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
<system.diagnostics>
<sources>
<!-- See here for recommended diagnostics settings: http://msdn.microsoft.com/en-us/library/aa702726.aspx -->
<source name="System.ServiceModel" switchValue="Warning,Information,ActivityTracing,Verbose" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="d:\logs\gah.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.webServer>
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
And the client configuration is just the autogenerated code:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ISSOBackChannel" 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 ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://blah.com/SSOBackChannel.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISSOBackChannel"
contract="SSOBackChannelService.ISSOBackChannel" name="WSHttpBinding_ISSOBackChannel" />
</client>
</system.serviceModel>
</configuration>
I wrote a unit test to see if the thing works which is where I’m getting the error...
[TestMethod]
public void Should_Call_Service_As_Machine_Does_Have_x509Certificate()
{
SSOBackChannelClient service = new SSOBackChannelClient();;
service.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "2e2ecba0f33265085cc53cb53c0b00977aaa9e9e");
var result = service.CheckBackChannelToken("123456789");
}
Any help would be so greatly appreciated!!
Josh
You are using wsHttpBinding but you havent specified the certificate it needs to use to secure your transport channel. Try to specify a certificate it needs to use. i.e. for SSL
Also try enabling tracing on your service. See here how to enable tracing.
Related
In my project I recently changed my WCF service to use Https. It is configured to be a mutual ssl setup and the client and server certificates are both installed appropriately. Server side looks fine and even started fine in the browser as shown below.
However, when trying to configure the service reference from the WPF client side (service proxy that was previously added and generated). I get a 403 forbidden error code as shown below. Any idea why?
Here are my configurations.
WCF Server Side Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<serviceCertificate storeLocation="LocalMachine" x509FindType="FindByIssuerName" findValue="QuickFire Root Authority" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="PushNotification_SignalR_PoC.WCF.PushNotificationService">
<endpoint binding="wsHttpBinding" bindingConfiguration="MutualSslLargeMessageBinding" contract="PushNotification_SignalR_PoC.WCF.IPushNotificationService" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MutualSslLargeMessageBinding" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport">
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
</wsHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
WPF Client Side Config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WsHttpBinding_IPushNotificationService"
closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:30:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://localhost:44367/PushNotificationService.svc"
binding="wsHttpBinding" bindingConfiguration="WsHttpBinding_IPushNotificationService"
contract="ServiceProxy.IPushNotificationService" name="WsHttpBinding_IPushNotificationService" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="MutualSslBehavior">
<clientCredentials>
<clientCertificate storeLocation="CurrentUser" x509FindType="FindBySubjectName" findValue="QuickFire Test Client"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
If we want to call the service by adding service reference, we should add the MEX endpoint in the service endpoints on the server side. It could exchange metadata of the service over all platforms.
Like below,
<services>
<service name="PushNotification_SignalR_PoC.WCF.PushNotificationService">
<endpoint binding="wsHttpBinding" bindingConfiguration="MutualSslLargeMessageBinding" contract="PushNotification_SignalR_PoC.WCF.IPushNotificationService" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"></endpoint>
</service>
</services>
For details,
https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/how-to-configure-a-custom-ws-metadata-exchange-binding
Feel free to let me know if there is anything I can help with.
I'm having an interesting issue setting up a WCF service message credential security. I'm getting this exception on my client side:
An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll
Additional information: The service certificate is not provided for target 'http://myMachine/SPTestService/Service1.svc'. Specify a service certificate in ClientCredentials.
This leads me to believe that I need to specify a server cert in my client config, but I'm not sure why. This should be using ChainTrust. Interestingly enough, when I switch it over to TransportWithMessageCredential (so it's working over SSL), it works, and correctly verifies the message credential as well. Is this a WCF bug? Fortunately, TransportWithMessageCredential was where I was heading, so I'll accelerate that process.
Using only Message credential, my configs look like this:
Client:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="serviceBehavior">
<clientCredentials>
<clientCertificate storeName="My" storeLocation="LocalMachine"
findValue="CN=myCert" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="serviceEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Message">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://myMachine/SPTestService/Service1.svc"
behaviorConfiguration="serviceBehavior"
binding="basicHttpBinding" bindingConfiguration="serviceEndpoint"
contract="ServiceReference2.IService1" name="serviceEndpoint" />
</client>
</system.serviceModel>
</configuration>
Service:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="serverBinding" messageEncoding="Mtom">
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
<serviceCredentials>
<serviceCertificate storeName="My" storeLocation="LocalMachine" findValue="CN=myCert" />
<clientCertificate>
<authentication revocationMode="NoCheck"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="serviceBehavior" name="SPTestService.Service1">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="serverBinding" name="serviceEndpoint" contract="SPTestService.IService1" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
Using TransportWithMessage, my configs look like this:
Client:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="serviceBehavior">
<clientCredentials>
<clientCertificate storeName="My" storeLocation="LocalMachine"
findValue="CN=myCert" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="serviceEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://myMachine/SPTestService/Service1.svc"
behaviorConfiguration="serviceBehavior"
binding="basicHttpBinding" bindingConfiguration="serviceEndpoint"
contract="ServiceReference2.IService1" name="serviceEndpoint" />
</client>
</system.serviceModel>
</configuration>
Service:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="serverBinding" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
<serviceCredentials>
<serviceCertificate storeName="My" storeLocation="LocalMachine" findValue="CN=myCert" />
<clientCertificate>
<authentication revocationMode="NoCheck"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="serviceBehavior" name="SPTestService.Service1">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="serverBinding" name="serviceEndpoint" contract="SPTestService.IService1" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
I am developing a WCF service that will be called by customer in internet. The service is hosted in IIS7 and accept only http. For clients call us from https we do is have a reverse proxy that forwards the request to the application https to http. The customer give a https url to connect and does so smoothly, adding the reference to the service properly. The problem comes when trying to create a client and add in your endpoint https and execute it, as it reads:
System.ArgumentException: The provided URI scheme 'https' is invalid,
expected 'http'. Parameter name: via.
I leave part of the service's web.config:
<bindings>
<wsHttpBinding>
<binding name="ConfigEP">
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
<baseAddressPrefixFilters>
<add prefix="http://serverInterno/App/"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
<services>
<service behaviorConfiguration="App.AppM_NameBehavior" name="App.AppM_Name">
<endpoint address="" behaviorConfiguration="App.AppM_NameEPBehavior" binding="wsHttpBinding" bindingConfiguration="ConfigEP" name="App.AppM_NameEP" bindingNamespace="http://siteName/AppM_Name" contract="App.IAppM_Name" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="App.AppM_NameEPBehavior">
<wsdlExtensions location="https://urlsegura/App/Appm_Name.svc" singleFile="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="App.AppM_NameBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceCredentials>
<clientCertificate>
<authentication customCertificateValidatorType="App.Validador, App" certificateValidationMode="Custom" />
</clientCertificate>
<serviceCertificate findValue="XX XX XX XX XX XX XX XX XX XX" x509FindType="FindBySerialNumber" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="wsdlExtensions" type="WCFExtras.Wsdl.WsdlExtensionsConfig, WCFExtras, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
and here the client's app.config:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior">
<clientCredentials>
<clientCertificate findValue="XX XX XX XX XX XX XX XX XX XX" x509FindType="FindBySerialNumber" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="App.AppM_NameEP" 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 ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="Message">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://urlsegura/App/Appm_Name.svc" binding="wsHttpBinding" bindingConfiguration="App.AppM_NameEP" contract="App.IAppM_Name" name="App.AppM_NameEP">
<identity>
<certificate encodedValue="XXXX" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Thanks in advance.
Best regards.
I think your error is being caused because you're using message based security on your configuration. Try changing it to Transport instead (in both the client and service configuration files), so that it uses SSL for security rather than encrypting the message.
You can use TransportWithMessageCredential if you absolutely must have the message encrypted also. Hope that helps.
I don't understand the reverse proxy you describe but it seems you're trying to support access from both HTTP & HTTPS. To do this, you will need to add a second endpoint. You'd configure the service something like this:
<wsHttpBinding>
<binding name="ConfigEP">
<security mode="Message">
<message clientCredentialType="Certificate" />
</security>
</binding>
<binding name="ConfigEPHttps">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
and this add the new endpoint:
<service behaviorConfiguration="App.AppM_NameBehavior" name="App.AppM_Name">
<endpoint address="" behaviorConfiguration="App.AppM_NameEPBehavior"
binding="wsHttpBinding"
bindingConfiguration="ConfigEP"
name="App.AppM_NameEP"
bindingNamespace="http://siteName/AppM_Name"
contract="App.IAppM_Name" />
<endpoint address="secure" behaviorConfiguration="App.AppM_NameEPBehavior"
binding="wsHttpBinding"
bindingConfiguration="ConfigEPHttps"
name="App.AppM_NameEPHttps"
bindingNamespace="http://siteName/AppM_Name"
contract="App.IAppM_Name" />
</service>
You also need make this change to get the WSDL over HTTPS:
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
I have made a wcf application, and a client. WCF app. have to know what user and password had accessed the service operation. That is what i done:
Server web config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Auth">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceMetadata httpGetEnabled="true"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
<serviceCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="Auth" name="Service">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="IService"/>
</service>
</services>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>
Client config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService" 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 ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="WcfClient" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" />
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://localhost:30341/WCFAuthTest/Service.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService"
contract="Service.IService" name="WSHttpBinding_IService" behaviorConfiguration="CustomBehavior">
<identity>
<dns value="WcfServer" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
How i generated certificates: http://www.codeproject.com/KB/WCF/9StepsWCF.aspx
Service operation:
public string TestAccess()
{
return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
}
Client:
ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "Admin";
client.ClientCredentials.UserName.Password = "123";
Console.WriteLine(client.TestAccess());
Console.ReadLine();
And program must return Admin but it doesn't:
http://img27.imageshack.us/img27/3104/returnz.png
I know that i have to change the clientCredentialType to UserName, but it gaves me an error
If you want to pass user name and password you must set client credential type to UserName. Setting it to certificate is for using client certificates. Here is some how to article.
These scenarios work in their pieces. Its when i put it all together that it breaks.
I have a WCF service using netTCP that uses impersonation to get the callers ID (role based security will be used at this level)
on top of this is a WCF service using basicHTTP with TransportCredientialOnly which also uses impersonation
I then have a client front end that connects to the basicHttp.
the aim of the game is to return the clients username from the netTCP service at the bottom - so ultimatley i can use role based security here.
each service is on a different machine - and each service works when you remove any calls they make to other services when you run a client for them both locally and remotley. IE the problem only manifests when you jump accross more than one machine boundary.
IE the setup breaks when i connect each part together - but they work fine on their own.
I also specify
[OperationBehavior(Impersonation = ImpersonationOption.Required)] in the method and
have IIS setup to only allow windows authentication (actually i have ananymous enabled still, but disabling makes no difference)
This impersonation works fine in the scenario where i have a netTCP Service on Machine A with a client with a basicHttp service on machine B with a clinet for the basicHttp service also on machine B ... however if i move that client to any machine C i get the following error:
The exception is 'The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:10:00''
the inner message is 'An existing connection was forcibly closed by the remote host'
Am beginning to think this is more a network issue than config ... but then im grasping at straws ...
the config files are as follows (heading from the client down to the netTCP layer)
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBindingEndpoint" closeTimeout="00:02:00"
openTimeout="00:02:00" receiveTimeout="00:10:00" sendTimeout="00:02:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://panrelease01/WCFTopWindowsTest/Service1.svc"
binding="basicHttpBinding" bindingConfiguration="basicHttpBindingEndpoint"
contract="ServiceReference1.IService1" name="basicHttpBindingEndpoint"
behaviorConfiguration="ImpersonationBehaviour" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ImpersonationBehaviour">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
the service for the client (basicHttp service and the client for the netTCP service)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTcpBindingEndpoint" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288"
maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
<message clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
<basicHttpBinding>
<binding name="basicHttpWindows">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"></transport>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="net.tcp://5d2x23j.panint.com/netTCPwindows/Service1.svc"
binding="netTcpBinding"
bindingConfiguration="netTcpBindingEndpoint"
contract="ServiceReference1.IService1"
name="netTcpBindingEndpoint"
behaviorConfiguration="ImpersonationBehaviour">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ImpersonationBehaviour">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation" allowNtlm="true"/>
</clientCredentials>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="WCFTopWindowsTest.basicHttpWindowsBehaviour">
<!-- 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" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WCFTopWindowsTest.Service1"
behaviorConfiguration="WCFTopWindowsTest.basicHttpWindowsBehaviour">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="basicHttpWindows"
name ="basicHttpBindingEndpoint"
contract ="WCFTopWindowsTest.IService1">
</endpoint>
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
then finally the service for the netTCP layer
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<authentication mode="Windows"></authentication>
<authorization>
<allow roles="*"/>
</authorization>
<compilation debug="true" targetFramework="4.0" />
<identity impersonate="true" />
</system.web>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="netTCPwindows">
<security mode="Transport">
<transport clientCredentialType="Windows"></transport>
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service behaviorConfiguration="netTCPwindows.netTCPwindowsBehaviour" name="netTCPwindows.Service1">
<endpoint address="" bindingConfiguration="netTCPwindows" binding="netTcpBinding" name="netTcpBindingEndpoint" contract="netTCPwindows.IService1">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mextcp" binding="mexTcpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:8721/test2" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="netTCPwindows.netTCPwindowsBehaviour">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="false" />
<!-- 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" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
If you need to make a more than one hop, you're going to need to enable delegation for that occur. You can get more information on that here.
That being said, if all you need to do is determine the role of a user that calls the backend service (netTcp), you don't necessarily need impersonation as the TokenImpersonationLevel of the WindowsIdentity should only need to be Information in order to determine role membership. In this case, you would only need to ensure impersonation was taking place in the middle-tier (basicHttp).