I have some legacy code on F#
let response =
Http.Request (
ArtifactoryUrl,
silentHttpErrors = true,
httpMethod = "POST",
body = HttpRequestBody.TextRequest requestJson,
headers = [
HttpRequestHeaders.BasicAuth ArtifactoryUserName ArtifactoryPassword
HttpRequestHeaders.ContentType "application/json"
HttpRequestHeaders.Accept "application/json"
]
)
Starting from some time, it failed with the following error
exception: System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
I suspect that it is due to recent web server limitation to TLS 1.2 only.
How can i fix it? How can i select TLS1.2 only?
Any help here will highly appreciated!
I believe it happens because you are using old version of .net framework (less than 4.7).
If so, you can set the default and fallback versions for outbound calls using the ServicePointManager:
ServicePointManager.SecurityProtocol <- SecurityProtocolType.Tls12 ||| SecurityProtocolType.Tls11
You can find more details here
Related
I am running ASP.Net 4.5, but using a very old version of the PayPal SOAP api. The reference is to paypal_base.dll with a reported version of 4.3.1.0. The code that calls the API has "using" statements that reference:
com.paypal.sdk.services
com.paypal.soap.api.
I have verified at the point where the call to the PayPal api is made, that this value
System.Net.ServicePointManager.SecurityProtocol
includes both ssl3 and tls1.2.
I am pointing at the "sandbox" mode.
But when the setExpressCheckout call is made, I get a runtime exception that says:
The request was aborted: Could not create SSL/TLS secure channel.
I have downloaded the PayPal API Samples project and using the same sandbox credentials, it works. Looking in Fiddler, the calls are nearly identical except the samples API call goes to api-3t.sandbox.paypal.com, while my code goes to api-aa.sandbox.paypal.com, but according to the documentation on TLS 1.2 readyness, both apis should work. I don't see anywhere in either API to set the endpoint other than switching between "live" and "sandbox".
In the fiddler response, both show:
"A SSLv3-compatible ServerHello handshake was found. Fiddler extracted the parameters below.
Version: 3.3 (TLS/1.2)"
And the responses are identical except for the "random" parameter. So the old API call is using TLS 1.2
My code and the Samples API code are only slightly different, the sample uses:
SetExpressCheckoutRequestType request = new SetExpressCheckoutRequestType();
populateRequestObject(request); //populate request data
SetExpressCheckoutReq wrapper = new SetExpressCheckoutReq();
wrapper.SetExpressCheckoutRequest = request;
Dictionary<string, string> configurationMap = Configuration.GetAcctAndConfig(); //set merchant config
PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(configurationMap);
SetExpressCheckoutResponseType setECResponse = service.SetExpressCheckout(wrapper); //make the call
Where my (again, very old code looks like this):
CallerServices caller = new CallerServices();
caller.APIProfile = SetProfile.ApplicationProfile; //set merchant config
SetExpressCheckoutRequestType pp_request = new SetExpressCheckoutRequestType();
// Create the request details object
pp_request.SetExpressCheckoutRequestDetails = new SetExpressCheckoutRequestDetailsType();
pp_request.SetExpressCheckoutRequestDetails.PaymentAction = paymentAction;
pp_request.SetExpressCheckoutRequestDetails.PaymentActionSpecified = true;
pp_request.SetExpressCheckoutRequestDetails.OrderTotal = new BasicAmountType();
pp_request.SetExpressCheckoutRequestDetails.OrderTotal.currencyID = currencyCodeType;
pp_request.SetExpressCheckoutRequestDetails.OrderTotal.Value = paymentAmount;
pp_request.SetExpressCheckoutRequestDetails.CancelURL = cancelURL;
pp_request.SetExpressCheckoutRequestDetails.ReturnURL = returnURL;
return (SetExpressCheckoutResponseType) caller.Call("SetExpressCheckout", pp_request); //do the call
The sample code works, my code throws the SSL/TLS error. I tried upgrading to the latest SDK, but so much has changed, it will be quite a large effort to migrate all that code.
From fiddler, it seems to be using TLS 1.2 even with the old API, but I get a runtime exception about the SSL/TLS connection. Is it because of the different endpoint? Is the old API just too old?
Thanks in advance for any help - I would love to avoid migrating all that ancient code!.
EDIT: I should mention I am using the UserName/Password/Signature credentials, not certificate based credentials.
As TLS1.2 is supported in .Net4.5 but it is not a default protocol. you need to opt-in to use it. The following code will make TLS 1.2 default, make sure to execute it before making a connection to secured resource:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
I was having a similar issue, with a PP Sandbox credentialing "HttpWebRequest" in C# Web Application 4.5, receiving the following error: "You must write ContentLength bytes to the request stream before calling [Begin]GetResponse".
I read this Q/A and applied the ServicePointManager reference from above answer - as the first line in my HttpWebRequest call method, and it worked. Thanks to all.
FYI, the example code I am building is from //learn.microsoft.com, "Getting Started with ASP.NET 4.5 Web Forms and Visual Studio 2017".
I am using the following code....
Dim myHttpWebRequest As HttpWebRequest = CType(WebRequest.Create(PostingUrl), HttpWebRequest)
myHttpWebRequest.Method = "POST"
myHttpWebRequest.Headers.Add("Authorization", "Bearer " & RSettings.access_token)
myHttpWebRequest.Headers.Add("Accept-Version", "2")
myHttpWebRequest.ContentType = "application/json; charset=UTF-8"
myHttpWebRequest.Accept = "application/json"
' myHttpWebRequest.Proxy = Nothing ' ** SEE NOTES ON THIS LINE **
Dim Byt As Byte() = Encoding.UTF8.GetBytes(DataString)
Using stream = myHttpWebRequest.GetRequestStream()
stream.Write(Byt, 0, Byt.Length)
End Using
Using myHttpWebResponse As HttpWebResponse = CType(myHttpWebRequest.GetResponse(), HttpWebResponse)
Using srRead As New StreamReader(myHttpWebResponse.GetResponseStream())
ListingResponse = srRead.ReadToEnd()
End Using
End Using
Where:
PostingUrl is "https://reverb.com/api/listings"
RSettings.access_token is (obviously) my access token for this API
DataString is a JSON string posting the data to the Reverb API
If I run my code from Visual Studio (localhost) it returns
The remote server returned an error: (406) Not Acceptable.
Trying to figure out why, I opened Fiddler hoping I could inspect content types and figure out the problem, but the response error changed to:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
(I'm guessing from this error that I also have an issue with my Auth key, but that's a separate subject I think.)
After a bit of Googling and S/O pages I found two suggestions:
Tools > Fiddler Options > HTTPS and uncheck "Capture HTTPS CONNECTs"
Add the commented out line: myHttpWebRequest.Proxy = Nothing
If I make any of those changes, I get back to my Error 406 that I get without Fiddler running.
However, if I add myHttpWebRequest.Proxy = Nothing line added, I can no longer see the Tunnel to http://reverb.com:443 Log entry in Fiddler, there's no record of a request to Reverb.com so I can't inspect anything.
I'm now very confused about what I'm doing, and I guess haven't actually made any progress at all!
I still have error 406 and don't seem to be able to inspect the headers/content type issues with Fiddler as I had hoped (please explain how if I am wrong!)
Even if I do correct the 406, I think I have an authentication error.
By the way... all this is an attempt to recreate the cURL example on the Rever docs page here:
https://dev.reverb.com/docs/create-a-listing
I have also been discussing this issue here:
https://dev.reverb.com/v1.0/discuss/57bb2ca0aa8f760e004588cf
Argh... well, my confusing over Fiddler still stands but the 406 error was caused by this:
myHttpWebRequest.Headers.Add("Accept-Version", "2")
Should have been
myHttpWebRequest.Headers.Add("Accept-Version", "2.0")
How simple!!
I am looking for a solution to embed jwt token as header in the get/post requests I sent to the server in my phpunit tests.
Is there any option to add header to the GET/POST calls? I am currently using following method to send a GET request to the server.
content = $this->get('users/logout')->response->getContent();
You need to prefix the header with HTTP_. As Example:
$server = ['HTTP_X-Requested-With' => 'XMLHttpRequest'];
$this->call('get', '/users/logout', [], [], $server);
Alternative syntax::
$this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
$this->call('get', '/users/logout');
Hope this help
Update: the code works on my desktop so it appears to be an issue with my server
I am trying to post some XML using vb/asp.net 4.0 via:
Dim request As HttpWebRequest = HttpWebRequest.Create(thePostingURL)
My code works for many clients, however there is one that I cannot seem to connect to.
I have attempted to research this and things I have tried based on posts I found are:
request.KeepAlive = False
request.KeepAlive = True
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3
Not all at the same time of course. I have tried running Wireshark while posting the XML and it appears to be failing on a "Handshake Failure (40)."
The client's url is https.
Not sure if this is a clue or not, but I cannot access the URL via IE8 while I can using Chrome. This is on a windows 2003 server.
Any ideas or suggestions of things to try?
I would like to write an HTTP server that answer to request using a non-standard HTTP method (verb). For instance, the client would make a request like FOO / HTTP/.1.1. And on the server side, this request would be handled by something like:
var express = require('express');
var app = express.createServer();
app.configure(function(){
app.use(express.logger({ format: ':method :url' }));
app.use(express.methodOverride());
});
app.foo('/', function(req, res){
res.send('Hello World');
});
app.listen(3000);
I appended my non-standard method to the array exported in ExpressJS's lib/router/methods.js. This allow me to write my server code as expected. When using express.methodOverride() and a POST request with _method=foo, it works. But an actual FOO request doesn't work. As soon as the client send the first line of the request the connection is closed by the server:
$telnet localhost 3000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
FOO / HTTP/1.1
Connection closed by foreign host.
I would like to be able to implement this with ExpressJS and without avoid hacking into its core file.
Any idea if this is possible and how?
Short answer: No, it's not possible. Not without implementing your own HTTP module.
To test, start a barebones HTTP server ...
$ node
> require('http').createServer(function(req, res) {
... console.log(req.method);
... res.end();
... }).listen(8080);
Then (as you've already done) telnet to it and issue a GET and FOO request ...
$ telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1
HTTP/1.1 200 OK
Connection: keep-alive
Transfer-Encoding: chunked
0
FOO / HTTP/1.1
Connection closed by foreign host.
$
In node console you'll see
GET
... but no FOO. So, node's native HTTP module, which Express uses, does not make these requests available.
Node has a hard-coded whitelist of acceptable HTTP verbs in C.
In order to accept custom verbs, you must modify the HTTP parser and recompile node.
You mentioned that you're trying to implement PURGE, which was added to the whitelist in v0.7.5.
As others have said, Node.js' HTTP server library is configured to accept only specific verbs. Ben Noordius' suggestion of using Parsley doesn't work either, since that library accepts an even smaller whitelist of verbs. (It also hasn't been maintained in quite some time.)
At this stage, if we want to support oddball requests, we have to take more drastic measures. Here's a nice ugly hack for you that involves duck punching some internal behavior. This works on v0.10.x of Node.js, but test carefully on newer versions as they become available.
In my case, I needed to support not only a non-standard verb, but a non-standard protocol version identifier as well, and a missing Content-Length header for Icecast source streams:
SOURCE /live ICE/1.0
The following should get you started:
server.on('connection', function (socket) {
var originalOnDataFunction = socket.ondata;
var newLineOffset;
var receiveBuffer = new Buffer(0);
socket.ondata = function (d, start, end) {
receiveBuffer = Buffer.concat([receiveBuffer, d.slice(start, end)]);
if ((newLineOffset = receiveBuffer.toString('ascii').indexOf('\n')) > -1) {
var firstLineParts = receiveBuffer.slice(0, newLineOffset).toString().split(' ');
firstLineParts[0] = firstLineParts[0].replace(/^SOURCE$/ig, 'PUT');
firstLineParts[2] = firstLineParts[2].replace(/^ICE\//ig, 'HTTP/');
receiveBuffer = Buffer.concat([
new Buffer(
firstLineParts.join(' ') + '\r\n' +
'Content-Length: 9007199254740992\r\n'
),
receiveBuffer.slice(newLineOffset +1)
]);
socket.ondata = originalOnDataFunction;
socket.ondata.apply(this, [receiveBuffer, 0, receiveBuffer.length]);
}
};
}
It's ugly, but works. I'm not particularly happy about it, but when choosing between a rough built-from-the-ground-up HTTP parser or tweaking an existing one, I choose to tweak in this instance.
For anyone who needs it, there is http-parser-js, which replaces Node's built-in HTTP parser.
Their README contains an example of monkey-patching the parser, though I find that it wasn't enough, as both the http-parser-js and the http modules have a hardcoded list of methods.
So, you have to replace the parser and edit the list of methods:
const { HTTPParser } = require('http-parser-js');
HTTPParser.methods.push('FOOBAR');
const binding = process.binding('http_parser');
binding.HTTPParser = HTTPParser;
binding.methods = HTTPParser.methods;
require('http').METHODS = HTTPParser.methods;
Later Node versions may not support process.binding, in which case, you can use the --expose-internals flag for Node (see this issue):
const { internalBinding } = require('internal/test/binding');
const binding = internalBinding('http_parser');
From the looks of it, the http2 module's parser accepts any method, in case that's an option. See this issue about invalid HTTP methods. Unfortunately, express and the likes do not use http2.
And for anyone who was in my shoes, proxying requests to a legacy server in Create React App, use the above snippet in webpack-dev-server, at the top of Server.js, in order to monkey-patch the parser. Hopefully everything switches to http2 soon...