Skip to content

Commit 5839bed

Browse files
author
Noor Dawod
committed
Out-of-the-box working example for custom CA.
I have contributed a sample link on my personal server. It's dedicated solely for use by the library, and hopefully will not be abused.
1 parent f60dd56 commit 5839bed

File tree

4 files changed

+74
-60
lines changed

4 files changed

+74
-60
lines changed

sample/src/main/java/com/loopj/android/http/sample/CustomCASample.java

Lines changed: 68 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@
2020

2121
import android.app.AlertDialog;
2222
import android.content.DialogInterface;
23+
import android.content.res.Resources;
2324
import android.os.Bundle;
2425
import android.util.Log;
25-
import android.widget.Toast;
26+
import com.fasterxml.jackson.core.JsonFactory;
27+
import com.fasterxml.jackson.databind.ObjectMapper;
2628

2729
import com.loopj.android.http.AsyncHttpClient;
28-
import com.loopj.android.http.BinaryHttpResponseHandler;
30+
import com.loopj.android.http.BaseJsonHttpResponseHandler;
2931
import com.loopj.android.http.RequestHandle;
3032
import com.loopj.android.http.ResponseHandlerInterface;
33+
import com.loopj.android.http.sample.util.SampleJSON;
3134
import com.loopj.android.http.sample.util.SecureSocketFactory;
3235

3336
import org.apache.http.Header;
@@ -53,9 +56,16 @@ public class CustomCASample extends SampleParentActivity {
5356

5457
private static final String LOG_TAG = "CustomCASample";
5558

56-
private static final String SERVER_TEST_URL = "https://httpbin.org/get";
57-
private static final String STORE_ALIAS = "TheAlias";
58-
private static final String STORE_PASS = "ThePass";
59+
// This is A TEST URL for use with AsyncHttpClient LIBRARY ONLY!
60+
// It is provided courtesy of Fineswap (http://fineswap.com) and must never
61+
// be used in ANY program except when running this sample (CustomCASample).
62+
private static final String SERVER_TEST_URL = "https://api.fineswap.io/ahc";
63+
64+
// The certificate's alias.
65+
private static final String STORE_ALIAS = "rootca";
66+
67+
// The certificate's password.
68+
private static final String STORE_PASS = "Fineswap";
5969

6070
// Instruct the library to retry connection when this exception is raised.
6171
static {
@@ -89,59 +99,18 @@ protected void onCreate(Bundle savedInstanceState) {
8999
}
90100
} catch (KeyStoreException e) {
91101
Log.e(LOG_TAG, "Unable to initialize key store", e);
92-
Toast.makeText(
93-
this,
94-
"Please read res/raw/custom_ca.txt\nto learn how to create your own\nkey store containing a custom CA",
95-
Toast.LENGTH_LONG).show();
96102
showCustomCAHelp();
97103
}
98104
}
99105

100-
/**
101-
* Returns contents of `custom_ca.txt` as CharSequence
102-
*
103-
* @return contents of custom_ca.txt from Assets
104-
*/
105-
private CharSequence getReadmeText() {
106-
String rtn = "";
107-
try {
108-
InputStream stream = getResources().openRawResource(R.raw.custom_ca);
109-
java.util.Scanner s = new java.util.Scanner(stream)
110-
.useDelimiter("\\A");
111-
rtn = s.hasNext() ? s.next() : "";
112-
} catch (Exception | Error e) {
113-
Log.e(LOG_TAG, "License couldn't be retrieved", e);
114-
}
115-
return rtn;
116-
}
117-
118-
/**
119-
* Will display AlertDialog reading `custom_ca.txt` from Assets, to avoid strict Lint issue
120-
*/
121-
private void showCustomCAHelp() {
122-
AlertDialog.Builder builder = new AlertDialog.Builder(this);
123-
builder.setTitle(R.string.title_custom_ca);
124-
builder.setMessage(getReadmeText());
125-
builder.setNeutralButton(android.R.string.cancel,
126-
new DialogInterface.OnClickListener() {
127-
128-
@Override
129-
public void onClick(DialogInterface dialog, int which) {
130-
dialog.dismiss();
131-
}
132-
}
133-
);
134-
builder.show();
135-
}
136-
137106
@Override
138107
public int getSampleTitle() {
139108
return R.string.title_custom_ca;
140109
}
141110

142111
@Override
143112
public boolean isRequestBodyAllowed() {
144-
return true;
113+
return false;
145114
}
146115

147116
@Override
@@ -156,38 +125,78 @@ public String getDefaultURL() {
156125

157126
@Override
158127
public ResponseHandlerInterface getResponseHandler() {
159-
return new BinaryHttpResponseHandler() {
128+
return new BaseJsonHttpResponseHandler<SampleJSON>() {
129+
160130
@Override
161131
public void onStart() {
162132
clearOutputs();
163133
}
164134

165135
@Override
166-
public String[] getAllowedContentTypes() {
167-
// Allowing all data for debug purposes
168-
return new String[]{".*"};
169-
}
170-
171-
public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {
172-
debugStatusCode(LOG_TAG, statusCode);
136+
public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, SampleJSON response) {
173137
debugHeaders(LOG_TAG, headers);
174-
debugResponse(LOG_TAG, "Received response is " + binaryData.length + " bytes");
138+
debugStatusCode(LOG_TAG, statusCode);
139+
if (response != null) {
140+
debugResponse(LOG_TAG, rawJsonResponse);
141+
}
175142
}
176143

177144
@Override
178-
public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
145+
public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, SampleJSON errorResponse) {
179146
debugHeaders(LOG_TAG, headers);
180147
debugStatusCode(LOG_TAG, statusCode);
181-
debugThrowable(LOG_TAG, e);
148+
debugThrowable(LOG_TAG, throwable);
182149
if (errorResponse != null) {
183-
debugResponse(LOG_TAG, "Received response is " + errorResponse.length + " bytes");
150+
debugResponse(LOG_TAG, rawJsonData);
184151
}
185152
}
153+
154+
@Override
155+
protected SampleJSON parseResponse(String rawJsonData, boolean isFailure) throws Throwable {
156+
return new ObjectMapper().readValues(new JsonFactory().createParser(rawJsonData), SampleJSON.class).next();
157+
}
186158
};
187159
}
188160

189161
@Override
190162
public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) {
191163
return client.get(this, URL, headers, null, responseHandler);
192164
}
165+
166+
/**
167+
* Returns contents of `custom_ca.txt` file from assets as CharSequence.
168+
*
169+
* @return contents of custom_ca.txt file
170+
*/
171+
private CharSequence getReadmeText() {
172+
String rtn = "";
173+
try {
174+
InputStream stream = getResources().openRawResource(R.raw.custom_ca);
175+
java.util.Scanner s = new java.util.Scanner(stream)
176+
.useDelimiter("\\A");
177+
rtn = s.hasNext() ? s.next() : "";
178+
} catch (Resources.NotFoundException e) {
179+
Log.e(LOG_TAG, "License couldn't be retrieved", e);
180+
}
181+
return rtn;
182+
}
183+
184+
/**
185+
* Displays a dialog showing contents of `custom_ca.txt` file from assets.
186+
* This is needed to avoid Lint's strict mode.
187+
*/
188+
private void showCustomCAHelp() {
189+
AlertDialog.Builder builder = new AlertDialog.Builder(this);
190+
builder.setTitle(R.string.title_custom_ca);
191+
builder.setMessage(getReadmeText());
192+
builder.setNeutralButton(android.R.string.cancel,
193+
new DialogInterface.OnClickListener() {
194+
@Override
195+
public void onClick(DialogInterface dialog, int which) {
196+
dialog.dismiss();
197+
}
198+
}
199+
);
200+
builder.show();
201+
}
193202
}

sample/src/main/java/com/loopj/android/http/sample/FilesSample.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public boolean isRequestBodyAllowed() {
3333
public RequestHandle executeSample(AsyncHttpClient client, String URL, Header[] headers, HttpEntity entity, ResponseHandlerInterface responseHandler) {
3434
try {
3535
RequestParams params = new RequestParams();
36-
final String contentType = "application/octet-stream";
36+
final String contentType = RequestParams.APPLICATION_OCTET_STREAM;
3737
params.put("fileOne", createTempFile("fileOne", 1020), contentType);
3838
params.put("fileTwo", createTempFile("fileTwo", 1030), contentType);
3939
params.put("fileThree", createTempFile("fileThree", 1040), contentType);

sample/src/main/res/raw/custom_ca.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
This is a short HOW-TO documenting the steps necessary to create a key store
22
file that Android could use to connect to servers with a custom CA.
33

4+
This file's location is: 'res/raw/custom_ca.txt'
5+
46
Prerequisities:
57
---------------
68

@@ -23,6 +25,9 @@ Let's see the fun part:
2325

2426
openssl req -newkey rsa:4096 -days 3650 -x509 -nodes -out ca.pem
2527

28+
This instructs openssl to create a 4096-bit RSA key and set its expiration
29+
date 10 years later.
30+
2631
You will be asked to provide details of the CA. When you're finished, a file
2732
called 'ca.pem' will exist in current directory.
2833

sample/src/main/res/raw/store.bks

1.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)