How to do an HTTPS POST from Android? - java

I want to do a HTTPS post method to send some data from my android app to my website.
I used HttpURLConnection first and it's working fine with my HTTP URL. My production website is on HTTPS and I want to send the same POST using HttpsURLConnection. Can someone help me use the class properly?
I found some source at this link:
KeyStore keyStore = ...;
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection)
url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
What should be the value of KeyStore keyStore = ...;?
I tried sending the data using the same HttpURLConnection, but I am seeing some POST data is missed or in error.
I've tried the method from this question. I am pasting my code below
String urlParameters="dateTime=" + URLEncoder.encode(dateTime,"UTF-8")+
"&mobileNum="+URLEncoder.encode(mobileNum,"UTF-8");
URL url = new URL(myurl);
HttpsURLConnection conn;
conn=(HttpsURLConnection)url.openConnection();
// Create the SSL connection
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setConnectTimeout(HTTP_CONNECT_TIME_OUT);
conn.setReadTimeout(HTTP_READ_TIME_OUT);
//set the output to true, indicating you are outputting(uploading) POST data
conn.setDoOutput(true);
//once you set the output to true, you don't really need to set the request method to post, but I'm doing it anyway
conn.setRequestMethod("POST");
conn.setFixedLengthStreamingMode(urlParameters.getBytes().length);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
PrintWriter out = new PrintWriter(conn.getOutputStream());
out.print(urlParameters);
out.close();
InputStream is = conn.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = in.readLine()) != null) {
response += inputLine;
}
The error I am getting is below:
05-12 19:36:10.758: W/System.err(1123): java.io.FileNotFoundException: https://www.myurl.com/fms/test
05-12 19:36:10.758: W/System.err(1123): at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
05-12 19:36:10.758: W/System.err(1123): at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:270)
05-12 19:36:10.758: W/System.err(1123): at .httpRequest(SMSToDBService.java:490)
05-12 19:36:10.758: W/System.err(1123): at com..access$0(SMSToDBService.java:424)
05-12 19:36:10.758: W/System.err(1123): at com.$ChildThread$1.handleMessage(SMSToDBService.java:182)
05-12 19:36:10.758: W/System.err(1123): at android.os.Handler.dispatchMessage(Handler.java:99)
05-12 19:36:10.758: W/System.err(1123): at android.os.Looper.loop(Looper.java:156)
05-12 19:36:10.758: W/System.err(1123): at com.$ChildThread.run(SMSToDBService.java:303)

You can use the default CAs that are defined in the android device, which is just fine for any public web.
If you have a self-signed certificate, you can either accept all certificates (risky, open to man-in-the-middle attacks) or create your own TrustManagerFactory, which is a bit out of this scope.
Here's some code to use the default CAs for a https POST call:
private InputStream getInputStream(String urlStr, String user, String password) throws IOException
{
URL url = new URL(urlStr);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
// Create the SSL connection
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
// Use this if you need SSL authentication
String userpass = user + ":" + password;
String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
conn.setRequestProperty("Authorization", basicAuth);
// 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();
return conn.getInputStream();
}
To read the response:
String result = new String();
InputStream is = getInputStream(urlStr, user, password);
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String inputLine;
while ((inputLine = in.readLine()) != null) {
result += inputLine;
}

You can take a look at this question I asked a few days ago:
Change HTTP post request to HTTPS post request:
I have supplied there a solution that worked for me, that basically accepts any self-signed certificate. As been said here this solution is not recommended as it's not secure and open to a man-in-the-middle attacks.
Here is the code:
EasySSLSocketFactory:
public class EasySSLSocketFactory implements SocketFactory, LayeredSocketFactory {
private SSLContext sslcontext = null;
private static SSLContext createEasySSLContext() throws IOException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] { new EasyX509TrustManager(null) }, null);
return context;
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
private SSLContext getSSLContext() throws IOException {
if (this.sslcontext == null) {
this.sslcontext = createEasySSLContext();
}
return this.sslcontext;
}
/**
* #see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket, java.lang.String, int,
* java.net.InetAddress, int, org.apache.http.params.HttpParams)
*/
public Socket connectSocket(Socket sock, String host, int port, InetAddress localAddress, int localPort,
HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException {
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
if ((localAddress != null) || (localPort > 0)) {
// we need to bind explicitly
if (localPort < 0) {
localPort = 0; // indicates "any"
}
InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
sslsock.bind(isa);
}
sslsock.connect(remoteAddress, connTimeout);
sslsock.setSoTimeout(soTimeout);
return sslsock;
}
/**
* #see org.apache.http.conn.scheme.SocketFactory#createSocket()
*/
public Socket createSocket() throws IOException {
return getSSLContext().getSocketFactory().createSocket();
}
/**
* #see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
*/
public boolean isSecure(Socket socket) throws IllegalArgumentException {
return true;
}
/**
* #see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket, java.lang.String, int,
* boolean)
*/
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException,
UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}
// -------------------------------------------------------------------
// javadoc in org.apache.http.conn.scheme.SocketFactory says :
// Both Object.equals() and Object.hashCode() must be overridden
// for the correct operation of some connection managers
// -------------------------------------------------------------------
public boolean equals(Object obj) {
return ((obj != null) && obj.getClass().equals(EasySSLSocketFactory.class));
}
public int hashCode() {
return EasySSLSocketFactory.class.hashCode();
}
}
EasyX509TrustManager:
public class EasyX509TrustManager implements X509TrustManager {
private X509TrustManager standardTrustManager = null;
/**
* Constructor for EasyX509TrustManager.
*/
public EasyX509TrustManager(KeyStore keystore) throws NoSuchAlgorithmException, KeyStoreException {
super();
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init(keystore);
TrustManager[] trustmanagers = factory.getTrustManagers();
if (trustmanagers.length == 0) {
throw new NoSuchAlgorithmException("no trust manager found");
}
this.standardTrustManager = (X509TrustManager) trustmanagers[0];
}
/**
* #see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
*/
public void checkClientTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
standardTrustManager.checkClientTrusted(certificates, authType);
}
/**
* #see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
*/
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException {
if ((certificates != null) && (certificates.length == 1)) {
certificates[0].checkValidity();
} else {
standardTrustManager.checkServerTrusted(certificates, authType);
}
}
/**
* #see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers() {
return this.standardTrustManager.getAcceptedIssuers();
}
}
And I added this method: getNewHttpClient()
public static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory 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();
}
}
Finally for every place in my code that I had:
DefaultHttpClient client = new DefaultHttpClient();
I replace it with:
HttpClient client = getNewHttpClient();

Here's an Android HttpsUrlConnection POST solution complete with certificate pinning, timeouts server side code and configurations.
The variable params should be in the form username=demo&password=abc123&.
#Override
public String sendHttpRequest(String params) {
String result = "";
try {
URL url = new URL(AUTHENTICATION_SERVER_ADDRESS);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(KeyPinStore.getInstance().getContext().getSocketFactory()); // Tell the URLConnection to use a SocketFactory from our SSLContext
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.println(params);
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()), 8192);
String inputLine;
while ((inputLine = in.readLine()) != null) {
result = result.concat(inputLine);
}
in.close();
//} catch (IOException e) {
} catch (IOException | KeyStoreException | CertificateException | KeyManagementException | NoSuchAlgorithmException e) {
result = e.toString();
e.printStackTrace();
}
return result;
}

Related

Android studio "Wrote stack traces to tombstoned" when connecting to server

I'm trying to log in to my server from my app with self-signed certificate. When I try to log in I get this error:
"Thread[6,tid=17486,WaitingInMainSignalCatcherLoop,Thread*=0xb4000074d0ac6570,peer=0x147c0000,"Signal Catcher"]: reacting to signal 3 "
"Wrote stack traces to tombstoned."
What could be the cause of that? I searched this error and found a few solutions but none worked.
Here is my code:
public class Connection extends AsyncTask{
#Override
protected Object doInBackground(Object[] objects) {
try {
Connect();
} catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException | NullPointerException e) {
e.printStackTrace();
ServerDirectActivity.response = true;
ServerDirectActivity.responseMsg = String.valueOf(e);
}
return null;
}
}
private void Connect() throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, NullPointerException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { #Override public boolean verify(String hostname, SSLSession session) { return true; } });
InputStream caInput = ServerDirectActivity.getmInstanceActivity().getAssets().open("client.csr");
Certificate ca = null;
try{
ca = cf.generateCertificate(caInput);
}catch (CertificateException e){
e.printStackTrace();
}finally {
caInput.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL url = new URL(serverIP);
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
final String basicAuth = "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
urlConnection.setRequestProperty("Authorization", basicAuth);
urlConnection.setSSLSocketFactory(context.getSocketFactory());
System.out.println(urlConnection.getResponseMessage());
System.out.println(urlConnection.getResponseCode());
if (urlConnection.getResponseCode() == 200){
InputStream in = urlConnection.getInputStream();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
while ((line = reader.readLine()) != null){
out.append(line);
}
System.out.println(out);
}
ServerDirectActivity.response = true;
ServerDirectActivity.responseMsg = String.valueOf(urlConnection.getResponseCode());
}
}

Java webapp with two URL connections: basic auth and cert auth

I have a java webapp which uses this class for connecting to server by using basic auth and cert. It works fine separately (without creating other url connections):
public void connectCert(String jsonParams) {
try {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream("d:\\certs\\api\\xx.p12"), "W*53as_G".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "W*53as_G".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("c:\\jdk1.8.0_51\\jre\\lib\\security\\cacerts"), "changeit".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kms, tms, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL("https://apis2s.ee/test");
HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();
urlConn.setRequestProperty("Authorization", "Basic " + Base64.encode("andrey:pass_1".getBytes()));
urlConn.setUseCaches(false);
urlConn.setAllowUserInteraction(true);
urlConn.setRequestProperty("Pragma", "no-cache");
urlConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
urlConn.setRequestProperty("Content-length", Integer.toString(jsonParams.length()));
urlConn.setDoOutput(true);
urlConn.setRequestProperty("Content-Length", Integer.toString(jsonParams.length()));
PrintStream out = new PrintStream(urlConn.getOutputStream());
out.print(jsonParams);
out.flush();
out.close();
StringBuilder builder = new StringBuilder();
int responseCode = urlConn.getResponseCode();
builder.append(responseCode).append(" ").append(urlConn.getResponseMessage()).append("\n");
InputStream inputStream = null;
if (responseCode == 200) inputStream = urlConn.getInputStream();
else inputStream = urlConn.getErrorStream();//this returns 400
Scanner in = new Scanner(inputStream);
String responseStr = "";
while (in.hasNextLine()) {
String str = in.nextLine();
responseStr += str;
}
System.out.println(builder);
System.out.println("responseStr: " + responseStr);
} catch (Exception e) {
}
}
Also I need to create in my webapp a connection to another server by using basic auth (without certificate):
private InputStream connectHTTPS(String loginData, String url, String params) {
TrustManager[] trustAllCerts =
new TrustManager[]{
new X509TrustManager(){
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType){
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public boolean isClientTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
public boolean isServerTrusted(java.security.cert.X509Certificate[] certs) {
return true;
}
}};
HostnameVerifier verifier = new HostnameVerifier() {
public boolean verify(String string, SSLSession sSLSession) {
return true;
}
public boolean verify(String string, String string2) {
return true;
}
};
SSLContext sc = null;
try{
sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(verifier);
}catch(Exception e){
e.printStackTrace();
}
javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(verifier);
URL serverURL = null;
try{
serverURL = new URL(null,url,new sun.net.www.protocol.https.Handler());
}catch (Exception e){
e.printStackTrace();
}
javax.net.ssl.HttpsURLConnection urlConn = null;
try{
urlConn = (javax.net.ssl.HttpsURLConnection)serverURL.openConnection();
urlConn.setSSLSocketFactory(sc.getSocketFactory());
urlConn.setRequestMethod("POST");
}catch(Exception i){
i.printStackTrace();
}
InputStream res = null;
urlConn.setDoOutput(true);
if(useLogin)
urlConn.setRequestProperty("Authorization", "Basic " + loginData);
urlConn.setUseCaches(false);
urlConn.setAllowUserInteraction(true);
urlConn.setRequestProperty("Pragma", "no-cache");
urlConn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
urlConn.setRequestProperty("Content-length", Integer.toString(params.length()));
try{
PrintStream out = new PrintStream(urlConn.getOutputStream());
out.print(params);
out.flush();
out.close();
res = urlConn.getInputStream();
}catch(Exception o){
o.printStackTrace();
}
return res;
}
If connectHTTPS() is invoked before connectCert() then I get
<html><head><title>400 No required SSL certificate was sent</title></head><body
bgcolor="white"><center><h1>400 Bad Request</h1></center><center>No required SSL certificate was sent</center><hr><center>nginx</center></body></html>
How can I solve the cert issue with the both connections in one webapp?
The issue was resolved by modifying the connectHTTPS() and removing all ssl factory/context configuration. The connectCert() was not changed. The updated method looks like below
private InputStream connectHTTPS(boolean useLogin, boolean showServerError, String loginData, String url, String params) {
InputStream res = null;
HttpURLConnection connect =null;
try{
URL theURL = new URL(url);
connect = (HttpURLConnection)theURL.openConnection();
connect.setRequestMethod("POST");
connect.setUseCaches(false);
connect.setDoOutput(true);
if(useLogin)
connect.setRequestProperty("Authorization", "Basic " + loginData);
connect.setRequestProperty("Pragma", "no-cache");
connect.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
connect.setRequestProperty("Content-length", Integer.toString(params.length()));
PrintStream out = new PrintStream(connect.getOutputStream());
out.print(params);
out.flush();
out.close();
res = connect.getInputStream();
}catch(IOException iox){
if (showServerError && connect != null){
res = connect.getErrorStream();
} else {
res = new ByteArrayInputStream((iox.getMessage()).getBytes());
}
}
return res;
}
Thank you pedrofb for the suggestions.

Delete request from custom Java client acts differently than e.g. Postman

I have a java application that is making an HTTP DELETE to an external REST service. This error gets back to me from the server (running C#):
"Value cannot be null.\r\nParameter name: source\n at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)\r\n at AppCloud_Framework.Controllers.NotificationItemsController.DeleteNotificationItem(NotificationItem[] notificationItems) in C:\\Users\\jonas\\OneDrive\\VS Projects\\AppCloud Framework\\AppCloud Framework\\Controllers\\NotificationItemsController.cs:line 101\nValue:null"
The thing is, when I setup Postman to make the HTTP request to the same URL, with the same Payload and same HTTP method, the action is successful.
I do not have access to the server to investigate further so I need to find the resolution from the client side. Anyway it appears to be a client side issue.
I've been trying to find the problem myself but haven't succeeded. All I could come up with was to add "application/json" to Accept and Content-Type header properties.
My HTTP client:
public static Response execute(String url, Method method, String body) {
Response response = new Response();
try {
////////////////////////////////////////
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
// Install the all-trusting trust manager
final SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
////////////////////////////////////////
URL urlObj = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) urlObj.openConnection();
conn.setInstanceFollowRedirects(false);
conn.setRequestMethod(method.toString());
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
//conn.setRequestProperty("Authorization", _authToken);
if (method == Method.POST || method == Method.PUT || method == Method.DELETE) {
conn.setDoOutput(true);
final OutputStream os = conn.getOutputStream();
os.write(body.getBytes());
os.flush();
os.close();
}
int status = conn.getResponseCode();
//log.info("HTTP request status code: "+status);
InputStream is;
if (status>399){
is = conn.getErrorStream();
}else{
is = conn.getInputStream();
}
if (is==null) return null;
BufferedReader rd = new BufferedReader(new InputStreamReader(is,
"UTF-8"));
String line;
while ((line = rd.readLine()) != null) {
response.body += line;
}
rd.close();
response.statusCode = conn.getResponseCode();
conn.disconnect();
} catch (Exception e) {
//log.error(e.getMessage());
e.printStackTrace();
System.out.println("");
response.exception = e.getMessage();
}
return response;
}
I am making a request with this body(disregard the encoding issue, source of that is somewhere else):
[{"hash":"150a17e99f67ce29fcc600c92eee831d","instanceid":"cb440a6f-44ef-4f05-ab41-143153655b6e","text":"{\"C_FirstAndLastName\":\"und\",\"ContactID\":\"1374231\",\"C_Fax\":\"\"}","queueDate":"2016-10-04T03:18:37"},{"hash":"1a94d9b5acff1a27dfe45be4ca5d9138","instanceid":"fdsfdsf-44ef-4f05-ab41-143153655b6e","text":"{\"C_FirstAndLastName\":\"J?รข??rgen\",\"ContactID\":\"323093\",\"C_Fax\":\"fsdfsd-B401-4AD3-AEA1-fdsfsdfsd\"}","queueDate":"2016-10-04T03:18:37"},{"hash":"8e592fb16d464bfd0f90f69818944198","instanceid":"fdsfsdf-44ef-4f05-ab41-143153655b6e","text":"{\"C_FirstAndLastName\":\"Claus\",\"ContactID\":\"2495844\",\"C_Fax\":\"fdsfsdgsd-304D-4E91-8586-fsdfsdfsd\"}","queueDate":"2016-10-04T03:18:37"},{"hash":"d6d226255e62690e50abbfa15c4b5462","instanceid":"cb440a6f-44ef-4f05-ab41-143153655b6e","text":"{\"C_FirstAndLastName\":\"Test J??rgen\",\"ContactID\":\"323093\",\"C_Fax\":\"fdsfsdfsd-B401-4AD3-AEA1-fdsfsdfsdf\"}","queueDate":"2016-10-04T03:18:49"}]
All I had to do was to define encoding in the output stream. Not sure if anyone could help me with that as I have just tried many things and some of it worked, but unfortunately nothing was pointing me into this direction.
os.write(body.getBytes("UTF-8"));

Android/Eclipse Open a file Outside the MainActivity in a Plugin

I have a problem with my Android Phonegap App.
I created a plugin to send Data from HTML/JAVASCRIPT to Java and Java will send this DATA to a
Server with HTTPS post.
To get this Worke I need to Open a ssl.crt (certification) from my Asset folder.
In the Cordova Class this function dose work because it extends the CordovaActivity.
My Plugin Class : public class ConnectPlugin extends CordovaPlugin
Here is the Login method:
protected String tryLogin_2(String d1) throws CertificateException, FileNotFoundException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException
{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(this.getAssets().open("ssl.crt"));
java.security.cert.Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
String httpsURL = "https://URL.com";
OutputStreamWriter request = null;
DataInputStream response_2 = null;
String parameters = "1="+d1;
String response = null;
try
{
URL myurl = new URL(httpsURL);
HttpsURLConnection con = (HttpsURLConnection)myurl.openConnection();
con.setSSLSocketFactory(context.getSocketFactory());
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(query.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setDoOutput(true);
con.setDoInput(true);
request = new OutputStreamWriter(con.getOutputStream());
request.write(parameters);
request.flush();
request.close();
String line = "";
InputStreamReader isr = new InputStreamReader(con.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
//Response from server after login process will be stored in response variable.
response = sb.toString();
isr.close();
reader.close();
}
catch(IOException e)
{
response = "Error"; // Error
}
return response;
}
The problem now is "The method getAssets() is undefined for the type ConnectPlugin".
I can't use the getAssets() method outside the Main Class.
In my MainClass the obove code work 100% fine and sends a request to my server.
But not in my Plugin Class.
Use
cordova.getActivity().getAssets().open("ssl.crt"));

Android: Problem exchanging messages with SSL

I have been trying to get a client to communicate with a server securely through SSL. I created my own self-signed certificates and it seems like that the client can connect to the server using the certificates, but the client never seems to be getting the response from the server. I tried printing the content-length which returns -1 and the actual content seems to be an empty string, although a simple HTML 'hello world' is expected.
What am I doing wrong?
Server:
public class SSLServer {
public static void main(String[] args) {
String ksName = "key.jks";
char ksPass[] = "password".toCharArray();
char ctPass[] = "password".toCharArray();
try {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(ksName), ksPass);
KeyManagerFactory kmf =
KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, ctPass);
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
SSLServerSocketFactory ssf = sc.getServerSocketFactory();
SSLServerSocket s
= (SSLServerSocket) ssf.createServerSocket(8888);
System.out.println("Server started:");
// Listening to the port
SSLSocket c = (SSLSocket) s.accept();
BufferedWriter w = new BufferedWriter(
new OutputStreamWriter(c.getOutputStream()));
w.write("HTTP/1.0 200 OK");
w.write("Content-Type: text/html");
w.write("<html><body>Hello world!</body></html>");
w.flush();
w.close();
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Client:
public class TestSSLActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://192.168.15.195:8888");
// Execute the GET call and obtain the response
HttpResponse getResponse;
try {
getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
Log.i("Connection",responseEntity.getContentLength()+"");
BufferedReader reader = new BufferedReader(new InputStreamReader(responseEntity.getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
Log.i("Connection","build: "+builder.toString());
} catch (Exception e) {
Log.i("Connection",e.getMessage());
}
}
Custom HTTP client:
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.key);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "password".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
You might want to change the server code to read the request from the client before sending the response. It could be that the client is blocking (and then timing out?) waiting for the server to read the request.

Categories

Resources