Configuring winform app to call SOAP https with windows autentication - c#

I have a SOAP that I'm trying to work with but I encounter the next problem that I didn't find the solution in similar questions:
The SOAP has to be called via HTTPS and with Windows credentials.
What I tried to do in the app config is the next things:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpsBinding>
<binding name="WebServiceSoap">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Windows" />
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpsBinding>
</bindings>
<client>
<endpoint address="https://someapp/SDK/WebService.asmx"
binding="basicHttpsBinding" bindingConfiguration="WebServiceSoap"
contract="someapp_contract.WebServiceSoap" name="WebServiceSoap" />
</client>
</system.serviceModel>
</configuration>
And the error that I get is:
The username is not provided. Specify username in ClientCredentials.And the error
I tried a differt confingruation too with basicHttpBinding
and
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
But than the error that is I get is(which is a very logical error):
provided URI scheme 'https' is invalid; expected 'http'...
Did anyone have the same issue in the past?
Thanks in advance.
Max
P.S:
If I do
<security mode="Transport">
instead of
<security mode="TransportWithMessageCredential">
I get the next error:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.

Following the settings above.
When I use:
<security mode="Transport">
and get the error:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.
What I did are the next changes.
1) first at the app.config
<security mode="Transport">
<transport clientCredentialType="Windows" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
Than at the code:
public static class Ssl
{
private static readonly string[] TrustedHosts = new[] {
"YourServiceName",
"YourServiceName2"
};
public static void EnableTrustedHosts()
{
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, errors) =>
{
if (errors == SslPolicyErrors.None)
{
return true;
}
var request = sender as HttpWebRequest;
if (request != null)
{
return TrustedHosts.Contains(request.RequestUri.Host);
}
return false;
};
}
}
And:
YourContractInstance.ClientCredentials.Windows.ClientCredential.UserName = ***;
YourContractInstance.ClientCredentials.Windows.ClientCredential.Domain = ***;
YourContractInstance.ClientCredentials.Windows.ClientCredential.Password = ***;
YourContractInstance.ClientCredentials.Windows.AllowNtlm = true;
All of this workaround was made because I have some problem with the certificate|DNS configuration on the host of the SOAP service that I'm not allowed to access so I had to add the Service reference by IP.

Related

C# ASMX Service throwing The content type text/html; charset=UTF-8 of the response message does not match the content type error

I have added a ASMX service reference to my project by doing right click on the root --> add service reference.
I have it like this on my web.config file:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="xxx" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="serviceaddress"
binding="basicHttpBinding" bindingConfiguration="xxx"
contract="xxx" name="xxx" />
</client>
</system.serviceModel>
This service has a method that receives a string with a username and validates if it exists.
The problem is that I'm testing it on Postman and it's returning the following error message:
The content type text/html; charset=UTF-8 of the response message does not match the content type
I've already checked on other posts similar like this one but I'm not able to find the solution.
Here's the method that I invoke which is throwing the error:
public static List<UserInformation> GetUsersByUserName(string userName)
{
try
{
var usersServiceClient = new LDapServicesSoapClient();
var requestMessage = new LDapUserNameLookupRequest();
requestMessage.UserName = userName;
requestMessage.AccessKey = "secretkey";
var response = usersServiceClient.LDapGetUserByUserName(requestMessage);
return response.Users.ToList();
}
catch (CommunicationException e)
{
if (e.InnerException is QuotaExceededException)
{
throw new Exception("We have found many users, please write another filter");
}
else
{
throw new Exception(e.Message, e);
}
}
}
Adding this configuration to my web.config file did the magic:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="LDapServicesSoap" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false" bypassProxyOnLocal="false" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="address"
binding="basicHttpBinding" bindingConfiguration="LDapServicesSoap"
contract="LDapServices.LDapServicesSoap" name="LDapServicesSoap" />
</client>
</system.serviceModel>

Programmatically define WCF Endpoints with Behaviours

Can anyone show me how to programmatically create WSHttpBindings with Endpoint behaviours?
This is what was generated from WCF Add Service references to 6 WebServices which I manually editted to add behaviours so that all the endpoints uses the same behaviour .
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="epBehaviour">
<clientCredentials>
<clientCertificate findValue="This is my TEST Cert" storeLocation="LocalMachine" x509FindType="FindBySubjectName" storeName="My" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IQuote" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
<binding name="WSHttpBinding_ICommit" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
<binding name="WSHttpBinding_IRetrieve" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
<binding name="WSHttpBinding_IInfo" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
<binding name="WSHttpBinding_IPurge" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
<binding name="WSHttpBinding_ISearch" messageEncoding="Mtom">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="Certificate" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://my.service.com/WCFServices/Info.svc" behaviorConfiguration="epBehaviour" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IInfo" contract="InfoWcfWS.IInfo" name="WSHttpBinding_IInfo" />
<endpoint address="https://my.service.com/WCFServices/Quote.svc" behaviorConfiguration="epBehaviour" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IQuote" contract="QuoteWcfWS.IQuote" name="WSHttpBinding_IQuote" />
<endpoint address="https://my.service.com/WCFServices/Commit.svc" behaviorConfiguration="epBehaviour" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICommit" contract="CommitWcfWS.ICommit" name="WSHttpBinding_ICommit" />
<endpoint address="https://my.service.com/WCFServices/Retrieve.svc" behaviorConfiguration="epBehaviour" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IRetrieve" contract="RetrieveWcfWS.IRetrieve" name="WSHttpBinding_IRetrieve" />
<endpoint address="https://my.service.com/WCFServices/Purge.svc" behaviorConfiguration="epBehaviour" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IPurge" contract="PurgeWcfWS.IPurge" name="WSHttpBinding_IPurge" />
<endpoint address="https://my.service.com/WCFServices/Search.svc" behaviorConfiguration="epBehaviour" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ISearch" contract="SearchWcfWS.ISearch" name="WSHttpBinding_ISearch" />
</client>
</system.serviceModel>
Currently with the generated Proxy from the "Add Service" and adding the behaviour "epBehaviour" which is referenced in the endpoints as a behaviourConfiguration, I can make calls to the endpoints.
Now, my next step is to define the behaviour part and the URL as configurations (May be in the of the web.config) so that I can have different config for Staging and Production.
So my sample Staging config will have the URL defined as below
<appSettings>
<add key="ServiceUrl.Tls12.Quote" value="https://my.service.com/WCFServices/Quote.svc" />
<add key="ServiceUrl.Tls12.Commit" value="https://my.service.com/WCFServices/Commit.svc" />
<add key="ServiceUrl.Tls12.Retrieve" value="https://my.service.com/WCFServices/Retrieve.svc" />
<add key="ServiceUrl.Tls12.Info" value="https://my.service.com/WCFServices/Info.svc" />
<add key="ServiceUrl.Tls12.Purge" value="https://my.service.com/WCFServices/Purge.svc" />
<add key="ServiceUrl.Tls12.Search" value="https://my.service.com/WCFServices/Search.svc" />
</appSettings>
So if I'm consuming the "Info" WebService, my code should be something like
//Code is missing how to define all the specifics like behaviours.
WSHttpBinding binding = new WSHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri(ConfigurationManager.AppSettings["ServiceUrl.Tls12.Info"]));
InfoWcfWS.InfoClient proxyNew = new InfoWcfWS.InfoClient(binding, endpoint);
In Summary, given the generated config after an "Add Service", to generate my Proxy Classes, I would like to remove all the config generated by VS and define my own config which will hold the URL; Everything else like endpoints URI, behaviours ..etc should be instantiated programmatically.
Thanks
You have to create instances of the behavior you need either from the System.ServiceModel.Description namespace or create them yourself and then add them to a ChannelFactory.
For your example you create a ChannelFactory for the interface you want and any binding you prefer. You then instantiate a ClientCredentials behavior, configure any of the settings you need on it and add it to the EndPointBehaviors of the ChannelFactory. Then you're ready to create a clientchannel that will give you an object that implements your service interface. You can use that similar as the generated client.
// binding
var binding = new WSHttpBinding();
// using System.ServiceModel
var channelFactory = new ChannelFactory<InfoWcfWS.IInfo>(binding);
// using System.ServiceModel.Description
var endpointClientbehavior = new ClientCredentials();
endpointClientbehavior.ClientCertificate
.SetCertificate(
"This is my TEST Cert",
StoreLocation.LocalMachine,
StoreName.My);
// add the behavior to the endpoint
channelFactory.Endpoint.EndpointBehaviors.Add(endpointClientbehavior);
// done configuring;
channelFactory.Open();
var endpoint = new EndpointAddress(
new Uri(ConfigurationManager.AppSettings["ServiceUrl.Tls12.Info"]));
// create the clientChannel
var client = channelFactory.CreateChannel(endpoint);
client.Open();
// client implements the operations on InfoWcfWS.IInfo
In the end, I found a simpler way of achieving this - This is one of the method Info I'm accessing:
WSHttpBinding binding = new WSHttpBinding();
EndpointAddress endpoint = new EndpointAddress(new Uri("https://my.service.com/WCFServices/Info.svc"));
binding.Name = "WSHttpBinding_IInfo";
binding.MessageEncoding = WSMessageEncoding.Mtom;
binding.Security = new WSHttpSecurity();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Transport = new HttpTransportSecurity();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message = new NonDualMessageSecurityOverHttp();
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
binding.Security.Message.EstablishSecurityContext = false;
InfoClient proxy = new InfoClient(binding, endpoint);
proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "This is my TEST Cert");
object response = proxy.ServiceMethod();

consuming webservice using https protocol

I'm developing an application where i have to consume webservice developed in Java using http protocol.
I'm developing the application using C#.NET winforms. Everything works fine until now. The webservice is now using SSL security hence the service protocol changed from http to https. I'm facing issues while accessing the https webservice.
I tried accessing the https webservice from the SoapUI by providing the Authenticaion Parameters (UserName and Password) from the Auth tab as shown below:
It is working fine from SoapUI.
but wen i provide the Authenticaion parameters from code as below its not working:
client.ClientCredentials.UserName.UserName = "admin";
client.ClientCredentials.UserName.Password = "*******";
I'm using Security Mode as : TransportWithMessageCredential
and
ClientCredentialTtype as : Basic
My App.Config file is as below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<client>
<endpoint address="https://xyz:8001/HelloWorldAPI/HelloWorldWebService"
binding="wsHttpBinding"
bindingConfiguration="myhttpsbinding" contract="API.HelloWorldWebService"
name="HelloWorldWebServicePort" />
</client>
<bindings>
<wsHttpBinding>
<binding name="myhttpsbinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
<system.net>
<defaultProxy useDefaultCredentials="true" />
</system.net>
</configuration>
My Code as below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using testingtool.API;
namespace testingtool
{
class Program
{
static void Main(string[] args)
{
new APITool();
}
}
class APITool
{
UserInfo userinfo = new UserInfo();
HelloWorldWebServiceClient client = new HelloWorldWebServiceClient();
private bool ValidationCallBack(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
public APITool()
{
try
{
//Authentication parameters
client.ClientCredentials.UserName.UserName = "admin";
client.ClientCredentials.UserName.Password = "*****";
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidationCallBack);
//client ClientCredentials # Application level
userinfo.userid = "myusername";
userinfo.password = "*****";
GetHelloWorldAPIVersionRequest request = new GetHelloWorldAPIVersionRequest();
APIVersionInfo versioninfo = new APIVersionInfo();
versioninfo.userinfo = userinfo;
request.APIVersionInfo = versioninfo;
APIVersionInfoResponse response = client.GetHelloWorldAPIVersion(versioninfo);
Console.WriteLine(response.Version);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadLine();
}
}
}
I'm getting following exception:
System.ServiceModel.Security.MessageSecurityException: The HTTP
request is unauthorized with client authentication scheme 'Anonymous'.
The authentication header received from the server was 'Basic
realm="EJBServiceEndpointServlet Realm"'. --->
System.Net.WebException: The remote server returned an error: (401)
Unauthorized.
EDIT: from the client i have verified with Fiddler the request window as below:
from the AUth tab it is saying that there is no Autherization Header present.
Fiddler Raw Request as below:
CONNECT 10.10.10.110:8001
HTTP/1.1 Host: 10.10.10.110:8001
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Any help wouldbe greatly appreciated.
Wondering if the issue could be with the binding, although hard to say for sure without reviewing the service configuration or seeing the successful soapUI request. (Note: you may want to include a snippet of the message, including the soap header, from the soapUI HTTP Log.)
In any case, you may want to make sure the service is really using ws-security (message level security) by trying the following binding:
<bindings>
<basicHttpBinding>
<binding name="httpBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
You should change your app config:
<wsHttpBinding>
<binding name="myhttpsbinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" establishSecurityContext="false" negotiateServiceCredential="false"/>
</security>
</binding>
</wsHttpBinding>
On transport level you have no authentication, so <transport clientCredentialType="None" /> and on message level you have username|password authentication, so <message clientCredentialType="UserName"
are you going thru a proxy server? If yes, are the details entered into IE ? Are you able to browse https pages in IE? If yes, this should be picked up by each WebRequest that makes an https call as it needs to issue a CONNECT to the proxy server (which its doing) but in your call the Proxy-Authorization header is missing. This should be your focus - try a plain WebRequest to say https:// google.com and see what you get in fiddler.
You may have an issue with your proxy server forwarding on your request. Are you able to try https on a different network not behind a proxy?
Maybe this link can help.
It explains how to configure your endpoint in case of REST/SOAP WebServices
Can not call web service with basic authentication using WCF
I have given <security mode="Transport" /> inside binding and issue solved for calling HTTPS service. Full code:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceSoap">
<security mode="Transport" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://yourlink/Service.asmx" binding="basicHttpBinding" bindingConfiguration="ServiceSoap" contract="EmployeeService.ServiceSoap" name="ServiceSoap"/>
</client>
</system.serviceModel>
Its binding issue you need to use custom binding here is example.
http://webservices20.blogspot.com/

Error "The username is not provided. Specify username in ClientCredentials." when passing CredentialCache.DefaultNetworkCredentials

I am writing a simple C# console application that will make a call to the "Lists.asmx" web service on a SharePoint site in order to pull down attachments. I've already added the service reference and tried to run it but it fails with the error
The username is not provided. Specify username in ClientCredentials.
when it tries to make a service method call to GetAttachmentCollection. Below is the code:
static void Main(string[] args)
{
ListsSoapClient client = new ListsSoapClient();
client.ClientCredentials.Windows.ClientCredential =
CredentialCache.DefaultNetworkCredentials;
XElement attachments = client.GetAttachmentCollection("Projects", "42");
// Do something with the attachments
}
As you can see I'm trying to set the ClientCredential to be the credentials for the the current user but it does not appear to be sending the user name. My SharePoint site is configured with https and Windows Authentication. Below is my simple config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpsBinding>
<binding name="ListsSoap">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Ntlm"
proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpsBinding>
</bindings>
<client>
<endpoint address="https://intranet.test.com/_vti_bin/Lists.asmx"
binding="basicHttpsBinding" bindingConfiguration="ListsSoap"
contract="ListServiceProxy.ListsSoap" name="ListsSoap" />
</client>
</system.serviceModel>
</configuration>
I have tried clientCredentialType="NtlM" and clientCredentialType="Windows" but I get the same result. Is there something wrong with my configuration file or some variable that I need to set on client?

How to pass user credentials to web service?

I am consuming a webservice using WSDL in windows application. When I try to use method, i get the following error:-
The HTTP request is unauthorized with client authentication scheme
'Anonymous'. The authentication header received from the server was '"
{"The remote server returned an error: (401) Unauthorized."}
I have user credentials but don't know how to pass it using c# code in windows application.
Here is the how it is working for me:-
Config file setting looks like this:-
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="bindingName" >
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" proxyCredentialType="None" realm=""/>
<message clientCredentialType="UserName" algorithmSuite="Default"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://10.10.10.10:1880/testpad/services/Testwebservice"
binding="basicHttpBinding" bindingConfiguration="bindingName"
contract=testService.GetData" name="test_Port1" />
</client>
</system.serviceModel>
</configuration>
and here i am passing user credentials:-
var ser = new GetDataClient();
ser.ClientCredentials.UserName.UserName = "userid";
ser.ClientCredentials.UserName.Password = "Pa$$word1";
You can try to genereate your service client proxy using the method mentioned here. Once you have an instance of your WCF client proxy, it will have a property ClientCreditials which you can populate as needed.
Hope this helps.

Categories

Resources