I'm trying to activate transport security for a WCF Client-Server application.
It works fine on our test machine, but in the target environment the connection is always reset after what looks to me like a successful handshake:
Wireshark capture
I've tried deactivating the firewall, although the application worked fine without TLS, but it made no difference. I've also tried TLS1.1 and TLS1.0 but that made no difference either.
Here is the source code for the service host:
public void Start()
{
var binding = new NetTcpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.Security.Transport.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
binding.ReliableSession.Enabled = true;
binding.ReliableSession.InactivityTimeout = TimeSpan.FromSeconds(30);
binding.ReceiveTimeout = TimeSpan.FromSeconds(5);
binding.SendTimeout = TimeSpan.FromSeconds(5);
binding.MaxReceivedMessageSize = 64 * 1048576;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
this.host = new ServiceHost(
this,
new[] { new Uri(string.Format("net.tcp://{0}:{1}", this.hostname, this.port)) }
);
this.host.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
this.host.AddServiceEndpoint(new UdpDiscoveryEndpoint());
this.host.AddServiceEndpoint(typeof(ILvsService), binding, "LvsService");
this.host.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindBySubjectName,
this.hostname
);
this.host.Open();
}
And here is the client side:
public ServiceClient(string server, ushort port)
{
var binding = new NetTcpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
binding.Security.Transport.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
binding.MaxReceivedMessageSize = 64 * 1048576;
binding.ReaderQuotas.MaxArrayLength = 2147483647;
binding.ReaderQuotas.MaxStringContentLength = 2147483647;
binding.ReceiveTimeout = TimeSpan.FromSeconds(5);
binding.SendTimeout = TimeSpan.FromSeconds(5);
var context = new InstanceContext(this);
this.channelFactory = new DuplexChannelFactory<ILvsService>(
context,
binding,
new EndpointAddress(string.Format("net.tcp://{0}:{1}/LvsService", server, port))
);
}
The server is running as a service on a Windows Server 2016 VM with .NET Framework 4.7.2. The clients are running on Windows 10 machines also with .NET Framework 4.7.2.
Related
I am trying to establish connection to external PKI SOAP web service, but not sure how to set BasicHttpBinding security in .NET 6. Constantly getting exception:
*System.ServiceModel.ProtocolException: 'The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding. '
*
I am using auto generated class from wsdl, but create my own binding.
BasicHttpBinding:
public BasicHttpBinding GetCustomBinding()
{
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport)
{
Security =
{
Message =
{
ClientCredentialType = BasicHttpMessageCredentialType.Certificate
},
Transport =
{
ClientCredentialType = HttpClientCredentialType.Certificate
},
Mode = BasicHttpSecurityMode.Transport
},
MaxReceivedMessageSize = MaxMessageSizeBytes
};
return binding;
}
Creating proxy client:
public autoGeneratedClient GetClient(string endpointUrl, string dnsIdentity, string clientCertificatePath, string clientCertificatePassword, string serviceCertificatePath, int timeout = 10)
{
DnsEndpointIdentity endpointIdentity = new DnsEndpointIdentity(dnsIdentity);
EndpointAddress endpointAddress = new EndpointAddress(new Uri(endpointUrl), endpointIdentity);
//CustomBinding for eBox web service with security setup
MyCustomBinding myCustomBinding = new MyCustomBinding();
Binding binding = myCustomBinding.GetCustomBinding();
binding.CloseTimeout = new TimeSpan(0, timeout, 0);
binding.ReceiveTimeout = new TimeSpan(0, timeout, 0);
binding.SendTimeout = new TimeSpan(0, timeout, 0);
binding.OpenTimeout = new TimeSpan(0, timeout, 0);
autoGeneratedClient client = new autoGeneratedClient(binding, endpointAddress);
client.ClientCredentials.ClientCertificate.Certificate = X509CertificateFactory.GetClientCertificate(clientCertificatePath, clientCertificatePassword);
client.ClientCredentials.ServiceCertificate.DefaultCertificate = X509CertificateFactory.GetServiceCertificate(serviceCertificatePath);
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
return client;
}
I'm trying to access a REST service in a WCF server from power BI using Windows Authentication.
Currently the web request from Power BI is done to a nodejs server where we can get the NTLM authentication data in the 'authorization' header of the request.
But I need to do the same request on a WCF server instead. The Rest service of the WCF is working well, when not using any authentication I can access it with the power BI request through https without any issue.
But when I activate the authentication in the WCF server (with binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows), the request is rejected because the authentication fails. I cannot even use the NTLM data as the 'authentication' field in header is not in the received request (when authentication is not set, but I assume that's normal).
For now, everything is running on my machine, and I'm using the "Use my current credentials" option when doing the Windows authentication in Power BI. OF course there's an Active Directory.
the code in the WCF server:
private void StartRestServiceHosts(int port)
{
try
{
using (ServerContainerScope containerScope = new ServerContainerScope())
{
RequestContext.Current.Initialize(LogAreas.Server, Shared.MainUserLogin);
string protocol = Shared.HttpsEnabled ? "https" : "http";
string uri = string.Format("{0}://{1}:{2}/Rest/", protocol, System.Environment.MachineName, port);
Uri httpBaseAddress = new Uri(uri);
var defaultWebHttpBehavior = new WebHttpBehavior()
{
AutomaticFormatSelectionEnabled = true,
DefaultBodyStyle = WebMessageBodyStyle.Wrapped,
DefaultOutgoingRequestFormat = WebMessageFormat.Json,
DefaultOutgoingResponseFormat = WebMessageFormat.Json,
HelpEnabled = false
};
foreach (ServiceDefinition serviceDefinition in _registeredRestServices.Values)
{
string currentServiceName = serviceDefinition.Name;
if (!_restServiceHosts.ContainsKey(currentServiceName))
{
ServiceHost host = new ServiceHost(serviceDefinition.Type,
new Uri(httpBaseAddress, serviceDefinition.Type.Name));
host.Authorization.ServiceAuthorizationManager = new PublicAuthorization();
Type contract = serviceDefinition.Type.GetInterface("I" + serviceDefinition.Type.Name);
ServiceEndpoint endPoint = new ServiceEndpoint(
ContractDescription.GetContract(contract),
_restBinding,
new EndpointAddress("{0}{1}".FormatWith(uri, contract.Name))
);
endPoint.Behaviors.Add(defaultWebHttpBehavior);
endPoint.Behaviors.Add(new CorsSupportBehavior());
host.AddServiceEndpoint(endPoint);
_restServiceHosts.Add(currentServiceName, host);
}
// Open
if (_restServiceHosts[currentServiceName].State != CommunicationState.Opened)
{
_restServiceHosts[currentServiceName].Open();
}
}
OnWcfRestServicesStarted?.Invoke(null, true);
}
}
catch (Exception ex)
{
OnWcfRestServicesStarted?.Invoke(null, false);
}
}
public WebHttpBinding CreateWebHttpBinding(string name)
{
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = Shared.HttpsEnabled ? WebHttpSecurityMode.Transport : WebHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
//binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
binding.Name = name;
binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.MaxBufferSize = 2147483647;
binding.MaxReceivedMessageSize = 2147483647;
return binding;
}
<appSettings>
<add key="HttpsEnabled" value="true"/>
</appSettings>
Any ideas as to why the authentication is not working?
Thanks in advance!!!
i want to host two services
Service 1 (located on D Drive)
process data based on configuration configured in xml
net.tcp://ServerIP/Pune_service
Service 2 (located on E Drive)
process data based on configuration configured in xml
net.tcp://ServerIP/Mumbai_service
now i tried to host these services with net.tcp binding in two different Windows Service
Windows service 1 Started Successfully
but when tried to start second windows service i'am getting Error i.e.
AddressAlreadyInUseException
string httpBaseAddress = "http://" + _szServerIP + "/" + _szCurruntLocation + "_FileServer";
string tcpBaseAddress = "net.tcp://" + _szServerIP + "/" + _szCurruntLocation + "_FileServer";
Uri[] adrbase = { new Uri(httpBaseAddress), new Uri(tcpBaseAddress) };
m_svcHost = new ServiceHost(typeof(MyService.CalcServiceClient), adrbase);
ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
//mBehave.AddressFilterMode=AddressFilterMode.Any)]
m_svcHost.Description.Behaviors.Add(mBehave);
BasicHttpBinding httpb = new BasicHttpBinding();
m_svcHost.AddServiceEndpoint(typeof(MyService.ICalcService), httpb, httpBaseAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
NetTcpBinding tcpb = new NetTcpBinding();
tcpb.MaxConnections = 10;
tcpb.MaxReceivedMessageSize = Int32.MaxValue;
tcpb.MaxBufferPoolSize = Int32.MaxValue;
tcpb.MaxBufferSize = Int32.MaxValue;
tcpb.ReceiveTimeout = new TimeSpan(0, 10, 0);
tcpb.OpenTimeout = new TimeSpan(0, 10, 0);
tcpb.CloseTimeout = new TimeSpan(0, 10, 0);
tcpb.PortSharingEnabled = true;
m_svcHost.AddServiceEndpoint(typeof(MyService.ICalcService), tcpb, tcpBaseAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
m_svcHost.Open();
Console.WriteLine("Service is live now at : {0}", httpBaseAddress);
Console.ReadLine();
Here is the link for AddressAlreadyInUseException.
I think you may remove;
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
You are trying to add a second IMetadataExchange contract for tcp binding.
Also you need to add;
mBehave.HttpGetEnabled = true;
to get mex information.
As far as I know,MexTcpBinding disable the port sharing. Which means that:
Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
CustomBinding mexBinding2 = new CustomBinding(mexBinding);
mexBinding2.Elements.Find<TcpTransportBindingElement>().PortSharingEnabled==false //true
Here is an article worth reading.
https://blogs.msdn.microsoft.com/drnick/2006/08/23/an-unanticipated-addendum-for-certain-mex-scenarios/
I suggest you could write the custom binding, and then add the binding to the mex endpoint.
TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement();
TcpTransportBindingElement transport = new TcpTransportBindingElement();
transport.PortSharingEnabled = true;
CustomBinding binding1 = new CustomBinding(encoding, transport);
m_svcHost.AddServiceEndpoint(typeof(IService), tcpb, tcpBaseAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange), binding1, "mex");
Here is related issue on this topic.
https://blogs.msdn.microsoft.com/praburaj/2012/10/16/nettcpbinding-mextcpbinding-sharing-same-port-throws-addressalreadyinuseexception-on-upgrade-to-net-4-5/
you could also comment the following lines to ensure that codes run correctly.
tcpb.MaxConnections = 10;
tcpb.PortSharingEnabled = true;
I have a WCF service with NetNamedPipe for interprocess communication and I would like to add security on it. Everything works great without security, but when I am trying to use tranport security I am getting "InvalidCredentialException: The server has rejected the client credentials" exception. Can you please help me?
Code sample:
var netPipeBinding = new NetNamedPipeBinding() { MaxReceivedMessageSize = 2147483647, SendTimeout = TimeSpan.FromMinutes(10), ReceiveTimeout = TimeSpan.FromMinutes(10) };
netPipeBinding.ReaderQuotas.MaxDepth = 2147483647;
netPipeBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
netPipeBinding.ReaderQuotas.MaxArrayLength = 2147483647;
netPipeBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;
netPipeBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
netPipeBinding.Security.Mode = NetNamedPipeSecurityMode.Transport;
netPipeBinding.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;
var host = new ServiceHost(typeof(MainService));
var netPipeEA = new EndpointAddress(new Uri("net.pipe://MyProject/ServerSide"));
var contractDescription = ContractDescription.GetContract(typeof (IMainService), typeof (MainService));
host.AddServiceEndpoint(new ServiceEndpoint(contractDescription, netPipeBinding, netPipeEA));
host.Opened += HostOnOpened;
host.Open();
...
...
private void HostOnOpened(object sender, EventArgs eventArgs)
{
var netPipeBinding = new NetNamedPipeBinding() { MaxReceivedMessageSize = 2147483647, SendTimeout = TimeSpan.FromMinutes(10), ReceiveTimeout = TimeSpan.FromMinutes(10) };
netPipeBinding.ReaderQuotas.MaxDepth = 2147483647;
netPipeBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
netPipeBinding.ReaderQuotas.MaxArrayLength = 2147483647;
netPipeBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;
netPipeBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
netPipeBinding.Security.Mode = NetNamedPipeSecurityMode.Transport;
netPipeBinding.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;
DuplexChannelFactory<IMainService> channelFactory = new DuplexChannelFactory<IMainService>(new InstanceContext(new CalbackHandler()), netPipeBinding,
new EndpointAddress(IMainService));
var proxy = channelFactory.CreateChannel();
proxy.DoPing();
}
Thank you
The machine name, in this case "localhost" because you are using named pipe should be defined in the EndpointAddress URI.
I am using WCF service in my WindowsApplication... when i was running the application both server and client, The server disconnected the connetion in few minutes.... How shall i reconnect the client automatically When Connection was aborted....
This is my Client code:
public void connecttoserver()
{
D:
try
{
EndpointAddress ea = new EndpointAddress(#"net.tcp://10.0.3.33:2222/ClsPCMain");
EndpointAddress ea = new EndpointAddress(StrAddress);
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, false);
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.PortSharingEnabled = true;
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.SendTimeout = TimeSpan.MaxValue;
binding.OpenTimeout = TimeSpan.MaxValue;
binding.CloseTimeout = TimeSpan.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxConnections = Int16.MaxValue;
binding.ReaderQuotas.MaxArrayLength = Int32.MaxValue;
binding.ReaderQuotas.MaxBytesPerRead = Int32.MaxValue;
binding.ReaderQuotas.MaxDepth = Int32.MaxValue;
binding.ReaderQuotas.MaxNameTableCharCount = Int32.MaxValue;
binding.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.Security.Mode = SecurityMode.None;
ChannelFactory<InterfaceClass.IService> Client = new ChannelFactory<InterfaceClass.IService>(binding,ea);
InterfaceClass.IService serviceobj = Client.CreateChannel(ea);
clsStatus.connectstatus = false;
ClsPC objclsPc = serviceobj.PCInfoMethod(Environment.UserName, Environment.UserDomainName, Dns.GetHostName(), Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString());
if (objclsPc.imageid == 1)
{
clsStatus.FullSizeImage = true;
clsStatus.ThumbnailImage = false;
}
else
{
clsStatus.ThumbnailImage = true;
clsStatus.FullSizeImage = false;
}
Client.Close();
Client=null;
//serviceobj = null;
}
catch (Exception ex)
{
logobj.Write(ex);
}
}
This Is My Server Code:
public clsHostService()
{
string StrAddress = File.ReadAllText(AppDomain.CurrentDomain.BaseDirectory + "url2.txt");
ServiceHost host = new ServiceHost(typeof(clsService));
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, false);
ServiceEndpoint endpointinfo = host.AddServiceEndpoint(typeof(IService), binding, StrAddress);
endpointinfo.Binding.CloseTimeout = TimeSpan.MaxValue;
endpointinfo.Binding.OpenTimeout = TimeSpan.MaxValue;
endpointinfo.Binding.ReceiveTimeout = TimeSpan.MaxValue;
endpointinfo.Binding.SendTimeout = TimeSpan.MaxValue;
XmlDictionaryReaderQuotas BindingQuota = binding.ReaderQuotas;
BindingQuota.MaxArrayLength = Int32.MaxValue;
BindingQuota.MaxBytesPerRead = Int32.MaxValue;
BindingQuota.MaxDepth = Int32.MaxValue;
binding.MaxConnections = Int16.MaxValue;
binding.MaxBufferPoolSize = Int32.MaxValue;
binding.MaxBufferSize = Int32.MaxValue;
binding.MaxReceivedMessageSize = Int32.MaxValue;
binding.CloseTimeout = TimeSpan.MaxValue;
binding.OpenTimeout = TimeSpan.MaxValue;
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.SendTimeout = TimeSpan.MaxValue;
ServiceThrottlingBehavior throttlingBehavior =new ServiceThrottlingBehavior();
throttlingBehavior.MaxConcurrentCalls = Int32.MaxValue;
throttlingBehavior.MaxConcurrentInstances = Int32.MaxValue;
throttlingBehavior.MaxConcurrentSessions = Int32.MaxValue;
host.Description.Behaviors.Add(throttlingBehavior);
host.Open();
Console.WriteLine("Server Started");
Console.ReadLine();
}
Now How Shall i Connect to the client Automatically When server cuts the Connection?
Anyone Tell me The Solution of this Problem...
Thanks in Advance.....
I use something like this:
//Somewhere in the main
ConfigureWcf();
ConnectToServer();
//...
void ConnectToServer()
{
myService = new ServiceReference.ServiceClient(context);
myService.Open();
myService.InnerChannel.UnknownMessageReceived += InnerChannel_UnknownMessageReceived;
myService.InnerChannel.Closed += InnerChannel_Closed;
}
void StartConnecting()
{
//use 5 attempts to connect to server
ConnectToServer();
}
void InnerChannel_Closing(object sender, EventArgs e)
{
//Connection to server closed!
//Write to log
StartConnecting();
}
I don't completely understand your question, I'm afraid - your Winforms app is hosting the service, or is it the client calling a WCF service??
WCF doesn't typically use the concept of having a constant connection between client and server.
The client builds a client-side proxy on which is calls methods that the server exposes. Basically, each call is independant of all the others - a connection only exists between the client and the server for the duration of the call. The connection isn't always up - it's only in place when a call is actually happening.
So I don't completely understand what you want to "reconnect" - there is not always-on connection in the first place.
What can happen is that if an exception happens on the server side and isn't caught and handled properly, then the client-side proxy can become invalid. In WCF terms, the "channel" between the client and the server has been "faulted" , e.g. has become unusable. If you were to call the server again with a client-side proxy in a faulted state, you'd receive a client-side exception.
You can check for a faulted channel state on the client-side proxy before making a call with this code:
if(client.State == CommunicationState.Faulted)
{
client = new YourServiceClient();
}
if the channel is indeed faulted, then you need to re-create the proxy again and you should be back in business.