Home » Android » sockets – HttpsURLconnection to post and get in Android

sockets – HttpsURLconnection to post and get in Android

Posted by: admin May 14, 2020 Leave a comment

Questions:

I am developing an simple application which uses https protocol to post and get data from the server. I searched on internet but there are few resources available, I tried most of them but couldn’t do it successfully.

I tried with HttpClient it was success, but I want to do it with HttpsURLconnection

Do I need to take the Public RSA key from the device, if so how can I do that.

Can someone tell me how can I achieve this using httpsURLconnection.

protected String doInBackground(String... arg0) {     
  try {
    ByteArrayInputStream derInputStream = new ByteArrayInputStream(app.certificateString.getBytes());
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509","BC");
    X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(derInputStream);
    String alias = "alias";//cert.getSubjectX500Principal().getName();

    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    trustStore.load(null);
    trustStore.setCertificateEntry(alias, cert);
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
    kmf.init(trustStore, null);
    KeyManager[] keyManagers = kmf.getKeyManagers();

    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
    tmf.init(trustStore);
    TrustManager[] trustManagers = tmf.getTrustManagers();

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(keyManagers, trustManagers, null);
    URL url = new URL("MY HTTPS URL");
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setSSLSocketFactory(sslContext.getSocketFactory());

    // set Timeout and method
    conn.setReadTimeout(7000);
    conn.setConnectTimeout(7000);
    conn.setRequestMethod("POST");
    conn.setDoInput(true);

    // Add any data you wish to post here
    conn.connect();
    String reult = String.valueOf(conn.getInputStream());
    Log.d("connection : ", String.valueOf(reult));

  } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
  } catch (IOException e) {
    e.printStackTrace();
  }  catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
  } catch (KeyManagementException e) {
    e.printStackTrace();
  } catch (CertificateException e) {
    e.printStackTrace();
  } catch (KeyStoreException e) {
    e.printStackTrace();
  } catch (NoSuchProviderException e) {
    e.printStackTrace();
  } catch (UnrecoverableKeyException e) {
    e.printStackTrace();
  }
  return null;
}

Most of the time I am getting getting the error:

Caused by: `java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.`
How to&Answers:

I’m using the following code in my app to post data to my server and read the response back.

boolean DEBUG = false;

private static String sendHttpsPost(String d, Map<String, String> params) {
  if(DEBUG)disableHttpsVerify(null);
  BufferedReader bis = null;
  InputStream in = null;
  OutputStream out = null;
  try {
    URL url = new URL(d);
    HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
    connection.setDoOutput(true);
    connection.setDoInput(true);
    connection.setRequestMethod("POST");
    out = connection.getOutputStream();

    StringBuilder sb = new StringBuilder();
    for(Map.Entry<String, String> entry : params.entrySet()) {
      sb.append(entry.getKey());
      sb.append('=');
      sb.append(entry.getValue());
      sb.append('&');
    }
    String str = sb.toString();
    byte[] data = str.substring(0, str.length() - 1).getBytes();
    out.write(data);

    connection.connect();
    in = connection.getInputStream();
    bis = new BufferedReader(new InputStreamReader(in));
    sb.setLength(0);
    while((str = bis.readLine()) != null) {
      sb.append(str);
    }
    return sb.toString();
  } catch (Exception e) {
    return "";
  } finally {
    try {
      if(bis != null) {
        bis.close();
      }
      if(in != null) {
        in.close();
      }
    } catch (Exception x) {

    }
  }
}

Note:

  1. params contains the parameters you want to send to your server
  2. disableHttpsVerify is used to bypass all security checking in case your server’s CA is untrusted. See the code below.

You can see that using https protocol is almostly the same as using http.

Code for disableHttpsVerify:

try {
  TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
     @Override
     public X509Certificate[] getAcceptedIssuers() {
       return null;
     }

     @Override
     public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
       // Not implemented
     }

     @Override
     public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
       // Not implemented
     }
   }};
   SSLContext sc = SSLContext.getInstance("TLS");

   sc.init(null, trustAllCerts, new java.security.SecureRandom());

   HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
 } catch (Exception e) {
   LogSaveUtil.savePayLog("disableHttpsVerify" + e.toString());
 }

Answer:

First Create a Key store and SSL Socket Factory.

public HttpClient getNewHttpClient() {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);

            MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

            HttpParams params = new BasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 443));

            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
            return new DefaultHttpClient(ccm, params);
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }

Then in your AsyncTask do this

@Override
        protected String doInBackground(String... arg0) {
            try {
                //Post Username and password
                HttpClient httpclient = getNewHttpClient();
                String secondParameter = applicationEnvironment.getForgetPasswordSecondParameter(context);
                String user_base_url = BASEURL +"Account/ForgotPassword?Email="+arg0[0];
                HttpPost httppost = new HttpPost(user_base_url);
                List<BasicNameValuePair> nameValuePairs = new ArrayList<>(1);
                nameValuePairs.add(new BasicNameValuePair("Email", arg0[0]));
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

                // Execute HTTP Post Request
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();
                String responseString = EntityUtils.toString(entity, "UTF-8");
                Log.d("Results ", responseString);
                return responseString;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }