WCF Security Authentication with https and validation - c#

I try to understand how authentication in WCF works. There is a self-hosting service with https endpoint which is bound to one of my certificates. Everything works fine when
security mode="None"
then it works fine even on different machines. Same situation with
mode="Transport" and <transport clientCredentialType="None"/>
. When I try to add validation by UserName it works fine but only on localhost, when hosted on different machines I receive an error:
"An unsecured or incorrectly secured fault was received from other
party..."
Why doesn't it work with UserName password validation?
EDIT2: I Found that following exception is thrown on the server and catched(but only while on different machines) :"The security timestamp is invalid because its creation time ('2014-11-29T01:30:48.824Z') is in the future. Current time is '2014-11-28T14:51:52.704Z' and allowed clock skew is '00:05:00'.". I don't know where was this creation time taken, but surely not from another machine. What happens?
Second question is about certificates. When hosting https and bind address to certificate, should this certificate be installed on client machine as trusted? (I bind it with netsh)
Without following code I cannot connect to my wcf service:
System.Net.ServicePointManager.ServerCertificateValidationCallback =
((sender, certificate, chain, sslPolicyErrors) => true);
Is it certificate validation on client side? It checks if it exists and if it is issued by trusted issuer?
EDIT:
Additional question:
When I try to enter service secured endpoint with browser, it says this connection is not secure, not trusted source etc. On my service machine I have bound certificate to https and that certificate is MyCertificate which is issued by "CertificateIssuer". Now I installed into Service and Client machine that issuer certificate - I mean "CertificateIssuer" into Trusted Root Certification Authorities" and still I am not trusted event when I enter from the same machine. How should I configure it to be trusted?
Server config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true"/>
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="SdrConfigExample.e2e"/>
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<services>
<service name="WcfService1.TestService" behaviorConfiguration="ServiceUsernameValidation">
<host>
<baseAddresses>
<add baseAddress="https://localhost:8734/Services/"/>
<add baseAddress="http://localhost:8735/Wsdl/"/>
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="Test" binding="basicHttpBinding" contract="WcfService1.ITestService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpsGetEnabled="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="False"/>
</behavior>
<behavior name="ServiceUsernameValidation">
<serviceMetadata httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfSecurity.PasswordValidator,WcfSecurity"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Client config:
<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="SdrConfigExample.e2e"/>
</listeners>
</source>
</sources>
</system.diagnostics>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITestService">
<security mode="TransportWithMessageCredential" >
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://175.28.233.153:8734/Services/Test" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ITestService" contract="ServiceReference1.ITestService"
name="BasicHttpBinding_ITestService" />
</client>
</system.serviceModel>
</configuration>
Server code:
ServiceHost host = new ServiceHost(typeof(TestService));
var uri = host.Description.Endpoints[0].Address.Uri;
var cert = FindCertificate("CN=MyCertificate");
if (!ReserveAddressForHttps(uri.Host, uri.Port, cert, 5000))
{
throw new Exception("Failed to assign service certificate into local interface.");
}
host.Open();
host.Description.Endpoints.ToList().ForEach(x => Console.WriteLine(x.Address));
Console.WriteLine();
Console.WriteLine("Service started...");
Console.ReadLine();
host.Close();
Client code:
TestServiceClient client = new TestServiceClient();
client.ClientCredentials.UserName.UserName = "hej";//this is valid
client.ClientCredentials.UserName.Password = "hej";
System.Net.ServicePointManager.ServerCertificateValidationCallback =
((sender, certificate, chain, sslPolicyErrors) => true);
try
{
var result = client.GetData(123);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();

The purpose of the Security Timestamp is to guard against "Replay Attacks"
In your case, the creation date (set on the client) is nearly 12 hours after the date on the server. The most obvious explanation is that one of the clocks is set incorrectly.
Replay attack detection can be disabled, which isn't a security risk as requests have to be signed anyway to benefit from it.
Regarding the certificates, the procedure for installtion is documented on TechNet - note you can view whether the certificate has been installed correctly:
If you want to verify the Certificate has been installed you can load
the certificates snap in and you should see it under Certificates
–Current User-Trusted Root Certification Authorities-Certificates.
Once your browser trusts the certificate, your WCF client will too.

Related

WCF client NTLM authentication returns 500

I have a problem with WinForms application connecting to WCF service using NTLM authentication.
<LongStory-optional>
Original application was written by me in 2005 as my first C# code. With small modifications it worked well. Web service was asmx with DataSets. Recently a time has come to upgrade it because of: performance issues and Windows 10 upgrade on client (Crystal Reports 10.5.37 upgrade was required to x64 and there is no official runtime download on SAP site).
I've rewrote it using WCF, .NET 4.8, replacing Crystal with library to create Excel files. In developer environment new version works well except 500 code. Rest and .NET Core was not considered (too difficult to explain; not technical reasons).
When user launched new version first immediate problem was "Access denied". Then it was started as administrator. Error code: "The application has failed to start because its side-by-side configuration is incorrect". Then I've tried to get more info in Event Viewer without success: there was no information. sxstrace tool raised access denied. After few days I've got it: I made a comment in config file containing national non-English characters. After removing comment an error 500 during connection has occured.
<\LongStory-optional>
Application makes a call to Verify service which just returns constant value 1.
Error message: "The content type text/html of the response message does not match the content type of the binding (text/xml; charset=utf-8).
If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 75 bytes of the response were:
The page cannot be displayed because an internal server error has occurred." .
Https was not used.
Strange thing is that after opening .svc once in IE the error have disappeared until workstation reboot. This proves that client and server are working correctly. In the same time old application doesn't have such an issue. Because of that I've tried to use "Web reference" instead of "Service reference". It appears that "Web reference" works correctly. Next thing I've tried different settings on the client side. I've found that "Service reference" works after this change: client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
With fiddler tool I've found that messages exchange are almost the same except final result: before change I have statuses 401/401/500, after change 401/401/200, the other differences are time and NTLM base64 value, nothing else.
I think that it is not a solution but only a workaround. Do you know how to handle correctly NTLM authentication with WCF?
Essential bits of my code and configuration:
var client = new ServiceClient();
client.ClientCredentials.Windows.ClientCredential.UserName = Dialog1.textBox1.Text;
client.ClientCredentials.Windows.ClientCredential.Domain = Dialog1.textBox2.Text;
client.ClientCredentials.Windows.ClientCredential.Password = Dialog1.textBox3.Text;
try
{
i = client.Verify().Status;
} ...
Configuration:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicEndpoint" sendTimeout="infinite" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://wro67zt2/AlsbWebServices/WindService/WindService.svc" binding="basicHttpBinding" bindingConfiguration="basicEndpoint" contract="WindService.IService" name="basicEndpoint"/>
</client>
</system.serviceModel>
I regard that server side configuration is unnecessary. It works well with Web reference so I can assume that everything is ok here. I've tried "Windows" instead "Ntlm" but problem remains the same, it changes string NTLM to Negotiate in request/response messages and also number of messages from 3 to 2 (401/500 or 401/200).
Edit - server configuration:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
<globalization culture="en-GB" requestEncoding="utf-8" responseEncoding="utf-8"/>
<pages controlRenderingCompatibilityVersion="4.0" clientIDMode="AutoID"/>
<identity impersonate="false" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicBinding" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" realm="XXXXX"/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="WindService.Behavior" name="WindLibrary.Service">
<endpoint
address=""
binding="basicHttpBinding"
bindingConfiguration="basicBinding"
name="basicEndpoint"
bindingNamespace="http://XXXXX.com/services/prime/"
contract="WindLibrary.IService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WindService.Behavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" bindingConfiguration="HttpBinding" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>

Deploying a WebForms with WCF inside to IIS 8, doesn't start WCF

I have a VisualStudio solution with WebForms (called EDWMS) & WCF projects (called EDWMS.SYNC) inside. WCF is added as Service Reference to WebForms project by using Discover function. When running it locally in "release" mode, the WCF gets called correctly from app & works fine (though I need to run VS as Administrator for it to work).
But when publishing the webforms project to IIS 8 both via Web Deploy Package & FTP Publish, WCF doesn't seem to get published.
I tried to create WCF as a separate Site in IIS, then setting WCF project as "Startup project" in VS & publishing it to new site slot, also adding it's port to the site bindings. In this case I can browse .svc file & see that it's set up You have created a service. To test this service, you will need.... But when I call it from WebForms app it still fails to respond with this error:
There was no endpoint listening at http://localhost:8733/Design_Time_Addresses/ED_WMS.SYNC/Sync/ that could accept the message. This is often caused by an incorrect address or SOAP action.
The remote server returned an error: (404) Not Found.
This is code from WebForms app which calls WCF:
var client = new SyncClient("BasicHttpBinding_ISync");
client.InnerChannel.OperationTimeout = new TimeSpan(2, 00, 0);
var message = string.Empty;
try
{
var syncResult = new SyncResult();
syncResult = client.GetInventory(1, 2, 3);
message += $"Sync Result<hr/>Added: {syncResult.ItemsAdded}<br/>Updated: {syncResult.ItemsUpdated}<br/>Duration: {syncResult.Duration}";
((ICommunicationObject)client).Close();
}
catch (System.Exception ex)
{
(client as ICommunicationObject)?.Abort();
message += $"Error<hr/>{ex?.Message ?? "null"}<hr/>{ex?.InnerException?.Message ?? "null"}";
}
inventoryItemsLbl.Text = message;
This is my WebForms Web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>...</connectionStrings>
<appSettings>...</appSettings>
<system.web>
<authentication mode="Forms">
<forms loginUrl="Login.aspx" timeout="2880" />
</authentication>
<compilation targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" executionTimeout="900" />
<pages>...</pages>
</system.web>
<system.webServer><modules>...</modules></system.webServer>
<runtime>...</runtime>
<system.codedom><compilers>...</compilers></system.codedom>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
</serviceHostingEnvironment>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ISync" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/ED_WMS.SYNC/Sync/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISync"
contract="ServiceReferenceWMS.ISync" name="BasicHttpBinding_ISync" />
</client>
</system.serviceModel>
</configuration>
This is my WCF App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>...</configSections>
<entityFramework>...</entityFramework>
<runtime>...</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MobilityBeanSoapBinding" closeTimeout="02:00:00" openTimeout="02:00:00"
receiveTimeout="02:00:00" sendTimeout="02:00:00" maxReceivedMessageSize="100000000"
maxBufferSize="100000000" maxBufferPoolSize="100000000">
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://warehouse:8080/wmwebservice_ejb/MobilityBean" binding="basicHttpBinding" bindingConfiguration="MobilityBeanSoapBinding" contract="EdWmsReference.MobilityBean" name="MobilityRemotePort" />
</client>
<services>
<service name="ED_WMS.SYNC.Sync" behaviorConfiguration="MyServiceTypeBehaviors">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/ED_WMS.SYNC/Sync/" />
</baseAddresses>
</host>
<endpoint name="basicHttpEndpoint" address="" binding="basicHttpBinding" contract="ED_WMS.SYNC.ISync" bindingConfiguration="MobilityBeanSoapBinding"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors" >
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
When you move from DEV -> Production( when the WCF app is now hosted in IIS), the design time URL changes, you would need to set the correct designTime URL in your webforms app now.
A few options are available, but they all point to changing the URI that is associated with the service
client.Endpoint.Address = new EndpointAddress(Server.IsLiveServer() ?
#"LiveUrl" : #"TestURl");
Where the TestURI is the designTime URL, and the LiveURL is the production URL. The IsLiveServer is just a boolean to check if you are in dev or production.
The other way you can go about it is to just to create a Realease vs a Debug webconfig, the release will have the URL of the deployed App, then set the client Endpoint using an appSetting or something similar
The third option would require using the IIS Administration DLL to query the hosted website and findout the URL of the WCF service and use that in your webforms.

Hosting WCF Service within WinForm Application doesn't work when running the application executable

Over the past few weeks I have developed a 64-bit WinForms application that needs to communicate with a 32-bit DLL (job specs require it).
After doing some reading around the internet and finding out that there is not going to be any fun way of doing this, I decided to go with hosting a WCF Service Application within my WinForms application for communicating to the 32-bit DLL... or so I thought I was doing.
During development (while running within Visual Studio) it has been working really well, but of course, now that I need to deploy, I am running into problems. I am having trouble getting a strong enough understanding of WCF Services to know if I am going about this in a terrible way or if I am just missing some minute detail.
I created the project as Admin. After development was finished I tried to run the WinForm executable (both debug and release), WindowsFormsApplication1.exe. The application started up, but after I tried to complete a task involving the use of the WCF service, an exception was thrown:
This has led me to believe that Visual Studio was doing the hosting of the service during development instead of the WinForm application, or my configs and/or directory structures are incorrect.
[UPDATED] WCF Service Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" maxRequestLength="2147483647"/>
</system.web>
<system.net>
<defaultProxy>
<proxy usesystemdefault="False"/>
</defaultProxy>
</system.net>
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource"
switchValue="Information, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\logs\Traces.svclog" />
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics wmiProviderEnabled="true">
<messageLogging
logEntireMessage="true"
logMalformedMessages="true"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true"
maxMessagesToLog="3000"
/>
</diagnostics>
<behaviors>
<serviceBehaviors>
<behavior name="metadadiscovery>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="ServiceReference1.Service1" behaviorConfiguration="metadadiscovery">
<endpoint address="" binding="basicHttpBinding" contract="ServiceReference1.IService1"></endpoint>
</service>
</services>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>
WinForm App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService2" />
<binding name="BasicHttpBinding_IService3" />
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:45053/Service2.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService2" contract="ServiceReference2.IService2"
name="BasicHttpBinding_IService2" />
<endpoint address="http://localhost:46351/Service3.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService3" contract="ServiceReference3.IService3"
name="BasicHttpBinding_IService3" />
<endpoint address="http://localhost:44848/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1"
name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
<appSettings>
<add key="ClientSettingsProvider.ServiceUri" value="" />
</appSettings>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
</providers>
</roleManager>
</system.web>
</configuration>
Directory Where EXE resides:
The directory containing the WCF Service resides within the directory WcfService1 from the image above.
I have mostly been using the following method of instantiating the service:
ServiceReference1.Service1Client = new ServiceReference1.SErvice1Client();
Once I tried to switch to using a service host (below), but when I used that method, the service would timeout whenever it tried to communicate to the DLL.
Uri address = new Uri("http://localhost:44848/Service1.svc");
ServiceHost host = new ServiceHost(typeof(ServiceReference1.Service1Client), address);
host.Open();
And then I closed the host later. At this point, I am willing to try anything to get this working.
[EDIT] Below is the code of my WindowsFormsApplication1.exe.config file. All three contracts are giving the warning that they're "invalid according to its datatype 'clientContractType'". I think this could be the source of my problems, but I do not know why it is showing this warning:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService2" />
<binding name="BasicHttpBinding_IService3" />
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:45053/Service2.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService2" contract="ServiceReference2.IService2" name="BasicHttpBinding_IService2" />
<endpoint address="http://localhost:46351/Service3.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService3" contract="ServiceReference3.IService3" name="BasicHttpBinding_IService3" />
<endpoint address="http://localhost:44848/Service1.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>
Thank you for any help and guidance you can provide.
There is no endpoint configured for your service.
<behaviors>
<serviceBehaviors>
<behavior name="metadadiscovery">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<service name="ServiceReference2.Yourimplementingservice" behaviorConfiguration="metadadiscovery">
<endpoint address="" binding="basicHttpBinding" contract="ServiceReference2.IService2">
</endpoint>
Above I have configured for Service2 ,similarly you have to configure for Service1 and Service3.
After sufficient struggling I decided to get rid of the WCF service that visual studio generates for you when you create it as a new project. I instead followed this tutorial verbatim:
Hosting Service In App
Doing this came with huge advantages:
No configuration file was necessary
Running it this way must've gotten rid of a large amount of overhead because the communication to the DLL (what I am using the service for) used to take several seconds to do large amounts of calls to the DLL, but now is able to handle 10k+ calls in the blink of an eye.
No service reference is necessary. I just needed the file for my main function, the file containing the service function implementations and the file containing the interface for the implementation.
So far, this has been the easiest and most robust way I have found for using a 32 bit DLL in a 64 bit application. Let me know if I can give any guidance for anyone else who may be struggling with this problem. I know this is not a fun thing to deal with if you've never done anything like it before.

WCF with Kerberos Authentication: The request for security token could not be satisfied because authentication failed

I am attempting to perform Kerberos authentication from a Client App (Windows Forms) to a WCF Web Service on one Windows 2008 R2 server running under IIS, which in-turn calls another WCF service running on another Windows 2008 R2 server also running under IIS. I've seen this referred to this as a Kerberos Double-Hop Authentication.
When I locate the two web services on the same Windows 2008 R2 server then our double-hop authentication works fine. However, when we move the second WCF service to a different server the authentication fails between the two web services. I do not know what causes this problem which may be a configuration issue, or something in our server/network set-up. Client and servers all exist in the same domain.
Here is more detail of what I have done so far. I've tried many of the suggestions in other related topics/questions about this issue, but no joy so far.
I have created a Windows Form client application that connects to a
WCF web service (I will refer to this as the Middle service), and
return the user name of the logged in user to the client app from the
service.
In the client app.config (see below) we have specified 'Windows'
authentication (pls see below for config).
The Middle service runs on our server 'SERVER1'.
The Middle service returns the User Name fine to the client app,
therefore the Middle service authentication must be working fine.
I have another method in the Middle service that calls another WCF
web service (I will refer to this second service as the End service),
and again Windows authentication is specified on the binding from
Middle service to End service. If I locate the End service on the
same server as the Middle service then again authentication works as
expected, and the User name for the logged in user (ie: me) is
returned to the client app from the End service, via the Middle
service. However, if I locate the End service on a different server
(SERVER2) the authentication (double hop) fails, 'Inner exception:The
request for security token could not be satisfied because
authentication failed.'
The Client app, Middle service and End service all exist in the same
Domain (MYDOMAIN).
I am using a service account (MYDOMAIN\MY-HOST_ACCOUNT) to run both
Middle and End service, and created a Service Principal Name (SPN)
for this called 'HTTP/SERVER1.int.mydomain.com'. I have also trusted
this service account, and the computer/machine 'SERVER1' for Kerberos
delegation in Active Directory (Trust this user/computer for
delegation to any service). The Bindings use 'Message' security mode
and this is specified in the Web Service bindings.
I have included the Client app.config and both Web Service
web.configs (pls see below).
I have tried a variety of different config settings, and these
current settings work fine when the services are located on the same
server, but the error occurs when the services are on different
servers. I have tried both 'true' and 'false' for
'negotiateServiceCredential', but believe this needs to be 'true'. I
get a different error message when this is set to false (The
authentication modes using Kerberos do not support the impersonation
level 'Delegation'. Specify identification or impersonation).
Hopefully someone who has dealt with 'double hop' WCF Kerberos authentication before may recognise this issue and be able to assist me.
Many thanks
CLIENT APP CONFIG
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IMiddleService">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="DelegationBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://SERVER1/KerberosMiddleService/MiddleService.svc"
behaviorConfiguration="DelegationBehavior" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMiddleService" contract="KerberosMiddleService.IMiddleService"
name="WSHttpBinding_IMiddleService">
<identity>
<servicePrincipalName value="HTTP/SERVER1.int.mydomain.com"/>
<userPrincipalName value="MYDOMAIN\MY-HOST_ACCOUNT#int.mydomain.com"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
MIDDLE SERVICE WEB CONFIG
<?xml version="1.0"?>
<configuration>
<appSettings/>
<system.web>
<compilation targetFramework="4.0"/>
<httpRuntime/>
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IEndService">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" algorithmSuite="Default"/>
</security>
</binding>
<binding name="WSHttpBinding_IEndService1">
<security mode="Message">
<message clientCredentialType="Windows" negotiateServiceCredential="true" establishSecurityContext="true" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="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"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="DelegationBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://SERVER2/endservice/endservice.svc"
behaviorConfiguration="DelegationBehavior" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IEndService" contract="KerberosEndService.IEndService"
name="WSHttpBinding_IEndService">
</endpoint>
<endpoint address="http://SERVER1/kerberosendservice/endservice.svc"
behaviorConfiguration="DelegationBehavior" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IEndService1" contract="BT01_KerberosEndService.IEndService"
name="WSHttpBinding_IEndService1">
</endpoint>
</client>
<protocolMapping>
<add binding="wsHttpBinding" scheme="http"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
END SERVICE WEB CONFIG
<?xml version="1.0"?>
<configuration>
<appSettings/>
<system.web>
<customErrors mode="Off"/>
<compilation targetFramework="4.0"/>
<httpRuntime/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme="http"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
A SECTION OF THE WCF STACK TRACE
<ExceptionString>System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service. ---&gt; System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
--- End of inner exception stack trace ---</ExceptionString><InnerException><ExceptionType>System.ServiceModel.FaultException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>The request for security token could not be satisfied because authentication failed.</Message><StackTrace> at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)</StackTrace><ExceptionString>System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)</ExceptionString></InnerException></Exception></TraceRecord></DataItem></TraceData></ApplicationData></E2ETraceEvent><E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent"><System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system"><EventID>131075</EventID><Type>3</Type><SubType Name="Error">0</SubType><Level>2</Level><TimeCreated SystemTime="2015-03-02T21:04:14.4059347Z" /><Source Name="System.ServiceModel" /><Correlation ActivityID="{acfc80d6-b119-4f57-aaf2-65f1319b9fca}" /><Execution ProcessName="w3wp" ProcessID="1432" ThreadID="43" /><Channel/><Computer>SERVER1</Computer></System><ApplicationData><TraceData><DataItem><TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error"><TraceIdentifier>http://msdn.microsoft.com/en-NZ/library/System.ServiceModel.Diagnostics.ThrowingException.aspx</TraceIdentifier><Description>Throwing an exception.</Description><AppDomain>/LM/W3SVC/1/ROOT/KerberosMiddleService-6-130698038017642990</AppDomain><Exception><ExceptionType>System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>The caller was not authenticated by the service.</Message><StackTrace> at System.ServiceModel.Security.SspiNegotiationTokenProvider.GetNextOutgoingMessageBody(Message incomingMessage, SspiNegotiationTokenProviderState sspiState)
at System.ServiceModel.Security.IssuanceTokenProviderBase`1.GetNextOutgoingMessage(Message incomingMessage, T negotiationState)
at System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)</StackTrace><ExceptionString>System.ServiceModel.Security.SecurityNegotiationException: The caller was not authenticated by the service. ---&gt; System.ServiceModel.FaultException: The request for security token could not be satisfied because authentication failed.
at System.ServiceModel.Security.SecurityUtils.ThrowIfNegotiationFault(Message message, EndpointAddress target)
Ok, you need to add another SPN for the end service as well:
HTTP/SERVER2.int.mydomain.com MYDOMAIN\MY-HOST_ACCOUNT)
HTTP/SERVER2 MYDOMAIN\MY-HOST_ACCOUNT)
It is best to specify both FQDN and Netbios name. Ensure that you don't have duplicate SPN's otherwise Kerberos authentication wont work. Add the SPN's as delegation targets to the domain account (this might not be needed since you are using the same domain account for both servers).
Since the MiddleService needs to impersonate/delegate to the EndService, you need to give the domain account the privileges to do so using the local security policies - Local Policies - User Rights Assignment:
Act as part of the operating system
This user right allows a process to impersonate any user without authentication. The process can therefore gain access to the same local resources as that user.
Impersonate a client after authentication
Assigning this privilege to a user allows programs running on behalf of that user to impersonate a client.
Remember to change your IIS application settings to use the application pool credentials so that the domain account is used for authentication.

maxReceivedMessageSize on Azure WCF service is too small

Whenever I connect my client to send data to my WCF Azure service, I get this error:
"The maximum message size quota for incoming messages (65536) has been exceeded. To
increase the quota, use the MaxReceivedMessageSize property on the appropriate binding
element."
I've read everywhere about setting this MaxReceivedMessageSize property on both the client and server config files. I have done this.
However, whenever I update the service reference in the client, it pulls the settings back to the default of 65536. (found via investigating the .svcinfo file)
This leads me to conclude the issue must be on the service side.
I've placed this in my web.config file:
<bindings>
<basicHttpBinding>
<!--The basicHttpBinding is used for clients which use the generated code to transmit data; the following settings make it possible to send larger amounts to the service-->
<binding maxReceivedMessageSize="10000000" receiveTimeout="01:00:00">
<readerQuotas maxStringContentLength="10000000" />
</binding>
</basicHttpBinding>
</bindings>
Now, many posts talk about naming the binding and setting it in the service endpoints on the server side as well. Something like this:
<services>
<service name="YourNamespace.YourServiceClass">
<endpoint name="endpoint1"
address="http://server:8888/YourService.svc"
binding="basicHttpBinding"
bindingConfiguration="lageMessageTransfer"
contract="IYourServiceContract" />
</service>
</services>
However, I don't have these service endpoints and my service works great for small sizes.
Where else would this need to be set?
EDIT:
More information, Tim seems to be on the right track with the default endpoints. I am using a default endpoint. It seems that you cannot just explicitly define a service for that default endpoint. or if you can, I must be doing it incorrectly.
However, it seems that you can modify the binding on a default endpoint as stated by Richard. This is done by simply not specifying a name for the binding. I have tried setting the values on my service to much lower values to see if something else was lowering them, but they are completely ignored. Its as if the default endpoint is simply ignoring the binding that I have created.
For my entire config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData="logging.e2e" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="100" maxBufferSize="100" receiveTimeout="00:11:00">
<readerQuotas maxStringContentLength="100" />
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add scheme="http" binding="basicHttpBinding" />
</protocolMapping>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
<connectionStrings><EDITEDOUT></connectionStrings>
</configuration>
Thoughts on why the new binding settings are not being picked up?
The attribute name maxReceivedMessageSize is very explicit - it all depends on who is receiving the message - if you are sending a large amount of data then it is the service, if you are getting a large amount of data back from the service then it is the client. The service and client do not need the same value for this setting (unlike many other binding settings)
Setting an unnamed binding section should work in general as, of .NET 4, it configures the binding for anyone who doesn't explicitly specify a configuration using bindingConfiguration. However, in your example above you need to set the maxBufferSize in addition to the maxReceivedMessageSize as you are buffering rather than streaming the message. The maxBufferSize and maxReceivedMessageSize must be the same
You don't have the section in the Web.config on your service side? If you're using WCF 4.0 is it possible you're using a default endpoint?
I don't know if you can specify a binding for a default endpoint, but you might want to try specifying an endpoint via the section of the Web.config and setting bindingConfiguration to the binding specified in your section.

Categories

Resources