I have added a Java WSDL in my project as Web Reference. I am consuming it to call a service on an endpoint. I have added a WebMethod in an ASMX file and calling the service there. The requirement is to use WSE Security and sign the request with X509 Certificate.
Unfortunately, the Timestamp is creating issues and I am getting the response " An error was discovered processing the header". The Same request works from SoapUI if I remove the TimeStamp element from it.
This is how the request look like
Here is the code which creates the Security elements
//Set WSSE Security
svc.RequestSoapContext.Security.Timestamp.TtlInSeconds = 300;
svc.RequestSoapContext.Security.MustUnderstand = true;
svc.RequestSoapContext.Security.Tokens.Add(newtoken);
Microsoft.Web.Services3.Security.MessageSignature signature = new Microsoft.Web.Services3.Security.MessageSignature(newtoken);
signature.SignatureOptions = Microsoft.Web.Services3.Security.SignatureOptions.IncludeSoapBody;
svc.RequestSoapContext.Security.Elements.Add(signature);
===============
USING WCF
The problem persists even if I do it using WCF. As soon as I add IncludeTimestamp = false; the request is not getting sent and setting it to true is able to create request.
Here is the WCF Code -
//Create Endpoint
EndpointAddress address = new EndpointAddress((istest == true ? CHORUS_UFB_EMMA : CHORUS_UFB_PROD));
//Add Certificate to EndPoint Service
X509Certificate2 cert = new X509Certificate2(#"Certificate Path", "Password", X509KeyStorageFlags.PersistKeySet);
//Setup custom binding with HTTPS + Body Signing + Soap1.1
CustomBinding binding = new CustomBinding();
//HTTPS Transport
HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
//Set Security Binding as Transport
TransportSecurityBindingElement tsec = SecurityBindingElement.CreateCertificateOverTransportBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
tsec.EnableUnsecuredResponse = true;
tsec.AllowInsecureTransport = true;
tsec.SecurityHeaderLayout = SecurityHeaderLayout.Lax;
tsec.LocalServiceSettings.DetectReplays = false;
tsec.LocalClientSettings.DetectReplays = false;
tsec.IncludeTimestamp = false;
tsec.SetKeyDerivation(false);
tsec.EndpointSupportingTokenParameters.Signed.Add(new SecureConversationSecurityTokenParameters());
//Setup for SOAP 11 and UTF8 Encoding
TextMessageEncodingBindingElement textMessageEncoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
//Bind in order (Security layer, message layer, transport layer)
binding.Elements.Add(tsec);
binding.Elements.Add(textMessageEncoding);
binding.Elements.Add(transport);
Here is the generated request using above code
Any help on this would be appreciated.
This could potentially be caused by time differences between your client and the web server where the service you are calling is hosted.
Double check if the time on both servers match and are in sync. Times might need to be within 5 minute window.
Related
I have a selfhosted WCF service publishing a REST web API. The service is configured programmatically, and currently is correctly working via HTTP.
Now I need to make it work over HTTPS, with an authentication based on certificate file.
I know the suggested way to do this is installing the certificate in the Windows Certificate Store on the server machine, but this way is not possible in my circumstances.
I need to load the certificate from the file.
After some resarches, I wrote my code, but when I try accessing the web service, a System.ServiceModel.CommunicationException is thrown, with the message:
An error occurred while making the HTTP request to ... 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 caused by a mismatch of the security binding between the client and the server.
Here's my code for the server side:
_host = new WebServiceHost(_hostedService, Uri);
//Configuring the webHttpBinding settings
var httpBinding = new WebHttpBinding();
httpBinding.Security.Mode = WebHttpSecurityMode.Transport;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
httpBinding.SendTimeout = new TimeSpan(0, 5, 0);
httpBinding.MaxBufferSize = 2147483647;
httpBinding.MaxBufferPoolSize = 2147483647;
httpBinding.MaxReceivedMessageSize = 2147483647;
httpBinding.ReaderQuotas.MaxDepth = 2147483647;
httpBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
httpBinding.ReaderQuotas.MaxArrayLength = 2147483647;
httpBinding.ReaderQuotas.MaxBytesPerRead = 2147483647;
httpBinding.ReaderQuotas.MaxNameTableCharCount = 2147483647;
//Add the endpoint with the webHttpBinding settings to the WebServiceHost configuration
_host.AddServiceEndpoint(typeof(IService), httpBinding, Uri);
ServiceDebugBehavior stp = _host.Description.Behaviors.Find<ServiceDebugBehavior>();
stp.HttpHelpPageEnabled = false;
ServiceBehaviorAttribute sba = _host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
sba.InstanceContextMode = InstanceContextMode.Single;
ServiceMetadataBehavior smb = new ServiceMetadataBehavior() { HttpsGetEnabled = true };
_host.Description.Behaviors.Add(smb);
X509Certificate2 trustedCertificate = new X509Certificate2("certificate.pfx", "password");
_host.Credentials.ServiceCertificate.Certificate = trustedCertificate;
_host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
Here's my code for the client side:
var httpBinding = new WebHttpBinding();
httpBinding.Security.Mode = WebHttpSecurityMode.Transport;
httpBinding.Security.Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Certificate };
var httpUri = new Uri(String.Format("https://{0}:{1}", ipAddress, tcpPort));
var httpEndpoint = new EndpointAddress(httpUri);
var newFactory = new ChannelFactory<IService>(httpBinding, httpEndpoint);
newFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());
X509Certificate2 trustedCertificate = new X509Certificate2("certificate.pfx", "password"); //SSL
newFactory.Credentials.ClientCertificate.Certificate = trustedCertificate;
var channel = newFactory.CreateChannel();
var response = channel.Ping("helo");
The Exception is thrown on the last line (channel.Ping("helo")).
I need to make it work WITHOUT installing the certificate on the server machine.
Thank you very much.
Bye.
As far as I know, when we host the self-hosted WCF service over Https, whatever way we use (load certificate file or configure the certificate via Windows Certificate Store), it is impossible to make the service works normally. The only way we need to do is binding the certificate manually by using the following command.
netsh http add sslcert ipport=0.0.0.0:8000 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF}
Here is official document, wish it is useful to you.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
https://learn.microsoft.com/en-us/windows/desktop/http/add-sslcert
Here are some examples were ever written by me.
WCF Service over HTTPS without IIS, with SSL Certificate from CERT and KEY strings or files
Chrome (v71) ERR_CONNECTION_RESET on Self Signed localhost on Windows 8 Embedded
Feel free to let know if there is anything I can help with.
I'm trying to get my generated WCF ServiceClient to send its requests to the WCF service through a HTTP (not HTTPS) proxy with username/password authentication, however I just can't get it work. My WCF service uses basicHttpBinding so I tried to configure my ServiceClient instance like so:
var svc = new ServiceClient();
var b = svc.Endpoint.Binding as BasicHttpBinding;
b.ProxyAddress = new Uri(proxyAddress);
b.UseDefaultWebProxy = false;
b.Security.Mode = BasicHttpSecurityMode.Transport;
b.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
b.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.Basic;
svc.ClientCredentials.UserName.UserName = proxyUsername;
svc.ClientCredentials.UserName.Password = proxyPassword;
This however results in a System.ArgumentException saying:
The provided URI scheme http is invalid. expected https
When I set the b.Security.Mode to BasicHttpSecurityMode.None though, it seems the HTTP proxy settings are ignored by WCF altogether!
The second solution I tried was to set the DefaultWebProxy property of WebRequest and set the UseDefaultWebProxy property to true such as so:
var webProxy = new WebProxy(proxyAddress, true);
webProxy.Credentials = new NetworkCredential(proxyUsername, proxyPassword);
WebRequest.DefaultWebProxy = webProxy;
var svc = new ServiceClient();
var b = svc.Endpoint.Binding as BasicHttpBinding;
b.UseDefaultWebProxy = true;
However this also doesn't work and ServiceClient doesn't send it's requests through the HTTP proxy.
I'm out of ideas here so please let me know what I am doing wrong, thank you!
Set the security mode to BasicHttpSecurityMode.TransportCredentialOnly. This allows for passing plain-text authentication details over HTTP.
I am implementing mutual handshake over https using wcf, and I receive an error:
"The HTTP request was forbidden with client authentication scheme 'Anonymous'."
Service code:
var binding = new BasicHttpBinding()
{
Security =
{
Mode = BasicHttpSecurityMode.Transport,
Transport = { ClientCredentialType = HttpClientCredentialType.Certificate },
},
};
var sh = new ServiceHost(typeof(EchoService), new Uri("https://localhost:9876"));
//sh.Description.Behaviors.Add(new ServiceMetadataBehavior());
//sh.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpsBinding(), "mex");
sh.AddServiceEndpoint(typeof(IEchoService), binding, "");
sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
sh.Open();
Client code:
var binding = new BasicHttpBinding()
{
Security =
{
Mode = BasicHttpSecurityMode.Transport,
Transport = { ClientCredentialType = HttpClientCredentialType.Certificate },
},
};
var sslClientFactory = new ChannelFactory<IEchoService>(binding, "https://localhost:9876");
sslClientFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
var sslClient = sslClientFactory.CreateChannel();
var response = sslClient.Echo("Https Echo");
I have assign this certificate to port using httpcfg.
If I change binding from BasicHttpBinding to NetTcpBinding it works fine.
If I run two instances of my service (in one process), one which uses NetTcpBinding and second one which uses BasicHttpBinding, and consume it from net tcp client and https client, both works fine (clients use the same certificate).
What cases that if i run only my https client I get "The HTTP request was forbidden with client authentication scheme 'Anonymous'."?
I have noticed that I have a lot of doubled certs (pairs of two identically certs - with the same thumbrpint) in store (I dont know how i put them there like that), and I think that this was a problem. Maybe when certs are doubled in store, server sends to client only those issuers from not doubled certs?
I would like to setup a module which will communicate with other modules remotely acting both as a service and as a client. The communcation should go in SOAP 1.2 and it should use OASIS WSS 1.1, and X.509 certificate token profile.
OASIS WSS 1.1 X.509 specs
I already made a development certificate using makecert and it is trusted already.
Since the module is essentially C# based, all settings are given in code. So far I got the following service code:
The code for the binding:
System.ServiceModel.Channels.AsymmetricSecurityBindingElement asbe = new AsymmetricSecurityBindingElement();
asbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
asbe.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient };
asbe.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient };
asbe.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
asbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
asbe.EnableUnsecuredResponse = true;
asbe.IncludeTimestamp = false;
asbe.SetKeyDerivation(false);
asbe.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
asbe.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
asbe.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(asbe);
myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap12, Encoding.UTF8));
HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
httpsBindingElement.RequireClientCertificate = true;
myBinding.Elements.Add(httpsBindingElement);
The code for the behaviour:
//Then initiate the service host
_Host = new ServiceHost(typeof(TClass), baseAddress);
//Add the service endpoint we defined
_Host.AddServiceEndpoint(typeof(TInterface), _Binding, typeof(TInterface).ToString());//BindingHelper.GetUserNameBinding(), "");
//Set searching the certificate
_Host.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyServerCert");
_Host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
_Host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
//Allow the metadata spreading
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpsGetEnabled = true;
smb.HttpGetEnabled = true;
_Host.Description.Behaviors.Add(smb);
ServiceDebugBehavior sdb = new ServiceDebugBehavior();
sdb.IncludeExceptionDetailInFaults = false; //Should only provide the endpoint property (GP WS-Message profile specs)
//Add the appropriate endpoint
if (baseAddress.AbsoluteUri.Contains("https"))
_Host.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpsBinding(),
"mex");
else
_Host.AddServiceEndpoint(
typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(),
"mex");
On the client side I use the same code to create the binding, plus I use the following behavior:
channelFactory = new ChannelFactory<T>(bindIn, serviceAddress);
if (wsFeature != null)
{
channelFactory.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
channelFactory.Endpoint.Behaviors.Add(wsFeature);
channelFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyServerCert");
channelFactory.Credentials.ServiceCertificate.SetScopedCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "MyServerCert",serviceAddress.Uri);
}
_ProxiObject = channelFactory.CreateChannel();
Here basically the behavior wsFeature is a simple class doing practically nothing (just implements blank functions for IEndpointBehavior).
I have both service and client on the same machine at https://localhost.:8084/testhosting4, and even though both service and client are successfully created I only got the famous "An error occurred while making the HTTP request to https://localhost.:8084/testhosting4. etc." error.
I already managed to connect via an unsecure channel with the module (BasicHttpBinding - no security) and exchange messages, so I am sure that I make a mistake in defining the binding or assigning credentials. Obviously, I browsed a lot here already, but couldn't come up with a working solution.
This is the first time I meet WCF and X509 and I'm not in secure communications at all either. So plenty of occasions to make a mistake. Please point out those which I've made.
Thank you!
I'm trying to develop a simple application that will enable users to purchase services off a website through the Paypal API. This application is running on ASP.NET with C#.
I have had very little luck trying to get the Paypal API to co-operate. The method I'm calling is SetExpressCheckout with all the appropriate variables.
I did my research and discovered that since I'm testing in Localhost, it may affect Paypal's ability to communicate with the application. So the next thing I tried was accessing my application through an open port and a publicly accessible IP address, but the same error occurs on the call to SetExpressCheckout.
Here is the error:
Exception Details: System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
Source Error:
Line 1790: [return: System.Xml.Serialization.XmlElementAttribute("SetExpressCheckoutResponse", Namespace="urn:ebay:api:PayPalAPI")]
Line 1791: public SetExpressCheckoutResponseType SetExpressCheckout([System.Xml.Serialization.XmlElementAttribute(Namespace="urn:ebay:api:PayPalAPI")] SetExpressCheckoutReq SetExpressCheckoutReq) {
Line 1792: object[] results = this.Invoke("SetExpressCheckout", new object[] {
Line 1793: SetExpressCheckoutReq});
Line 1794: return ((SetExpressCheckoutResponseType)(results[0]));
Source File: c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\anan_p2\730602d6\31a8d74e\App_WebReferences.c8vgyrf8.2.cs Line: 1792
I've also tried generating certificates using OpenSSL and uploading them to the Paypal account's encrypted seller option but still no effect.
Thank you very much for reading through my question!
Update: As requested here is the code being used.
String hostingOn = ConfigurationManager.AppSettings["default_site_url"];
reqDetails.ReturnURL = hostingOn + "marketplace_confirm.aspx";
reqDetails.CancelURL = hostingOn + "marketplace.aspx";
reqDetails.NoShipping = "1";
reqDetails.ReqConfirmShipping = "0";
reqDetails.OrderTotal = new BasicAmountType()
{
currencyID = CurrencyCodeType.CAD,
Value = payment_amt.Value,
};
SetExpressCheckoutReq req = new SetExpressCheckoutReq()
{
SetExpressCheckoutRequest = new SetExpressCheckoutRequestType()
{
Version = UtilPayPalAPI.Version,
SetExpressCheckoutRequestDetails = reqDetails
}
};
PayPalAPIAASoapBinding paypal = new PayPalAPIAASoapBinding();
paypal.SetExpressCheckout(req);
I am also using the https://api-aa-3t.paypal.com/2.0/ url for accessing the API
Since early 2016, Paypal started requiring TLS 1.2 protocol for communications in the Sandbox, and will enforce it for the live environment starting June 17. See here for reference.
In most .NET applications TLS 1.2 will come disabled by default, and therefore you'll need to enable it.
You need to add the following line, for example, at the beginning of you Application_Start method:
public class Site : HttpApplication
{
protected void Application_Start()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
// other configuration
}
}
You're probably connecting to api.paypal.com or api.sandbox.paypal.com, and not sending along your API certificate. The API certificate is a client SSL certificate used to complete the SSL chain.
If you don't have or are not using an API certificate, you should connect to api-3t.paypal.com or api-3t.sandbox.paypal.com for Live or Sandbox respectively.
I've been working with a PayPal (NVP/Signature) Express Checkout integration and have been hit with this SSL/TLS error.
Nothing I did seemed to get around it but then I found the following code to add above my request. For reference, I'm using MVC3/.NET 4 so Tls1.2 isn't available to me by default (like in .NET 4.5 +). This first three lines of this code gets around that. I hope it helps people!
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
ServicePointManager.DefaultConnectionLimit = 9999;
var url = "https://[paypal-api-url]/nvp";
var uri = new Uri(url);
var request = WebRequest.Create(uri);
var encoding = new UTF8Encoding();
var requestData = encoding.GetBytes(data);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.Timeout = (300 * 1000);
request.ContentLength = requestData.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(requestData, 0, requestData.Length);
}
var response = request.GetResponse();
...
Thanks a lot that really helps me.
For reference here is my code for establishing the interface in VB.NET
'Create a service Binding in code
Dim ppEndpointAddress As New System.ServiceModel.EndpointAddress("https://api-3t.sandbox.paypal.com/2.0/")
Dim ppBinding As New System.ServiceModel.BasicHttpBinding(System.ServiceModel.BasicHttpSecurityMode.Transport)
Dim ppIface As New PayPalAPI.PayPalAPIAAInterfaceClient(ppBinding, ppEndpointAddress)
Dim ppPaymentReq As New PayPalAPI.DoDirectPaymentReq()
ppPaymentReq.DoDirectPaymentRequest = ppRequest