Sending request to PKI Web service in .NET 6 - c#

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;
}

Related

ะก# WCF web service exception : a required header representing a Message Addressing Property is not present

I generated a Service Reference from url https://portal.shipsea.ru/services/ShipService?wsdl with Visual Studio 2022.
I tried to invoke some method of generated client.
Here is my code:
var binding = new BasicHttpsBinding();
binding.MaxReceivedMessageSize = 2147483647;
var endpointAddress = new EndpointAddress("https://portal.shipsea.ru:443/services/ShipService");
using var client = new ShipServiceClient(binding, endpointAddress);
client.ClientCredentials.Windows.ClientCredential.UserName = "******";
client.ClientCredentials.Windows.ClientCredential.Password = "******";
var responce = client
.getShipPositionsAsync(
new ShipPositionRequest
{
start = 0,
limit = 1000,
minLatitude = 0,
minLongitude = 0,
maxLatitude = 0,
maxLongitude = 0,
minReceiveDate = DateTime.Now,
maxReceiveDate = DateTime.Now.AddDays(-30)
})
When making the call, I get an exception:
System.ServiceModel.FaultException: A required header representing a Message Addressing Property is not present
Is there something wrong with the client generation? Or how to add the missing header when called?

TCP connection with TLS reset after handshake

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.

Windows Authentication not working in WCF REST service from a Power BI request

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!!!

WCF UDP discovery only works for BasicHttpBinding not for NetTcpBinding

I have a WCF service that has announced two service endpoints. One is for net.tcp and one is for http.
net.tcp://localhost:11110/MyService
http://localhost:11111/MyService
// Make service discoverable
var discoveryBehavior = new ServiceDiscoveryBehavior();
var announceEndpointAddress = ConfigurationManager.AppSettings["AnnouncementEndpoint"];
var netTcpBinding = new NetTcpBinding(SecurityMode.None)
{
ReceiveTimeout = TimeSpan.MaxValue,
SendTimeout = TimeSpan.MaxValue,
OpenTimeout =TimeSpan.MaxValue,
CloseTimeout = TimeSpan.MaxValue
};
discoveryBehavior.AnnouncementEndpoints.Add(
new AnnouncementEndpoint(netTcpBinding,
new EndpointAddress(announceEndpointAddress)
));
_serviceHost.Description.Behaviors.Add(discoveryBehavior);
_serviceHost.AddServiceEndpoint(new UdpDiscoveryEndpoint());
On the client side, I am using WCF Discovery.
class Program
{
static void Main(string[] args)
{
var optionalBindings = new Binding[]
{
new NetTcpBinding(),
new BasicHttpBinding(),
new NetNamedPipeBinding()
};
var executed = false;
foreach (var binding in optionalBindings)
{
var contract = ContractDescription.GetContract(typeof(IMyService));
var endpoint = new DynamicEndpoint(contract, binding);
var factory = new ChannelFactory<IMyService>(endpoint);
var proxy = factory.CreateChannel();
try
{
var result = proxy.GetData(123456);
((ICommunicationObject) proxy).Close();
executed = true;
break;
}
catch (EndpointNotFoundException)
{
// Ignored
}
}
}
}
What confuses me is that it only works with BasicHttpBinding and never works with NetTcpBinding. So if BasicHttpBinding from optionalBindings list, i am not able to call the service although net.tcp endpoint is there.
Can anyone explain the reason for it?

How to host two WCF services with .net.tcp binding in windows Service

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;

Categories

Resources