Exception during secure communication implementation - wcf

im trying to implement simple secured client server communiction using WCF.
when im launching mt server everty thing is OK , But when im launching my client im getting this error:
Error : An error occurred while making the HTTP request to https://localhost:800
0/ExchangeService. 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 caus
ed by a mismatch of the security binding between the client and the server.
this is the server code :
Uri address = new Uri("https://localhost:8000/ExchangeService");
WSHttpBinding binding = new WSHttpBinding();
//Set Binding Params
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
Type contract = typeof(ExchangeService.ServiceContract.ITradeService);
ServiceHost host = new ServiceHost(typeof(TradeService));
host.AddServiceEndpoint(contract, binding, address);
host.Open();
this is the client configuration (app.config):
</client>
<bindings>
<wsHttpBinding>
<binding name="TradeWsHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None"
proxyCredentialType ="None"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
the security configuration at both the client and the server are the same , and i dont need certificate for the server in that kind of security (transport) so why do i get
this exception ????
thanks...

Well looking at your code:
Uri address = new Uri("https://localhost:8000/ExchangeService");
You're specifying that the address is using SSL (https) so it would require a certificate for that purpose. Either use a http binding or install a certificate.
I'd check out the Application Scenarios and How Tos section on this CodePlex Link for different configurations and details of how to configure them.

Related

Cannot set ClientCredentials for WCF SOAP Request

I am using Visual Studio 2019 to try to create a .Net 4.5.2 client that consumes a remote Web service using SOAP over HTTPS. To authenticate, the service requires a client certificate be attached to all requests. The client instantiates the System.ServiceModel.ClientBase class. It seems no matter how I generate the client class, I cannot set the ClientCredentials I think because the ClientCredentials are read-only.
Here's the commands I used to generate the client class:
svcutil.exe /t:metadata https://example.com?WSDL
svcutil.exe /language:cs /config:app.config /messagecontract *.xsd *.wsdl
Here's the binding I use in my web.config file:
<bindings>
<basicHttpBinding>
<binding name="TCSOnlineServicePortBinding">
<!-- I am not sure of the mode below, message also does not work -->
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Certificate" proxyCredentialType="None" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://example.com"
binding="basicHttpBinding" bindingConfiguration="TCSOnlineServicePortBinding"
contract="TCSOnlineService" name="TCSOnlineServicePort" />
</client>
Here's the code that doesn't work:
var TCSSvcClient = new TCSOnlineServiceClient(tcs_endpoint, TCSEndpointAddr);
var aCert = new X509Certificate2();
... [omitting code to find cert in MY store]
// The line below leave the ClientCertificate.Certificate set to NULL????? Why??
TCSSvcClient.ClientCredentials.ClientCertificate.Certificate = aCert;
// This also does not work, certificate is left NULL
TCSSvcClient.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2();
Can anybody see what I'm doing wrong? Thanks in advance.
We had better configure the certificate by using the LocalMachine store and then add the current user running the client application to the management group of the private key of the certificate.
ServiceReference1.TestServiceClient client = new ServiceReference1.TestServiceClient();
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "9ee8be61d875bd6e1108c98b590386d0a489a9ca");
var result = client.GetResult("a");
result = client.Test();
Console.WriteLine(result);
For the client’s certificate generated with Powershell, we had better target the application DotNet4.6.2 or above.
There is a problem to supply a client certificate in this way. We need to ensure that the current user can read the private key of the certificate.
TCSSvcClient.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2();
Besides, authenticating the client with a certificate requires a trust relationship between the client-side and the server-side. have you established the trust relationship before calling the service?
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.

WCF - How to configure netTcpBinding for NTLM authentication?

I know how to configure basicHttpBinding for NTLM authentication, but can't figure out a way to do the same for netTcpBinding.
Does netTcpBinding support NTLM? If so, how to force WCF service to use NTLM?
BTW a well known method using identity element for some reason didn't work at all. I am looking for something like this - clientCredentialType ="Ntlm" but for tcp.
Here is basicHttp setting:
<basicHttpBinding>
<binding name="BasicHttpBinding">
<security mode ="TransportCredentialOnly">
<transport clientCredentialType ="Ntlm"/>
</security>
</binding>
</basicHttpBinding>
Here is the comprehensive answer that I finally found, tested, and confirmed.
A. My WCF client used to build an EndPoint.Address dynamically as follow
EndPointAddress myEdpintAddress = new EndPointAddress(stringURL);
But in the case of a secure transport (net.tcp) it has to be initialized as follow
EndPointAddress myEdpintAddress = new EndPointAddress(new UrRL(string), myEndPointIdentity)
Without the EndPointIdentity parameters the Identity property in the EndPointAddress object is null, and generates the “...target principal name is incorrect... " error on the server side.
B. Our domain controller supports both Kerberos and Ntlm authentication. After above is done, generally there are four configuration scenarios on the client side for the net.tcp binding if security is other than “None”, and the WCF service runs as a domain account:
No <identity> elements in the client endpoint specified - WCF call fails
<identity> element provided, but with an empty value for dns, userPrioncipalName or servicePrincipalName elements - WCF call successful, but uses the Ntlm authentication
<identity> element provided with the a value for dsn or SPN – WCF call successfull; service uses Ntlm to authenticate.
<identity> element provided with the correct value for upn – WCF call successfull; service uses Kerberos for authenticate. Incorrect or missing value for upn trigger Ntlm authentication
Thanks.
The Net TCP Binding does not support "NTLM" as a client credentials type - you have a choice of None, Windows or Certificate only (see the MSDN docs on TcpClientCredentialType).
So in your case, try this:
<netTcpBinding>
<binding name="tcpWindows">
<security mode ="TransportCredentialOnly">
<transport clientCredentialType ="Windows"/>
</security>
</binding>
</netTcpBinding>
Any reason why this doesn't work??

Connecting to a WSE 3.0 Web Service From a WCF Client

I'm having difficulty connecting to a 3rd party WSE 3.0 web service from a WCF client. I have implemented the custom binding class as indicated in this KB article:
http://msdn.microsoft.com/en-us/library/ms734745.aspx
The problem seems to have to do with the security assertion used by the web service - UsernameOverTransport.
When I attempt to call a method, I get the following exception:
System.InvalidOperationException: The
'WseHttpBinding'.'[namespace]'
binding for the
'MyWebServiceSoap'.'[namespace]'
contract is configured with an
authentication mode that requires
transport level integrity and
confidentiality. However the transport
cannot provide integrity and
confidentiality..
It is expecting a username, password, and CN number. In the example code supplied to us by the vendor, these credentials are bundled in a Microsoft.Web.Services3.Security.Tokens.UsernameToken. Here's the example supplied by the vendor:
MyWebServiceWse proxy = new MyWebServiceWse();
UsernameToken token = new UsernameToken("Username", "password", PasswordOption.SendPlainText);
token.Id = "<supplied CN Number>";
proxy.SetClientCredential(token);
proxy.SetPolicy(new Policy(new UsernameOverTransportAssertion(), new RequireActionHeaderAssertion()));
MyObject mo = proxy.MyMethod();
This works fine from a 2.0 app w/ WSE 3.0 installed. Here is a snippet of the code from my WCF client:
EndpointAddress address = new EndpointAddress(new Uri("<web service uri here>"));
WseHttpBinding binding = new WseHttpBinding(); // This is the custom binding I created per the MS KB article
binding.SecurityAssertion = WseSecurityAssertion.UsernameOverTransport;
binding.EstablishSecurityContext = false;
// Not sure about the value of either of these next two
binding.RequireDerivedKeys = true;
binding.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
MembershipServiceSoapClient proxy = new MembershipServiceSoapClient(binding, address);
// This is where I believe the problem lies – I can’t seem to properly setup the security credentials the web service is expecting
proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "pwd";
// How do I supply the CN number?
MyObject mo = proxy.MyMethod(); // this throws the exception
I've scoured the web looking for an answer to this question. Some sources get me close (like the MS KB article), but I can't seem to get over the hump. Can someone help me out?
I had success in a similar case with the following binding configuration:
<bindings>
<customBinding>
<binding name="FNCEWS40MTOMBinding">
<security enableUnsecuredResponse="true" authenticationMode="UserNameOverTransport"
allowInsecureTransport="true" messageProtectionOrder="SignBeforeEncrypt">
<secureConversationBootstrap />
</security>
<mtomMessageEncoding messageVersion="Soap12WSAddressingAugust2004"
maxBufferSize="2147483647" />
<httpTransport maxReceivedMessageSize="2147483647" />
</binding>
</customBinding>
</bindings>
Hope it works for you too.
The error message is refering to Transport Level Security, this usually means https.
You have not shown your configuration files. But I am guessing that you have configured security to be transport (or it is required as a consiquence of another choice) and used an address that is http instead of https.

Can not call web service with basic authentication using WCF

I've been given a web service written in Java that I'm not able to make any changes to. It requires the user authenticate with basic authentication to access any of the methods. The suggested way to interact with this service in .NET is by using Visual Studio 2005 with WSE 3.0 installed.
This is an issue, since the project is already using Visual Studio 2008 (targeting .NET 2.0). I could do it in VS2005, however I do not want to tie the project to VS2005 or do it by creating an assembly in VS2005 and including that in the VS2008 solution (which basically ties the project to 2005 anyway for any future changes to the assembly). I think that either of these options would make things complicated for new developers by forcing them to install WSE 3.0 and keep the project from being able to use 2008 and features in .NET 3.5 in the future... ie, I truly believe using WCF is the way to go.
I've been looking into using WCF for this, however I'm unsure how to get the WCF service to understand that it needs to send the authentication headers along with each request. I'm getting 401 errors when I attempt to do anything with the web service.
This is what my code looks like:
WebHttpBinding webBinding = new WebHttpBinding();
ChannelFactory<MyService> factory =
new ChannelFactory<MyService>(webBinding, new EndpointAddress("http://127.0.0.1:80/Service/Service/"));
factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
factory.Credentials.UserName.UserName = "username";
factory.Credentials.UserName.Password = "password";
MyService proxy = factory.CreateChannel();
proxy.postSubmission(_postSubmission);
This will run and throw the following exception:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server
was 'Basic realm=realm'.
And this has an inner exception of:
The remote server returned an error: (401) Unauthorized.
Any thoughts about what might be causing this issue would be greatly appreciated.
First question: is this a SOAP or a REST based Java service you're trying to call?
Right now, with the "webHttpBinding", you're using a REST-based approach. If the Java service is a SOAP service, then you'd need to change your binding to be "basicHttpBinding" instead.
IF it's a SOAP based service, you should try this:
BasicHttpBinding binding = new BasicHttpBinding();
binding.SendTimeout = TimeSpan.FromSeconds(25);
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Basic;
EndpointAddress address = new EndpointAddress(your-url-here);
ChannelFactory<MyService> factory =
new ChannelFactory<MyService>(binding, address);
MyService proxy = factory.CreateChannel();
proxy.ClientCredentials.UserName.UserName = "username";
proxy.ClientCredentials.UserName.Password = "password";
I've used this with various web services and it works - most of the time.
If that doesn't work, you'll have to find out more about what that Java webservice expects and how to send that relevant info to it.
Marc
First of all put the following in your app.config or your web.config. (no need to change this as you move it through environments):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IConfigService">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:55283/ConfigService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IConfigService"
contract="IConfigService" name="BasicHttpBinding_IService" />
</client>
</system.serviceModel>
Change the contract attribute to the the Namespace.Interface name accordingly.
Note the security mode = TransportCredentialOnly
Now to programmatically change the endpoint and pass the credentials, use the following code:
var myBinding = new BasicHttpBinding("BasicHttpBinding_IConfigService");
var myEndpoint = new EndpointAddress("http://yourbaseurl/configservice.svc");
var myChannelFactory = new ChannelFactory<IConfigService>(myBinding, myEndpoint);
var credentialBehaviour = myChannelFactory.Endpoint.Behaviors.Find<ClientCredentials>();
credentialBehaviour.UserName.UserName = #"username";
credentialBehaviour.UserName.Password = #"password";
IConfigService client = null;
try
{
client = myChannelFactory.CreateChannel();
var brands = client.YourServiceFunctionName();
((ICommunicationObject)client).Close();
}
catch (Exception ex)
{
if (client != null)
{
((ICommunicationObject)client).Abort();
}
}
I will add to this as well based on a similar problem I just experienced. I auto-generated the config / proxy with VS -- but the config it created didn't actually work.
Although it had security mode="Transport" set correctly, it didn't have clientCredentialType="Basic" set. I added to that my config and it still didn't work. Then I actually removed the message security that the tool created since the service I'm contacting is SSL + Basic only:
<message clientCredentialType="UserName" algorithmSuite="Default" />
Voila -- it worked.
I'm not sure why this had an effect considering the element did not specify message level security... but it did.

Enable SSL for my WCF service

I have a WCF service that uses basicHttpbinding in development.
Now in product we want to use SSL, what changes do I have to make to force SSL connections only?
This page on MSDN explains WCF Binding Security.
http://msdn.microsoft.com/en-us/library/ms729700.aspx
The BasicHttpBinding class is
primarily used to interoperate with
existing Web services, and many of
those services are hosted by Internet
Information Services (IIS).
Consequently, the transport security
for this binding is designed for
seamless interoperation with IIS
sites. This is done by setting the
security mode to Transport and then
setting the client credential type.
The credential type values correspond
to IIS directory security mechanisms.
The following code shows the mode
being set and the credential type set
to Windows. You can use this
configuration when both client and
server are on the same Windows domain.
C#
BasicHttpBinding b = new BasicHttpBinding();
b.Security.Mode = BasicHttpSecurityMode.Transport ;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Or, in configuration:
<bindings>
<basicHttpBinding>
<binding name="SecurityByTransport">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
To enable ssl, without a login, set clientCredentialType to "None".
Options for security mode are:
None, Transport, Message, TransportWithMessageCredential and TransportCredentialOnly
You can find more details at: http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode.aspx
I just faced the same problem and found this MSDN article:
How to: Configure an IIS-hosted WCF service with SSL
At the end of the article you will find the xml configuration of the WebConfig file.
The solution worked just fine for me. One more thing to say, keep in mind that you need a REAL certificate for your release!
I think that if under your bindings where you have the <Security mode="Transport">, if you would change it to be <security mode="None">, you would be ok.
This is a copy of a code base that I'm working on and I tried that in-code, and it appears to be working.
I get the WSDL at least when I call the service, if that helps at all.
BasicHttpBinding basicBinding = new BasicHttpBinding();
if (RegistryConnectionStringFactory.UseSslForCommunications)
{
basicBinding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
basicBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
}
else
{
basicBinding.Security.Mode = BasicHttpSecurityMode.None;
basicBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
}