Need to know why HttpsURLConnection giving connection reset but works with REST Template (SSLContext) - resttemplate

I have a Spring Boot application to make an API call to a remote service and parse incoming data.
I am connecting to the secure site using a .pfx and truststore.jks. I have used plain Java HttpsUrlConnection to establish the SSL connection and write output (Json payload) and then read the input (Json response). It used to work fine but now it started giving Connection Reset error
Partial error stack trace is as below:
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:975)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
I tried alternative of using REST Template by building the SSLContext and that is working fine.
What could be the reason the HttpsURLConnection code is now not working? Is there a difference in the ssl context built in these two ways - below are the 2 different creations:
Using HttpsURLConnection:
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLSv1.1");
sslContext.init(kms, tms, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
Using REST Template:
SSLContext sslContext2 = SSLContextBuilder.create()
.loadKeyMaterial(ResourceUtils.getFile(<PFX File Path>),<store_password>,
<key_password>)
.loadTrustMaterial(ResourceUtils.getFile(<trusstore path>),
<trustore_password>).build();
HttpClient client = HttpClients.custom()
.setSSLContext(sslContext2)
.build();
RestTemplateBuilder builder = new RestTemplateBuilder();
RestTemplate restTemplate = builder.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client)).build();
I am not even sure if it is a difference between the SSL Context building or something else. I am testing with the same data in both cases and the same data was working earlier.

Related

BizTalk 2016: How to use HTTP Send adapter with API token

I need to make calls to a rest API service via BizTalk Send adapter. The API simply uses a token in the header for authentication/authorization. I have tested this in a C# console app using httpclient and it works fine:
string apiUrl = "https://api.site.com/endpoint/<method>?";
string dateFormat = "dateFormat = 2017-05-01T00:00:00";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("token", "<token>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
string finalurl = apiUrl + dateFormat;
HttpResponseMessage resp = await client.GetAsync(finalurl);
if (resp.IsSuccessStatusCode)
{
string result = await resp.Content.ReadAsStringAsync();
var rootresult = JsonConvert.DeserializeObject<jobList>(result);
return rootresult;
}
else
{
return null;
}
}
however I want to use BizTalk to make the call and handle the response.
I have tried using the wcf-http adapter, selecting 'Transport' for security (it is an https site so security is required(?)) with no credential type specified and placed the header with the token in the 'messages' tab of the adapter configuration. This fails though with the exception: System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
I have tried googling for this specific scenario and cannot find a solution. I did find this article with suggestions for OAUth handling but I'm surprised that even with BizTalk 2016 I still have to create a custom assembly for something so simple.
Does anyone know how this might be done in the wcf-http send adapter?
Yes, you have to write a custom Endpoint Behaviour and add it to the send port. In fact with the WCF-WebHttp adapter even Basic Auth doesn't work so I'm currently writing an Endpoint Behaviour to address this.
One of the issues with OAuth, is that there isn't one standard that everyone follows, so far I've had to write 2 different OAuth behaviours as they have implemented things differently. One using a secret and time stamp hashed to has to get a token, and the other using Basic Auth to get a token. Also one of them you could get multiple tokens using the same creds, whereas the other would expire the old token straight away.
Another thing I've had to write a custom behaviour for is which version of TLS the end points expects as by default BizTalk 2013 R2 tries TLS 1.0, and then will fail if the web site does not allow it.
You can feedback to Microsoft that you wish to have this feature by voting on Add support for OAuth 2.0 / OpenID Connect authentication
Maybe someone will open source their solution. See Announcement: BizTalk Server embrace open source!
Figured it out. I should have used the 'Certificate' for client credential type.
I just had to:
Add token in the Outbound HTTP Headers box in the Messages tab and select 'Transport' security and 'Certificate' for Transport client credential type.
Downloaded the certificate from the API's website via the browser (manually) and installed it on the local servers certificate store.
I then selected that certificate and thumbprint in the corresponding fields in the adapter via the 'browse' buttons (had to scroll through the available certificates and select the API/website certificate I was trying to connect to).
I discovered this on accident when I had Fiddler running and set the adapter proxy setting to the local Fiddler address (http://localhost:8888). I realized that since Fiddler negotiates the TLS connection/certificate (I enabled tls1.2 in fiddler) to the remote server, messages were able to get through but not directly between the adapter and the remote API server (when Fiddler WASN'T running).

Signalr send message from browser to .net client on the same machine

We need to communicate a native application with a web application.
We think to use signalr to send the message/command.
The pipeline would be:
User clicks to make an action.
Javascript (with signalr) send a message to a server in azure.
The server re-send the message a specific client. It must be the client installed on the same machine.
Once the result is completed, NET sends the resulting reverse.
The matter is, How I can find client from the same machine in the signalr Server?
The organization in our system is:
There is center/gym.
Every center has staff who can login.
We could identify client at the same center with some file configuration. Saving our key center, for example. But, in a center, could there are more than one.NET client installed on the different computer.
We think to use the private IP of the computer to make a key on the signalr server.
var ips = [];
var RTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var pc = new RTCPeerConnection({
// Don't specify any stun/turn servers, otherwise you will
// also find your public IP addresses.
iceServers: []
});
// Add a media line, this is needed to activate candidate gathering.
pc.createDataChannel('');
// onicecandidate is triggered whenever a candidate has been found.
pc.onicecandidate = function (e) {
if (!e.candidate) { // Candidate gathering completed.
pc.close();
console.log(ips);
return;
}
var ip = /^candidate:.+ (\S+) \d+ typ/.exec(e.candidate.candidate)[1];
ips.push(ip);
};
pc.createOffer(function (sdp) {
pc.setLocalDescription(sdp);
}, function onerror() { });
This data can be obtained in .NET client without a problem. But in javascript, the previous code works regularly. In some PC, it only returns ipv4. And in Mozilla it doesn't work.
How can we identify both clients? Do You know another way to reach the goal?
Thanks,
Finally, we didn't find a good solution filtering ip adress.
We did the as follow:
We used URI schema to launch our app. URI Schema windows
Public Class RegistrarURI
Const URI_SCHEME As String = "xxx"
Const URI_KEY As String = "URL:xxx"
Private Shared APP_PATH As String = Location.AssemblyDirectory() ' "C:\Program Files (x86)\xxx.exe"
Public Shared Sub RegisterUriScheme()
Using hkcrClass As RegistryKey = Registry.ClassesRoot.CreateSubKey(URI_SCHEME)
hkcrClass.SetValue(Nothing, URI_KEY)
hkcrClass.SetValue("URL Protocol", [String].Empty, RegistryValueKind.[String])
Using defaultIcon As RegistryKey = hkcrClass.CreateSubKey("DefaultIcon")
Dim iconValue As String = [String].Format("""{0}"",0", APP_PATH)
defaultIcon.SetValue(Nothing, iconValue)
End Using
Using shell As RegistryKey = hkcrClass.CreateSubKey("shell")
Using open As RegistryKey = shell.CreateSubKey("open")
Using command As RegistryKey = open.CreateSubKey("command")
Dim cmdValue As String = [String].Format("""{0}"" ""%1""", APP_PATH)
command.SetValue(Nothing, cmdValue)
End Using
End Using
End Using
End Using
End Sub
End Class
In an Azure WebApp we launch a SignalR Server. This server will send data from our .NET app to Chrome.
To achive that, when the web is loaded, we connect to the signalR server. To build de uri, We send the connectionId from Javascript client to the .NET Client.
Then, when the native process is completed. .NET client send the information to signalR server, and this server mirrored the data to javacript client using the connectionId.
To avoid launch some instance of our native app, we use IPC channel to send data to one instance to the previous and closind the new one.
Link to source Blog source

Do I need a new PayPal API to support TLS 1.2 on .Net server?

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".

Netty - sending http requests over ssl

I'm trying to get a client/server program exchanging http messages over ssl. To start, I created client and server programs that successfully exchange http requests using DefaultHttpRequest. The code that sends the request looks something like this:
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "https://localhost:8443");
ChannelBuffer buf = ChannelBuffers.copiedBuffer(line, "UTF-8");
request.setContent(buf);
request.setHeader(HttpHeaders.Names.HOST, host);
request.setHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
request.setHeader(HttpHeaders.Names.CONTENT_TYPE, "text/xml");
request.setHeader(HttpHeaders.Names.CONTENT_LENGTH, Integer.toString(buf.capacity()));
ChannelFuture writeFuture = channel.write(request);
The client pipeline factory contains this:
pipeline.addLast("decoder", new HttpResponseDecoder());
pipeline.addLast("encoder", new HttpRequestEncoder());
// and then business logic.
...
The server pipeline factory contains this:
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
// and then business logic.
....
So far so good. Client sends, server receives and decodes the request. The messageReceived method on my handler is called with the correct data.
In order to enable the SSL, I've taken some code from the SecureChat example and added to both client and server pipeline factories:
For the server:
SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
engine.setUseClientMode(false);
pipeline.addLast("ssl", new SslHandler(engine));
// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
8192, Delimiters.lineDelimiter()));
For the client:
SSLEngine engine = SecureChatSslContextFactory.getClientContext().createSSLEngine();
engine.setUseClientMode(true);
pipeline.addLast("ssl", new SslHandler(engine));
// On top of the SSL handler, add the text line codec.
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(
8192, Delimiters.lineDelimiter()));
Now when I send the request from the client, nothing seems to happen on the server. When I start up the applications, the server seems to connect (channelConnected is called), but when I send the message none of the data gets to the server (messageReceived is never called).
Is there something obviously wrong with what I am doing? Is this the way that https should work? Or is there a different method for sending http requests over ssl?
Thanks,
Weezn
You need to call SslHandler.handshake() on the client side. Check the example again its in there.
Oops, it seems like I copied and pasted too much from the SecureChat example.
Removing the DelimiterBasedFrameDecoder seems to fix the issue.

Blackberry http connection not working on 3g

hi friends i'm a newbie in blackberry programming and have managed to make a small application... The application downloads an xml file through http and parses it and displays it on the screen... now the problem is that though it works fine on my simulator... the client complains that he's getting an error in connection if he connects it through 3G... do i need to add anything other than the following...
// Build a document based on the XML file.
url = <my clients url file>;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
hc = (HttpConnection)Connector.open(url+";deviceside=true");
hc.setRequestMethod(HttpConnection.GET);
InputStream inputStream = hc.openInputStream();
hc.getFile();
Document document = builder.parse(inputStream);
hc.close();
inputStream.close();
Do i need to add anything to make it download http content through 3G also??
Specifying "deviceside=true" requires the device have the APN correctly configured, or you include APN specification in the URL. Have a look at this video.
You need to be able to detect what sort of connection the device is using as was said above deviceside=true works only for APN. If you want to just test it out try using
;deviceside=false //for mds
;deviceside=false;ConnectionType=mds-public //for bis-b
;interface=wifi //for wifi

Resources