I am in the process of building a WCF client for a SOAP HTTPS webservice in .Net Core 2.1.
The service provider has supplied a .key and a .cert file which I have converted to a .p12 file using openssl. By adding this to a keystore I am able, through SoapUI, to successfully sent a request to the webservice (no other authentication than the certificate is required).
To do the same operation in .Net Core I have added a Connected Service to my project through the WCF wizard in Visual Studio. This service is based on the supplied service contract (WSDL file). I have then installed the .p12 certificate locally on my PC and I am using the following code to make the request. "MyService" is the connected service.
var binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
var endpoint = new EndpointAddress("https://x.x.x.x:8300/MyService.asmx");
var channelFactory = new ChannelFactory<MyService>(binding, endpoint);
channelFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
channelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication()
{
CertificateValidationMode = X509CertificateValidationMode.None,
RevocationMode = X509RevocationMode.NoCheck,
TrustedStoreLocation = StoreLocation.LocalMachine
};
channelFactory.Credentials.ClientCertificate.SetCertificate(
StoreLocation.CurrentUser,
StoreName.My,
X509FindType.FindByIssuerName,
"xxxxxxxxxxxxxxxxxxxxxxxxxx");
var service = channelFactory.CreateChannel();
ExecuteResponse response = service.Execute(new ExecuteRequest());
When running this code I am getting the following error:
System.ServiceModel.Security.MessageSecurityException: 'The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate'.'
The strange thing is that I am allowed to make the request if I use the HttpClientHandler which tells me that there must be a mismatch between the underlying structure of the two implementations.
Anyone who knows how I can fix this error?
The certificate might just be used to establish the trust relationship between the client-side and the server-side.
For making a successful call to the service, we should keep the binding type between the client-side and the server-side consistent. Therefore, I would like to know the automatically generated client-side configuration by Adding service reference, please post the System.servicemodel section located in the appconfig of the client project.
If the server authenticates the client-side with a certificate, the error typically indicates the trust relationship has not established yet between the client-side and the server-side.
On the client-side, we should install the server certificate in the LocalCA. On the server-side, we should install the client certificate in the LocalCA certificate store.
Feel free to let me know if the problem still exists.
Related
We have third party API provider that provided an SOAP API. They have provided 3 certificates,
Client Cert
Intermediate Cert
Root Cert
All certs are installed locally. They have provided a pfx cert with password. We have uploaded this pfx in SOAP UI tool and run a request it worked. Then we tried the same with .NET request,
var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
var client = new ServiceReference1.myClient(binding, new EndpointAddress(serviceUrl));
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var certificate = new X509Certificate2(certificateBinary, certificatePassword);
client.ClientCredentials.ClientCertificate.Certificate = certificate;
It failed with handshake failure error.
Then we monitored both SOAP UI traffic and .NET code traffic using WireShark.
Clearly the .NET is not sending Root CA. The problem is that request is rejected by the third party API if Root CA is not present in the request. How can force send ROOT CA.
I'm having some issues implementing a client that talks to a WCF service. It's a WCF hosted by another company so I don't have access to its code. I used the Connected Service provider tool in Visual Studio to generate the client code so that I could make requests and everything works fine on my local machine. I am having an issue on our development environment where I receive the following error if I try to make a request with the client:
The HTTP request was forbidden with client authentication scheme 'Anonymous'
I've been looking at the client code (it's a lot of code) which is generated by the Provider tool and I think it may have something to do with the following block of code.
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
return result;
This more linked to firewall rules within corporate network.
I had same issue using non authorized proxy but got resolved secured proxy with ntlm ClientCredentialType
This error typically indicates that the WCF server authenticates the client-side with a certificate. The error will occur when the trust relationship between the server and the client have not been established yet.
In general, we need to provide client credential to be authenticated by the server so that be able to call the service. As for what kind of credentials need to be provided, it depends on the binding information on the server-side.
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Namely, the above errors have indicated that the server authenticates the client with a certificate.
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
About authenticating the client with a certificate, you could refer to the below link for details.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication
Feel free to let me know if there is anything I can help with.
Thanks for all the suggestions. This was actually just caused by a firewall rule that was setup within our organisation. Once that was removed the code worked as expected.
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
Security is provided using HTTPS. The service must be configured with SSL certificates. The SOAP message is protected as a whole using HTTPS. The service is authenticated by the client using the service's SSL certificate. The client authentication is controlled through the ClientCredentialType.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.basichttpsecuritymode?view=netframework-4.8
I've successfully created a WCF service which validates the incoming client certificate against the chain configured in IIS. However, as this is only a security mechanism to support authentication, I also need the Windows user calling my WCF service to handle authorization.
Normally when extracting the Windows User, you would do it like this
ServiceSecurityContext.Current.WindowsIdentity.Name
When my service is configured with security mode TransportWithMessageCredentials, the PrimaryIdentity in the ServiceSecurityContext will return the certificate's SubjectName and the WindowsIdentity will be empty.
To look at the client configuration, I've specified the WsHttpBinding like this
private static Binding GetHttpsBinding()
{
var binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
return binding;
}
The client certificate is added like to the proxy client like this:
private static void ApplyClientCertificate(HelloServiceClient client)
{
client.ClientCredentials.ClientCertificate.SetCertificate(
storeLocation: StoreLocation.CurrentUser,
storeName: StoreName.My,
findType: X509FindType.FindBySubjectName,
findValue: "ClientCertificatesTest"
);
}
Switching the two ClientCredentialType values so the binding looks like this
private static Binding GetHttpsBinding()
{
var binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
return binding;
}
will work for extracting the Windows Credentials as described above, but when presenting an invalid certificate or no certificate at all are also accepted! Therefore the authentication requirement is not fulfilled. I can also add that when configured this way my implementation of X509CertificateValidator on the server-side will not trigger, hence my suspicion that the client certificate is not added.
Surely there must be some way to add a client certificate for authentication and add Windows Credentials to handle authorization in WCF? Is there any other way that I can add the certificate than adding it to the client credentials?
Thanks in advance!
So the answer to this question will be to create your own CustomBinding to get both Windows Credentails and Certificate validation.
With Web Service references you could present both a client certificate and Windows authentication credentials, so it's strange that this isn't available out of the box for WCF?
Did you implement the custom binding or have any links of examples of getting this working?
UPDATE: here's the solution to create a custom binding to get both Windows Authentication and Client Certificates.
http://david-homer.blogspot.com/2021/05/using-net-wcf-basichttpbinding-to.html
Thanks,
Dave
Scenario: User talks with WebApi called 'Gateway' by angularjs client. 'Gateway' is like a facade or a proxy, so all requests from User to 'Gateway' will be forwarded to another WebApis.
Security details: 'Gateway' WebApi and all others WebApis are placed in IIS with HTTPS binding and SSL client certificate option is 'Accept'. So, user will provide valid client certificate to IIS and after verification, request will be handled by WebApi.
The problem: when 'Gateway' WebApi receives a request, client certificate is presented in Request object. Then I just forward this request using HttpClient to another WebApi. But when another WebApi endpoint receives a request, there is not client certificate attached any more.
Below is a code snipped of request forwarding:
var request = Request; // income request from angularjs
var handler = new WebRequestHandler();
handler.ClientCertificates.Add(request.GetClientCertificate()); // setting up client certificate from user's request
using (var httpClient = new HttpClient(handler))
{
request.RequestUri = *chaning request address here*;
var response = await httpClient.SendAsync(request);
return ResponseMessage(response);
}
Note: If I try to go directly to the another WebApi, client certificate is presented as expected. If I try to go via 'Gateway', client certificate is presented as well in 'Gateway' request, but after it's successfully attached and request is sent, another WebApi does not receive any certificate attached.
Any ideas?
Thank you.
On your gateway server, you need to import an authentication key onto the "machine" certificate store (MMC.exe, add snap-in "Certificates", Computer account", Certficates-Personal-Certificates, import).
Grant permissions (for the auth cert) to the account which your IIS pool is using. (right-click the cert, All-Tasks, Manage private keys. Add, Advanced, Locations=[machine-name], find now, (probably) Network Service, Read).
In your web.config (on your gateway server), check your system.serviceModel / behaviors / endpointBehaviors / behavior / clientCredentials / clientCertificate. Make sure the attribute: storeLoction="LocalMachine", to use the cert from the machine key store.
I am trying to access service bus via a squid3 webproxy with Basic authentication enabled in the proxy using C#
i am using below code to set the web proxy
webproxy webproxy = new webproxy("http://weproxyuri:port", false);
webproxy.credentials = new networkcredential("username", "password","domain");
WebRequest.DefaultWebProxy = webProxy
i am using below code to access service bus
MessagingFactory messagingFactory = MessagingFactory.CreateFromConnectionString(connectionstring);
QueueClient queueSendClient = messagingFactory.CreateQueueClient(queuename);
var bm1 = queueSendClient.Peek();
access of service bus is failing with error - The X.509 certificate CN=servicebus.windows.net is not in the trusted people store
in the proxy log i am seeing 1454679317.842 0 10.168.84.150 TCP_DENIED/407 4046 GET http://www.microsoft.com/pki/mscorp/msitwww2.crt - HIER_NONE/- text/html
in the network traces i am seeing host trying to connect to http://www.microsoft.com/pki/mscorp/msitwww2.crt first it is trying to connect with out authentication then proxy is saying HTTP/1.1 407 Proxy Authentication required as a response to the request for this ideally host should resend the request with Proxy-Authorization Header which contains username and password but i am seeing a weird behavior where host is not send the Proxy-Authorization Header in the second time
any registry key needs to be set ?
i am using windows core 2012 R2 as host
this issue is fixed in 3.0.50496.1 or higher version of Microsoft.ServiceBus.dll