P
PaulJHurt
Guest
I've got some sample code I've written trying to get a WCF Client talking to a WCF Server (not hosted in IIS) in a request / reply scenario. But I need to do it using certificates for authentication instead of user name / password. My test works fine when the computers have the same user name and password, but fails when I change the passwords to be different.
I've tried several different ideas, and none have worked. Can someone please tell me what I am doing wrong.
Here is my sample code: The WCF request reply library (Service1.cs):
using System;
namespace Test2ServLib
{
public class Service1 : IService1
{
public CompositeTypeRsp GetDataUsingDataContract(CompositeTypeReq composite)
{
CompositeTypeRsp Rsp = new CompositeTypeRsp();
if (composite == null)
{
Rsp.Value = "Hello {null} from " + Environment.MachineName;
return Rsp;
}
Rsp.Value = "Hello " + composite.Value + " from " + Environment.MachineName;
return Rsp;
}
}
}
Interface contract (IService1.cs):
using System;
using System.Runtime.Serialization;
using System.ServiceModel;
namespace Test2ServLib
{
[ServiceContract]
public interface IService1
{
[OperationContract]
CompositeTypeRsp GetDataUsingDataContract(CompositeTypeReq composite);
}
[DataContract]
public class CompositeTypeReq
{
string stringValue = "Hello ";
[DataMember]
public string Value
{
get { return stringValue; }
set { stringValue = value; }
}
}
[DataContract]
public class CompositeTypeRsp
{
string stringValue = "Hello ";
[DataMember]
public string Value
{
get { return stringValue; }
set { stringValue = value; }
}
}
}
Test application (Can be both server and client, Hoster.cs)
using System;
using System.ServiceModel;
using System.Threading;
using System.Windows.Forms;
using Test2ServLib;
namespace Test2HostApp
{
public partial class Hoster : Form
{
public Hoster()
{
InitializeComponent();
textBox1.Text = Environment.MachineName;
}
private void StartServer_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(runHost);
}
private static bool bRunning = false;
private static object locker = new object();
private static string proto = "https";// <-- this line changes between tests
private void runHost(object state)
{
lock (locker)
{
if (bRunning)
{
MessageBox.Show("Host already running");
return;
}
bRunning = true;
}
Uri baseAddress = new Uri($"{proto}://localhost:2202/Test2ServLib/Service1/");
WSHttpBinding binding = new WSHttpBinding();
try
{
using (ServiceHost host = new ServiceHost(typeof(Service1), baseAddress))
{
host.Open();
MessageBox.Show("Host started");
while (bRunning == true)
{
Thread.Sleep(100);
}
host.Close();
MessageBox.Show("Host stopped");
}
}
catch (Exception ex)
{
MessageBox.Show($"{ex}");
}
}
private void StopServer_Click(object sender, EventArgs e)
{
lock (locker)
{
bRunning = false;
Thread.Sleep(100); // wait for the host to close
}
}
private void ClientReq_Click(object sender, EventArgs e)
{
try
{
Uri baseAddress = new Uri($"{proto}://{textBox1.Text}:2202/Test2ServLib/Service1/");
EndpointAddress address = new EndpointAddress(baseAddress);
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>("Test2ServLib.IService1", address);
var patientSvc = factory.CreateChannel();
var rsp = patientSvc.GetDataUsingDataContract(new CompositeTypeReq { Value = "me" } );
MessageBox.Show(rsp.Value);
}
catch(Exception ex)
{
MessageBox.Show($"error-{ex}");
}
}
}
}
The designer code is:
namespace Test2HostApp
{
partial class Hoster
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStart = new System.Windows.Forms.Button();
this.btnStop = new System.Windows.Forms.Button();
this.btnSend = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.btnStart.Location = new System.Drawing.Point(12, 12);
this.btnStart.Name = "btn_Start";
this.btnStart.Size = new System.Drawing.Size(75, 23);
this.btnStart.TabIndex = 0;
this.btnStart.Text = "Start";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.StartServer_Click);
//
// button2
//
this.btnStop.Location = new System.Drawing.Point(12, 41);
this.btnStop.Name = "btn_Stop";
this.btnStop.Size = new System.Drawing.Size(75, 23);
this.btnStop.TabIndex = 1;
this.btnStop.Text = "Stop";
this.btnStop.UseVisualStyleBackColor = true;
this.btnStop.Click += new System.EventHandler(this.StopServer_Click);
//
// button3
//
this.btnSend.Location = new System.Drawing.Point(12, 70);
this.btnSend.Name = "btn_Send";
this.btnSend.Size = new System.Drawing.Size(75, 23);
this.btnSend.TabIndex = 2;
this.btnSend.Text = "Send";
this.btnSend.UseVisualStyleBackColor = true;
this.btnSend.Click += new System.EventHandler(this.ClientReq_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(93, 70);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 22);
this.textBox1.TabIndex = 3;
//
// Hoster
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(282, 255);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.btnSend);
this.Controls.Add(this.btnStop);
this.Controls.Add(this.btnStart);
this.Name = "Hoster";
this.Text = "Hoster";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Button btnStop;
private System.Windows.Forms.Button btnSend;
private System.Windows.Forms.TextBox textBox1;
}
}
My first test, my protocol was set to "net.tcp" (the marked line in hoster.cs) My app.config file was the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<services>
<service behaviorConfiguration="announcementBehavior"
name="Test2ServLib.Service1">
<endpoint binding="netTcpBinding"
bindingConfiguration="RequestReplyNetTcpBinding"
contract="Test2ServLib.IService1" />
<host>
</host>
</service>
</services>
<client>
<endpoint binding="netTcpBinding"
bindingConfiguration="StandardNetTcpBinding"
contract="Test2ServLib.IService1"
name="Test2ServLib.IService1"
behaviorConfiguration="LargeEndpointBehavior">
</endpoint>
</client>
<behaviors>
<serviceBehaviors>
<behavior name="announcementBehavior">
<!--The following behavior attribute is required to enable WCF serialization of large data sets -->
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceDiscovery>
<announcementEndpoints>
<endpoint kind="announcementEndpoint"
address="net.tcp://localhost:8005/Announcement"
binding="netTcpBinding"
bindingConfiguration="RequestReplyNetTcpBinding"/>
</announcementEndpoints>
</serviceDiscovery>
<serviceThrottling maxConcurrentCalls="1500"
maxConcurrentSessions="1500"
maxConcurrentInstances="1500"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
<serviceCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
<behavior name="discoveryBehavior">
<serviceDiscovery>
</serviceDiscovery>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
<serviceCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="LargeEndpointBehavior">
<!--The behavior is required to enable WCF deserialization of large data sets -->
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<clientCredentials>
<clientCertificate findValue="WcfClient"
x509FindType="FindBySubjectName"
storeLocation="CurrentUser"
storeName="My" />
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="StandardNetTcpBinding"
receiveTimeout="05:00:00"
openTimeout="00:00:59"
closeTimeout="00:00:59"
maxBufferPoolSize="524288"
maxBufferSize="25000000"
maxConnections="50"
maxReceivedMessageSize="25000000"
listenBacklog="1500"
sendTimeout="00:05:00">
<security>
<message clientCredentialType="Certificate"/>
</security>
<reliableSession ordered="false"
inactivityTimeout="00:01:00"
enabled="true" />
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
<binding name="RequestReplyNetTcpBinding"
receiveTimeout="05:00:00"
openTimeout="00:00:59"
closeTimeout="00:00:59"
maxBufferPoolSize="524288"
maxBufferSize="25000000"
maxConnections="50"
maxReceivedMessageSize="25000000"
sendTimeout="00:05:00"
listenBacklog="1500">
<reliableSession ordered="false"
inactivityTimeout="00:01:00"
enabled="true" />
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security >
<message clientCredentialType="Certificate"/>
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
With this, I can communication from one system to another, but both systems have to have the same user name and passwords. If I change the password on one system, I get:
error-System.ServiceModel.Security.SecurityNegotiationException: The server has rejected the client credentials. ---> System.Security.Authentication.InvalidCredentialException: The server has rejected the client credentials. ---> System.ComponentModel.Win32Exception: The logon attempt failed
So it looks like it's still using user name and password authentication. So I've tried it with https. I changed the protocol to "https", and changed my app config to the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="CertificateWithTransport" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" />
</security>
</binding>
<binding name="CertificateWithTransportService" messageEncoding="Mtom" >
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Test2ServLib.Service1"
behaviorConfiguration="credentialConfigService" >
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="CertificateWithTransportService"
contract="Test2ServLib.IService1" />
</service>
</services>
<client>
<endpoint address=""
behaviorConfiguration="credentialConfigurationClient"
binding="wsHttpBinding"
bindingConfiguration="CertificateWithTransport"
contract="Test2ServLib.IService1"
name="Test2ServLib.IService1" />
</client>
<behaviors>
<serviceBehaviors>
<behavior name="credentialConfigService">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="credentialConfigurationClient">
<clientCredentials>
<clientCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Now, which this change I can't even get the client to talk to the server when they are running on the same computer with the same account, I get:
error-System.ServiceModel.CommunicationException: An error occurred while making the HTTP request to https://vm-pjh-135-2c:2202/Test2ServLib/Service1/. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
I created my certs using "makecert.exe -sr CurrentUser -ss My -a sha1 -n CN=WCFServer -sky exchange -pe" And copied them around as needed. If I need to create the cert some other way, please let me know. This is Proof of Concept code, so self signed works for me.
What do I need to do to get either (or both) of these solutions working?
Continue reading...
I've tried several different ideas, and none have worked. Can someone please tell me what I am doing wrong.
Here is my sample code: The WCF request reply library (Service1.cs):
using System;
namespace Test2ServLib
{
public class Service1 : IService1
{
public CompositeTypeRsp GetDataUsingDataContract(CompositeTypeReq composite)
{
CompositeTypeRsp Rsp = new CompositeTypeRsp();
if (composite == null)
{
Rsp.Value = "Hello {null} from " + Environment.MachineName;
return Rsp;
}
Rsp.Value = "Hello " + composite.Value + " from " + Environment.MachineName;
return Rsp;
}
}
}
Interface contract (IService1.cs):
using System;
using System.Runtime.Serialization;
using System.ServiceModel;
namespace Test2ServLib
{
[ServiceContract]
public interface IService1
{
[OperationContract]
CompositeTypeRsp GetDataUsingDataContract(CompositeTypeReq composite);
}
[DataContract]
public class CompositeTypeReq
{
string stringValue = "Hello ";
[DataMember]
public string Value
{
get { return stringValue; }
set { stringValue = value; }
}
}
[DataContract]
public class CompositeTypeRsp
{
string stringValue = "Hello ";
[DataMember]
public string Value
{
get { return stringValue; }
set { stringValue = value; }
}
}
}
Test application (Can be both server and client, Hoster.cs)
using System;
using System.ServiceModel;
using System.Threading;
using System.Windows.Forms;
using Test2ServLib;
namespace Test2HostApp
{
public partial class Hoster : Form
{
public Hoster()
{
InitializeComponent();
textBox1.Text = Environment.MachineName;
}
private void StartServer_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(runHost);
}
private static bool bRunning = false;
private static object locker = new object();
private static string proto = "https";// <-- this line changes between tests
private void runHost(object state)
{
lock (locker)
{
if (bRunning)
{
MessageBox.Show("Host already running");
return;
}
bRunning = true;
}
Uri baseAddress = new Uri($"{proto}://localhost:2202/Test2ServLib/Service1/");
WSHttpBinding binding = new WSHttpBinding();
try
{
using (ServiceHost host = new ServiceHost(typeof(Service1), baseAddress))
{
host.Open();
MessageBox.Show("Host started");
while (bRunning == true)
{
Thread.Sleep(100);
}
host.Close();
MessageBox.Show("Host stopped");
}
}
catch (Exception ex)
{
MessageBox.Show($"{ex}");
}
}
private void StopServer_Click(object sender, EventArgs e)
{
lock (locker)
{
bRunning = false;
Thread.Sleep(100); // wait for the host to close
}
}
private void ClientReq_Click(object sender, EventArgs e)
{
try
{
Uri baseAddress = new Uri($"{proto}://{textBox1.Text}:2202/Test2ServLib/Service1/");
EndpointAddress address = new EndpointAddress(baseAddress);
ChannelFactory<IService1> factory =
new ChannelFactory<IService1>("Test2ServLib.IService1", address);
var patientSvc = factory.CreateChannel();
var rsp = patientSvc.GetDataUsingDataContract(new CompositeTypeReq { Value = "me" } );
MessageBox.Show(rsp.Value);
}
catch(Exception ex)
{
MessageBox.Show($"error-{ex}");
}
}
}
}
The designer code is:
namespace Test2HostApp
{
partial class Hoster
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStart = new System.Windows.Forms.Button();
this.btnStop = new System.Windows.Forms.Button();
this.btnSend = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.btnStart.Location = new System.Drawing.Point(12, 12);
this.btnStart.Name = "btn_Start";
this.btnStart.Size = new System.Drawing.Size(75, 23);
this.btnStart.TabIndex = 0;
this.btnStart.Text = "Start";
this.btnStart.UseVisualStyleBackColor = true;
this.btnStart.Click += new System.EventHandler(this.StartServer_Click);
//
// button2
//
this.btnStop.Location = new System.Drawing.Point(12, 41);
this.btnStop.Name = "btn_Stop";
this.btnStop.Size = new System.Drawing.Size(75, 23);
this.btnStop.TabIndex = 1;
this.btnStop.Text = "Stop";
this.btnStop.UseVisualStyleBackColor = true;
this.btnStop.Click += new System.EventHandler(this.StopServer_Click);
//
// button3
//
this.btnSend.Location = new System.Drawing.Point(12, 70);
this.btnSend.Name = "btn_Send";
this.btnSend.Size = new System.Drawing.Size(75, 23);
this.btnSend.TabIndex = 2;
this.btnSend.Text = "Send";
this.btnSend.UseVisualStyleBackColor = true;
this.btnSend.Click += new System.EventHandler(this.ClientReq_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(93, 70);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 22);
this.textBox1.TabIndex = 3;
//
// Hoster
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(282, 255);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.btnSend);
this.Controls.Add(this.btnStop);
this.Controls.Add(this.btnStart);
this.Name = "Hoster";
this.Text = "Hoster";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button btnStart;
private System.Windows.Forms.Button btnStop;
private System.Windows.Forms.Button btnSend;
private System.Windows.Forms.TextBox textBox1;
}
}
My first test, my protocol was set to "net.tcp" (the marked line in hoster.cs) My app.config file was the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<services>
<service behaviorConfiguration="announcementBehavior"
name="Test2ServLib.Service1">
<endpoint binding="netTcpBinding"
bindingConfiguration="RequestReplyNetTcpBinding"
contract="Test2ServLib.IService1" />
<host>
</host>
</service>
</services>
<client>
<endpoint binding="netTcpBinding"
bindingConfiguration="StandardNetTcpBinding"
contract="Test2ServLib.IService1"
name="Test2ServLib.IService1"
behaviorConfiguration="LargeEndpointBehavior">
</endpoint>
</client>
<behaviors>
<serviceBehaviors>
<behavior name="announcementBehavior">
<!--The following behavior attribute is required to enable WCF serialization of large data sets -->
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<serviceDiscovery>
<announcementEndpoints>
<endpoint kind="announcementEndpoint"
address="net.tcp://localhost:8005/Announcement"
binding="netTcpBinding"
bindingConfiguration="RequestReplyNetTcpBinding"/>
</announcementEndpoints>
</serviceDiscovery>
<serviceThrottling maxConcurrentCalls="1500"
maxConcurrentSessions="1500"
maxConcurrentInstances="1500"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
<serviceCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
<behavior name="discoveryBehavior">
<serviceDiscovery>
</serviceDiscovery>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</clientCertificate>
<serviceCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="LargeEndpointBehavior">
<!--The behavior is required to enable WCF deserialization of large data sets -->
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<clientCredentials>
<clientCertificate findValue="WcfClient"
x509FindType="FindBySubjectName"
storeLocation="CurrentUser"
storeName="My" />
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<netTcpBinding>
<binding name="StandardNetTcpBinding"
receiveTimeout="05:00:00"
openTimeout="00:00:59"
closeTimeout="00:00:59"
maxBufferPoolSize="524288"
maxBufferSize="25000000"
maxConnections="50"
maxReceivedMessageSize="25000000"
listenBacklog="1500"
sendTimeout="00:05:00">
<security>
<message clientCredentialType="Certificate"/>
</security>
<reliableSession ordered="false"
inactivityTimeout="00:01:00"
enabled="true" />
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>
<binding name="RequestReplyNetTcpBinding"
receiveTimeout="05:00:00"
openTimeout="00:00:59"
closeTimeout="00:00:59"
maxBufferPoolSize="524288"
maxBufferSize="25000000"
maxConnections="50"
maxReceivedMessageSize="25000000"
sendTimeout="00:05:00"
listenBacklog="1500">
<reliableSession ordered="false"
inactivityTimeout="00:01:00"
enabled="true" />
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
<security >
<message clientCredentialType="Certificate"/>
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
With this, I can communication from one system to another, but both systems have to have the same user name and passwords. If I change the password on one system, I get:
error-System.ServiceModel.Security.SecurityNegotiationException: The server has rejected the client credentials. ---> System.Security.Authentication.InvalidCredentialException: The server has rejected the client credentials. ---> System.ComponentModel.Win32Exception: The logon attempt failed
So it looks like it's still using user name and password authentication. So I've tried it with https. I changed the protocol to "https", and changed my app config to the following:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="CertificateWithTransport" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" />
</security>
</binding>
<binding name="CertificateWithTransportService" messageEncoding="Mtom" >
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Test2ServLib.Service1"
behaviorConfiguration="credentialConfigService" >
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="CertificateWithTransportService"
contract="Test2ServLib.IService1" />
</service>
</services>
<client>
<endpoint address=""
behaviorConfiguration="credentialConfigurationClient"
binding="wsHttpBinding"
bindingConfiguration="CertificateWithTransport"
contract="Test2ServLib.IService1"
name="Test2ServLib.IService1" />
</client>
<behaviors>
<serviceBehaviors>
<behavior name="credentialConfigService">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="ChainTrust" revocationMode="NoCheck" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="credentialConfigurationClient">
<clientCredentials>
<clientCertificate findValue="WCfServer"
storeLocation="CurrentUser"
storeName="My"
x509FindType="FindBySubjectName" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Now, which this change I can't even get the client to talk to the server when they are running on the same computer with the same account, I get:
error-System.ServiceModel.CommunicationException: An error occurred while making the HTTP request to https://vm-pjh-135-2c:2202/Test2ServLib/Service1/. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
I created my certs using "makecert.exe -sr CurrentUser -ss My -a sha1 -n CN=WCFServer -sky exchange -pe" And copied them around as needed. If I need to create the cert some other way, please let me know. This is Proof of Concept code, so self signed works for me.
What do I need to do to get either (or both) of these solutions working?
Continue reading...