How to make Android app connect to Heroku app over HTTPS? [duplicate] - java

This question already has answers here:
Https Connection Android
(11 answers)
Closed 9 years ago.
I've got a Heroku app on the Cedar stack, which has a URL like this:
https://my-app.herokuapp.com/
I'm using piggyback SSL, I don't have my own certificate. But this works fine and I'm not seeing any errors/warnings in the browser.
Now I want to let my Android app securely connect to this Heroku app. The code I tried was the following:
BasicHttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 4000);
HttpConnectionParams.setSoTimeout(httpParameters, 4000);
DefaultHttpClient client = new DefaultHttpClient(httpParameters);
HttpRequestBase httpRequest = new HttpGet("https://my-app.herokuapp.com/api/player");
client.execute(httpRequest);
But this does not work. I'm not seeing any warnings, errors or exceptions, but it just doesn't connect over HTTPS but HTTP.
What am I doing wrong?
Are there any other subclasses that I have to use? I thought that just providing the HTTPS URL would be enough, and some posts I found on the internet seem to verify this.
I've found answers regarding HttpClient with SSL/TLS here, here and here, but they don't really help me. Apart from the fact that I don't exactly know what to do, I'm not sure if these answers affect me at all, because I'm not seeing any exceptions that hint to problems with the certificate.

You can try this:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient defaultclient = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
cm = new ThreadSafeClientConnManager(defaultclient.getParams(), registry);
client = new DefaultHttpClient(cm, defaultclient.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
post = new HttpPost("https://my-app.herokuapp.com/api/player");

Related

HttpClient : hostname didn't match - accessible from browser but not from code

I am trying to access a website from my code using HttpClient :
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://www.datamed.org/search.php?query=gene&searchtype=data");
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String responseBody = httpclient.execute(httpget, responseHandler);
This is the error i am getting :
Exception in thread "main" javax.net.ssl.SSLException: hostname in certificate didn't match: <www.datamed.org> != <ucrexdc.ucsd.edu> OR <ucrexdc.ucsd.edu>
I checked the certificate from browser, it seems correct, with correct names.
Not sure from where it is picking up ucrexdc.ucsd.edu .
The code does work if I use a proxy.
Gone through a lot of similar issues on StackOverflow, but in most cases the server was under user's control. In my case, this is an already existing website. and i have this problem only for this website.
Can it be a problem with my environment?
UPDATE:
I found out that both the websites (datamed.org and ucrexdc.ucsd.edu) have the same IP , 169.228.51.21 . Can it be a problem, why doesn't the browser have issues with this?
UPDATE 2:
I was using apache http-client 4.3.1,
When i updated to 4.4.1, it was resolved. the issue was most possibly related to SNI.
HttpClient provides two implementations for Hostname verification.
DefaultHostnameVerifier
NoopHostnameVerifier
by default HttpClient uses DefaultHostnameVerifier implementation. You can try the different hostname verifier implementation.
SSLContext sslContext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
HttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build();

Change code from httpClient to httpClient builder. Android API 23+

I am currently struggling to prepare my code for SOAP communication with SOAP protocol behind it (no I can't use JSON). The idea is that I send a certificate for server, that tells me, if the device is allowed to connect and than we developed our system with tokens, which works quite well. I am not sure how API 23 is far, but I am sure that at one point I would need to change my network solution. Everything is working correctly right now.
So far looks like this:
private static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance("BKS");
InputStream trustStoreStream = SampleApp.appContext.getResources().openRawResource(R.raw.server);
trustStore.load(trustStoreStream, "A123456a".toCharArray());
SSLSocketFactory sslf = new SSLSocketFactory(trustStore);
sslf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme ("https", sslf, 443));
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
HttpConnectionParams.setConnectionTimeout(params, 20000000);
HttpConnectionParams.setSoTimeout(params, 20000000);
SingleClientConnManager cm = new SingleClientConnManager(params, schemeRegistry);
return new DefaultHttpClient(cm, params);
} catch (Exception e) {
e.printStackTrace();
return new DefaultHttpClient();
}
}
And that works fine until i change in my gradle SDK 23, than all of the sudden everything was red. Can someone point me out how to solve this. This application should be secure and it's used by more 1000+ users, which are clients of private company. We've got just jet certificate of security and this happened. I want my application transmission to be as secure as possible. Can someone help me?
Passwords and names was obviously change, for sake of security. Thanks for any help. Maybe I am idiot, but Apache description of functions isn't enough.
Thanks a lot for anyone willing to help.

HTTPs over a proxy with apache http client

I have a http client which is based on the apache http client and it seems to have no problem with ssl certificates. I have a unit test for both globally recognized certs and self signed certs with a custom SSLSocketFactory.
However when I ran the same code behind a proxy, it stopped working. I keep getting this dreaded exception:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
I reduced the code to the bare minimum and it still throws the same exception. The code:
URI uri = new URI("https://www.google.com");
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost("proxy.int", 8080, "https"));
HttpUriRequest request = new HttpGet(uri);
HttpResponse response = client.execute(request);
I wasn't sure if it uses the default ssl settings if nothing is specified so I added it explicitly as well:
URI uri = new URI("https://www.google.com");
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost("proxy.int", 8080, "https"));
client.getConnectionManager().getSchemeRegistry().register(
new Scheme("https", 443, SSLSocketFactory.getSystemSocketFactory()));
HttpUriRequest request = new HttpGet(uri);
HttpResponse response = client.execute(request);
I also tried the getSocketFactory() (not entirely sure what the difference is with getSystemSocketFactory()), still the same error though.
EDIT:
The proxy has optional authentication and I have tried both with and without. The authentication information was set using the following code:
client.getCredentialsProvider().setCredentials(
new AuthScope("proxy.int", 8080),
new UsernamePasswordCredentials("user", "password")
);
Exactly the same error.
The problem was in the proxy declaration, I had to specify "http" instead of "https":
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost("proxy.int", 8080, "http"));

Android: How can i set a timeout for SSL sockets for a blocking read/write using the ThreadSafeClientConnectionMana­ger?

How can i set a timeout for SSL sockets for a blocking read/write using the ThreadSafeClientConnectionMana­get? I've found that losing network connectivity while reading or writing a SSL socket results in a 15 minute timeout on Android OS 2.2 and 2.3 devices.
I set the following timeouts on my HttpClient:
mParams = new BasicHttpParams();
HttpProtocolParams.setVersion(mParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(mParams, "UTF-8");
HttpProtocolParams.setUserAgent(mParams, USER_AGENT);
HttpConnectionParams.setConnectionTimeout(mParams, TIME_OUT);
HttpConnectionParams.setSoTimeout(mParams, TIME_OUT);
ConnManagerParams.setTimeout(mParams, TIME_OUT);
final SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme(HTTP_SCHEME, PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme(HTTPS_SCHEME, SSLSocketFactory.getSocketFactory(), 443));
final ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(mParams, registry);
mClient = new DefaultHttpClient(manager, mParams);
I then use the client to perform a http put request with a file entity. If I turn on airplane mode in mid upload, wait 15-30 seconds and then turn off airplane mode the socket will be stuck in either a read or write and won't timeout for 15 mins.
Not to pivot away from your very legitimate question, but the blog post Android's HTTP Clients recommends using HttpURLConnection for new development. Have you considered switching APIs?

connect over ssl without certificate

I'm trying to connect to my server over SSL port 443 without a certificate.
I'm getting an error thrown:
javax.net.ssl.SSLException: Not trusted server certificate
Reading other questions to solve the problem, the following code should work, but I'm still getting the error message. What could I be doing wrong?
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
httpclient = new DefaultHttpClient(mgr, client.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpGet httpget = new HttpGet(this.requestedURL);
httpget.addHeader(new BasicScheme().authenticate(creds, httpget));
try
{
response = httpclient.execute(httpget);
}
catch(java.lang.Throwable t) {}
Your client truststore doesn't trust the server certificate. It is probably a self-signed certificate, so you need to import it into your clients truststore. Or get it signed by a CA. Ignoring the server certificate isn't secure, you may as well not use HTTPS at all.
After trying all other solutions, android 2.2 + needs special code. This worked
Custom SSL handling stopped working on Android 2.2 FroYo

Categories

Resources