Reputation: 6222
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();
Upvotes: 1
Views: 849
Reputation: 73253
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.
Upvotes: 1