From 8e47afc7f4f85b80d59d253378681cb85ec54d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 16 Apr 2013 20:12:13 +0200 Subject: Made SRP working with ProviderAPI methods more frequently than not in localhost, but I cannot succeed in api.bitmask.net with my personal account. Next step: add tests from api.bitmask.net. --- src/se/leap/leapclient/LeapSRPSession.java | 2 ++ src/se/leap/leapclient/ProviderAPI.java | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index abdf6b2..6fc8b2b 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -70,6 +70,8 @@ public class LeapSRPSession { */ this.a = new BigInteger(abytes); } + else + A_LEN = 64; // Calculate x = H(s | H(U | ':' | password)) byte[] salt_bytes = Util.trim(params.s); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4ffd276..5113ebc 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -20,6 +20,7 @@ import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; +import org.jboss.security.Util; import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -56,6 +57,12 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { + if(authenticateBySRP(task)) + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, Bundle.EMPTY); + else + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + } } private boolean downloadJsonFiles(Bundle task) { @@ -105,17 +112,16 @@ public class ProviderAPI extends IntentService { LeapSRPSession client = new LeapSRPSession(username, password.toCharArray(), params); byte[] A = client.exponential(); try { - JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(A).toString(16)); + JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { byte[] B = saltAndB.getString("B").getBytes(); salt = saltAndB.getString("salt"); params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - //client = new SRPClientSession(username, password.toCharArray(), params); client = new LeapSRPSession(username, password.toCharArray(), params); A = client.exponential(); - saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(A).toString(16)); - String Bhex = saltAndB.getString("B"); - byte[] M1 = client.response(new BigInteger(Bhex, 16).toByteArray()); + saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); + byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); + byte[] M1 = client.response(Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) throw new SecurityException("Failed to validate server reply"); @@ -162,7 +168,7 @@ public class ProviderAPI extends IntentService { private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + new BigInteger(m1).toString(16); + String parameter_chain = "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16); HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); @@ -175,7 +181,9 @@ public class ProviderAPI extends IntentService { return new byte[0]; } - return json_response.getString("M2").getBytes(); + byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); + return Util.trim(M2_not_trimmed); + //return M2_not_trimmed; } private boolean downloadNewProviderDotJSON(Bundle task) { -- cgit v1.2.3 From f9b9827ec1975cb01e83826f0ad77542e514b21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 17 Apr 2013 21:17:22 +0200 Subject: This commit contains: - SRP algorithm improved (validate method uses trim, and some other trims have been added). - Refactored calculatePasswordHash, so that it receives a String instead of a char array, and now it is capable of escaping "\" correctly. - A 1000*2 successful logins, with a new test that performs 1000 trials for 2 different username/password/server trios. Next step: think about how the user is going to trigger the log in fragment. --- src/se/leap/leapclient/LeapSRPSession.java | 36 +++++++++++++++++------------- src/se/leap/leapclient/ProviderAPI.java | 6 ++--- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 6fc8b2b..d266cd7 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -34,7 +34,7 @@ public class LeapSRPSession { @param password, the user clear text password @param params, the SRP parameters for the session */ - public LeapSRPSession(String username, char[] password, SRPParameters params) + public LeapSRPSession(String username, String password, SRPParameters params) { this(username, password, params, null); } @@ -47,7 +47,7 @@ public class LeapSRPSession { @param abytes, the random exponent used in the A public key. This must be 8 bytes in length. */ - public LeapSRPSession(String username, char[] password, SRPParameters params, + public LeapSRPSession(String username, String password, SRPParameters params, byte[] abytes) { try { // Initialize the secure random number and message digests @@ -117,11 +117,11 @@ public class LeapSRPSession { * @param salt the salt of the user * @return x */ - public byte[] calculatePasswordHash(String username, char[] password, byte[] salt) + public byte[] calculatePasswordHash(String username, String password, byte[] salt) { + password = password.replaceAll("\\\\", "\\\\\\\\"); // Calculate x = H(s | H(U | ':' | password)) MessageDigest x_digest = newDigest(); - // Try to convert the username to a byte[] using UTF-8 byte[] user = null; byte[] colon = {}; @@ -135,10 +135,10 @@ public class LeapSRPSession { colon = Util.trim(":".getBytes()); } - byte[] passBytes = new byte[2*password.length]; + byte[] passBytes = new byte[2*password.toCharArray().length]; int passBytesLength = 0; - for(int p = 0; p < password.length; p++) { - int c = (password[p] & 0x00FFFF); + for(int p = 0; p < password.toCharArray().length; p++) { + int c = (password.toCharArray()[p] & 0x00FFFF); // The low byte of the char byte b0 = (byte) (c & 0x0000FF); // The high byte of the char @@ -159,7 +159,7 @@ public class LeapSRPSession { x_digest.reset(); x_digest.update(salt); x_digest.update(h); - byte[] x_digest_bytes = Util.trim(x_digest.digest()); + byte[] x_digest_bytes = x_digest.digest(); return x_digest_bytes; } @@ -171,7 +171,8 @@ public class LeapSRPSession { */ private BigInteger calculateV(String k_string) { BigInteger k = new BigInteger(k_string, 16); - return k.multiply(g.modPow(x, N)); // g^x % N + BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N + return v; } public byte[] xor(byte[] b1, byte[] b2, int length) @@ -229,13 +230,13 @@ public class LeapSRPSession { // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); - K = sessionDigest.digest(S_bytes); + K = Util.trim(sessionDigest.digest(S_bytes)); //K = Util.trim(K); //String K_bytes_string = new BigInteger(1, K).toString(16); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); - byte[] M1 = clientHash.digest(); + byte[] M1 = Util.trim(clientHash.digest()); // serverHash = Astr + M + K serverHash.update(M1); @@ -250,10 +251,11 @@ public class LeapSRPSession { */ private BigInteger calculateS(byte[] Bbytes) { byte[] Abytes = Util.trim(A.toByteArray()); + Bbytes = Util.trim(Bbytes); byte[] u_bytes = getU(Abytes, Bbytes); - //ub = Util.trim(ub); BigInteger B = new BigInteger(1, Bbytes); + //String Bstring = B.toString(16); BigInteger u = new BigInteger(1, u_bytes); //String u_string = u.toString(16); @@ -273,9 +275,10 @@ public class LeapSRPSession { */ public byte[] getU(byte[] Abytes, byte[] Bbytes) { MessageDigest u_digest = newDigest(); - u_digest.update(Abytes); - u_digest.update(Bbytes); - return new BigInteger(1, u_digest.digest()).toByteArray(); + u_digest.update(Util.trim(Abytes)); + u_digest.update(Util.trim(Bbytes)); + byte[] u_digest_bytes = u_digest.digest();//Util.trim(u_digest.digest()); + return Util.trim(new BigInteger(1, u_digest_bytes).toByteArray()); } /** @@ -285,7 +288,8 @@ public class LeapSRPSession { public boolean verify(byte[] M2) { // M2 = H(A | M1 | K) - byte[] myM2 = serverHash.digest(); + M2 = Util.trim(M2); + byte[] myM2 = Util.trim(serverHash.digest()); boolean valid = Arrays.equals(M2, myM2); return valid; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 5113ebc..55686f7 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -109,7 +109,7 @@ public class ProviderAPI extends IntentService { SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); //SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); - LeapSRPSession client = new LeapSRPSession(username, password.toCharArray(), params); + LeapSRPSession client = new LeapSRPSession(username, password, params); byte[] A = client.exponential(); try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); @@ -117,14 +117,14 @@ public class ProviderAPI extends IntentService { byte[] B = saltAndB.getString("B").getBytes(); salt = saltAndB.getString("salt"); params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - client = new LeapSRPSession(username, password.toCharArray(), params); + client = new LeapSRPSession(username, password, params); A = client.exponential(); saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) - throw new SecurityException("Failed to validate server reply"); + throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); return true; } else return false; -- cgit v1.2.3 From 5c05094401d6ed3c69ab8f64e47278973bc87425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 18 Apr 2013 21:56:06 +0200 Subject: Coded logout method, and tested. --- src/se/leap/leapclient/ConfigHelper.java | 7 ++-- src/se/leap/leapclient/ProviderAPI.java | 60 +++++++++++++++----------------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 7476c89..8f38cbe 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -32,6 +32,7 @@ public class ConfigHelper { final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; public static final String srpRegister = "srpRegister"; final public static String srpAuth = "srpAuth"; + public static String logOut = "logOut"; final public static String resultKey = "result"; final static String provider_key = "provider"; final static String cert_key = "cert"; @@ -53,8 +54,10 @@ public class ConfigHelper { final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 2; final public static int SRP_AUTHENTICATION_SUCCESSFUL = 3; final public static int SRP_AUTHENTICATION_FAILED = 4; - public static final int SRP_REGISTRATION_SUCCESSFUL = 5; - public static final int SRP_REGISTRATION_FAILED = 6; + final public static int SRP_REGISTRATION_SUCCESSFUL = 5; + final public static int SRP_REGISTRATION_FAILED = 6; + final public static int LOGOUT_SUCCESSFUL = 7; + final public static int LOGOUT_FAILED = 8; static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 55686f7..d47e3b6 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -12,6 +12,7 @@ import java.util.Scanner; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; @@ -63,6 +64,12 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.logOut)) != null) { + if(logOut(task)) + receiver.send(ConfigHelper.LOGOUT_SUCCESSFUL, Bundle.EMPTY); + else + receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); + } } private boolean downloadJsonFiles(Bundle task) { @@ -215,38 +222,6 @@ public class ProviderAPI extends IntentService { } } - private boolean downloadJsonFilesBundleExtra(Bundle task) { - //TODO task only contains provider main url -> we need to infer cert_url, provider_name and eip_service_json_url from that. - String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); - String provider_name = ConfigHelper.extractProviderName(provider_main_url); - String cert_url = (String) task.get(ConfigHelper.cert_key); - String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); - try { - //JSONObject provider_json = new JSONObject("{ \"provider\" : \"" + provider_name + "\"}"); - //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - - /*String cert_string = getStringFromProvider(cert_url); - JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); - ConfigHelper.addTrustedCertificate(provider_name, cert_string);*/ - URL cacert = new URL(cert_url); - ConfigHelper.addTrustedCertificate(provider_name, cacert.openStream()); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); - ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); - return true; - } catch (IOException e) { - //TODO It could happen when the url is not valid. - e.printStackTrace(); - return false; - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - return false; - } catch(Exception e) { - e.printStackTrace(); - return false; - } - } - private JSONObject downloadNewProviderDotJsonWithoutCert( String provider_json_url) { JSONObject provider_json = null; @@ -284,8 +259,29 @@ public class ProviderAPI extends IntentService { return json_file_content; } + private JSONObject getJSONFromProvider(String json_url) throws IOException, JSONException { String json_file_content = getStringFromProvider(json_url); return new JSONObject(json_file_content); } + + private boolean logOut(Bundle task) { + DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); + int session_id_index = 0; + //String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/sessions/" + client.getCookieStore().getCookies().get(0).getValue(); + String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + HttpDelete delete = new HttpDelete(delete_url); + try { + HttpResponse getResponse = client.execute(delete); + HttpEntity responseEntity = getResponse.getEntity(); + responseEntity.consumeContent(); + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; + } } -- cgit v1.2.3 From 75728462433b19567710f54a9d4767681b10be95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 22 Apr 2013 18:07:07 +0200 Subject: Coded dialog (now there is a button in the Dashboard), time to test. I need to implement bypass for dev.bitmask.net, because bitmask.net is down. --- res/layout/log_in_dialog.xml | 32 +++++++++++ res/menu/client_dashboard.xml | 1 + res/values/strings.xml | 4 ++ src/se/leap/leapclient/ConfigHelper.java | 7 ++- src/se/leap/leapclient/ConfigurationWizard.java | 4 +- src/se/leap/leapclient/Dashboard.java | 64 +++++++++++++++++++++- src/se/leap/leapclient/LogInDialog.java | 73 +++++++++++++++++++++++++ src/se/leap/leapclient/ProviderAPI.java | 8 +-- 8 files changed, 184 insertions(+), 9 deletions(-) create mode 100644 res/layout/log_in_dialog.xml create mode 100644 src/se/leap/leapclient/LogInDialog.java diff --git a/res/layout/log_in_dialog.xml b/res/layout/log_in_dialog.xml new file mode 100644 index 0000000..6f28118 --- /dev/null +++ b/res/layout/log_in_dialog.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/menu/client_dashboard.xml b/res/menu/client_dashboard.xml index 87e7ae6..fffd4e2 100644 --- a/res/menu/client_dashboard.xml +++ b/res/menu/client_dashboard.xml @@ -7,5 +7,6 @@ android:title="@string/menu_settings"/> + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 2deb23f..6e84bed 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -265,5 +265,9 @@ Introduce new provider Save New provider\'s main URL + Introduce your username + Enter your password + Log in + Log In \ No newline at end of file diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 8f38cbe..de14eed 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -30,8 +30,11 @@ public class ConfigHelper { final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; - public static final String srpRegister = "srpRegister"; + final public static String logInDialog = "logInDialog"; + final public static String newProviderDialog = "logInDialog"; + final public static String srpRegister = "srpRegister"; final public static String srpAuth = "srpAuth"; + public static String logIn = "logIn"; public static String logOut = "logOut"; final public static String resultKey = "result"; final static String provider_key = "provider"; @@ -40,7 +43,7 @@ public class ConfigHelper { public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; public static String provider_main_url = "provider_main_url"; - final public static String srp_server_url_key = "srp_server_url"; + final public static String api_url_key = "srp_server_url"; final public static String username_key = "username"; final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 0d44522..417752e 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -172,14 +172,14 @@ public class ConfigurationWizard extends Activity public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag("newProviderDialog"); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.newProviderDialog); if (previous_new_provider_dialog != null) { fragment_transaction.remove(previous_new_provider_dialog); } fragment_transaction.addToBackStack(null); DialogFragment newFragment = NewProviderDialog.newInstance(); - newFragment.show(fragment_transaction, "newProviderDialog"); + newFragment.show(fragment_transaction, ConfigHelper.newProviderDialog); } @Override diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index dce99b1..815df18 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -1,13 +1,20 @@ package se.leap.leapclient; +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; +import android.app.DialogFragment; import android.app.Fragment; +import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Handler; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -16,7 +23,7 @@ import android.widget.CompoundButton; import android.widget.Switch; import android.widget.TextView; -public class Dashboard extends Activity { +public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, Receiver { protected static final int CONFIGURE_LEAP = 0; @@ -26,6 +33,8 @@ public class Dashboard extends Activity { private TextView providerNameTV; private TextView eipTypeTV; + public ProviderAPIResultReceiver providerAPI_result_receiver; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -127,6 +136,9 @@ public class Dashboard extends Activity { // TODO call se.leap.openvpn.MainActivity intent = new Intent(this,MainActivity.class); startActivity(intent); + return true; + case R.id.login_button: + return true; default: return super.onOptionsItemSelected(item); @@ -139,4 +151,54 @@ public class Dashboard extends Activity { // TODO Expand the one line overview item to show some details } + @Override + public void authenticate(String username, String password) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.username_key, username); + method_and_parameters.putString(ConfigHelper.password_key, password); + + JSONObject provider_json; + try { + provider_json = new JSONObject(preferences.getString(ConfigHelper.provider_key, "")); + method_and_parameters.putString(ConfigHelper.api_url_key, provider_json.getString(ConfigHelper.api_url_key)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + provider_API_command.putExtra(ConfigHelper.srpAuth, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } + + public void logInDialog(View view) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.logInDialog); + if (previous_log_in_dialog != null) { + fragment_transaction.remove(previous_log_in_dialog); + } + fragment_transaction.addToBackStack(null); + + DialogFragment newFragment = LogInDialog.newInstance(); + newFragment.show(fragment_transaction, ConfigHelper.logInDialog); + } + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ + setResult(RESULT_OK); + //TODO What should we do know? + } + else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { + setResult(RESULT_CANCELED); + finish(); + } + } + } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java new file mode 100644 index 0000000..b9583d8 --- /dev/null +++ b/src/se/leap/leapclient/LogInDialog.java @@ -0,0 +1,73 @@ +package se.leap.leapclient; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +public class LogInDialog extends DialogFragment { + + public interface LogInDialogInterface { + public void authenticate(String username, String password); + } + + LogInDialogInterface interface_with_ConfigurationWizard; + + public static DialogFragment newInstance() { + LogInDialog dialog_fragment = new LogInDialog(); + return dialog_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // Verify that the host activity implements the callback interface + try { + // Instantiate the NoticeDialogListener so we can send events to the host + interface_with_ConfigurationWizard = (LogInDialogInterface) activity; + } catch (ClassCastException e) { + // The activity doesn't implement the interface, throw exception + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null); + final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); + final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + builder.setView(log_in_dialog_view) + .setPositiveButton(R.string.log_in_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String username = username_field.getText().toString().trim(); + String password = password_field.getText().toString().trim(); + if(validPassword(password)) { + interface_with_ConfigurationWizard.authenticate(username, password); + Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); + } else { + password_field.setText(""); + Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", Toast.LENGTH_LONG).show(); + } + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + // Create the AlertDialog object and return it + return builder.create(); + } + + boolean validPassword(String entered_password) { + return !(entered_password.length() > 8); + } +} diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index d47e3b6..0b114e3 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -83,7 +83,7 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; } catch (IOException e) { - // TODO Auto-generated catch block + // TODO e.printStackTrace(); return false; } catch (JSONException e) { @@ -98,7 +98,7 @@ public class ProviderAPI extends IntentService { private boolean registerWithSRP(Bundle task) { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + String authentication_server = (String) task.get(ConfigHelper.api_url_key); BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); BigInteger salt = ng_1024.probablePrime(1024, null); @@ -110,7 +110,7 @@ public class ProviderAPI extends IntentService { private boolean authenticateBySRP(Bundle task) { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + String authentication_server = (String) task.get(ConfigHelper.api_url_key); String salt = "abcd"; @@ -269,7 +269,7 @@ public class ProviderAPI extends IntentService { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); int session_id_index = 0; //String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/sessions/" + client.getCookieStore().getCookies().get(0).getValue(); - String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); HttpDelete delete = new HttpDelete(delete_url); try { HttpResponse getResponse = client.execute(delete); -- cgit v1.2.3 From bfe2263d6b73159a4f929bc7b1fdeb724c88e8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 22 Apr 2013 20:17:43 +0200 Subject: Added danger mode: we can bypass dev.bitmask.net hostname io exception. --- res/layout/new_provider_dialog.xml | 6 +++ res/values/strings.xml | 1 + src/se/leap/leapclient/ConfigHelper.java | 3 +- src/se/leap/leapclient/ConfigurationWizard.java | 3 +- src/se/leap/leapclient/Dashboard.java | 4 +- src/se/leap/leapclient/LogInDialog.java | 8 ++-- src/se/leap/leapclient/NewProviderDialog.java | 8 +++- src/se/leap/leapclient/ProviderAPI.java | 50 ++++++++++++++++++++++++- 8 files changed, 72 insertions(+), 11 deletions(-) diff --git a/res/layout/new_provider_dialog.xml b/res/layout/new_provider_dialog.xml index 2812286..19b8f44 100644 --- a/res/layout/new_provider_dialog.xml +++ b/res/layout/new_provider_dialog.xml @@ -15,4 +15,10 @@ android:layout_marginBottom="4dp" android:hint="@string/new_provider_uri" /> + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 6e84bed..eac73bc 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -269,5 +269,6 @@ Enter your password Log in Log In + Trust completely \ No newline at end of file diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index de14eed..78c71cc 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -42,7 +42,8 @@ public class ConfigHelper { final static String eip_service_key = "eip"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; - public static String provider_main_url = "provider_main_url"; + final public static String provider_main_url = "provider_main_url"; + final public static String danger_on = "danger_on"; final public static String api_url_key = "srp_server_url"; final public static String username_key = "username"; final public static String password_key = "password"; diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 417752e..9edaa28 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -183,7 +183,7 @@ public class ConfigurationWizard extends Activity } @Override - public void saveProvider(String provider_main_url) { + public void saveProvider(String provider_main_url, boolean danger_on) { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -193,6 +193,7 @@ public class ConfigurationWizard extends Activity method_and_parameters.putString(ConfigHelper.provider_main_url, provider_main_url); provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.danger_on, danger_on); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 815df18..a169c9d 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -18,6 +18,7 @@ import android.os.Handler; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.ViewStub; import android.widget.CompoundButton; import android.widget.Switch; @@ -138,7 +139,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startActivity(intent); return true; case R.id.login_button: - + View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); + logInDialog(view); return true; default: return super.onOptionsItemSelected(item); diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index b9583d8..61526c6 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -17,7 +17,7 @@ public class LogInDialog extends DialogFragment { public void authenticate(String username, String password); } - LogInDialogInterface interface_with_ConfigurationWizard; + LogInDialogInterface interface_with_Dashboard; public static DialogFragment newInstance() { LogInDialog dialog_fragment = new LogInDialog(); @@ -30,7 +30,7 @@ public class LogInDialog extends DialogFragment { // Verify that the host activity implements the callback interface try { // Instantiate the NoticeDialogListener so we can send events to the host - interface_with_ConfigurationWizard = (LogInDialogInterface) activity; + interface_with_Dashboard = (LogInDialogInterface) activity; } catch (ClassCastException e) { // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() @@ -50,7 +50,7 @@ public class LogInDialog extends DialogFragment { String username = username_field.getText().toString().trim(); String password = password_field.getText().toString().trim(); if(validPassword(password)) { - interface_with_ConfigurationWizard.authenticate(username, password); + interface_with_Dashboard.authenticate(username, password); Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); } else { password_field.setText(""); @@ -68,6 +68,6 @@ public class LogInDialog extends DialogFragment { } boolean validPassword(String entered_password) { - return !(entered_password.length() > 8); + return entered_password.length() > 8; } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 88e4711..6101846 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -8,13 +8,14 @@ import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; public class NewProviderDialog extends DialogFragment { public interface NewProviderDialogInterface { - public void saveProvider(String url_provider); + public void saveProvider(String url_provider, boolean danger_on); } NewProviderDialogInterface interface_with_ConfigurationWizard; @@ -43,13 +44,16 @@ public class NewProviderDialog extends DialogFragment { LayoutInflater inflater = getActivity().getLayoutInflater(); View new_provider_dialog_view = inflater.inflate(R.layout.new_provider_dialog, null); final EditText url_input_field = (EditText)new_provider_dialog_view.findViewById(R.id.new_provider_url); + final CheckBox danger_checkbox = (CheckBox)new_provider_dialog_view.findViewById(R.id.danger_checkbox); + builder.setView(new_provider_dialog_view) .setMessage(R.string.introduce_new_provider) .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { String entered_url = url_input_field.getText().toString().trim(); + boolean danger_on = danger_checkbox.isChecked(); if(validURL(entered_url)) { - interface_with_ConfigurationWizard.saveProvider(entered_url); + interface_with_ConfigurationWizard.saveProvider(entered_url, danger_on); Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); } else { url_input_field.setText(""); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0b114e3..63db18e 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -9,6 +9,10 @@ import java.net.URL; import java.net.UnknownHostException; import java.util.Scanner; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; @@ -195,6 +199,8 @@ public class ProviderAPI extends IntentService { private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; + boolean danger_on = ((Boolean)task.get(ConfigHelper.danger_on)).booleanValue(); + String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); @@ -203,7 +209,7 @@ public class ProviderAPI extends IntentService { provider_json = getJSONFromProvider(provider_json_url); } catch (IOException e) { // It could happen that an https site used a certificate not trusted. - provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url); + provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url, danger_on); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -223,7 +229,7 @@ public class ProviderAPI extends IntentService { } private JSONObject downloadNewProviderDotJsonWithoutCert( - String provider_json_url) { + String provider_json_url, boolean danger_on) { JSONObject provider_json = null; try { URL provider_url = new URL(provider_json_url); @@ -234,6 +240,12 @@ public class ProviderAPI extends IntentService { } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (IOException e1) { + if(danger_on) { + provider_json = downloadNewProviderDotJsonWithoutValidate(provider_json_url); + } + else { + //TODO Show error message advising to check the checkbox if the url is completely trusted. + } e1.printStackTrace(); } catch (JSONException e1) { e1.printStackTrace(); @@ -241,6 +253,40 @@ public class ProviderAPI extends IntentService { return provider_json; } + private JSONObject downloadNewProviderDotJsonWithoutValidate( + String provider_json_url) { + JSONObject provider_json = null; + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + HostnameVerifier hostname_verifier = + HttpsURLConnection.getDefaultHostnameVerifier(); + return hostname_verifier.verify("", session); + } + }; + + // Tell the URLConnection to use our HostnameVerifier + try { + URL url = new URL(provider_json_url); + HttpsURLConnection urlConnection = + (HttpsURLConnection)url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + String provider_json_string = new Scanner(url.openStream()).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_json_string); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return provider_json; + + } + private String guessURL(String provider_main_url) { return provider_main_url + "/provider.json"; } -- cgit v1.2.3 From 69389ee7db23ce7182b21da08d227d88d6cfdc46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 24 Apr 2013 20:01:28 +0200 Subject: "Trust completely" checkbox saves that trust for the new provider entered, so that if in the future the client tries to log in or whatever, it can use the certificate downloaded when added. Log in dialog works ok, showing a toast when authentication fails (by this time, I have not managed to get a correct login due to dev.bitmask.net problems). dev.bitmask.net works perfectly, via adding it as a new provider (MeanderingCode, this is for you ;) ). All GET requests are done by default Android URL class, which means that certificates trusted by Android are also trusted by us. If there are problems when logging in due to certificates, the app is able to use only the certificate associated to the provider in the moment it was selected as the chosen provider. --- assets/urls/bitmask.url | 3 +- hosts-for-android-emulator | 1 + src/se/leap/leapclient/ConfigHelper.java | 21 ++- src/se/leap/leapclient/ConfigurationWizard.java | 5 +- src/se/leap/leapclient/Dashboard.java | 4 +- src/se/leap/leapclient/LogInDialog.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 193 +++++++++++++++--------- src/se/leap/leapclient/ProviderListContent.java | 16 +- 8 files changed, 163 insertions(+), 82 deletions(-) diff --git a/assets/urls/bitmask.url b/assets/urls/bitmask.url index 910f040..bc4d59d 100644 --- a/assets/urls/bitmask.url +++ b/assets/urls/bitmask.url @@ -3,5 +3,6 @@ "assets_json_provider" : "providers/bitmask.net_provider.json", "json_provider" : "https://bitmask.net/provider.json", "cert" : "https://bitmask.net/ca.crt", - "json_eip_service" : "https://api.bitmask.net:4430/1/config/eip-service.json" + "json_eip_service_antiguo" : "https://api.bitmask.net:4430/1/config/eip-service.json", + "json_eip_service" : "https://api.bitmask.net:4430/config/eip-service.json" } \ No newline at end of file diff --git a/hosts-for-android-emulator b/hosts-for-android-emulator index b10103e..ab0cf90 100644 --- a/hosts-for-android-emulator +++ b/hosts-for-android-emulator @@ -1,5 +1,6 @@ 127.0.0.1 localhost 10.0.2.2 api.lvh.me +10.0.2.2 lvh.me # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 78c71cc..7c52629 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -16,6 +16,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -44,7 +45,7 @@ public class ConfigHelper { public static final String user_directory = "leap_android"; final public static String provider_main_url = "provider_main_url"; final public static String danger_on = "danger_on"; - final public static String api_url_key = "srp_server_url"; + final public static String api_url_key = "api_uri"; final public static String username_key = "username"; final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; @@ -63,6 +64,20 @@ public class ConfigHelper { final public static int LOGOUT_SUCCESSFUL = 7; final public static int LOGOUT_FAILED = 8; + static String getStringFromSharedPref(String shared_preferences_key) { + String value = ""; + String content = shared_preferences.getString(shared_preferences_key, ""); + try { + JSONObject json_object = new JSONObject(content); + JSONArray names = json_object.names(); + String key = names.getString(0); + value = json_object.getString(key); + } catch (JSONException e) { + value = content; + } + return value; + } + static void saveSharedPref(String shared_preferences_key, JSONObject content) { SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -164,8 +179,8 @@ public class ConfigHelper { try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore - keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - //keystore_trusted.load(null, null); + //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + keystore_trusted.load(null, null); } finally { leap_keystore.close(); } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 9edaa28..3d16521 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -95,7 +95,7 @@ public class ConfigurationWizard extends Activity boolean custom = false; provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString(); if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list - ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom)); + ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, true)); // By default, it trusts the provider } } catch (IOException e) { // TODO Auto-generated catch block @@ -163,6 +163,7 @@ public class ConfigurationWizard extends Activity method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); + method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on); provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); @@ -191,9 +192,9 @@ public class ConfigurationWizard extends Activity Bundle method_and_parameters = new Bundle(); method_and_parameters.putString(ConfigHelper.provider_main_url, provider_main_url); + method_and_parameters.putBoolean(ConfigHelper.danger_on, danger_on); provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); - provider_API_command.putExtra(ConfigHelper.danger_on, danger_on); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a169c9d..577092b 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -23,6 +23,7 @@ import android.view.ViewStub; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.TextView; +import android.widget.Toast; public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, Receiver { @@ -195,11 +196,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ setResult(RESULT_OK); + Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); //TODO What should we do know? } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); - finish(); + Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); } } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 61526c6..74db92e 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -68,6 +68,6 @@ public class LogInDialog extends DialogFragment { } boolean validPassword(String entered_password) { - return entered_password.length() > 8; + return entered_password.length() > 4; } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 63db18e..04185ed 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,17 +1,26 @@ package se.leap.leapclient; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.util.List; import java.net.MalformedURLException; import java.net.URL; -import java.net.UnknownHostException; import java.util.Scanner; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -36,6 +45,7 @@ import android.app.IntentService; import android.content.Intent; import android.os.Bundle; import android.os.ResultReceiver; +import android.util.Base64; import android.util.Log; public class ProviderAPI extends IntentService { @@ -58,7 +68,7 @@ public class ProviderAPI extends IntentService { } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { if(downloadNewProviderDotJSON(task)) - receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); else receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } @@ -77,25 +87,21 @@ public class ProviderAPI extends IntentService { } private boolean downloadJsonFiles(Bundle task) { - String cert_url = (String) task.get(ConfigHelper.cert_key); - String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); + String provider_name = task.getString(ConfigHelper.provider_key); + String cert_url = task.getString(ConfigHelper.cert_key); + String eip_service_json_url = task.getString(ConfigHelper.eip_service_key); + boolean danger_on = task.getBoolean(ConfigHelper.danger_on); try { - String cert_string = getStringFromProvider(cert_url); + String cert_string = getStringFromProvider(cert_url, danger_on); + ConfigHelper.addTrustedCertificate(provider_name, cert_string); JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); + JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; - } catch (IOException e) { - // TODO - e.printStackTrace(); - return false; } catch (JSONException e) { ConfigHelper.rescueJSONException(e); return false; - } catch(Exception e) { - e.printStackTrace(); - return false; } } @@ -135,7 +141,8 @@ public class ProviderAPI extends IntentService { byte[] M1 = client.response(Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) - throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); + //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); + return false; return true; } else return false; @@ -199,17 +206,14 @@ public class ProviderAPI extends IntentService { private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; - boolean danger_on = ((Boolean)task.get(ConfigHelper.danger_on)).booleanValue(); + boolean danger_on = task.getBoolean(ConfigHelper.danger_on); String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); JSONObject provider_json = null; try { - provider_json = getJSONFromProvider(provider_json_url); - } catch (IOException e) { - // It could happen that an https site used a certificate not trusted. - provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url, danger_on); + provider_json = getJSONFromProvider(provider_json_url, danger_on); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -223,75 +227,128 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveFile(filename, provider_json.toString()); ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on)); return true; } } - private JSONObject downloadNewProviderDotJsonWithoutCert( - String provider_json_url, boolean danger_on) { - JSONObject provider_json = null; - try { - URL provider_url = new URL(provider_json_url); - String provider_json_string = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_json_string); - } catch (MalformedURLException e1) { - e1.printStackTrace(); - } catch (UnknownHostException e1) { - e1.printStackTrace(); - } catch (IOException e1) { - if(danger_on) { - provider_json = downloadNewProviderDotJsonWithoutValidate(provider_json_url); - } - else { - //TODO Show error message advising to check the checkbox if the url is completely trusted. - } - e1.printStackTrace(); - } catch (JSONException e1) { - e1.printStackTrace(); - } - return provider_json; - } - - private JSONObject downloadNewProviderDotJsonWithoutValidate( - String provider_json_url) { - JSONObject provider_json = null; + private String getStringFromProviderWithoutValidate( + URL provider_json_url) { + + String json_string = ""; HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - HostnameVerifier hostname_verifier = - HttpsURLConnection.getDefaultHostnameVerifier(); - return hostname_verifier.verify("", session); - } + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } }; // Tell the URLConnection to use our HostnameVerifier try { - URL url = new URL(provider_json_url); HttpsURLConnection urlConnection = - (HttpsURLConnection)url.openConnection(); - urlConnection.setHostnameVerifier(hostnameVerifier); - String provider_json_string = new Scanner(url.openStream()).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_json_string); + (HttpsURLConnection)provider_json_url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + json_string = getStringFromProviderWithCACertAdded(provider_json_url); + //e.printStackTrace(); } - return provider_json; - + return json_string; } private String guessURL(String provider_main_url) { return provider_main_url + "/provider.json"; } + + private String getStringFromProvider(String string_url, boolean danger_on) { + + String json_file_content = ""; + + URL provider_url = null; + try { + provider_url = new URL(string_url); + json_file_content = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO SSLHandshakeException + // This means that we have not added ca.crt to the trusted certificates. + if(provider_url != null && danger_on) { + json_file_content = getStringFromProviderWithoutValidate(provider_url); + } + //json_file_content = downloadStringFromProviderWithCACertAdded(string_url); + e.printStackTrace(); + } + + return json_file_content; + } + + private String getStringFromProviderWithCACertAdded(URL url) { + String json_file_content = ""; + + // Load CAs from an InputStream + // (could be from a resource or ByteArrayInputStream or ...) + CertificateFactory cf; + try { + cf = CertificateFactory.getInstance("X.509"); + + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); + cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); + byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); + InputStream caInput = new ByteArrayInputStream(cert_bytes); + java.security.cert.Certificate ca; + try { + ca = cf.generateCertificate(caInput); + System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); + } 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); + + // Tell the URLConnection to use a SocketFactory from our SSLContext + HttpsURLConnection urlConnection = + (HttpsURLConnection)url.openConnection(); + urlConnection.setSSLSocketFactory(context.getSocketFactory()); + json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return json_file_content; + } - private String getStringFromProvider(String string_url) throws IOException { + private String getStringFromProvider_2(String string_url) throws IOException { String json_file_content = ""; @@ -306,8 +363,8 @@ public class ProviderAPI extends IntentService { return json_file_content; } - private JSONObject getJSONFromProvider(String json_url) throws IOException, JSONException { - String json_file_content = getStringFromProvider(json_url); + private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { + String json_file_content = getStringFromProvider(json_url, danger_on); return new JSONObject(json_file_content); } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index dd227bf..9ed7e9b 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -44,6 +44,7 @@ public class ProviderListContent { public String provider_json_filename; public String eip_service_json_url; public String cert_json_url; + public boolean danger_on = false; public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) { this.id = id; @@ -53,7 +54,7 @@ public class ProviderListContent { this.cert_json_url = cert_json_url; } - public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom) { + public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom, boolean danger_on) { try { byte[] urls_file_bytes = new byte[urls_file_input_stream.available()]; @@ -62,11 +63,12 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; - provider_json_url = (String) file_contents.get("json_provider"); - provider_json_filename = (String) file_contents.get("assets_json_provider"); - eip_service_json_url = (String) file_contents.get("json_eip_service"); - cert_json_url = (String) file_contents.get("cert"); + provider_json_url = file_contents.getString("json_provider"); + provider_json_filename = file_contents.getString("assets_json_provider"); + eip_service_json_url = file_contents.getString("json_eip_service"); + cert_json_url = file_contents.getString("cert"); this.custom = custom; + this.danger_on = danger_on; } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -76,7 +78,7 @@ public class ProviderListContent { } } - public ProviderItem(String name, FileInputStream provider_json, boolean custom) { + public ProviderItem(String name, String provider_json_url, FileInputStream provider_json, boolean custom, boolean danger_on) { try { byte[] urls_file_bytes = new byte[provider_json.available()]; @@ -85,9 +87,11 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; + this.provider_json_url = provider_json_url; eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; + this.danger_on = danger_on; if(custom) provider_json_filename = name + "_provider.json".replaceFirst("__", "_"); } catch (JSONException e) { -- cgit v1.2.3 From 09493a9dec5fb235d5c4914eb8f8142e3312e246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 29 Apr 2013 21:32:10 +0200 Subject: Changed the message shown when checking if the password is valid or not. Refactored LeapSRPSession so that there is no need to send A twice. --- src/se/leap/leapclient/LeapSRPSession.java | 94 ++++++++++++++++-------------- src/se/leap/leapclient/LogInDialog.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 8 +-- 3 files changed, 57 insertions(+), 49 deletions(-) diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index d266cd7..f9037de 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -14,7 +14,10 @@ import org.jboss.security.srp.SRPPermission; public class LeapSRPSession { private SRPParameters params; + private String username; + private String password; private BigInteger N; + private byte[] N_bytes; private BigInteger g; private BigInteger x; private BigInteger v; @@ -58,9 +61,11 @@ public class LeapSRPSession { this.params = params; this.g = new BigInteger(1, params.g); - byte[] N_bytes = Util.trim(params.N); + N_bytes = Util.trim(params.N); this.N = new BigInteger(1, N_bytes); - + this.username = username; + this.password = password; + if( abytes != null ) { A_LEN = 8*abytes.length; /* TODO Why did they put this condition? @@ -73,41 +78,8 @@ public class LeapSRPSession { else A_LEN = 64; - // Calculate x = H(s | H(U | ':' | password)) - byte[] salt_bytes = Util.trim(params.s); - byte[] xb = calculatePasswordHash(username, password, salt_bytes); - this.x = new BigInteger(1, xb); - - // Calculate v = kg^x mod N - String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; - this.v = calculateV(k_string); - //String v_string = v.toString(16); - serverHash = newDigest(); clientHash = newDigest(); - - // H(N) - byte[] digest_of_n = newDigest().digest(N_bytes); - - // H(g) - byte[] digest_of_g = newDigest().digest(params.g); - - // clientHash = H(N) xor H(g) - byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); - //String hxg_string = new BigInteger(1, xor_digest).toString(16); - clientHash.update(xor_digest); - - // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); - username_digest = Util.trim(username_digest); - //String username_digest_string = new BigInteger(1, username_digest).toString(16); - clientHash.update(username_digest); - - // clientHash = H(N) xor H(g) | H(U) | s - //String salt_string = new BigInteger(1, salt_bytes).toString(16); - clientHash.update(salt_bytes); - - K = null; } /** @@ -198,13 +170,6 @@ public class LeapSRPSession { } A = g.modPow(a, N); Abytes = Util.trim(A.toByteArray()); - //String Abytes_string = new BigInteger(1, Abytes).toString(16); - - // clientHash = H(N) xor H(g) | H(U) | A - clientHash.update(Abytes); - - // serverHash = A - serverHash.update(Abytes); } return Abytes; } @@ -213,10 +178,52 @@ public class LeapSRPSession { * Calculates the parameter M1, to be sent to the SRP server. * It also updates hashes of client and server for further calculations in other methods. * @param Bbytes the parameter received from the server, in bytes + * @param bs * @return the parameter M1 * @throws NoSuchAlgorithmException */ - public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { + public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { + // Calculate x = H(s | H(U | ':' | password)) + byte[] xb = calculatePasswordHash(username, password, salt_bytes); + this.x = new BigInteger(1, xb); + + // Calculate v = kg^x mod N + String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; + this.v = calculateV(k_string); + //String v_string = v.toString(16); + + + // H(N) + byte[] digest_of_n = newDigest().digest(N_bytes); + + // H(g) + byte[] digest_of_g = newDigest().digest(params.g); + + // clientHash = H(N) xor H(g) + byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); + //String hxg_string = new BigInteger(1, xor_digest).toString(16); + clientHash.update(xor_digest); + + // clientHash = H(N) xor H(g) | H(U) + byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); + username_digest = Util.trim(username_digest); + //String username_digest_string = new BigInteger(1, username_digest).toString(16); + clientHash.update(username_digest); + + // clientHash = H(N) xor H(g) | H(U) | s + //String salt_string = new BigInteger(1, salt_bytes).toString(16); + clientHash.update(Util.trim(salt_bytes)); + + K = null; + + // clientHash = H(N) xor H(g) | H(U) | s | A | B + + byte[] Abytes = Util.trim(A.toByteArray()); + //String Abytes_string = new BigInteger(1, Abytes).toString(16); + + // clientHash = H(N) xor H(g) | H(U) | A + clientHash.update(Abytes); + // clientHash = H(N) xor H(g) | H(U) | s | A | B Bbytes = Util.trim(Bbytes); //String Bbytes_string = new BigInteger(1, Bbytes).toString(16); @@ -239,6 +246,7 @@ public class LeapSRPSession { byte[] M1 = Util.trim(clientHash.digest()); // serverHash = Astr + M + K + serverHash.update(Abytes); serverHash.update(M1); serverHash.update(K); return M1; diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 74db92e..30984db 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -51,10 +51,10 @@ public class LogInDialog extends DialogFragment { String password = password_field.getText().toString().trim(); if(validPassword(password)) { interface_with_Dashboard.authenticate(username, password); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "Your password is valid", Toast.LENGTH_LONG).show(); } else { password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "Your password is not valid: it should have at least 8 characters", Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 04185ed..66eb3e6 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -131,14 +131,14 @@ public class ProviderAPI extends IntentService { try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { - byte[] B = saltAndB.getString("B").getBytes(); - salt = saltAndB.getString("salt"); + /*byte[] B = saltAndB.getString("B").getBytes(); params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); client = new LeapSRPSession(username, password, params); A = client.exponential(); - saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); + saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16));*/ + salt = saltAndB.getString("salt"); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); - byte[] M1 = client.response(Bbytes); + byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); -- cgit v1.2.3 From ff3d469a9549e3670e097fc0e49c043c84e7b7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 1 May 2013 18:41:05 +0200 Subject: If the app is restarted with a custom provider selected, the client can request a log in without certificates problems. I've removed the addition of the certificate when downloaded eip-service.json, because I already do that in LeapHttpClient. Solves issue 2367: https://leap.se/code/issues/2367 --- src/se/leap/leapclient/ConfigHelper.java | 16 ++++++++++++---- src/se/leap/leapclient/Dashboard.java | 4 +++- src/se/leap/leapclient/LeapHttpClient.java | 7 ++++++- src/se/leap/leapclient/ProviderAPI.java | 8 ++++++-- src/se/leap/leapclient/ProviderListContent.java | 2 +- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 7c52629..7684522 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -48,7 +48,7 @@ public class ConfigHelper { final public static String api_url_key = "api_uri"; final public static String username_key = "username"; final public static String password_key = "password"; - final public static String eip_service_api_path = "/config/eip-service.json"; + final public static String eip_service_api_path = "config/eip-service.json"; final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; @@ -159,6 +159,9 @@ public class ConfigHelper { cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); + if(keystore_trusted == null) { + getNewKeystore(null); + } keystore_trusted.setCertificateEntry(provider, cert); } catch (CertificateException e) { // TODO Auto-generated catch block @@ -179,10 +182,15 @@ public class ConfigHelper { try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore - //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - keystore_trusted.load(null, null); + if(leap_keystore != null) { + //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + keystore_trusted.load(null, null); + } else { + keystore_trusted.load(null, null); + } } finally { - leap_keystore.close(); + if(leap_keystore != null) + leap_keystore.close(); } } catch (KeyStoreException e) { // TODO Auto-generated catch block diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 577092b..a68c048 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -43,7 +43,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf setContentView(R.layout.client_dashboard); preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); - + if(ConfigHelper.shared_preferences == null) + ConfigHelper.setSharedPreferences(preferences); + // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! if (!preferences.contains("provider") ) diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index d1908c3..f911982 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -51,8 +51,13 @@ public class LeapHttpClient extends DefaultHttpClient { } public static LeapHttpClient getInstance(Context context) { - if(client == null) + if(client == null) { client = new LeapHttpClient(context); + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + } + } return client; } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 66eb3e6..4a28878 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -93,7 +93,7 @@ public class ProviderAPI extends IntentService { boolean danger_on = task.getBoolean(ConfigHelper.danger_on); try { String cert_string = getStringFromProvider(cert_url, danger_on); - ConfigHelper.addTrustedCertificate(provider_name, cert_string); + //ConfigHelper.addTrustedCertificate(provider_name, cert_string); JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); @@ -177,9 +177,11 @@ public class ProviderAPI extends IntentService { if(!json_response.isNull("errors") || json_response.has("errors")) { return new JSONObject(); } + + String session_id = ""; List cookies = client.getCookieStore().getCookies(); if(!cookies.isEmpty()) { - String session_id = cookies.get(0).getValue(); + session_id = cookies.get(0).getValue(); } return json_response; } @@ -190,6 +192,8 @@ public class ProviderAPI extends IntentService { HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); + String session_id = client.getCookieStore().getCookies().get(0).getValue(); + int number_of_cookies = client.getCookieStore().getCookies().size(); HttpResponse getResponse = client.execute(put, localContext); HttpEntity responseEntity = getResponse.getEntity(); diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 9ed7e9b..8cc349c 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -88,7 +88,7 @@ public class ProviderListContent { id = name; this.name = name; this.provider_json_url = provider_json_url; - eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; + eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; -- cgit v1.2.3 From a16605fd16a87faa5fa530288e01f0d7c7c7bf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 1 May 2013 19:01:16 +0200 Subject: Logging in successfully to dev.bitmask.net :) The problem was that I needed to append the api_version to the api_uri. I was doing well in tests because I hardcoded the api urls, but in production code I was getting from provider.json only api_url and not api_version. --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/Dashboard.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 7684522..72d966b 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,6 +37,7 @@ public class ConfigHelper { final public static String srpAuth = "srpAuth"; public static String logIn = "logIn"; public static String logOut = "logOut"; + public static String api_version_key = "api_version"; final public static String resultKey = "result"; final static String provider_key = "provider"; final static String cert_key = "cert"; diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a68c048..67e33e7 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -170,7 +170,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf JSONObject provider_json; try { provider_json = new JSONObject(preferences.getString(ConfigHelper.provider_key, "")); - method_and_parameters.putString(ConfigHelper.api_url_key, provider_json.getString(ConfigHelper.api_url_key)); + method_and_parameters.putString(ConfigHelper.api_url_key, provider_json.getString(ConfigHelper.api_url_key) + "/" + provider_json.getString(ConfigHelper.api_version_key)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 0cb5d9470127e280d2d955effd32b82e533d9de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 7 May 2013 16:10:20 +0200 Subject: Ready to create a new branch for the download of the new user auth'ed certificate. Next step in this branch: detect what the selected provider support in terms of authenticated/anon users, and show login/logout methods consecuently. --- src/se/leap/leapclient/Dashboard.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 67e33e7..0444502 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -199,7 +199,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); - //TODO What should we do know? + //TODO Download certificate requesting /1/cert with session_id cookie + } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); -- cgit v1.2.3 From fb5e26c2ff4f95dd826a3ce3545865ac4388b711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 8 May 2013 18:23:10 +0200 Subject: After loggin in successfully, the new client certificate is downloaded. It is stored in SharedPrefs, with ConfigHelper.cert_key (="cert") key. --- src/se/leap/leapclient/ConfigHelper.java | 27 +++-- src/se/leap/leapclient/ConfigurationWizard.java | 8 +- src/se/leap/leapclient/Dashboard.java | 31 ++++- src/se/leap/leapclient/LeapHttpClient.java | 17 ++- src/se/leap/leapclient/ProviderAPI.java | 146 ++++++++++++++++-------- 5 files changed, 170 insertions(+), 59 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 72d966b..98761b6 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,11 +37,15 @@ public class ConfigHelper { final public static String srpAuth = "srpAuth"; public static String logIn = "logIn"; public static String logOut = "logOut"; + public static String downloadUserAuthedCertificate = "downloadUserAuthedCertificate"; public static String api_version_key = "api_version"; final public static String resultKey = "result"; final static String provider_key = "provider"; + final static String main_cert_key = "main_cert"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; + final static String session_id_cookie_key = "session_id_cookie_key"; + final static String session_id_key = "session_id"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; final public static String provider_main_url = "provider_main_url"; @@ -64,17 +68,23 @@ public class ConfigHelper { final public static int SRP_REGISTRATION_FAILED = 6; final public static int LOGOUT_SUCCESSFUL = 7; final public static int LOGOUT_FAILED = 8; + final public static int CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9; + final public static int INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10; static String getStringFromSharedPref(String shared_preferences_key) { String value = ""; - String content = shared_preferences.getString(shared_preferences_key, ""); - try { - JSONObject json_object = new JSONObject(content); - JSONArray names = json_object.names(); - String key = names.getString(0); - value = json_object.getString(key); - } catch (JSONException e) { - value = content; + //TODO This is not OK -> when reading provider.json it only shows "open" + if(shared_preferences != null) { + String content = shared_preferences.getString(shared_preferences_key, ""); + try { + JSONObject json_object = new JSONObject(content); + value = json_object.toString(); + /*JSONArray names = json_object.names(); + String key = names.getString(0); + value = json_object.getString(key);*/ + } catch (JSONException e) { + value = content; + } } return value; } @@ -184,6 +194,7 @@ public class ConfigHelper { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore if(leap_keystore != null) { + InputStream android_default_keystore; //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); keystore_trusted.load(null, null); } else { diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 3d16521..a50a8e6 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -150,6 +150,12 @@ public class ConfigurationWizard extends Activity ConfigHelper.rescueJSONException(e); } ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + try { + ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { @@ -161,7 +167,7 @@ public class ConfigurationWizard extends Activity Bundle method_and_parameters = new Bundle(); method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); - method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); + method_and_parameters.putString(ConfigHelper.main_cert_key, current_provider_item.cert_json_url); method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 0444502..dbee9c4 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -1,5 +1,7 @@ package se.leap.leapclient; +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.cookie.BasicClientCookie; import org.json.JSONException; import org.json.JSONObject; @@ -194,18 +196,45 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf newFragment.show(fragment_transaction, ConfigHelper.logInDialog); } + private void downloadAuthedUserCertificate(Cookie session_id) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.session_id_cookie_key, session_id.getName()); + method_and_parameters.putString(ConfigHelper.session_id_key, session_id.getValue()); + + provider_API_command.putExtra(ConfigHelper.downloadUserAuthedCertificate, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } + @Override public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ + String session_id_cookie_key = resultData.getString(ConfigHelper.session_id_cookie_key); + String session_id_string = resultData.getString(ConfigHelper.session_id_key); setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); //TODO Download certificate requesting /1/cert with session_id cookie - + Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); + downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); + } } } diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index f911982..4de7ae0 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -9,6 +9,8 @@ import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; +import org.json.JSONException; +import org.json.JSONObject; import android.content.Context; @@ -49,13 +51,20 @@ public class LeapHttpClient extends DefaultHttpClient { throw new AssertionError(e); } } - + public static LeapHttpClient getInstance(Context context) { if(client == null) { client = new LeapHttpClient(context); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); - if(!cert_string.isEmpty()) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); + String cert_string; + try { + cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } return client; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4a28878..bdfd620 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -12,7 +12,12 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.List; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.HttpCookie; +import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.util.Scanner; @@ -25,13 +30,16 @@ import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.CookieStore; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.jboss.security.Util; @@ -73,10 +81,20 @@ public class ProviderAPI extends IntentService { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { - if(authenticateBySRP(task)) - receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, Bundle.EMPTY); - else - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + try { + JSONObject session_idAndResult = authenticateBySRP(task); + if(session_idAndResult.getBoolean(ConfigHelper.resultKey)) { + Bundle session_id_bundle = new Bundle(); + session_id_bundle.putString(ConfigHelper.session_id_cookie_key, session_idAndResult.getString(ConfigHelper.session_id_cookie_key)); + session_id_bundle.putString(ConfigHelper.session_id_key, session_idAndResult.getString(ConfigHelper.session_id_key)); + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); + } else { + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else if ((task = task_for.getBundleExtra(ConfigHelper.logOut)) != null) { if(logOut(task)) @@ -84,18 +102,24 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.downloadUserAuthedCertificate)) != null) { + if(getNewCert(task)) + receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + else + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + } } private boolean downloadJsonFiles(Bundle task) { - String provider_name = task.getString(ConfigHelper.provider_key); - String cert_url = task.getString(ConfigHelper.cert_key); + //String provider_name = task.getString(ConfigHelper.provider_key); + String cert_url = task.getString(ConfigHelper.main_cert_key); String eip_service_json_url = task.getString(ConfigHelper.eip_service_key); boolean danger_on = task.getBoolean(ConfigHelper.danger_on); try { String cert_string = getStringFromProvider(cert_url, danger_on); //ConfigHelper.addTrustedCertificate(provider_name, cert_string); - JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + JSONObject cert_json = new JSONObject().put(ConfigHelper.main_cert_key, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.main_cert_key, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; @@ -117,7 +141,9 @@ public class ProviderAPI extends IntentService { return false; } - private boolean authenticateBySRP(Bundle task) { + private JSONObject authenticateBySRP(Bundle task) { + JSONObject successfulAndsession_id = new JSONObject(); + String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.api_url_key); @@ -131,38 +157,36 @@ public class ProviderAPI extends IntentService { try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { - /*byte[] B = saltAndB.getString("B").getBytes(); - params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - client = new LeapSRPSession(username, password, params); - A = client.exponential(); - saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16));*/ salt = saltAndB.getString("salt"); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); - byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); - if( client.verify(M2) == false ) + //byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); + JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); + if( client.verify((byte[])session_idAndM2.get("M2")) == false ) { //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); - return false; - return true; + successfulAndsession_id.put(ConfigHelper.resultKey, false); + return successfulAndsession_id; + } else { + successfulAndsession_id.put(ConfigHelper.resultKey, true); + successfulAndsession_id.put(ConfigHelper.session_id_key, session_idAndM2.getString(ConfigHelper.session_id_key)); + successfulAndsession_id.put(ConfigHelper.session_id_cookie_key, session_idAndM2.getString(ConfigHelper.session_id_cookie_key)); + return successfulAndsession_id; + } } - else return false; } catch (ClientProtocolException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - return false; } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - return false; } catch (JSONException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - return false; } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); - return false; } + return successfulAndsession_id; } private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { @@ -186,7 +210,8 @@ public class ProviderAPI extends IntentService { return json_response; } - private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { + private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { + JSONObject session_idAndM2 = new JSONObject(); DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); String parameter_chain = "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16); HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); @@ -200,12 +225,15 @@ public class ProviderAPI extends IntentService { String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); if(!json_response.isNull("errors") || json_response.has("errors")) { - return new byte[0]; + return session_idAndM2; } - + + number_of_cookies = client.getCookieStore().getCookies().size(); byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); - return Util.trim(M2_not_trimmed); - //return M2_not_trimmed; + session_idAndM2.put(ConfigHelper.session_id_cookie_key, client.getCookieStore().getCookies().get(0).getName()); + session_idAndM2.put(ConfigHelper.session_id_key, client.getCookieStore().getCookies().get(0).getValue()); + session_idAndM2.put("M2", Util.trim(M2_not_trimmed)); + return session_idAndM2; } private boolean downloadNewProviderDotJSON(Bundle task) { @@ -229,7 +257,7 @@ public class ProviderAPI extends IntentService { } else { String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on)); return true; @@ -301,7 +329,8 @@ public class ProviderAPI extends IntentService { try { cf = CertificateFactory.getInstance("X.509"); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); + String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); @@ -348,24 +377,12 @@ public class ProviderAPI extends IntentService { } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } return json_file_content; } - - private String getStringFromProvider_2(String string_url) throws IOException { - - String json_file_content = ""; - - DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - HttpGet get = new HttpGet(string_url); - // Execute the GET call and obtain the response - HttpResponse getResponse = client.execute(get); - HttpEntity responseEntity = getResponse.getEntity(); - - json_file_content = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); - - return json_file_content; - } private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { String json_file_content = getStringFromProvider(json_url, danger_on); @@ -391,4 +408,43 @@ public class ProviderAPI extends IntentService { } return true; } + + private boolean getNewCert(Bundle task) { + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); + HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.session_id_cookie_key), task.getString(ConfigHelper.session_id_key)); + + try { + JSONObject provider_json = new JSONObject(provider_json_string); + URL provider_main_url = new URL(provider_json.getString(ConfigHelper.api_url_key).replace("api.", "")); + String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.api_version_key) + "/" + ConfigHelper.cert_key; + + CookieManager cookieManager = new CookieManager(); + cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); + CookieHandler.setDefault(cookieManager); + + String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.danger_on); + boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.danger_on); + String cert_string = getStringFromProvider(new_cert_string_url, danger_on); + if(!cert_string.isEmpty()) { + JSONObject cert_json = new JSONObject().put(ConfigHelper.cert_key, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + return true; + } else { + return false; + } + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; + } } -- cgit v1.2.3 From 84a11bb1620d2b9080992427c847b58007f2304a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 9 May 2013 17:29:38 +0200 Subject: Log in and Log out options are shown only if allow registration is true. Allow registration is present in provider.json. Provider.json is downloaded from both preseeded and custom providers. Authentication success or fail is notified correctly to the user. --- assets/providers/bitmask.net_provider.json | 25 ------- res/menu/client_dashboard.xml | 3 +- res/values/strings.xml | 1 + src/se/leap/leapclient/ConfigHelper.java | 14 +++- src/se/leap/leapclient/ConfigurationWizard.java | 78 ++++++++++++++------- src/se/leap/leapclient/Dashboard.java | 62 ++++++++++++++--- src/se/leap/leapclient/ProviderAPI.java | 90 +++++++++++++++++++++---- src/se/leap/leapclient/ProviderListContent.java | 5 +- 8 files changed, 205 insertions(+), 73 deletions(-) delete mode 100644 assets/providers/bitmask.net_provider.json diff --git a/assets/providers/bitmask.net_provider.json b/assets/providers/bitmask.net_provider.json deleted file mode 100644 index d61be19..0000000 --- a/assets/providers/bitmask.net_provider.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "api_uri": "https://api.bitmask.net:4430", - "api_version": "1", - "ca_cert_fingerprint": "SHA256: 0f17c033115f6b76ff67871872303ff65034efe7dd1b910062ca323eb4da5c7e", - "ca_cert_uri": "https://bitmask.net/ca.crt", - "default_language": "en", - "description": { - "el": "Bitmask είναι ένα έργο του LEAP με σκοπό τον έλεγχο της απόδοσης και της αξιοπιστίας του λογισμικού LEAP. Bitmask τρέχει για τις τελευταίες αιμορραγία άκρο του κώδικα LEAP, και θα έχει πιθανότατα περισσότερες δυνατότητες και λιγότερα αξιοπιστία από άλλους φορείς παροχής υπηρεσιών.", - "en": "Bitmask is a project of LEAP with the purpose to test the performance and reliability of the LEAP software. Bitmask runs on the latest bleeding edge of the LEAP code, and will likely have more features and less reliability than other service providers.", - "es": "Bitmask es un proyecto de LEAP con el propósito de probar el rendimiento y la fiabilidad del software LEAP. Bitmask corre la última versión del código LEAP, y es de esperar que tenga más funciones y menos fiabilidad que los proveedores de servicios." - }, - "domain": "bitmask.net", - "enrollment_policy": "open", - "languages": [ - "el", - "en", - "es" - ], - "name": { - "en": "Bitmask" - }, - "services": [ - "openvpn" - ] -} \ No newline at end of file diff --git a/res/menu/client_dashboard.xml b/res/menu/client_dashboard.xml index fffd4e2..a8eaf79 100644 --- a/res/menu/client_dashboard.xml +++ b/res/menu/client_dashboard.xml @@ -7,6 +7,7 @@ android:title="@string/menu_settings"/> - + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index eac73bc..03de1ee 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -269,6 +269,7 @@ Enter your password Log in Log In + Log Out Trust completely \ No newline at end of file diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 98761b6..0dab26f 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -16,7 +16,6 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -30,6 +29,7 @@ public class ConfigHelper { private static KeyStore keystore_trusted; final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; + final static String updateProviderDotJSON = "updateProviderDotJSON"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; final public static String logInDialog = "logInDialog"; final public static String newProviderDialog = "logInDialog"; @@ -41,6 +41,7 @@ public class ConfigHelper { public static String api_version_key = "api_version"; final public static String resultKey = "result"; final static String provider_key = "provider"; + final static String service_key = "service"; final static String main_cert_key = "main_cert"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; @@ -48,11 +49,15 @@ public class ConfigHelper { final static String session_id_key = "session_id"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; + final public static String provider_name = "provider_name"; final public static String provider_main_url = "provider_main_url"; + final public static String provider_json_url = "provider_json_url"; + final public static String custom = "custom"; final public static String danger_on = "danger_on"; final public static String api_url_key = "api_uri"; final public static String username_key = "username"; final public static String password_key = "password"; + final public static String allow_registration_key = "allow_registration"; final public static String eip_service_api_path = "config/eip-service.json"; final public static String NG_1024 = @@ -70,6 +75,8 @@ public class ConfigHelper { final public static int LOGOUT_FAILED = 8; final public static int CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9; final public static int INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10; + final public static int CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11; + final public static int INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12; static String getStringFromSharedPref(String shared_preferences_key) { String value = ""; @@ -194,7 +201,6 @@ public class ConfigHelper { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore if(leap_keystore != null) { - InputStream android_default_keystore; //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); keystore_trusted.load(null, null); } else { @@ -221,7 +227,9 @@ public class ConfigHelper { public static int getSrpAuthenticationFailed() { return SRP_AUTHENTICATION_FAILED; - }static String extractProviderName(String provider_main_url) { + } + + static String extractProviderName(String provider_main_url) { return null; } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index a50a8e6..ba17f9b 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -3,6 +3,7 @@ package se.leap.leapclient; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URL; import java.util.Iterator; import java.util.Scanner; @@ -133,29 +134,27 @@ public class ConfigurationWizard extends Activity } } - private void saveProviderJson(ProviderItem current_provider_item) { - AssetManager assets_manager = getAssets(); - JSONObject provider_json = new JSONObject(); - try { - String provider_contents = ""; - if(!current_provider_item.custom) - provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); - else - provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_contents); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - } - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - try { - ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + private void saveProviderJson(ProviderItem current_provider_item) { + JSONObject provider_json = new JSONObject(); + try { + String provider_contents = ""; + if(!current_provider_item.custom) { + //provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); + updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); + } else { + provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_contents); + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + try { + ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); + } } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { @@ -205,6 +204,23 @@ public class ConfigurationWizard extends Activity startService(provider_API_command); } + + public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.provider_name, provider_name); + method_and_parameters.putString(ConfigHelper.provider_json_url, provider_json_url); + method_and_parameters.putBoolean(ConfigHelper.danger_on, danger_on); + + provider_API_command.putExtra(ConfigHelper.updateProviderDotJSON, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } @Override public void onReceiveResult(int resultCode, Bundle resultData) { @@ -224,5 +240,21 @@ public class ConfigurationWizard extends Activity setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL", Toast.LENGTH_LONG).show(); } + else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + JSONObject provider_json; + try { + provider_json = new JSONObject(resultData.getString(ConfigHelper.provider_key)); + boolean danger_on = resultData.getBoolean(ConfigHelper.danger_on); + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + } + } } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index dbee9c4..c8cbc5a 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -11,7 +11,6 @@ import se.leap.openvpn.MainActivity; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; -import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; @@ -115,6 +114,25 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf // TODO attach settings button to something } + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); + try { + JSONObject provider_json = new JSONObject(provider_json_string); + JSONObject service_description = provider_json.getJSONObject(ConfigHelper.service_key); + if(service_description.getBoolean(ConfigHelper.allow_registration_key)) { + menu.findItem(R.id.login_button).setVisible(true); + menu.findItem(R.id.logout_button).setVisible(true); + return true; + } + } catch (JSONException e) { + menu.findItem(R.id.login_button).setVisible(false); + menu.findItem(R.id.logout_button).setVisible(false); + return false; + } + return false; + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. @@ -147,6 +165,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); logInDialog(view); return true; + case R.id.logout_button: + logOut(); + return true; default: return super.onOptionsItemSelected(item); } @@ -184,6 +205,28 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(provider_API_command); } + public void logOut() { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + + JSONObject provider_json; + try { + provider_json = new JSONObject(preferences.getString(ConfigHelper.provider_key, "")); + method_and_parameters.putString(ConfigHelper.api_url_key, provider_json.getString(ConfigHelper.api_url_key) + "/" + provider_json.getString(ConfigHelper.api_version_key)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + provider_API_command.putExtra(ConfigHelper.logOut, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } + public void logInDialog(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.logInDialog); @@ -219,19 +262,22 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf String session_id_string = resultData.getString(ConfigHelper.session_id_key); setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); - //TODO Download certificate requesting /1/cert with session_id cookie + Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(session_id); - } - else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { + } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); - } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { + setResult(RESULT_OK); + Toast.makeText(getApplicationContext(), "Logged out", Toast.LENGTH_LONG).show(); + } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Didn't logged out", Toast.LENGTH_LONG).show(); + } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); - } - else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index bdfd620..b44c997 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -15,7 +15,6 @@ import java.util.List; import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpCookie; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; @@ -30,16 +29,12 @@ import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.CookieStore; import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.jboss.security.Util; @@ -74,6 +69,24 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.updateProviderDotJSON)) != null) { + JSONObject result = updateProviderDotJSON(task); + boolean successful; + try { + successful = result.getBoolean(ConfigHelper.resultKey); + if(successful) { + Bundle provider_dot_json_and_danger_on = new Bundle(); + provider_dot_json_and_danger_on.putBoolean(ConfigHelper.danger_on, result.getBoolean(ConfigHelper.danger_on)); + provider_dot_json_and_danger_on.putString(ConfigHelper.provider_key, result.getJSONObject(ConfigHelper.provider_key).toString()); + receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, provider_dot_json_and_danger_on); + } else { + receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { if(downloadNewProviderDotJSON(task)) receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); @@ -172,6 +185,9 @@ public class ProviderAPI extends IntentService { successfulAndsession_id.put(ConfigHelper.session_id_cookie_key, session_idAndM2.getString(ConfigHelper.session_id_cookie_key)); return successfulAndsession_id; } + } else { + successfulAndsession_id.put(ConfigHelper.resultKey, false); + return successfulAndsession_id; } } catch (ClientProtocolException e1) { // TODO Auto-generated catch block @@ -236,6 +252,50 @@ public class ProviderAPI extends IntentService { return session_idAndM2; } + private JSONObject updateProviderDotJSON(Bundle task) { + JSONObject result = new JSONObject(); + boolean custom = task.getBoolean(ConfigHelper.custom); + boolean danger_on = task.getBoolean(ConfigHelper.danger_on); + String provider_json_url = task.getString(ConfigHelper.provider_json_url); + String provider_name = task.getString(ConfigHelper.provider_name); + + JSONObject provider_json = null; + try { + provider_json = getJSONFromProvider(provider_json_url, danger_on); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + try { + return result.put(ConfigHelper.resultKey, false); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + if(provider_json == null) { + try { + return result.put(ConfigHelper.resultKey, false); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else { + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); + ConfigHelper.saveFile(filename, provider_json.toString()); + //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); + try { + return result.put(ConfigHelper.resultKey, true).put(ConfigHelper.provider_key, provider_json).put(ConfigHelper.danger_on, danger_on); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return result; + } + private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; boolean danger_on = task.getBoolean(ConfigHelper.danger_on); @@ -259,7 +319,7 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveFile(filename, provider_json.toString()); //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on)); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); return true; } } @@ -291,10 +351,6 @@ public class ProviderAPI extends IntentService { } return json_string; } - - private String guessURL(String provider_main_url) { - return provider_main_url + "/provider.json"; - } private String getStringFromProvider(String string_url, boolean danger_on) { @@ -388,23 +444,33 @@ public class ProviderAPI extends IntentService { String json_file_content = getStringFromProvider(json_url, danger_on); return new JSONObject(json_file_content); } + + private String guessURL(String provider_main_url) { + return provider_main_url + "/provider.json"; + } private boolean logOut(Bundle task) { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); int session_id_index = 0; //String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/sessions/" + client.getCookieStore().getCookies().get(0).getValue(); - String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); - HttpDelete delete = new HttpDelete(delete_url); try { + String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + HttpDelete delete = new HttpDelete(delete_url); HttpResponse getResponse = client.execute(delete); HttpEntity responseEntity = getResponse.getEntity(); responseEntity.consumeContent(); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); + return false; + } catch (IndexOutOfBoundsException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); + return false; } return true; } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 8cc349c..d4bb6a9 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -78,8 +78,10 @@ public class ProviderListContent { } } - public ProviderItem(String name, String provider_json_url, FileInputStream provider_json, boolean custom, boolean danger_on) { + public ProviderItem(String name, String provider_json_url, String provider_json_filename, boolean custom, boolean danger_on) { + + FileInputStream provider_json = ConfigHelper.openFileInputStream(provider_json_filename); try { byte[] urls_file_bytes = new byte[provider_json.available()]; provider_json.read(urls_file_bytes); @@ -88,6 +90,7 @@ public class ProviderListContent { id = name; this.name = name; this.provider_json_url = provider_json_url; + this.provider_json_filename = provider_json_filename; eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; -- cgit v1.2.3 From 80a8106afc8956008beb9d1ed9396f1d695d5b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 13 May 2013 20:39:34 +0200 Subject: A bit more clean. I've upper cased ConfigHelper constants. I've created a new method in ConfigHelper, to send requests to a server, that it's used when sending A and M1. --- src/se/leap/leapclient/ConfigHelper.java | 185 ++++++--------- src/se/leap/leapclient/ConfigurationWizard.java | 210 ++++++++--------- src/se/leap/leapclient/Dashboard.java | 40 ++-- src/se/leap/leapclient/LeapHttpClient.java | 96 ++++---- src/se/leap/leapclient/LeapSRPSession.java | 39 +--- src/se/leap/leapclient/LogInDialog.java | 67 +++--- src/se/leap/leapclient/NewProviderDialog.java | 7 +- src/se/leap/leapclient/Provider.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 289 +++++++++--------------- src/se/leap/leapclient/ProviderListContent.java | 2 +- 10 files changed, 391 insertions(+), 546 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 0dab26f..5d44f00 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,6 +1,5 @@ package se.leap.leapclient; - import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; @@ -28,103 +27,94 @@ public class ConfigHelper { public static SharedPreferences shared_preferences; private static KeyStore keystore_trusted; - final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; - final static String updateProviderDotJSON = "updateProviderDotJSON"; - final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; - final public static String logInDialog = "logInDialog"; - final public static String newProviderDialog = "logInDialog"; - final public static String srpRegister = "srpRegister"; - final public static String srpAuth = "srpAuth"; - public static String logIn = "logIn"; - public static String logOut = "logOut"; - public static String downloadUserAuthedCertificate = "downloadUserAuthedCertificate"; - public static String api_version_key = "api_version"; - final public static String resultKey = "result"; - final static String provider_key = "provider"; - final static String service_key = "service"; - final static String main_cert_key = "main_cert"; - final static String cert_key = "cert"; - final static String eip_service_key = "eip"; - final static String session_id_cookie_key = "session_id_cookie_key"; - final static String session_id_key = "session_id"; - public static final String PREFERENCES_KEY = "LEAPPreferences"; - public static final String user_directory = "leap_android"; - final public static String provider_name = "provider_name"; - final public static String provider_main_url = "provider_main_url"; - final public static String provider_json_url = "provider_json_url"; - final public static String custom = "custom"; - final public static String danger_on = "danger_on"; - final public static String api_url_key = "api_uri"; - final public static String username_key = "username"; - final public static String password_key = "password"; - final public static String allow_registration_key = "allow_registration"; - final public static String eip_service_api_path = "config/eip-service.json"; + final public static String + DOWNLOAD_JSON_FILES_BUNDLE_EXTRA = "downloadJSONFiles", + UPDATE_PROVIDER_DOTJSON = "updateProviderDotJSON", + DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", + LOG_IN_DIALOG = "logInDialog", + NEW_PROVIDER_DIALOG = "logInDialog", + SRP_REGISTER = "srpRegister", + SRP_AUTH = "srpAuth", + LOG_IN = "logIn", + LOG_OUT = "logOut", + DOWNLOAD_USER_AUTHED_CERTIFICATE = "downloadUserAuthedCertificate", + API_VERSION_KEY = "api_version", + RESULT_KEY = "result", + PROVIDER_KEY = "provider", + SERVICE_KEY = "service", + MAIN_CERT_KEY = "main_cert", + CERT_KEY = "cert", + EIP_SERVICE_KEY = "eip", + SALT_KEY = "salt", + SESSION_ID_COOKIE_KEY = "session_id_cookie_key", + SESSION_ID_KEY = "session_id", + PREFERENCES_KEY = "LEAPPreferences", + USER_DIRECTORY = "leap_android", + PROVIDER_NAME = "provider_name", + PROVIDER_MAIN_URL = "provider_main_url", + PROVIDER_JSON_URL = "provider_json_url", + CUSTOM = "custom", + DANGER_ON = "danger_on", + API_URL_KEY = "api_uri", + USERNAME_KEY = "username", + PASSWORD_KEY = "password", + ALLOW_REGISTRATION_KEY = "allow_registration", + EIP_SERVICE_API_PATH = "config/eip-service.json" + ; - final public static String NG_1024 = - "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; - final public static BigInteger g = BigInteger.valueOf(2); + final public static String NG_1024 = + "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; + final public static BigInteger G = new BigInteger("2"); + + final public static int + CUSTOM_PROVIDER_ADDED = 0, + CORRECTLY_DOWNLOADED_JSON_FILES = 1, + INCORRECTLY_DOWNLOADED_JSON_FILES = 2, + SRP_AUTHENTICATION_SUCCESSFUL = 3, + SRP_AUTHENTICATION_FAILED = 4, + SRP_REGISTRATION_SUCCESSFUL = 5, + SRP_REGISTRATION_FAILED = 6, + LOGOUT_SUCCESSFUL = 7, + LOGOUT_FAILED = 8, + CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9, + INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10, + CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, + INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12 + ; - final public static int CUSTOM_PROVIDER_ADDED = 0; - final public static int CORRECTLY_DOWNLOADED_JSON_FILES = 1; - final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 2; - final public static int SRP_AUTHENTICATION_SUCCESSFUL = 3; - final public static int SRP_AUTHENTICATION_FAILED = 4; - final public static int SRP_REGISTRATION_SUCCESSFUL = 5; - final public static int SRP_REGISTRATION_FAILED = 6; - final public static int LOGOUT_SUCCESSFUL = 7; - final public static int LOGOUT_FAILED = 8; - final public static int CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9; - final public static int INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10; - final public static int CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11; - final public static int INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12; + public static void saveSharedPref(String shared_preferences_key, JSONObject content) { + + SharedPreferences.Editor shared_preferences_editor = shared_preferences + .edit(); + shared_preferences_editor.putString(shared_preferences_key, + content.toString()); + shared_preferences_editor.commit(); + } - static String getStringFromSharedPref(String shared_preferences_key) { + public static String getStringFromSharedPref(String shared_preferences_key) { String value = ""; - //TODO This is not OK -> when reading provider.json it only shows "open" if(shared_preferences != null) { String content = shared_preferences.getString(shared_preferences_key, ""); try { JSONObject json_object = new JSONObject(content); value = json_object.toString(); - /*JSONArray names = json_object.names(); - String key = names.getString(0); - value = json_object.getString(key);*/ } catch (JSONException e) { value = content; } } return value; } - - static void saveSharedPref(String shared_preferences_key, JSONObject content) { - - SharedPreferences.Editor shared_preferences_editor = shared_preferences - .edit(); - shared_preferences_editor.putString(shared_preferences_key, - content.toString()); - shared_preferences_editor.commit(); - System.out.println("Shared preferences updated: key = " - + shared_preferences_key - + " Content = " - + shared_preferences.getString( - shared_preferences_key, "Default")); - } - static void rescueJSONException(JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - static void saveFile(String filename, String content) { + public static void saveFile(String filename, String content) { File root = Environment.getExternalStorageDirectory(); - File leap_dir = new File(root.getAbsolutePath() + File.separator + user_directory); + File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); if (!leap_dir.isDirectory()) { leap_dir.mkdir(); } try { if (!leap_dir.isDirectory()) { throw new IOException( - "Unable to create directory " + user_directory + ". Maybe the SD card is mounted?"); + "Unable to create directory " + USER_DIRECTORY + ". Maybe the SD card is mounted?"); } File outputFile = new File(leap_dir, filename); BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); @@ -135,10 +125,10 @@ public class ConfigHelper { } } - static FileInputStream openFileInputStream(String filename) { + public static FileInputStream openFileInputStream(String filename) { FileInputStream input_stream = null; File root = Environment.getExternalStorageDirectory(); - File leap_dir = new File(root.getAbsolutePath() + File.separator + user_directory); + File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); try { input_stream = new FileInputStream(leap_dir + File.separator + filename); } catch (FileNotFoundException e) { @@ -178,7 +168,8 @@ public class ConfigHelper { X509Certificate cert = (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); if(keystore_trusted == null) { - getNewKeystore(null); + keystore_trusted = KeyStore.getInstance("BKS"); + keystore_trusted.load(null); } keystore_trusted.setCertificateEntry(provider, cert); } catch (CertificateException e) { @@ -187,50 +178,16 @@ public class ConfigHelper { } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); - } - } - - public static KeyStore getKeystore() { - return keystore_trusted; - } - - public static void getNewKeystore(InputStream leap_keystore) { - try { - keystore_trusted = KeyStore.getInstance("BKS"); - try { - // Initialize the keystore with the provided trusted certificates - // Also provide the password of the keystore - if(leap_keystore != null) { - //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - keystore_trusted.load(null, null); - } else { - keystore_trusted.load(null, null); - } - } finally { - if(leap_keystore != null) - leap_keystore.close(); - } - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } - - public static int getSrpAuthenticationFailed() { - return SRP_AUTHENTICATION_FAILED; - } - static String extractProviderName(String provider_main_url) { - - return null; + public static KeyStore getKeystore() { + return keystore_trusted; } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index ba17f9b..78ac046 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -1,9 +1,6 @@ package se.leap.leapclient; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; import java.util.Iterator; import java.util.Scanner; @@ -12,6 +9,9 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.ProviderListContent.ProviderItem; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -24,23 +24,6 @@ import android.os.Handler; import android.view.View; import android.widget.Toast; - -/** - * An activity representing a list of Providers. This activity - * has different presentations for handset and tablet-size devices. On - * handsets, the activity presents a list of items, which when touched, - * lead to a {@link DashboardActivity} representing - * item details. On tablets, the activity presents the list of items and - * item details side-by-side using two vertical panes. - *

- * The activity makes heavy use of fragments. The list of items is a - * {@link ProviderListFragment} and the item details - * (if present) is a {@link DashboardFragment}. - *

- * This activity also implements the required - * {@link ProviderListFragment.Callbacks} interface - * to listen for item selections. - */ public class ConfigurationWizard extends Activity implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { @@ -63,11 +46,6 @@ public class ConfigurationWizard extends Activity loadPreseededProviders(); - if(ConfigHelper.getKeystore() == null) { - InputStream keystore_input_stream = getResources().openRawResource(R.raw.leapkeystore); - ConfigHelper.getNewKeystore(keystore_input_stream); - } - // Only create our fragments if we're not restoring a saved instance if ( savedInstanceState == null ){ // TODO Some welcome screen? @@ -83,7 +61,67 @@ public class ConfigurationWizard extends Activity // TODO: If exposing deep links into your app, handle intents here. } - private void loadPreseededProviders() { + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ + ProviderListFragment providerList = new ProviderListFragment(); + + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.configuration_wizard_layout, providerList, "providerlist") + .commit(); + } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + setResult(RESULT_OK); + finish(); + } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + } + else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + JSONObject provider_json; + try { + provider_json = new JSONObject(resultData.getString(ConfigHelper.PROVIDER_KEY)); + boolean danger_on = resultData.getBoolean(ConfigHelper.DANGER_ON); + ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + } + } + + /** + * Callback method from {@link ProviderListFragment.Callbacks} + * indicating that the item with the given ID was selected. + */ + @Override + public void onItemSelected(String id) { + //TODO Code 2 pane view + Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); + while(preseeded_providers_iterator.hasNext()) + { + ProviderItem current_provider_item = preseeded_providers_iterator.next(); + if(current_provider_item.id.equalsIgnoreCase(id)) + { + try { + saveProviderJson(current_provider_item); + downloadJSONFiles(current_provider_item); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + private boolean loadPreseededProviders() { + boolean loaded_preseeded_providers = false; AssetManager asset_manager = getAssets(); String[] urls_filepaths = null; try { @@ -97,65 +135,33 @@ public class ConfigurationWizard extends Activity provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString(); if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, true)); // By default, it trusts the provider + loaded_preseeded_providers = true; } } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + loaded_preseeded_providers = false; + } + + return loaded_preseeded_providers; } - /** - * Callback method from {@link ProviderListFragment.Callbacks} - * indicating that the item with the given ID was selected. - */ - @Override - public void onItemSelected(String id) { - if (mTwoPane) { - // TODO Hmmm...is this how we should do this? What if it /is/ two pane? - } else { - // In single-pane mode, simply start the detail activity - // for the selected item ID. - - Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); - while(preseeded_providers_iterator.hasNext()) - { - ProviderItem current_provider_item = preseeded_providers_iterator.next(); - if(current_provider_item.id.equalsIgnoreCase(id)) - { - try { - saveProviderJson(current_provider_item); - downloadJSONFiles(current_provider_item); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - } - } - - private void saveProviderJson(ProviderItem current_provider_item) { + private boolean saveProviderJson(ProviderItem current_provider_item) { JSONObject provider_json = new JSONObject(); try { String provider_contents = ""; if(!current_provider_item.custom) { - //provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); + return true; } else { provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - try { - ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, current_provider_item.danger_on)); + return true; } } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); + return false; } - } + } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); @@ -165,12 +171,12 @@ public class ConfigurationWizard extends Activity Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); - method_and_parameters.putString(ConfigHelper.main_cert_key, current_provider_item.cert_json_url); - method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); - method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on); + method_and_parameters.putString(ConfigHelper.PROVIDER_KEY, current_provider_item.name); + method_and_parameters.putString(ConfigHelper.MAIN_CERT_KEY, current_provider_item.cert_json_url); + method_and_parameters.putString(ConfigHelper.EIP_SERVICE_KEY, current_provider_item.eip_service_json_url); + method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, current_provider_item.danger_on); - provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -178,14 +184,14 @@ public class ConfigurationWizard extends Activity public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.newProviderDialog); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); if (previous_new_provider_dialog != null) { fragment_transaction.remove(previous_new_provider_dialog); } fragment_transaction.addToBackStack(null); DialogFragment newFragment = NewProviderDialog.newInstance(); - newFragment.show(fragment_transaction, ConfigHelper.newProviderDialog); + newFragment.show(fragment_transaction, ConfigHelper.NEW_PROVIDER_DIALOG); } @Override @@ -196,10 +202,10 @@ public class ConfigurationWizard extends Activity Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.provider_main_url, provider_main_url); - method_and_parameters.putBoolean(ConfigHelper.danger_on, danger_on); + method_and_parameters.putString(ConfigHelper.PROVIDER_MAIN_URL, provider_main_url); + method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); - provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -212,49 +218,13 @@ public class ConfigurationWizard extends Activity Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.provider_name, provider_name); - method_and_parameters.putString(ConfigHelper.provider_json_url, provider_json_url); - method_and_parameters.putBoolean(ConfigHelper.danger_on, danger_on); + method_and_parameters.putString(ConfigHelper.PROVIDER_NAME, provider_name); + method_and_parameters.putString(ConfigHelper.PROVIDER_JSON_URL, provider_json_url); + method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); - provider_API_command.putExtra(ConfigHelper.updateProviderDotJSON, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); } - - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ - ProviderListFragment providerList = new ProviderListFragment(); - - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction() - .replace(R.id.configuration_wizard_layout, providerList, "providerlist") - .commit(); - } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { - setResult(RESULT_OK); - finish(); - } - else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL", Toast.LENGTH_LONG).show(); - } - else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { - JSONObject provider_json; - try { - provider_json = new JSONObject(resultData.getString(ConfigHelper.provider_key)); - boolean danger_on = resultData.getBoolean(ConfigHelper.danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, danger_on)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { - Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); - } - - } } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index c8cbc5a..b937c94 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -6,6 +6,10 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; +import se.leap.leapclient.R.menu; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; @@ -116,11 +120,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public boolean onPrepareOptionsMenu(Menu menu) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); try { JSONObject provider_json = new JSONObject(provider_json_string); - JSONObject service_description = provider_json.getJSONObject(ConfigHelper.service_key); - if(service_description.getBoolean(ConfigHelper.allow_registration_key)) { + JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); + if(service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY)) { menu.findItem(R.id.login_button).setVisible(true); menu.findItem(R.id.logout_button).setVisible(true); return true; @@ -187,19 +191,19 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.username_key, username); - method_and_parameters.putString(ConfigHelper.password_key, password); + method_and_parameters.putString(ConfigHelper.USERNAME_KEY, username); + method_and_parameters.putString(ConfigHelper.PASSWORD_KEY, password); JSONObject provider_json; try { - provider_json = new JSONObject(preferences.getString(ConfigHelper.provider_key, "")); - method_and_parameters.putString(ConfigHelper.api_url_key, provider_json.getString(ConfigHelper.api_url_key) + "/" + provider_json.getString(ConfigHelper.api_version_key)); + provider_json = new JSONObject(preferences.getString(ConfigHelper.PROVIDER_KEY, "")); + method_and_parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - provider_API_command.putExtra(ConfigHelper.srpAuth, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.SRP_AUTH, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -214,14 +218,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf JSONObject provider_json; try { - provider_json = new JSONObject(preferences.getString(ConfigHelper.provider_key, "")); - method_and_parameters.putString(ConfigHelper.api_url_key, provider_json.getString(ConfigHelper.api_url_key) + "/" + provider_json.getString(ConfigHelper.api_version_key)); + provider_json = new JSONObject(preferences.getString(ConfigHelper.PROVIDER_KEY, "")); + method_and_parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - provider_API_command.putExtra(ConfigHelper.logOut, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.LOG_OUT, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -229,14 +233,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public void logInDialog(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.logInDialog); + Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); if (previous_log_in_dialog != null) { fragment_transaction.remove(previous_log_in_dialog); } fragment_transaction.addToBackStack(null); DialogFragment newFragment = LogInDialog.newInstance(); - newFragment.show(fragment_transaction, ConfigHelper.logInDialog); + newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); } private void downloadAuthedUserCertificate(Cookie session_id) { @@ -246,10 +250,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.session_id_cookie_key, session_id.getName()); - method_and_parameters.putString(ConfigHelper.session_id_key, session_id.getValue()); + method_and_parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); + method_and_parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); - provider_API_command.putExtra(ConfigHelper.downloadUserAuthedCertificate, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -258,8 +262,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ - String session_id_cookie_key = resultData.getString(ConfigHelper.session_id_cookie_key); - String session_id_string = resultData.getString(ConfigHelper.session_id_key); + String session_id_cookie_key = resultData.getString(ConfigHelper.SESSION_ID_COOKIE_KEY); + String session_id_string = resultData.getString(ConfigHelper.SESSION_ID_KEY); setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 4de7ae0..a2ee8ad 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -16,57 +16,57 @@ import android.content.Context; public class LeapHttpClient extends DefaultHttpClient { final Context context; - + private static LeapHttpClient client; - public LeapHttpClient(Context context) { - this.context = context; - } + public static LeapHttpClient getInstance(Context context) { + if(client == null) { + client = new LeapHttpClient(context); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + String cert_string; + try { + cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return client; + } + + @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 = ConfigHelper.getKeystore(); + + // Pass the keystore to the SSLSocketFactory. The factory is responsible + // for the verification of the server certificate. + SSLSocketFactory sf = new SSLSocketFactory(trusted); - @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); - } + // Hostname verification from certificate + // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - private SSLSocketFactory newSslSocketFactory() { - try { - // Get an instance of the Bouncy Castle KeyStore format - KeyStore trusted = ConfigHelper.getKeystore(); - - // 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.ALLOW_ALL_HOSTNAME_VERIFIER); - - return sf; - } catch (Exception e) { - throw new AssertionError(e); - } - } + return sf; + } catch (Exception e) { + throw new AssertionError(e); + } + } - public static LeapHttpClient getInstance(Context context) { - if(client == null) { - client = new LeapHttpClient(context); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); - String cert_string; - try { - cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); - if(!cert_string.isEmpty()) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - return client; - } + public LeapHttpClient(Context context) { + this.context = context; + } } diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index f9037de..7b32e79 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -47,8 +47,7 @@ public class LeapSRPSession { @param username, the user ID @param password, the user clear text password @param params, the SRP parameters for the session - @param abytes, the random exponent used in the A public key. This must be - 8 bytes in length. + @param abytes, the random exponent used in the A public key */ public LeapSRPSession(String username, String password, SRPParameters params, byte[] abytes) { @@ -177,8 +176,9 @@ public class LeapSRPSession { /** * Calculates the parameter M1, to be sent to the SRP server. * It also updates hashes of client and server for further calculations in other methods. + * It uses a predefined k. + * @param salt_bytes * @param Bbytes the parameter received from the server, in bytes - * @param bs * @return the parameter M1 * @throws NoSuchAlgorithmException */ @@ -190,8 +190,6 @@ public class LeapSRPSession { // Calculate v = kg^x mod N String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; this.v = calculateV(k_string); - //String v_string = v.toString(16); - // H(N) byte[] digest_of_n = newDigest().digest(N_bytes); @@ -201,54 +199,45 @@ public class LeapSRPSession { // clientHash = H(N) xor H(g) byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); - //String hxg_string = new BigInteger(1, xor_digest).toString(16); clientHash.update(xor_digest); // clientHash = H(N) xor H(g) | H(U) byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); username_digest = Util.trim(username_digest); - //String username_digest_string = new BigInteger(1, username_digest).toString(16); clientHash.update(username_digest); // clientHash = H(N) xor H(g) | H(U) | s - //String salt_string = new BigInteger(1, salt_bytes).toString(16); clientHash.update(Util.trim(salt_bytes)); K = null; - - // clientHash = H(N) xor H(g) | H(U) | s | A | B - - byte[] Abytes = Util.trim(A.toByteArray()); - //String Abytes_string = new BigInteger(1, Abytes).toString(16); // clientHash = H(N) xor H(g) | H(U) | A + byte[] Abytes = Util.trim(A.toByteArray()); clientHash.update(Abytes); // clientHash = H(N) xor H(g) | H(U) | s | A | B Bbytes = Util.trim(Bbytes); - //String Bbytes_string = new BigInteger(1, Bbytes).toString(16); clientHash.update(Bbytes); // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); byte[] S_bytes = Util.trim(S.toByteArray()); - //String S_bytes_string = new BigInteger(1, S_bytes).toString(16); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); K = Util.trim(sessionDigest.digest(S_bytes)); - //K = Util.trim(K); - //String K_bytes_string = new BigInteger(1, K).toString(16); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); + byte[] M1 = Util.trim(clientHash.digest()); // serverHash = Astr + M + K serverHash.update(Abytes); serverHash.update(M1); serverHash.update(K); + return M1; } @@ -263,13 +252,10 @@ public class LeapSRPSession { byte[] u_bytes = getU(Abytes, Bbytes); BigInteger B = new BigInteger(1, Bbytes); - //String Bstring = B.toString(16); BigInteger u = new BigInteger(1, u_bytes); - //String u_string = u.toString(16); BigInteger B_minus_v = B.subtract(v); BigInteger a_ux = a.add(u.multiply(x)); - //String a_ux_string = a_ux.toString(16); BigInteger S = B_minus_v.modPow(a_ux, N); return S; @@ -285,7 +271,7 @@ public class LeapSRPSession { MessageDigest u_digest = newDigest(); u_digest.update(Util.trim(Abytes)); u_digest.update(Util.trim(Bbytes)); - byte[] u_digest_bytes = u_digest.digest();//Util.trim(u_digest.digest()); + byte[] u_digest_bytes = u_digest.digest(); return Util.trim(new BigInteger(1, u_digest_bytes).toByteArray()); } @@ -302,17 +288,6 @@ public class LeapSRPSession { return valid; } - /** Returns the negotiated session K, K = SHA_Interleave(S) - @return the private session K byte[] - @throws SecurityException - if the current thread does not have an - getSessionKey SRPPermission. - */ - public byte[] getSessionKey() throws SecurityException - { - return K; - } - - /** * @return a new SHA-256 digest. */ diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 30984db..370a138 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -1,8 +1,11 @@ package se.leap.leapclient; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; +import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; -import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; import android.os.Bundle; @@ -12,49 +15,25 @@ import android.widget.EditText; import android.widget.Toast; public class LogInDialog extends DialogFragment { - - public interface LogInDialogInterface { - public void authenticate(String username, String password); - } - - LogInDialogInterface interface_with_Dashboard; - - public static DialogFragment newInstance() { - LogInDialog dialog_fragment = new LogInDialog(); - return dialog_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - // Verify that the host activity implements the callback interface - try { - // Instantiate the NoticeDialogListener so we can send events to the host - interface_with_Dashboard = (LogInDialogInterface) activity; - } catch (ClassCastException e) { - // The activity doesn't implement the interface, throw exception - throw new ClassCastException(activity.toString() - + " must implement NoticeDialogListener"); - } - } - public Dialog onCreateDialog(Bundle savedInstanceState) { + public AlertDialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null); + final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + builder.setView(log_in_dialog_view) .setPositiveButton(R.string.log_in_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { String username = username_field.getText().toString().trim(); String password = password_field.getText().toString().trim(); - if(validPassword(password)) { + if(wellFormedPassword(password)) { interface_with_Dashboard.authenticate(username, password); - Toast.makeText(getActivity().getApplicationContext(), "Your password is valid", Toast.LENGTH_LONG).show(); } else { password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "Your password is not valid: it should have at least 8 characters", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "Your password is not well-formed: it should have at least 8 characters", Toast.LENGTH_LONG).show(); } } }) @@ -63,11 +42,33 @@ public class LogInDialog extends DialogFragment { dialog.cancel(); } }); - // Create the AlertDialog object and return it + return builder.create(); } - boolean validPassword(String entered_password) { - return entered_password.length() > 4; + boolean wellFormedPassword(String entered_password) { + return entered_password.length() > 8; } + + public interface LogInDialogInterface { + public void authenticate(String username, String password); + } + + LogInDialogInterface interface_with_Dashboard; + + public static DialogFragment newInstance() { + LogInDialog dialog_fragment = new LogInDialog(); + return dialog_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + interface_with_Dashboard = (LogInDialogInterface) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 6101846..9978800 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -1,5 +1,9 @@ package se.leap.leapclient; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; +import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -28,12 +32,9 @@ public class NewProviderDialog extends DialogFragment { @Override public void onAttach(Activity activity) { super.onAttach(activity); - // Verify that the host activity implements the callback interface try { - // Instantiate the NoticeDialogListener so we can send events to the host interface_with_ConfigurationWizard = (NewProviderDialogInterface) activity; } catch (ClassCastException e) { - // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement NoticeDialogListener"); } diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index 4235acf..f86bbf5 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -18,7 +18,7 @@ import android.content.SharedPreferences; * @author Sean Leonard * */ -final class Provider implements Serializable { +public final class Provider implements Serializable { private static final long serialVersionUID = 6003835972151761353L; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index b44c997..0003344 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -11,7 +11,6 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.List; import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpCookie; @@ -32,6 +31,7 @@ import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; @@ -63,89 +63,72 @@ public class ProviderAPI extends IntentService { final ResultReceiver receiver = task_for.getParcelableExtra("receiver"); Bundle task; - if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { - if(!downloadJsonFiles(task)) + if((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) != null) { + if(!downloadJsonFiles(task)) { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } } - else if ((task = task_for.getBundleExtra(ConfigHelper.updateProviderDotJSON)) != null) { - JSONObject result = updateProviderDotJSON(task); - boolean successful; - try { - successful = result.getBoolean(ConfigHelper.resultKey); - if(successful) { - Bundle provider_dot_json_and_danger_on = new Bundle(); - provider_dot_json_and_danger_on.putBoolean(ConfigHelper.danger_on, result.getBoolean(ConfigHelper.danger_on)); - provider_dot_json_and_danger_on.putString(ConfigHelper.provider_key, result.getJSONObject(ConfigHelper.provider_key).toString()); - receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, provider_dot_json_and_danger_on); - } else { - receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + else if ((task = task_for.getBundleExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON)) != null) { + Bundle result = updateProviderDotJSON(task); + if(result.getBoolean(ConfigHelper.RESULT_KEY)) { + receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); + } else { + receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); } } - else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { - if(downloadNewProviderDotJSON(task)) + else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON)) != null) { + if(downloadNewProviderDotJSON(task)) { receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } } - else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { - try { - JSONObject session_idAndResult = authenticateBySRP(task); - if(session_idAndResult.getBoolean(ConfigHelper.resultKey)) { - Bundle session_id_bundle = new Bundle(); - session_id_bundle.putString(ConfigHelper.session_id_cookie_key, session_idAndResult.getString(ConfigHelper.session_id_cookie_key)); - session_id_bundle.putString(ConfigHelper.session_id_key, session_idAndResult.getString(ConfigHelper.session_id_key)); - receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); - } else { - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + else if ((task = task_for.getBundleExtra(ConfigHelper.SRP_AUTH)) != null) { + Bundle session_id_bundle = authenticateBySRP(task); + if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); + } else { + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); } } - else if ((task = task_for.getBundleExtra(ConfigHelper.logOut)) != null) { - if(logOut(task)) + else if ((task = task_for.getBundleExtra(ConfigHelper.LOG_OUT)) != null) { + if(logOut(task)) { receiver.send(ConfigHelper.LOGOUT_SUCCESSFUL, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); + } } - else if ((task = task_for.getBundleExtra(ConfigHelper.downloadUserAuthedCertificate)) != null) { - if(getNewCert(task)) + else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE)) != null) { + if(getNewCert(task)) { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + } } } private boolean downloadJsonFiles(Bundle task) { - //String provider_name = task.getString(ConfigHelper.provider_key); - String cert_url = task.getString(ConfigHelper.main_cert_key); - String eip_service_json_url = task.getString(ConfigHelper.eip_service_key); - boolean danger_on = task.getBoolean(ConfigHelper.danger_on); + String cert_url = task.getString(ConfigHelper.MAIN_CERT_KEY); + String eip_service_json_url = task.getString(ConfigHelper.EIP_SERVICE_KEY); + boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); try { String cert_string = getStringFromProvider(cert_url, danger_on); - //ConfigHelper.addTrustedCertificate(provider_name, cert_string); - JSONObject cert_json = new JSONObject().put(ConfigHelper.main_cert_key, cert_string); - ConfigHelper.saveSharedPref(ConfigHelper.main_cert_key, cert_json); + JSONObject cert_json = new JSONObject().put(ConfigHelper.MAIN_CERT_KEY, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); + ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, eip_service_json); return true; } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); return false; } } private boolean registerWithSRP(Bundle task) { - String username = (String) task.get(ConfigHelper.username_key); - String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.api_url_key); + String username = (String) task.get(ConfigHelper.USERNAME_KEY); + String password = (String) task.get(ConfigHelper.PASSWORD_KEY); + String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); BigInteger salt = ng_1024.probablePrime(1024, null); @@ -154,173 +137,127 @@ public class ProviderAPI extends IntentService { return false; } - private JSONObject authenticateBySRP(Bundle task) { - JSONObject successfulAndsession_id = new JSONObject(); - - String username = (String) task.get(ConfigHelper.username_key); - String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.api_url_key); + private Bundle authenticateBySRP(Bundle task) { + Bundle session_id_bundle = new Bundle(); - String salt = "abcd"; + String username = (String) task.get(ConfigHelper.USERNAME_KEY); + String password = (String) task.get(ConfigHelper.PASSWORD_KEY); + String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); - SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - //SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); + SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); LeapSRPSession client = new LeapSRPSession(username, password, params); byte[] A = client.exponential(); try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { - salt = saltAndB.getString("salt"); + String salt = saltAndB.getString(ConfigHelper.SALT_KEY); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); - //byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify((byte[])session_idAndM2.get("M2")) == false ) { - //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); - successfulAndsession_id.put(ConfigHelper.resultKey, false); - return successfulAndsession_id; + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } else { - successfulAndsession_id.put(ConfigHelper.resultKey, true); - successfulAndsession_id.put(ConfigHelper.session_id_key, session_idAndM2.getString(ConfigHelper.session_id_key)); - successfulAndsession_id.put(ConfigHelper.session_id_cookie_key, session_idAndM2.getString(ConfigHelper.session_id_cookie_key)); - return successfulAndsession_id; + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, true); + session_id_bundle.putString(ConfigHelper.SESSION_ID_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_KEY)); + session_id_bundle.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_COOKIE_KEY)); } } else { - successfulAndsession_id.put(ConfigHelper.resultKey, false); - return successfulAndsession_id; + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } - } catch (ClientProtocolException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); + } catch (ClientProtocolException e) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + } catch (IOException e) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + } catch (JSONException e) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } - return successfulAndsession_id; + + return session_id_bundle; } private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - String parameter_chain = "A" + "=" + clientA + "&" + "login" + "=" + username; - HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); - - HttpResponse getResponse = client.execute(post); - HttpEntity responseEntity = getResponse.getEntity(); - String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); - JSONObject json_response = new JSONObject(plain_response); - if(!json_response.isNull("errors") || json_response.has("errors")) { - return new JSONObject(); - } - - String session_id = ""; - List cookies = client.getCookieStore().getCookies(); - if(!cookies.isEmpty()) { - session_id = cookies.get(0).getValue(); - } - return json_response; + HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); + return sendToServer(post); } private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { + HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16)); + JSONObject json_response = sendToServer(put); + JSONObject session_idAndM2 = new JSONObject(); + if(json_response.length() > 0) { + byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); + Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); + session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); + session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue()); + session_idAndM2.put("M2", Util.trim(M2_not_trimmed)); + } + return session_idAndM2; + } + + private JSONObject sendToServer(HttpUriRequest request) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16); - HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); - String session_id = client.getCookieStore().getCookies().get(0).getValue(); - int number_of_cookies = client.getCookieStore().getCookies().size(); - HttpResponse getResponse = client.execute(put, localContext); + HttpResponse getResponse = client.execute(request, localContext); HttpEntity responseEntity = getResponse.getEntity(); String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); if(!json_response.isNull("errors") || json_response.has("errors")) { - return session_idAndM2; + return new JSONObject(); } - number_of_cookies = client.getCookieStore().getCookies().size(); - byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); - session_idAndM2.put(ConfigHelper.session_id_cookie_key, client.getCookieStore().getCookies().get(0).getName()); - session_idAndM2.put(ConfigHelper.session_id_key, client.getCookieStore().getCookies().get(0).getValue()); - session_idAndM2.put("M2", Util.trim(M2_not_trimmed)); - return session_idAndM2; + return json_response; } - private JSONObject updateProviderDotJSON(Bundle task) { - JSONObject result = new JSONObject(); - boolean custom = task.getBoolean(ConfigHelper.custom); - boolean danger_on = task.getBoolean(ConfigHelper.danger_on); - String provider_json_url = task.getString(ConfigHelper.provider_json_url); - String provider_name = task.getString(ConfigHelper.provider_name); + private Bundle updateProviderDotJSON(Bundle task) { + Bundle result = new Bundle(); + boolean custom = task.getBoolean(ConfigHelper.CUSTOM); + boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); + String provider_json_url = task.getString(ConfigHelper.PROVIDER_JSON_URL); + String provider_name = task.getString(ConfigHelper.PROVIDER_NAME); - JSONObject provider_json = null; try { - provider_json = getJSONFromProvider(provider_json_url, danger_on); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - try { - return result.put(ConfigHelper.resultKey, false); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - - if(provider_json == null) { - try { - return result.put(ConfigHelper.resultKey, false); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); - //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + JSONObject provider_json = getJSONFromProvider(provider_json_url, danger_on); + if(provider_json == null) { + result.putBoolean(ConfigHelper.RESULT_KEY, false); + } else { + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); + ConfigHelper.saveFile(filename, provider_json.toString()); - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); - try { - return result.put(ConfigHelper.resultKey, true).put(ConfigHelper.provider_key, provider_json).put(ConfigHelper.danger_on, danger_on); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); + result.putBoolean(ConfigHelper.RESULT_KEY, true); + result.putString(ConfigHelper.PROVIDER_KEY, provider_json.toString()); + result.putBoolean(ConfigHelper.DANGER_ON, danger_on); } + } catch (JSONException e) { + result.putBoolean(ConfigHelper.RESULT_KEY, false); } + return result; } private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; - boolean danger_on = task.getBoolean(ConfigHelper.danger_on); + boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); - String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); + String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); JSONObject provider_json = null; try { provider_json = getJSONFromProvider(provider_json_url, danger_on); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - - if(provider_json == null) { - return false; - } else { + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); - //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); return true; + } catch (JSONException e) { + return false; } } @@ -385,8 +322,8 @@ public class ProviderAPI extends IntentService { try { cf = CertificateFactory.getInstance("X.509"); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); - String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); @@ -454,7 +391,7 @@ public class ProviderAPI extends IntentService { int session_id_index = 0; //String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/sessions/" + client.getCookieStore().getCookies().get(0).getValue(); try { - String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + String delete_url = task.getString(ConfigHelper.API_URL_KEY) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); HttpDelete delete = new HttpDelete(delete_url); HttpResponse getResponse = client.execute(delete); HttpEntity responseEntity = getResponse.getEntity(); @@ -476,24 +413,24 @@ public class ProviderAPI extends IntentService { } private boolean getNewCert(Bundle task) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); - HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.session_id_cookie_key), task.getString(ConfigHelper.session_id_key)); + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); + HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); try { JSONObject provider_json = new JSONObject(provider_json_string); - URL provider_main_url = new URL(provider_json.getString(ConfigHelper.api_url_key).replace("api.", "")); - String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.api_version_key) + "/" + ConfigHelper.cert_key; + URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY).replace("api.", "")); + String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; CookieManager cookieManager = new CookieManager(); cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); CookieHandler.setDefault(cookieManager); - String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.danger_on); - boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.danger_on); + String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.DANGER_ON); + boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.DANGER_ON); String cert_string = getStringFromProvider(new_cert_string_url, danger_on); if(!cert_string.isEmpty()) { - JSONObject cert_json = new JSONObject().put(ConfigHelper.cert_key, cert_string); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + JSONObject cert_json = new JSONObject().put(ConfigHelper.CERT_KEY, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, cert_json); return true; } else { return false; diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index d4bb6a9..b83bbd8 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -91,7 +91,7 @@ public class ProviderListContent { this.name = name; this.provider_json_url = provider_json_url; this.provider_json_filename = provider_json_filename; - eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.eip_service_api_path; + eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; -- cgit v1.2.3 From 75edcdb601be69f4c1ee6783cf7f80390a9f094d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 14 May 2013 21:03:07 +0200 Subject: Anon certificate is downloaded if possible. I download the anon certificate only if allow_anonymous is true, and before launching Dashboard. I store it in SharedPreferences, with "cert" key, as a JSON object. --- src/se/leap/leapclient/ConfigHelper.java | 14 ++++++--- src/se/leap/leapclient/ConfigurationWizard.java | 39 ++++++++++++++++++++++++- src/se/leap/leapclient/Dashboard.java | 7 +++-- src/se/leap/leapclient/ProviderAPI.java | 24 ++++++++------- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5d44f00..6a70378 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,14 +37,18 @@ public class ConfigHelper { SRP_AUTH = "srpAuth", LOG_IN = "logIn", LOG_OUT = "logOut", - DOWNLOAD_USER_AUTHED_CERTIFICATE = "downloadUserAuthedCertificate", + DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", API_VERSION_KEY = "api_version", RESULT_KEY = "result", PROVIDER_KEY = "provider", SERVICE_KEY = "service", + ALLOWED_ANON = "allow_anonymous", MAIN_CERT_KEY = "main_cert", CERT_KEY = "cert", EIP_SERVICE_KEY = "eip", + TYPE_OF_CERTIFICATE = "type_of_certificate", + ANON_CERTIFICATE = "anon_certificate", + AUTHED_CERTIFICATE = "authed_certificate", SALT_KEY = "salt", SESSION_ID_COOKIE_KEY = "session_id_cookie_key", SESSION_ID_KEY = "session_id", @@ -76,10 +80,12 @@ public class ConfigHelper { SRP_REGISTRATION_FAILED = 6, LOGOUT_SUCCESSFUL = 7, LOGOUT_FAILED = 8, - CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9, - INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10, + CORRECTLY_DOWNLOADED_CERTIFICATE = 9, + INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, - INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12 + INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12, + CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, + INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 ; public static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 78ac046..fff155a 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -73,7 +73,6 @@ public class ConfigurationWizard extends Activity } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { setResult(RESULT_OK); - finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { setResult(RESULT_CANCELED); @@ -86,6 +85,7 @@ public class ConfigurationWizard extends Activity boolean danger_on = resultData.getBoolean(ConfigHelper.DANGER_ON); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, danger_on)); + downloadAnonCert(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -94,6 +94,14 @@ public class ConfigurationWizard extends Activity else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_OK); + Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + finish(); + } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); + } } /** @@ -155,7 +163,9 @@ public class ConfigurationWizard extends Activity provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, new JSONObject().put(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON))); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, current_provider_item.danger_on)); + downloadAnonCert(); return true; } } catch (JSONException e) { @@ -182,6 +192,33 @@ public class ConfigurationWizard extends Activity startService(provider_API_command); } + private boolean downloadAnonCert() { + + JSONObject allowed_anon; + try { + allowed_anon = new JSONObject(ConfigHelper.getStringFromSharedPref(ConfigHelper.ALLOWED_ANON)); + if(allowed_anon.getBoolean(ConfigHelper.ALLOWED_ANON)) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + + method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); + + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + return true; + } else { + return false; + } + } catch (JSONException e) { + return false; + } + } public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index b937c94..5ffbc19 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -250,10 +250,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.AUTHED_CERTIFICATE); method_and_parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); method_and_parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -278,10 +279,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Didn't logged out", Toast.LENGTH_LONG).show(); - } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); - } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0003344..d5e164d 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -100,11 +100,11 @@ public class ProviderAPI extends IntentService { receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); } } - else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE)) != null) { + else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_CERTIFICATE)) != null) { if(getNewCert(task)) { - receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } else { - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } } } @@ -224,7 +224,9 @@ public class ProviderAPI extends IntentService { JSONObject provider_json = getJSONFromProvider(provider_json_url, danger_on); if(provider_json == null) { result.putBoolean(ConfigHelper.RESULT_KEY, false); - } else { + } else { + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, new JSONObject().put(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON))); + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); @@ -414,17 +416,20 @@ public class ProviderAPI extends IntentService { private boolean getNewCert(Bundle task) { String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); - HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); - + String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { JSONObject provider_json = new JSONObject(provider_json_string); URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY).replace("api.", "")); String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; - CookieManager cookieManager = new CookieManager(); - cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); - CookieHandler.setDefault(cookieManager); + if(type_of_certificate.equalsIgnoreCase(ConfigHelper.AUTHED_CERTIFICATE)) { + HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); + CookieManager cookieManager = new CookieManager(); + cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); + CookieHandler.setDefault(cookieManager); + } + String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.DANGER_ON); boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.DANGER_ON); String cert_string = getStringFromProvider(new_cert_string_url, danger_on); @@ -435,7 +440,6 @@ public class ProviderAPI extends IntentService { } else { return false; } - } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 8cf70d4f69db6326407956a44a54c7fe5530a22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20G=C3=A1lvez=20Vizca=C3=ADno?= Date: Mon, 27 May 2013 20:44:03 +0200 Subject: First version of the README and ant build.xml This is the first commit of this branch. It contains the README file with instructions for different user targets (Compiling, Running on the emulator and Debugging from console), and the ant build.xml file. debug.sh is an experimental script, because it uses "sleep" to synchronize between Emulator and adb install and run. If you want to use it, please look for that "sleep" lines and update their numbers according to your experience. --- .classpath | 3 +- README.txt | 81 ++++++++++++++++++++++++++++++--------------- README_icsopenvpn.txt | 43 ++++++++++++++++++++++++ build.xml | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ debug.sh | 19 +++++++++++ lint.xml | 3 ++ 6 files changed, 214 insertions(+), 27 deletions(-) create mode 100644 README_icsopenvpn.txt create mode 100644 build.xml create mode 100755 debug.sh create mode 100644 lint.xml diff --git a/.classpath b/.classpath index e449cbf..dfadf67 100644 --- a/.classpath +++ b/.classpath @@ -1,8 +1,9 @@ + - + diff --git a/README.txt b/README.txt index f6690f5..badaaf5 100644 --- a/README.txt +++ b/README.txt @@ -1,43 +1,72 @@ -This is my first Android project, so some things may be done in a completely stupid way. +Compiling +========= -See the file todo.txt for ideas/not yet implemented features (and the bug tracker). +Preconditions +---------------- -Build instraction: +1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) +2. API version 16 or version installed. +2. Ant 1.6 or greater -Checkout google breakcode: +Instructions to compile +----------------------- -svn co http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad +1. cd $PROJECT_LOCATION/leap_android +2. android update project --path $PROJECT_LOCATION/leap_android/ +3. ant debug -- Install sdk -- Install ndk +Postconditions +-------------- -Do ./build-native.sh in the root directory of the project. +1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists -Use eclipse with android plugins to build the project. +Running on the emulator +========================= -Optional: Copy minivpn from lib/ to assets (if you want your own compiled version) +Preconditions +----------------- +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) +Instructions to run on the emulator +----------------------------------- +1. Run emulator: emulator @AVD-NAME (avd names are the names of the files in ~/.android/avd with extension .avd). + - If you want to test the app from scratch, run emulator -wipe-data @AVD-NAME +2. Run app: adb shell am start se.leap.leapclient/.Dashboard -Starting a VPN by name from an external app: +Postconditions +-------------- -public class StartOpenVPNActivity extends Activity { - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); - - final String EXTRA_NAME = "se.leap.openvpn.shortcutProfileName"; +1. LEAP Android is running. - Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); - shortcutIntent.setClassName("se.leap.openvpn", "se.leap.openvpn.LaunchVPN"); - shortcutIntent.putExtra(EXTRA_NAME,"upb ssl"); - startActivity(shortcutIntent); - } -} +Debugging from console +====================== -or from the shell: +Preconditions +----------------- -am start -a android.intent.action.VPNLEGACY -n se.leap.openvpn/.LaunchVPN -e se.leap.openvpn.shortcutProfileName Home +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). +4. jdb is installed (this program is part of OpenJDK 7) +Instructions to debug from the console +----------------------------------- + +1. emulator @AVD-NAME # (avd names are the names of the files in ~/.android/avd with extension .avd). + - emulator -wipe-data @AVD-NAME # If you want to test the app from scratch +2. adb install -r $PROJECT_LOCATION/leap_android/bin/LEAP\ Android-debug.apk # Install the new version of the application +3. adb shell am start -D se.leap.leapclient/.Dashboard # Run app +4. pid=`adb shell ps | grep leap | awk '{print $2}'` # Identify the process id (pid) of the current leapclient process instance +5. localport=`expr $RANDOM % 65536` +6. adb forward tcp:$localport jdwp:$pid +7. jdb -sourcepath $PROJECT_LOCATION/leap_android/src/ -attach localhost:$localport + +Postconditions +-------------- + +1. LEAP Android is running. +2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". diff --git a/README_icsopenvpn.txt b/README_icsopenvpn.txt new file mode 100644 index 0000000..f6690f5 --- /dev/null +++ b/README_icsopenvpn.txt @@ -0,0 +1,43 @@ +This is my first Android project, so some things may be done in a completely stupid way. + +See the file todo.txt for ideas/not yet implemented features (and the bug tracker). + +Build instraction: + +Checkout google breakcode: + +svn co http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad + +- Install sdk +- Install ndk + +Do ./build-native.sh in the root directory of the project. + +Use eclipse with android plugins to build the project. + +Optional: Copy minivpn from lib/ to assets (if you want your own compiled version) + + + + +Starting a VPN by name from an external app: + +public class StartOpenVPNActivity extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + final String EXTRA_NAME = "se.leap.openvpn.shortcutProfileName"; + + Intent shortcutIntent = new Intent(Intent.ACTION_MAIN); + shortcutIntent.setClassName("se.leap.openvpn", "se.leap.openvpn.LaunchVPN"); + shortcutIntent.putExtra(EXTRA_NAME,"upb ssl"); + startActivity(shortcutIntent); + } +} + +or from the shell: + +am start -a android.intent.action.VPNLEGACY -n se.leap.openvpn/.LaunchVPN -e se.leap.openvpn.shortcutProfileName Home + diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..538f2ee --- /dev/null +++ b/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/debug.sh b/debug.sh new file mode 100755 index 0000000..c3f96ba --- /dev/null +++ b/debug.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +if [ -z "$2" ] +then + echo Usage: debug.sh \"avd name\" \"project folder\" + exit 0; +fi +avd_name=$1 +PROJECT_FOLDER=$2 +localport=`expr $RANDOM % 65536` + +emulator -wipe-data @$avd_name & # If you want to test the app from scratch +sleep 70 +adb install -r $PROJECT_FOLDER/bin/LEAP\ Android-debug.apk # Install the new version of the application +adb shell am start -D se.leap.leapclient/.Dashboard # Run app +pid=`adb shell ps | grep leap | awk '{print $2}'` # Identify the process id (pid) of the current leapclient process instance +adb forward tcp:$localport jdwp:$pid +sleep 3 +jdb -sourcepath $PROJECT_FOLDER/src/ -attach localhost:$localport diff --git a/lint.xml b/lint.xml new file mode 100644 index 0000000..ee0eead --- /dev/null +++ b/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file -- cgit v1.2.3 From 14935459df410017f97428b0d98e0710b4141b63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 28 May 2013 17:18:49 +0200 Subject: debug.sh works without initial big sleep. I've found the way to detect if the emulator has finished booting, so that I can install and start leap_android without problems. I've moved the last sleep before the pid calculation, because sometimes it wasn't calculated well (I think because I asked for it too soon). --- debug.sh | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/debug.sh b/debug.sh index c3f96ba..1867936 100755 --- a/debug.sh +++ b/debug.sh @@ -9,11 +9,25 @@ avd_name=$1 PROJECT_FOLDER=$2 localport=`expr $RANDOM % 65536` +wait_until_booted() { + OUT=`adb shell getprop init.svc.bootanim` + RES="stopped" + + while [[ ${OUT:0:7} != 'stopped' ]]; do + OUT=`adb shell getprop init.svc.bootanim` +# echo 'Waiting for emulator to fully boot...' + sleep 5 + done + + echo "Emulator booted!" +} + emulator -wipe-data @$avd_name & # If you want to test the app from scratch -sleep 70 +wait_until_booted adb install -r $PROJECT_FOLDER/bin/LEAP\ Android-debug.apk # Install the new version of the application adb shell am start -D se.leap.leapclient/.Dashboard # Run app +sleep 1 pid=`adb shell ps | grep leap | awk '{print $2}'` # Identify the process id (pid) of the current leapclient process instance +echo forwarding tcp:$localport to jwdp:$pid adb forward tcp:$localport jdwp:$pid -sleep 3 jdb -sourcepath $PROJECT_FOLDER/src/ -attach localhost:$localport -- cgit v1.2.3 From be9dc79cff4b04b2bb6af6dbbe679a0c8a5f6df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 28 May 2013 19:03:10 +0200 Subject: Added new file: run.sh It just runs the emulator, installs leap_android and runs it. No debugger session is returned. --- run.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 run.sh diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..eace457 --- /dev/null +++ b/run.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +if [ -z "$2" ] +then + echo Usage: run.sh \"avd name\" \"project folder\" + exit 0; +fi +avd_name=$1 +PROJECT_FOLDER=$2 +localport=`expr $RANDOM % 65536` + +wait_until_booted() { + OUT=`adb shell getprop init.svc.bootanim` + RES="stopped" + + while [[ ${OUT:0:7} != 'stopped' ]]; do + OUT=`adb shell getprop init.svc.bootanim` +# echo 'Waiting for emulator to fully boot...' + sleep 5 + done + + echo "Emulator booted!" +} + +emulator -wipe-data @$avd_name & # If you want to test the app from scratch +wait_until_booted +adb install -r $PROJECT_FOLDER/bin/LEAP\ Android-debug.apk # Install the new version of the application +adb shell am start se.leap.leapclient/.Dashboard # Run app -- cgit v1.2.3 From 086a98886a5b28c1f9426fd40c093bf2affa960e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 28 May 2013 20:14:01 +0200 Subject: Starting basic adt vim plugin. If I execute AndroidRun, run.sh is not called but echoes are printed. --- vim-plugin/basic-adt.vim | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 vim-plugin/basic-adt.vim diff --git a/vim-plugin/basic-adt.vim b/vim-plugin/basic-adt.vim new file mode 100644 index 0000000..366b3f2 --- /dev/null +++ b/vim-plugin/basic-adt.vim @@ -0,0 +1,47 @@ +function! AndroidRun() + let new_project_root = s:Find_in_parent("AndroidManifest.xml", s:windowdir() ,$HOME) + echo "Found Android Project at: " . new_project_root + echo "Windowdir: " . s:windowdir() + if new_project_root != "Nothing" + let b:project_root = new_project_root + new + set buftype=nofile + silent! exec "r!../run.sh SII b:project_root + endif +endfunc + +" Find_in_parent +" " find the file argument and returns the path to it. +" " Starting with the current working dir, it walks up the parent folders +" " until it finds the file, or it hits the stop dir. +" " If it doesn't find it, it returns "Nothing" +function s:Find_in_parent(fln,flsrt,flstp) + let here = a:flsrt + while ( strlen( here) > 0 ) + if filereadable( here . "/" . a:fln ) + return here + endif + let fr = match(here, "/[^/]*$") + if fr == -1 + break + endif + let here = strpart(here, 0, fr) + if here == a:flstp + break + endif + endwhile + return "Nothing" +endfunc + +" windowdir +" " Gets the directory for the file in the current window +" " Or the current working dir if there isn't one for the window. +" " Use tr to allow that other OS paths, too +function s:windowdir() + if winbufnr(0) == -1 + let unislash = getcwd() + else + let unislash = fnamemodify(bufname(winbufnr(0)), ':p:h') + endif + return tr(unislash, '\', '/') +endfunc -- cgit v1.2.3 From 10cb3dc6835d89f288eaa78739a5a60c1c849a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 29 May 2013 16:06:31 +0200 Subject: README now suggest to use scripts. I've also simlinked README.txt to README. In the future, if we want to write another file in another format (MarkDown?), we will only have to change the target of the README file. --- README | 1 + README.txt | 19 ++++++------------- build.xml | 2 +- run.sh | 12 +++++++++++- 4 files changed, 19 insertions(+), 15 deletions(-) create mode 120000 README diff --git a/README b/README new file mode 120000 index 0000000..c3ca074 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.txt \ No newline at end of file diff --git a/README.txt b/README.txt index badaaf5..7d57a6e 100644 --- a/README.txt +++ b/README.txt @@ -12,8 +12,7 @@ Instructions to compile ----------------------- 1. cd $PROJECT_LOCATION/leap_android -2. android update project --path $PROJECT_LOCATION/leap_android/ -3. ant debug +2. ./compile.sh Postconditions -------------- @@ -33,9 +32,8 @@ Preconditions Instructions to run on the emulator ----------------------------------- -1. Run emulator: emulator @AVD-NAME (avd names are the names of the files in ~/.android/avd with extension .avd). - - If you want to test the app from scratch, run emulator -wipe-data @AVD-NAME -2. Run app: adb shell am start se.leap.leapclient/.Dashboard +1. cd $PROJECT_LOCATION/leap_android +1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). Postconditions -------------- @@ -56,17 +54,12 @@ Preconditions Instructions to debug from the console ----------------------------------- -1. emulator @AVD-NAME # (avd names are the names of the files in ~/.android/avd with extension .avd). - - emulator -wipe-data @AVD-NAME # If you want to test the app from scratch -2. adb install -r $PROJECT_LOCATION/leap_android/bin/LEAP\ Android-debug.apk # Install the new version of the application -3. adb shell am start -D se.leap.leapclient/.Dashboard # Run app -4. pid=`adb shell ps | grep leap | awk '{print $2}'` # Identify the process id (pid) of the current leapclient process instance -5. localport=`expr $RANDOM % 65536` -6. adb forward tcp:$localport jdwp:$pid -7. jdb -sourcepath $PROJECT_LOCATION/leap_android/src/ -attach localhost:$localport +1. cd $PROJECT_LOCATION/leap_android +2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). Postconditions -------------- 1. LEAP Android is running. 2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". +3. You are in a jdb debuggin session. diff --git a/build.xml b/build.xml index 538f2ee..a10a914 100644 --- a/build.xml +++ b/build.xml @@ -1,5 +1,5 @@ - + + + + Certificaten + PKCS12 Bestand + Android Certificaat + Gebruikersnaam/Wachtwoord + Statische Sleutels + Gebruiker/WW + Certificaten + Gebruiker/WW + PKCS12 + Gebruiker/WW + Android + + + 0 + 1 + Niet-gespecificeerd + + + 0 - Geen logboek + 1 - Standaard logboek + 2 - Uitgebreid logboek + 3 + 4 + 5 - Debug logboek + + diff --git a/res/values/values-nl/strings.xml b/res/values/values-nl/strings.xml new file mode 100755 index 0000000..459c80e --- /dev/null +++ b/res/values/values-nl/strings.xml @@ -0,0 +1,108 @@ + + + + LEAP voor Android + Server Adres: + Server Poort: + Locatie + Selecteer + Annuleer + Geen Gegevens + LZO Compressie + Geen Certificaat + Client Certificaat + Client Certificaat Sleutel + PKCS12 Bestand + CA Certificaat + Over + Over LEAP voor Android + Lijst van alle geconfigureerde VPN verbindingen + VPN Profielen + Type + PKCS12 Wachtwoord + Selecteer… + Gebruik TLS autentificatie + TLS Richting + Voer een IPv6 Adres/Netmask in met het CIDR Formaat (v.b. 2000:dd::23/64) + Voer een IPv4 Adres/Netmask in met het CIDR Formaat (v.b. 1.2.3.4/24) + IPv4 Adres + IPv4 Adres + Gebruikersnaam + wachtwoord + VPN configureren + Profiel toevoegen + Voer een naam in voor het nieuwe Profiel + Profiel name + Geen fout. + Fout in de configuratie + Open VPN shortcut + Met VPN verbinden + Het profiel zoals aangegeven in de snelkoppeling kon niet gevonden worden. + Willekeurig Host Voorvoegsel + Voegt 6 willekeurige tekens toe voor de hostname + Eigen configuratie opties + Geef je eigen configuratieopties aan. Wees voorzichtig! + Route geweigert door Android + Verbinding verbreken + logboek wissen + Annuleer bevestiging + Sluit de verbonden VPN af/annuleer de verbindingspoging? + VPN wissen + Checkt of de server een TLS server certificaat gebruikt. + Controleer Certificaat Hostname + Externe Hostname(CN) + TLS Auth Bestand + Vraag IP adres, routes en timing opties van de server. + Pull Instellingen + DNS + DNS Instellingen van Server Overschrijven + Gebruik eigen DNS Servers + Zoekd domein + Primaire DNS server + DNS Server + Secundaire DNS server. Deze wordt gebruikt voor het geval dat de primaire DNS server niet bereikbaar is + Backup DNS server + Negeer ontvangen routes + Negeer routes ontvangen van de server. + Leid al het Verkeer over de VPN + Gebruik standaard Route + Eigen routes + Geverifieerde pakketen zijn vanuit elk IP toegestaan + Zwevende server toestaan + Aangepaste Opties + VPN Instellingen Bewerken + "Fout:" + Leeg maken + info + Details van de verbinding weergeven + Laatste interfaceconfiguratie van OpenVPN: + Lokaal IPv4: %1$s/%2$d IPv6: %3$s MTU: %4$d + DNS Server: %s + DNS Domein: %s + Routes: %s + Routes IPv6: %s + %1$s %2$s + Logboek verzenden + Verzenden + Tap mode + De VPN API van Android werkt zonder rooten van de telefoon en ondersteunt alleen de tun modus. Daarom is de tap modus niet mogelijk met deze app. + configuratie bestand importeren + Beveiligingsoverwegingen + Importeren + Fout bij het weergeven van de certificaat selectie + IPv4 + IPv6 + Wachten op status bericht… + Geïmporteerd profiel + Geïmporteerd profiel %d + Niet Werkende Afbeeldingen + De gebruikersnaam moet niet leeg zijn. + PKCS12 Bestand Encryptie Sleutel + Privé Sleutel Wachtwoord + Wachtwoord + bestands pictogram + TLS Verificatie + Gegenereerde Configuratie + Algemene Instellingen + IP en DNS + -- cgit v1.2.3 From 626b32fba7b6b45bead3b79fb7e7aa6cddc5c535 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:07:39 -0600 Subject: Add ProgressDialog to ConfigurationWizard while downloading from provider --- res/values/strings.xml | 4 ++++ src/se/leap/leapclient/ConfigurationWizard.java | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index ed32f61..0efa941 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -271,6 +271,10 @@ Log In Log Out Trust completely + Configuring LEAP provider + Downloading provider configuration + Downloading service definitions + Downloading authentication certificates Error parsing provider\'s responses! Success! diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 389c291..164b1d4 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -17,6 +17,7 @@ import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.app.ProgressDialog; import android.content.Intent; import android.content.res.AssetManager; import android.os.Bundle; @@ -34,6 +35,7 @@ public class ConfigurationWizard extends Activity */ private boolean mTwoPane; private ProviderItem mSelectedProvider; + private ProgressDialog mProgressDialog; private Intent mConfigState = new Intent(); protected static final String PROVIDER_SET = "PROVIDER SET"; @@ -81,9 +83,11 @@ public class ConfigurationWizard extends Activity } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); mConfigState.putExtra(SERVICES_RETRIEVED, true); downloadAnonCert(); } else { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); setResult(RESULT_OK); finish(); @@ -105,28 +109,33 @@ public class ConfigurationWizard extends Activity mConfigState.setAction(PROVIDER_SET); + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); downloadJSONFiles(mSelectedProvider); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); + mProgressDialog.dismiss(); Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); setResult(RESULT_CANCELED, mConfigState); finish(); } } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); @@ -146,6 +155,7 @@ public class ConfigurationWizard extends Activity ProviderItem provider = preseeded_providers_iterator.next(); if(provider.id.equalsIgnoreCase(id)) { + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); mSelectedProvider = provider; saveProviderJson(mSelectedProvider); } @@ -192,6 +202,7 @@ public class ConfigurationWizard extends Activity ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, current_provider_item.danger_on); + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); downloadJSONFiles(mSelectedProvider); } } catch (JSONException e) { -- cgit v1.2.3 From 769344327d5cb16adbdc04db224ff6902b4a4771 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:27:25 -0600 Subject: Better config/partial config handling in Dashboard --- res/values/strings.xml | 4 ++++ src/se/leap/leapclient/Dashboard.java | 30 +++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 0efa941..4501ac1 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -271,6 +271,10 @@ Log In Log Out Trust completely + Configuration Error + Configure + Exit + There was an error configuring LEAP with your chosen provider.\n\nYou may choose to reconfigure, or exit and configure a provider upon next launch. Configuring LEAP provider Downloading provider configuration Downloading service definitions diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index de7946e..6bdd74d 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -13,10 +13,12 @@ import se.leap.leapclient.R.menu; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; +import android.app.AlertDialog; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; @@ -58,10 +60,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! - if (!preferences.contains("provider") ) - startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); - else + if (preferences.contains("provider") && preferences.getString(ConfigHelper.PROVIDER_KEY, null) != null) buildDashboard(); + else + startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); } @Override @@ -73,8 +75,26 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf buildDashboard(); } else { - // Something went wrong... TODO figure out what - // TODO Error dialog + // Something went wrong in configuration + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); + alertBuilder.setTitle(getResources().getString(R.string.setup_error_title)); + alertBuilder + .setMessage(getResources().getString(R.string.setup_error_text)) + .setCancelable(false) + .setPositiveButton(getResources().getString(R.string.setup_error_configure_button), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivityForResult(new Intent(getAppContext(),ConfigurationWizard.class),CONFIGURE_LEAP); + } + }) + .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences.Editor prefsEdit = getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE).edit(); + prefsEdit.remove(ConfigHelper.PROVIDER_KEY).commit(); + finish(); + } + }); } } } -- cgit v1.2.3 From 8acc7febb78c5a6480aa0b326e9464592e792097 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:44:01 -0600 Subject: Fixed onPrepareOptionsMenu to not return prematurely. Also implements ConfigHelper.getJsonFromSharedPref(), now --- src/se/leap/leapclient/Dashboard.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 6bdd74d..f72af80 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -145,21 +145,19 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public boolean onPrepareOptionsMenu(Menu menu) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); + JSONObject provider_json; try { - JSONObject provider_json = new JSONObject(provider_json_string); + provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); if(service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY)) { menu.findItem(R.id.login_button).setVisible(true); menu.findItem(R.id.logout_button).setVisible(true); - return true; } } catch (JSONException e) { - menu.findItem(R.id.login_button).setVisible(false); - menu.findItem(R.id.logout_button).setVisible(false); - return false; - } - return false; + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; } @Override -- cgit v1.2.3 From e581c6f2c1844d5dd96b12413df91dbb06102282 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:50:07 -0600 Subject: Clean up some unused and some formatting --- src/se/leap/leapclient/ConfigurationWizard.java | 10 +--------- src/se/leap/leapclient/Dashboard.java | 5 +---- src/se/leap/leapclient/LeapSRPSession.java | 2 -- src/se/leap/leapclient/LogInDialog.java | 3 --- src/se/leap/leapclient/NewProviderDialog.java | 3 --- src/se/leap/leapclient/Provider.java | 3 ++- src/se/leap/leapclient/ProviderListFragment.java | 3 --- 7 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 164b1d4..69f7356 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -10,8 +10,6 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.ProviderListContent.ProviderItem; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -26,14 +24,8 @@ import android.view.View; import android.widget.Toast; public class ConfigurationWizard extends Activity - implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { +implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { - - /** - * Whether or not the activity is in two-pane mode, i.e. running on a tablet - * device. - */ - private boolean mTwoPane; private ProviderItem mSelectedProvider; private ProgressDialog mProgressDialog; private Intent mConfigState = new Intent(); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index f72af80..c1f4697 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -7,9 +7,6 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; -import se.leap.leapclient.R.menu; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; @@ -116,7 +113,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private void serviceItemEIP() { // FIXME Provider service (eip/openvpn) - View eipOverview = ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); + ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); // Set our EIP type title eipTypeTV = (TextView) findViewById(R.id.eipType); diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 47dff27..8eb28c4 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -7,9 +7,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.jboss.security.Util; -import org.jboss.security.srp.SRPClientSession; import org.jboss.security.srp.SRPParameters; -import org.jboss.security.srp.SRPPermission; public class LeapSRPSession { diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 2688967..c20413d 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -1,9 +1,6 @@ package se.leap.leapclient; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; -import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 07185b4..60ac8d2 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -1,9 +1,6 @@ package se.leap.leapclient; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; -import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index f86bbf5..50bd292 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -11,6 +11,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import android.content.Context; import android.app.Activity; import android.content.SharedPreferences; @@ -67,7 +68,7 @@ public final class Provider implements Serializable { //preferences = context.getgetPreferences(0); // 0 == MODE_PRIVATE, but we don't extend Android's classes... // Load SharedPreferences - preferences = activity.getSharedPreferences(ConfigHelper.PREFERENCES_KEY,0); // We don't get MODE_PRIVATE by importing SharedPreferences; i guess it's in Activity? + preferences = activity.getSharedPreferences(ConfigHelper.PREFERENCES_KEY,Context.MODE_PRIVATE); // Inflate our provider.json data try { definition = new JSONObject( preferences.getString("provider", "") ); diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index 4316e9f..ee3ee8e 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -2,9 +2,6 @@ package se.leap.leapclient; import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.Activity; -import android.app.DialogFragment; -import android.app.Fragment; -import android.app.FragmentTransaction; import android.app.ListFragment; import android.os.Bundle; import android.view.LayoutInflater; -- cgit v1.2.3 From 1559bc45048fb877d45247f1aa9b51ee3632a3b8 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 23:07:36 -0600 Subject: Rearrange if/elseif statements in ConfigurationWizard for logical sequence readability --- src/se/leap/leapclient/ConfigurationWizard.java | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 69f7356..2a9b93b 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -73,23 +73,6 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn .replace(R.id.configuration_wizard_layout, providerList, "providerlist") .commit(); } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { - if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ - mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); - mConfigState.putExtra(SERVICES_RETRIEVED, true); - downloadAnonCert(); - } else { - mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); - setResult(RESULT_OK); - finish(); - } - } - else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); - setResult(RESULT_CANCELED, mConfigState); - finish(); - } else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { JSONObject provider_json; try { @@ -119,6 +102,23 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn setResult(RESULT_CANCELED, mConfigState); finish(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); + mConfigState.putExtra(SERVICES_RETRIEVED, true); + downloadAnonCert(); + } else { + mProgressDialog.dismiss(); + Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); + setResult(RESULT_OK); + finish(); + } + } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + setResult(RESULT_CANCELED, mConfigState); + finish(); + } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); -- cgit v1.2.3 From 57ac2c271561fe9f1255109733f5daae06e9234c Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 23:12:49 -0600 Subject: More changes to calls for SharedPreferences via ConfigHelper methods --- src/se/leap/leapclient/LeapHttpClient.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index a2ee8ad..646f80f 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -9,9 +9,6 @@ import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; -import org.json.JSONException; -import org.json.JSONObject; - import android.content.Context; public class LeapHttpClient extends DefaultHttpClient { @@ -22,16 +19,9 @@ public class LeapHttpClient extends DefaultHttpClient { public static LeapHttpClient getInstance(Context context) { if(client == null) { client = new LeapHttpClient(context); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - String cert_string; - try { - cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); - if(!cert_string.isEmpty()) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); } } return client; -- cgit v1.2.3 From 5d14f128f8da5384e6834008326e435524c8fe33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 10 Jun 2013 18:18:07 +0200 Subject: NullPointer solved. ConfigHelper refactored methods returning nulls instead of empty objects broke LeapHttpClient getInstance implementation, because it checked the emptiness of the object and not if it was null. --- src/se/leap/leapclient/LeapHttpClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 646f80f..3eeebe9 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -20,7 +20,7 @@ public class LeapHttpClient extends DefaultHttpClient { if(client == null) { client = new LeapHttpClient(context); String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - if(!cert_string.isEmpty()) { + if(cert_string != null) { ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); } } -- cgit v1.2.3 From 265a66e66cffacbd2c99f99bebbcec3bf100a546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 10 Jun 2013 18:43:50 +0200 Subject: OpenVPN certificate is downloaded from API_BASE, using api_uri field from provider.json. This fixes bug #2780 --- README | 66 ++++++++++++++++++++++++++++++++- src/se/leap/leapclient/ProviderAPI.java | 4 +- 2 files changed, 67 insertions(+), 3 deletions(-) mode change 120000 => 100644 README diff --git a/README b/README deleted file mode 120000 index c3ca074..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -README.txt \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..7d57a6e --- /dev/null +++ b/README @@ -0,0 +1,65 @@ +Compiling +========= + +Preconditions +---------------- + +1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) +2. API version 16 or version installed. +2. Ant 1.6 or greater + +Instructions to compile +----------------------- + +1. cd $PROJECT_LOCATION/leap_android +2. ./compile.sh + +Postconditions +-------------- + +1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists + +Running on the emulator +========================= + +Preconditions +----------------- + +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) + +Instructions to run on the emulator +----------------------------------- + +1. cd $PROJECT_LOCATION/leap_android +1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). + +Postconditions +-------------- + +1. LEAP Android is running. + +Debugging from console +====================== + +Preconditions +----------------- + +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). +4. jdb is installed (this program is part of OpenJDK 7) + +Instructions to debug from the console +----------------------------------- + +1. cd $PROJECT_LOCATION/leap_android +2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). + +Postconditions +-------------- + +1. LEAP Android is running. +2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". +3. You are in a jdb debuggin session. diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index cd19da0..a51c3a0 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -423,8 +423,8 @@ public class ProviderAPI extends IntentService { String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); - URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY).replace("api.", "")); - String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; + URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY)); + String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; if(type_of_certificate.equalsIgnoreCase(ConfigHelper.AUTHED_CERTIFICATE)) { HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); -- cgit v1.2.3 From 1e2470b1e940877f6fe247a65bccd2b62b621eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 10 Jun 2013 18:56:34 +0200 Subject: Removed unused methods and variables. Variables from LeapSRPSession were there because I used it while testing srp calculations, comparing that strings with the ones from javascript. Unused method from ProviderAPI was there because I foresee I'll have to implement it in the future, but I've removed it since it's already in the history. This fixes #2781. --- README | 66 +----------------------------- src/se/leap/leapclient/LeapSRPSession.java | 6 --- src/se/leap/leapclient/ProviderAPI.java | 12 ------ 3 files changed, 1 insertion(+), 83 deletions(-) mode change 100644 => 120000 README diff --git a/README b/README deleted file mode 100644 index 7d57a6e..0000000 --- a/README +++ /dev/null @@ -1,65 +0,0 @@ -Compiling -========= - -Preconditions ----------------- - -1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) -2. API version 16 or version installed. -2. Ant 1.6 or greater - -Instructions to compile ------------------------ - -1. cd $PROJECT_LOCATION/leap_android -2. ./compile.sh - -Postconditions --------------- - -1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists - -Running on the emulator -========================= - -Preconditions ------------------ - -1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. -3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) - -Instructions to run on the emulator ------------------------------------ - -1. cd $PROJECT_LOCATION/leap_android -1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). - -Postconditions --------------- - -1. LEAP Android is running. - -Debugging from console -====================== - -Preconditions ------------------ - -1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. -3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). -4. jdb is installed (this program is part of OpenJDK 7) - -Instructions to debug from the console ------------------------------------ - -1. cd $PROJECT_LOCATION/leap_android -2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). - -Postconditions --------------- - -1. LEAP Android is running. -2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". -3. You are in a jdb debuggin session. diff --git a/README b/README new file mode 120000 index 0000000..c3ca074 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.txt \ No newline at end of file diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 8eb28c4..0a8e735 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -173,7 +173,6 @@ public class LeapSRPSession { // Calculate x = H(s | H(U | ':' | password)) byte[] xb = calculatePasswordHash(username, password, Util.trim(salt_bytes)); this.x = new BigInteger(1, xb); - String xstr = x.toString(16); // Calculate v = kg^x mod N String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; @@ -210,7 +209,6 @@ public class LeapSRPSession { // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); byte[] S_bytes = Util.trim(S.toByteArray()); - String Sstr = S.toString(16); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; @@ -219,10 +217,8 @@ public class LeapSRPSession { // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); - String Kstr = new BigInteger(1, K).toString(16); byte[] M1 = Util.trim(clientHash.digest()); - String M1str = new BigInteger(1, M1).toString(16); // serverHash = Astr + M + K serverHash.update(Abytes); @@ -246,9 +242,7 @@ public class LeapSRPSession { BigInteger u = new BigInteger(1, u_bytes); BigInteger B_minus_v = B.subtract(v); - String vstr = v.toString(16); BigInteger a_ux = a.add(u.multiply(x)); - String xstr = x.toString(16); BigInteger S = B_minus_v.modPow(a_ux, N); return S; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index a51c3a0..0898ebb 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -125,18 +125,6 @@ public class ProviderAPI extends IntentService { return false; } } - - private boolean registerWithSRP(Bundle task) { - String username = (String) task.get(ConfigHelper.USERNAME_KEY); - String password = (String) task.get(ConfigHelper.PASSWORD_KEY); - String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); - - BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); - BigInteger salt = ng_1024.probablePrime(1024, null); - byte[] salt_in_bytes = salt.toByteArray(); - - return false; - } private Bundle authenticateBySRP(Bundle task) { Bundle session_id_bundle = new Bundle(); -- cgit v1.2.3 From 6c90e0043ec68254c15562fd12a707f5e45f47e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 11 Jun 2013 19:01:36 +0200 Subject: We are not using SD storage anymore. We were using it to save certificate and provider.json files from chosen provider, so that exporting them was easily done. We don't need that files, because if we wanted to export that files we would be able to recover them easily and updated. This fixes #2783 --- AndroidManifest.xml | 5 +---- src/se/leap/leapclient/ConfigHelper.java | 20 -------------------- src/se/leap/leapclient/ProviderAPI.java | 2 -- 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 56ca7d4..68a1ef1 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -22,10 +22,7 @@ - - - @@ -158,4 +155,4 @@ - \ No newline at end of file + diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index e8bc27c..11f9504 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -156,26 +156,6 @@ public class ConfigHelper { return value; } - public static void saveFile(String filename, String content) { - File root = Environment.getExternalStorageDirectory(); - File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); - if (!leap_dir.isDirectory()) { - leap_dir.mkdir(); - } - try { - if (!leap_dir.isDirectory()) { - throw new IOException( - "Unable to create directory " + USER_DIRECTORY + ". Maybe the SD card is mounted?"); - } - File outputFile = new File(leap_dir, filename); - BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); - writer.write(content); - writer.close(); - } catch (IOException e) { - Log.w("leap_android", e.getMessage(), e); - } - } - public static FileInputStream openFileInputStream(String filename) { FileInputStream input_stream = null; File root = Environment.getExternalStorageDirectory(); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0898ebb..10f04c5 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -217,7 +217,6 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); result.putBoolean(ConfigHelper.RESULT_KEY, true); @@ -243,7 +242,6 @@ public class ProviderAPI extends IntentService { provider_json = getJSONFromProvider(provider_json_url, danger_on); String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); return true; -- cgit v1.2.3 From 2f69eb6eb9aa3993354e8de295df68558ab7b71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 12 Jun 2013 18:51:44 +0200 Subject: Removed some unnecessary libraries. I've also removed some unnecessary comments from LeapHttpClient. --- libs/bcprov-ext-jdk15on-146.jar | Bin 1825975 -> 0 bytes libs/jboss-common-client.jar | Bin 399031 -> 0 bytes src/se/leap/leapclient/LeapHttpClient.java | 10 +--------- 3 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 libs/bcprov-ext-jdk15on-146.jar delete mode 100644 libs/jboss-common-client.jar diff --git a/libs/bcprov-ext-jdk15on-146.jar b/libs/bcprov-ext-jdk15on-146.jar deleted file mode 100644 index 7d8a22e..0000000 Binary files a/libs/bcprov-ext-jdk15on-146.jar and /dev/null differ diff --git a/libs/jboss-common-client.jar b/libs/jboss-common-client.jar deleted file mode 100644 index af5fb00..0000000 Binary files a/libs/jboss-common-client.jar and /dev/null differ diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 3eeebe9..00ee15e 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -31,23 +31,15 @@ public class LeapHttpClient extends DefaultHttpClient { 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 = ConfigHelper.getKeystore(); - - // 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.ALLOW_ALL_HOSTNAME_VERIFIER); return sf; -- cgit v1.2.3 From 30c7bab5d8618df665e602fdd08bafa010a15497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 13 Jun 2013 17:37:37 +0200 Subject: bitmask json files are downloaded. There was a problem on the assets file "bitmask.url". It had an error in the eip-service url. We should use this file only for main url, and proceed as if it were a new provider but with a preseeded main url. --- README | 66 ++++++++++++++++++++++++- assets/urls/bitmask.url | 3 +- src/se/leap/leapclient/ConfigHelper.java | 1 - src/se/leap/leapclient/ConfigurationWizard.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 18 +++---- src/se/leap/leapclient/ProviderListContent.java | 17 ++----- 6 files changed, 79 insertions(+), 30 deletions(-) mode change 120000 => 100644 README diff --git a/README b/README deleted file mode 120000 index c3ca074..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -README.txt \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..7d57a6e --- /dev/null +++ b/README @@ -0,0 +1,65 @@ +Compiling +========= + +Preconditions +---------------- + +1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) +2. API version 16 or version installed. +2. Ant 1.6 or greater + +Instructions to compile +----------------------- + +1. cd $PROJECT_LOCATION/leap_android +2. ./compile.sh + +Postconditions +-------------- + +1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists + +Running on the emulator +========================= + +Preconditions +----------------- + +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) + +Instructions to run on the emulator +----------------------------------- + +1. cd $PROJECT_LOCATION/leap_android +1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). + +Postconditions +-------------- + +1. LEAP Android is running. + +Debugging from console +====================== + +Preconditions +----------------- + +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). +4. jdb is installed (this program is part of OpenJDK 7) + +Instructions to debug from the console +----------------------------------- + +1. cd $PROJECT_LOCATION/leap_android +2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). + +Postconditions +-------------- + +1. LEAP Android is running. +2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". +3. You are in a jdb debuggin session. diff --git a/assets/urls/bitmask.url b/assets/urls/bitmask.url index bc4d59d..910f040 100644 --- a/assets/urls/bitmask.url +++ b/assets/urls/bitmask.url @@ -3,6 +3,5 @@ "assets_json_provider" : "providers/bitmask.net_provider.json", "json_provider" : "https://bitmask.net/provider.json", "cert" : "https://bitmask.net/ca.crt", - "json_eip_service_antiguo" : "https://api.bitmask.net:4430/1/config/eip-service.json", - "json_eip_service" : "https://api.bitmask.net:4430/config/eip-service.json" + "json_eip_service" : "https://api.bitmask.net:4430/1/config/eip-service.json" } \ No newline at end of file diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 11f9504..0e50c7d 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -192,7 +192,6 @@ public class ConfigHelper { public static void addTrustedCertificate(String provider, String certificate) { String filename_to_save = provider + "_certificate.cer"; - saveFile(filename_to_save, certificate); CertificateFactory cf; try { cf = CertificateFactory.getInstance("X.509"); diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 2a9b93b..1dc0093 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -80,8 +80,8 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn boolean danger_on = resultData.getBoolean(ConfigHelper.DANGER_ON); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getBoolean(ConfigHelper.ALLOWED_ANON)); - + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); + mConfigState.setAction(PROVIDER_SET); mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 10f04c5..471eb6c 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -216,9 +216,7 @@ public class ProviderAPI extends IntentService { } else { ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); result.putBoolean(ConfigHelper.RESULT_KEY, true); result.putString(ConfigHelper.PROVIDER_KEY, provider_json.toString()); result.putBoolean(ConfigHelper.DANGER_ON, danger_on); @@ -237,17 +235,17 @@ public class ProviderAPI extends IntentService { String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); - JSONObject provider_json = null; + + JSONObject provider_json; try { provider_json = getJSONFromProvider(provider_json_url, danger_on); - - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); - return true; + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); } catch (JSONException e) { - return false; + // TODO Auto-generated catch block + e.printStackTrace(); } + + return true; } private String getStringFromProviderWithoutValidate( diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index b83bbd8..10dce57 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -1,6 +1,5 @@ package se.leap.leapclient; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -78,21 +77,14 @@ public class ProviderListContent { } } - public ProviderItem(String name, String provider_json_url, String provider_json_filename, boolean custom, boolean danger_on) { + public ProviderItem(String name, String provider_json_url, JSONObject provider_json, boolean custom, boolean danger_on) { - - FileInputStream provider_json = ConfigHelper.openFileInputStream(provider_json_filename); try { - byte[] urls_file_bytes = new byte[provider_json.available()]; - provider_json.read(urls_file_bytes); - String urls_file_content = new String(urls_file_bytes); - JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; this.provider_json_url = provider_json_url; - this.provider_json_filename = provider_json_filename; - eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; - cert_json_url = (String) file_contents.get("ca_cert_uri"); + eip_service_json_url = provider_json.getString("api_uri") + "/" + provider_json.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; + cert_json_url = (String) provider_json.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; if(custom) @@ -100,9 +92,6 @@ public class ProviderListContent { } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } } -- cgit v1.2.3 From a4e731679c3e28eefd839da45b76130a0de29112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 13 Jun 2013 18:21:13 +0200 Subject: Login is working OK. I removed a library that was not directly used by my code, but for one of the libraries that I needed. --- README | 66 +------------------------------------------ libs/jboss-common-client.jar | Bin 0 -> 399031 bytes 2 files changed, 1 insertion(+), 65 deletions(-) mode change 100644 => 120000 README create mode 100644 libs/jboss-common-client.jar diff --git a/README b/README deleted file mode 100644 index 7d57a6e..0000000 --- a/README +++ /dev/null @@ -1,65 +0,0 @@ -Compiling -========= - -Preconditions ----------------- - -1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) -2. API version 16 or version installed. -2. Ant 1.6 or greater - -Instructions to compile ------------------------ - -1. cd $PROJECT_LOCATION/leap_android -2. ./compile.sh - -Postconditions --------------- - -1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists - -Running on the emulator -========================= - -Preconditions ------------------ - -1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. -3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) - -Instructions to run on the emulator ------------------------------------ - -1. cd $PROJECT_LOCATION/leap_android -1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). - -Postconditions --------------- - -1. LEAP Android is running. - -Debugging from console -====================== - -Preconditions ------------------ - -1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. -3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). -4. jdb is installed (this program is part of OpenJDK 7) - -Instructions to debug from the console ------------------------------------ - -1. cd $PROJECT_LOCATION/leap_android -2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). - -Postconditions --------------- - -1. LEAP Android is running. -2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". -3. You are in a jdb debuggin session. diff --git a/README b/README new file mode 120000 index 0000000..c3ca074 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.txt \ No newline at end of file diff --git a/libs/jboss-common-client.jar b/libs/jboss-common-client.jar new file mode 100644 index 0000000..af5fb00 Binary files /dev/null and b/libs/jboss-common-client.jar differ -- cgit v1.2.3 From bffd21a326bcb86d814dd3fe2caf5295ea705f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 13 Jun 2013 21:12:24 +0200 Subject: Bypasses self signed certificates. It's working against cdev.bitmask.net and bitmask.net. Look at #2840 for further explanation about self signed certificates. I've also removed some file dependant configuration (when a provider was custom, ConfigurationWizard still tried to read from file a provider.json that now I store in memory via ProviderItem class). --- src/se/leap/leapclient/ConfigurationWizard.java | 3 +- src/se/leap/leapclient/ProviderAPI.java | 126 +++++++++++++++++------- src/se/leap/leapclient/ProviderListContent.java | 2 + 3 files changed, 94 insertions(+), 37 deletions(-) diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 1dc0093..6f26adc 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -188,8 +188,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn // FIXME!! We should we be updating our seeded providers list at ConfigurationWizard onStart() ? // I think yes, but if so, where does this list live? leap.se, as it's the non-profit project for the software? // If not, we should just be getting names/urls, and fetching the provider.json like in custom entries - provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_contents); + provider_json = current_provider_item.provider_json; ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, current_provider_item.danger_on); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 471eb6c..f98e436 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -26,6 +26,8 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -247,34 +249,6 @@ public class ProviderAPI extends IntentService { return true; } - - private String getStringFromProviderWithoutValidate( - URL provider_json_url) { - - String json_string = ""; - HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - // Tell the URLConnection to use our HostnameVerifier - try { - HttpsURLConnection urlConnection = - (HttpsURLConnection)provider_json_url.openConnection(); - urlConnection.setHostnameVerifier(hostnameVerifier); - json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - json_string = getStringFromProviderWithCACertAdded(provider_json_url); - //e.printStackTrace(); - } - return json_string; - } private String getStringFromProvider(String string_url, boolean danger_on) { @@ -307,25 +281,56 @@ public class ProviderAPI extends IntentService { return json_file_content; } + private String getStringFromProviderWithoutValidate( + URL provider_json_url) { + + String json_string = ""; + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + try { + HttpsURLConnection urlConnection = + (HttpsURLConnection)provider_json_url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + json_string = getStringFromProviderWithCACertAdded(provider_json_url); + //e.printStackTrace(); + } + + return json_string; + } + private String getStringFromProviderWithCACertAdded(URL url) { String json_file_content = ""; - + // Load CAs from an InputStream // (could be from a resource or ByteArrayInputStream or ...) + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + if(cert_string.isEmpty()) { + cert_string = downloadCertificateWithoutTrusting(url.getProtocol() + "://" + url.getHost() + "/" + "ca.crt"); + ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); + } CertificateFactory cf; try { cf = CertificateFactory.getInstance("X.509"); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); java.security.cert.Certificate ca; try { - ca = cf.generateCertificate(caInput); - System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); + ca = cf.generateCertificate(caInput); + System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); } finally { - caInput.close(); + caInput.close(); } // Create a KeyStore containing our trusted CAs @@ -345,7 +350,7 @@ public class ProviderAPI extends IntentService { // Tell the URLConnection to use a SocketFactory from our SSLContext HttpsURLConnection urlConnection = - (HttpsURLConnection)url.openConnection(); + (HttpsURLConnection)url.openConnection(); urlConnection.setSSLSocketFactory(context.getSocketFactory()); json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (CertificateException e) { @@ -364,10 +369,61 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - return json_file_content; } + private String downloadCertificateWithoutTrusting(String certificate_url_string) { + + String cert_string = ""; + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + 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) { + } + } + }; + + try { + URL certificate_url = new URL(certificate_url_string); + HttpsURLConnection urlConnection = + (HttpsURLConnection)certificate_url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + + SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + + urlConnection.setSSLSocketFactory(sc.getSocketFactory()); + + cert_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // This should never happen + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return cert_string; + } + private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { String json_file_content = getStringFromProvider(json_url, danger_on); return new JSONObject(json_file_content); diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 10dce57..4cf0a5f 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -40,6 +40,7 @@ public class ProviderListContent { public String id; public String name; public String provider_json_url; + public JSONObject provider_json; public String provider_json_filename; public String eip_service_json_url; public String cert_json_url; @@ -83,6 +84,7 @@ public class ProviderListContent { id = name; this.name = name; this.provider_json_url = provider_json_url; + this.provider_json = provider_json; eip_service_json_url = provider_json.getString("api_uri") + "/" + provider_json.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; cert_json_url = (String) provider_json.get("ca_cert_uri"); this.custom = custom; -- cgit v1.2.3 From d475ae617d8dc0994a1294be7c8cca338a68fd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 19 Jun 2013 19:05:12 +0200 Subject: First round of comments. This resolves the first step from issue #2908. Next step: Put user message strings into an appropiate place. --- README | 66 ++++++++++- src/se/leap/leapclient/ConfigHelper.java | 59 +++++++++- src/se/leap/leapclient/ConfigurationWizard.java | 63 ++++++++--- src/se/leap/leapclient/Dashboard.java | 11 ++ src/se/leap/leapclient/LeapHttpClient.java | 17 +++ src/se/leap/leapclient/LeapSRPSession.java | 19 +++- src/se/leap/leapclient/LogInDialog.java | 31 +++++- src/se/leap/leapclient/NewProviderDialog.java | 15 +++ src/se/leap/leapclient/ProviderAPI.java | 121 ++++++++++++++++++++- .../leap/leapclient/ProviderAPIResultReceiver.java | 12 +- src/se/leap/leapclient/ProviderListContent.java | 44 ++++---- 11 files changed, 409 insertions(+), 49 deletions(-) mode change 120000 => 100644 README diff --git a/README b/README deleted file mode 120000 index c3ca074..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -README.txt \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..7d57a6e --- /dev/null +++ b/README @@ -0,0 +1,65 @@ +Compiling +========= + +Preconditions +---------------- + +1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) +2. API version 16 or version installed. +2. Ant 1.6 or greater + +Instructions to compile +----------------------- + +1. cd $PROJECT_LOCATION/leap_android +2. ./compile.sh + +Postconditions +-------------- + +1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists + +Running on the emulator +========================= + +Preconditions +----------------- + +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) + +Instructions to run on the emulator +----------------------------------- + +1. cd $PROJECT_LOCATION/leap_android +1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). + +Postconditions +-------------- + +1. LEAP Android is running. + +Debugging from console +====================== + +Preconditions +----------------- + +1. Android SDK is installed, and its tools are in the PATH. +2. leap_android has been compiled. +3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). +4. jdb is installed (this program is part of OpenJDK 7) + +Instructions to debug from the console +----------------------------------- + +1. cd $PROJECT_LOCATION/leap_android +2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). + +Postconditions +-------------- + +1. LEAP Android is running. +2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". +3. You are in a jdb debuggin session. diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 0e50c7d..5838f52 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,10 +1,8 @@ package se.leap.leapclient; -import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileWriter; import java.io.IOException; import java.math.BigInteger; import java.io.InputStream; @@ -21,8 +19,14 @@ import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; -import android.util.Log; +/** + * Stores constants, and implements auxiliary methods used across all LEAP Android classes. + * + * @author parmegv + * @author MeanderingCode + * + */ public class ConfigHelper { public static SharedPreferences shared_preferences; @@ -100,6 +104,11 @@ public class ConfigHelper { return true; } + /** + * Saves a JSON object into class scope Shared Preferences + * @param shared_preferences_key + * @param content + */ public static void saveSharedPref(String shared_preferences_key, JSONObject content) { SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -109,6 +118,11 @@ public class ConfigHelper { shared_preferences_editor.commit(); } + /** + * Saves a String object into class scope Shared Preferences + * @param shared_preferences_key + * @param content + */ public static void saveSharedPref(String shared_preferences_key, String content) { SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -117,7 +131,12 @@ public class ConfigHelper { content); shared_preferences_editor.commit(); } - + + /** + * Saves a boolean object into class scope Shared Preferences + * @param shared_preferences_key + * @param content + */ public static void saveSharedPref(String shared_preferences_key, boolean content) { SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -126,6 +145,11 @@ public class ConfigHelper { shared_preferences_editor.commit(); } + /** + * Gets String object from class scope Shared Preferences + * @param shared_preferences_key + * @return the string correspondent to the key parameter + */ public static String getStringFromSharedPref(String shared_preferences_key) { String content = null; if ( checkSharedPrefs() ) { @@ -134,6 +158,11 @@ public class ConfigHelper { return content; } + /** + * Gets JSON object from class scope Shared Preferences + * @param shared_preferences_key + * @return the JSON object correspondent to the key parameter + */ public static JSONObject getJsonFromSharedPref(String shared_preferences_key) throws JSONException { JSONObject content = null; if ( checkSharedPrefs() ) { @@ -156,6 +185,11 @@ public class ConfigHelper { return value; } + /** + * Opens a FileInputStream from the user directory of the external storage directory. + * @param filename + * @return a file input stream + */ public static FileInputStream openFileInputStream(String filename) { FileInputStream input_stream = null; File root = Environment.getExternalStorageDirectory(); @@ -169,11 +203,20 @@ public class ConfigHelper { return input_stream; } + /** + * Sets class scope Shared Preferences + * @param shared_preferences + */ public static void setSharedPreferences( SharedPreferences shared_preferences) { ConfigHelper.shared_preferences = shared_preferences; } + /** + * Adds a new X509 certificate given its input stream and its provider name + * @param provider used to store the certificate in the keystore + * @param inputStream from which X509 certificate must be generated. + */ public static void addTrustedCertificate(String provider, InputStream inputStream) { CertificateFactory cf; try { @@ -190,6 +233,11 @@ public class ConfigHelper { } } + /** + * Adds a new X509 certificate given in its string from and using its provider name + * @param provider used to store the certificate in the keystore + * @param certificate + */ public static void addTrustedCertificate(String provider, String certificate) { String filename_to_save = provider + "_certificate.cer"; CertificateFactory cf; @@ -217,6 +265,9 @@ public class ConfigHelper { } } + /** + * @return class wide keystore + */ public static KeyStore getKeystore() { return keystore_trusted; } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 6f26adc..91b92d6 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -2,7 +2,6 @@ package se.leap.leapclient; import java.io.IOException; import java.util.Iterator; -import java.util.Scanner; import org.json.JSONException; import org.json.JSONObject; @@ -23,6 +22,14 @@ import android.os.Handler; import android.view.View; import android.widget.Toast; +/** + * Activity that builds and shows the list of known available providers. + * + * It also allows the user to enter custom providers with a button. + * + * @author parmegv + * + */ public class ConfigurationWizard extends Activity implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { @@ -154,6 +161,10 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } + /** + * Loads providers data from url file contained in the project + * @return true if the file was read correctly + */ private boolean loadPreseededProviders() { boolean loaded_preseeded_providers = false; AssetManager asset_manager = getAssets(); @@ -178,20 +189,26 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn return loaded_preseeded_providers; } - private void saveProviderJson(ProviderItem current_provider_item) { + /** + * Saves provider.json file associated with provider. + * + * If the provider is custom, the file has already been downloaded so we load it from memory. + * If not, the file is updated using the provider's URL. + * @param provider + */ + private void saveProviderJson(ProviderItem provider) { JSONObject provider_json = new JSONObject(); try { - String provider_contents = ""; - if(!current_provider_item.custom) { - updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); + if(!provider.custom) { + updateProviderDotJson(provider.name, provider.provider_json_url, provider.danger_on); } else { // FIXME!! We should we be updating our seeded providers list at ConfigurationWizard onStart() ? // I think yes, but if so, where does this list live? leap.se, as it's the non-profit project for the software? // If not, we should just be getting names/urls, and fetching the provider.json like in custom entries - provider_json = current_provider_item.provider_json; + provider_json = provider.provider_json; ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); - ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, current_provider_item.danger_on); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, provider.danger_on); mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); downloadJSONFiles(mSelectedProvider); @@ -202,15 +219,21 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } - private void downloadJSONFiles(ProviderItem current_provider_item) { + /** + * Asks ProviderAPI to download provider site's certificate and eip-service.json + * + * URLs are fetched from the provider parameter + * @param provider from which certificate and eip-service.json files are going to be downloaded + */ + private void downloadJSONFiles(ProviderItem provider) { Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.PROVIDER_KEY, current_provider_item.name); - method_and_parameters.putString(ConfigHelper.MAIN_CERT_KEY, current_provider_item.cert_json_url); - method_and_parameters.putString(ConfigHelper.EIP_SERVICE_KEY, current_provider_item.eip_service_json_url); - method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, current_provider_item.danger_on); + method_and_parameters.putString(ConfigHelper.PROVIDER_KEY, provider.name); + method_and_parameters.putString(ConfigHelper.MAIN_CERT_KEY, provider.cert_json_url); + method_and_parameters.putString(ConfigHelper.EIP_SERVICE_KEY, provider.eip_service_json_url); + method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, provider.danger_on); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); @@ -218,7 +241,10 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn startService(provider_API_command); } - private boolean downloadAnonCert() { + /** + * Asks ProviderAPI to download an anonymous (anon) VPN certificate. + */ + private void downloadAnonCert() { Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); @@ -229,9 +255,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); - return true; } + /** + * Open the new provider dialog + * @param view from which the dialog is showed + */ public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); @@ -258,6 +287,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn startService(provider_API_command); } + /** + * Asks ProviderAPI to download a new provider.json file + * @param provider_name + * @param provider_json_url + * @param danger_on tells if HTTPS client should bypass certificate errors + */ public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { Intent provider_API_command = new Intent(this, ProviderAPI.class); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index c1f4697..e8ea270 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -229,6 +229,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(provider_API_command); } + /** + * Asks ProviderAPI to log out. + */ public void logOut() { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -251,6 +254,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(provider_API_command); } + /** + * Shows the log in dialog. + * @param view from which the dialog is created. + */ public void logInDialog(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); @@ -263,6 +270,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); } + /** + * Asks ProviderAPI to download an authenticated OpenVPN certificate. + * @param session_id cookie for the server to allow us to download the certificate. + */ private void downloadAuthedUserCertificate(Cookie session_id) { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 00ee15e..42f9a52 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -11,11 +11,22 @@ import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; import android.content.Context; +/** + * Implements an HTTP client, enabling LEAP Android app to manage its own runtime keystore or bypass default Android security measures. + * + * @author rafa + * + */ public class LeapHttpClient extends DefaultHttpClient { final Context context; private static LeapHttpClient client; + /** + * If the class scope client is null, it creates one and imports, if existing, the main certificate from Shared Preferences. + * @param context + * @return the new client. + */ public static LeapHttpClient getInstance(Context context) { if(client == null) { client = new LeapHttpClient(context); @@ -36,6 +47,12 @@ public class LeapHttpClient extends DefaultHttpClient { return new SingleClientConnManager(getParams(), registry); } + /** + * Uses keystore from ConfigHelper for the SSLSocketFactory. + * + * Sets hostname verifier to allow all hostname verifier. + * @return + */ private SSLSocketFactory newSslSocketFactory() { try { KeyStore trusted = ConfigHelper.getKeystore(); diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 0a8e735..beb286d 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -9,6 +9,14 @@ import java.util.Arrays; import org.jboss.security.Util; import org.jboss.security.srp.SRPParameters; +/** + * Implements all SRP algorithm logic. + * + * It's derived from JBoss implementation, with adjustments to make it work with LEAP platform. + * + * @author parmegv + * + */ public class LeapSRPSession { private SRPParameters params; @@ -133,7 +141,14 @@ public class LeapSRPSession { return v; } - public byte[] xor(byte[] b1, byte[] b2, int length) + /** + * Calculates the trimmed xor from two BigInteger numbers + * @param b1 the positive source to build first BigInteger + * @param b2 the positive source to build second BigInteger + * @param length + * @return + */ + public byte[] xor(byte[] b1, byte[] b2) { //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa byte[] xor_digest = new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); @@ -185,7 +200,7 @@ public class LeapSRPSession { byte[] digest_of_g = newDigest().digest(params.g); // clientHash = H(N) xor H(g) - byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); + byte[] xor_digest = xor(digest_of_n, digest_of_g); clientHash.update(xor_digest); // clientHash = H(N) xor H(g) | H(U) diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index c20413d..00429d1 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -11,6 +11,16 @@ import android.view.View; import android.widget.EditText; import android.widget.Toast; +/** + * Implements the log in dialog, currently without progress dialog. + * + * It returns to the previous fragment when finished, and sends username and password to the authenticate method. + * + * It also notifies the user if the password is not valid. + * + * @author parmegv + * + */ public class LogInDialog extends DialogFragment { public AlertDialog onCreateDialog(Bundle savedInstanceState) { @@ -43,16 +53,35 @@ public class LogInDialog extends DialogFragment { return builder.create(); } - boolean wellFormedPassword(String entered_password) { + /** + * Validates a password + * @param entered_password + * @return true if the entered password length is greater or equal to eight (8). + */ + private boolean wellFormedPassword(String entered_password) { return entered_password.length() >= 8; } + /** + * Interface used to communicate LogInDialog with Dashboard. + * + * @author parmegv + * + */ public interface LogInDialogInterface { + /** + * Starts authentication process. + * @param username + * @param password + */ public void authenticate(String username, String password); } LogInDialogInterface interface_with_Dashboard; + /** + * @return a new instance of this DialogFragment. + */ public static DialogFragment newInstance() { LogInDialog dialog_fragment = new LogInDialog(); return dialog_fragment; diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 60ac8d2..5b84ec0 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -13,6 +13,12 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.Toast; +/** + * Implements the new custom provider dialog. + * + * @author parmegv + * + */ public class NewProviderDialog extends DialogFragment { public interface NewProviderDialogInterface { @@ -21,6 +27,9 @@ public class NewProviderDialog extends DialogFragment { NewProviderDialogInterface interface_with_ConfigurationWizard; + /** + * @return a new instance of this DialogFragment. + */ public static DialogFragment newInstance() { NewProviderDialog dialog_fragment = new NewProviderDialog(); return dialog_fragment; @@ -37,6 +46,7 @@ public class NewProviderDialog extends DialogFragment { } } + @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); @@ -71,6 +81,11 @@ public class NewProviderDialog extends DialogFragment { return builder.create(); } + /** + * Checks if the entered url is valid or not. + * @param entered_url + * @return true if it's not empty nor contains only the protocol. + */ boolean validURL(String entered_url) { return !entered_url.isEmpty() && entered_url.matches("http[s]?://.+") && !entered_url.replaceFirst("http[s]?://", "").isEmpty(); } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index f98e436..f8d730e 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -55,6 +55,15 @@ import android.os.ResultReceiver; import android.util.Base64; import android.util.Log; +/** + * Implements HTTP api methods used to manage communications with the provider server. + * + * It's an IntentService because it downloads data fromt he Internet, so it operates in the background. + * + * @author parmegv + * @author MeanderingCode + * + */ public class ProviderAPI extends IntentService { public ProviderAPI() { @@ -113,6 +122,11 @@ public class ProviderAPI extends IntentService { } } + /** + * Downloads the main cert and the eip-service.json files given through the task parameter + * @param task + * @return true if eip-service.json was parsed as a JSON object correctly. + */ private boolean downloadJsonFiles(Bundle task) { String cert_url = task.getString(ConfigHelper.MAIN_CERT_KEY); String eip_service_json_url = task.getString(ConfigHelper.EIP_SERVICE_KEY); @@ -128,6 +142,12 @@ public class ProviderAPI extends IntentService { } } + /** + * Starts the authentication process using SRP protocol. + * + * @param task containing: username, password and api url. + * @return a bundle with a boolean value mapped to a key named ConfigHelper.RESULT_KEY, and which is true if authentication was successful. + */ private Bundle authenticateBySRP(Bundle task) { Bundle session_id_bundle = new Bundle(); @@ -168,11 +188,31 @@ public class ProviderAPI extends IntentService { return session_id_bundle; } + /** + * Sends an HTTP POST request to the authentication server with the SRP Parameter A. + * @param server_url + * @param username + * @param clientA First SRP parameter sent + * @return response from authentication server + * @throws ClientProtocolException + * @throws IOException + * @throws JSONException + */ private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); return sendToServer(post); } + /** + * Sends an HTTP PUT request to the authentication server with the SRP Parameter M1 (or simply M). + * @param server_url + * @param username + * @param m1 Second SRP parameter sent + * @return response from authentication server + * @throws ClientProtocolException + * @throws IOException + * @throws JSONException + */ private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16)); JSONObject json_response = sendToServer(put); @@ -188,6 +228,14 @@ public class ProviderAPI extends IntentService { return session_idAndM2; } + /** + * Executes an HTTP request expecting a JSON response. + * @param request + * @return response from authentication server + * @throws ClientProtocolException + * @throws IOException + * @throws JSONException + */ private JSONObject sendToServer(HttpUriRequest request) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); HttpContext localContext = new BasicHttpContext(); @@ -204,6 +252,11 @@ public class ProviderAPI extends IntentService { return json_response; } + /** + * Downloads a provider.json from a given URL, adding a new provider using the given name. + * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. + * @return a bundle with a boolean value mapped to a key named ConfigHelper.RESULT_KEY, and which is true if the update was successful. + */ private Bundle updateProviderDotJSON(Bundle task) { Bundle result = new Bundle(); boolean custom = task.getBoolean(ConfigHelper.CUSTOM); @@ -230,13 +283,18 @@ public class ProviderAPI extends IntentService { return result; } + /** + * Downloads a custom provider provider.json file + * @param task containing a boolean meaning if the user completely trusts this provider, and the provider main url entered in the new custom provider dialog. + * @return true if provider.json file was successfully parsed as a JSON object. + */ private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); - String provider_json_url = guessURL(provider_main_url); + String provider_json_url = guessProviderDotJsonURL(provider_main_url); JSONObject provider_json; try { @@ -245,11 +303,20 @@ public class ProviderAPI extends IntentService { } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); + return false; } return true; } + /** + * Tries to download whatever is pointed by the string_url. + * + * If danger_on flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods. + * @param string_url + * @param danger_on if the user completely trusts this provider + * @return + */ private String getStringFromProvider(String string_url, boolean danger_on) { String json_file_content = ""; @@ -281,8 +348,15 @@ public class ProviderAPI extends IntentService { return json_file_content; } + /** + * Tries to download a string from given url without verifying the hostname. + * + * If a IOException still occurs, it tries with another bypass method: getStringFromProviderWithCACertAdded. + * @param string_url + * @return an empty string if everything fails, the url content if not. + */ private String getStringFromProviderWithoutValidate( - URL provider_json_url) { + URL string_url) { String json_string = ""; HostnameVerifier hostnameVerifier = new HostnameVerifier() { @@ -294,20 +368,25 @@ public class ProviderAPI extends IntentService { try { HttpsURLConnection urlConnection = - (HttpsURLConnection)provider_json_url.openConnection(); + (HttpsURLConnection)string_url.openConnection(); urlConnection.setHostnameVerifier(hostnameVerifier); json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { - json_string = getStringFromProviderWithCACertAdded(provider_json_url); + json_string = getStringFromProviderWithCACertAdded(string_url); //e.printStackTrace(); } return json_string; } + /** + * Tries to download the contents of the provided url using main certificate from choosen provider. + * @param url + * @return an empty string if it fails, the url content if not. + */ private String getStringFromProviderWithCACertAdded(URL url) { String json_file_content = ""; @@ -372,6 +451,11 @@ public class ProviderAPI extends IntentService { return json_file_content; } + /** + * Downloads the certificate from the parameter url bypassing self signed certificate SSL errors. + * @param certificate_url_string + * @return the certificate, as a string + */ private String downloadCertificateWithoutTrusting(String certificate_url_string) { String cert_string = ""; @@ -424,15 +508,34 @@ public class ProviderAPI extends IntentService { return cert_string; } + /** + * Downloads a JSON object from the given url. + * + * It first downloads the JSON object as a String, and then parses it to JSON object. + * @param json_url + * @param danger_on if the user completely trusts the certificate of the url address. + * @return + * @throws JSONException + */ private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { String json_file_content = getStringFromProvider(json_url, danger_on); return new JSONObject(json_file_content); } - private String guessURL(String provider_main_url) { + /** + * Tries to guess the provider.json url given the main provider url. + * @param provider_main_url + * @return the guessed provider.json url + */ + private String guessProviderDotJsonURL(String provider_main_url) { return provider_main_url + "/provider.json"; } + /** + * Logs out from the api url retrieved from the task. + * @param task containing api url from which the user will log out + * @return true if there were no exceptions + */ private boolean logOut(Bundle task) { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); int session_id_index = 0; @@ -459,6 +562,12 @@ public class ProviderAPI extends IntentService { return true; } + /** + * Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate. + * + * @param task containing the type of the certificate to be downloaded + * @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error. + */ private boolean getNewCert(Bundle task) { String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { @@ -493,7 +602,7 @@ public class ProviderAPI extends IntentService { } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); + return false; } - return true; } } diff --git a/src/se/leap/leapclient/ProviderAPIResultReceiver.java b/src/se/leap/leapclient/ProviderAPIResultReceiver.java index a6a8d9d..e32f6ff 100644 --- a/src/se/leap/leapclient/ProviderAPIResultReceiver.java +++ b/src/se/leap/leapclient/ProviderAPIResultReceiver.java @@ -4,6 +4,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.ResultReceiver; +/** + * Implements the ResultReceiver needed by Activities using ProviderAPI to receive the results of its operations. + * @author parmegv + * + */ public class ProviderAPIResultReceiver extends ResultReceiver { private Receiver mReceiver; @@ -11,11 +16,16 @@ public class ProviderAPIResultReceiver extends ResultReceiver { super(handler); // TODO Auto-generated constructor stub } - + public void setReceiver(Receiver receiver) { mReceiver = receiver; } + /** + * Interface to enable ProviderAPIResultReceiver to receive results from the ProviderAPI IntentService. + * @author parmegv + * + */ public interface Receiver { public void onReceiveResult(int resultCode, Bundle resultData); } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 4cf0a5f..4ae4609 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -10,30 +10,29 @@ import java.util.Map; import org.json.JSONException; import org.json.JSONObject; - +/** + * Models the provider list shown in the ConfigurationWizard. + * + * @author parmegv + * + */ public class ProviderListContent { - /** - * An array of sample (dummy) items. - */ public static List ITEMS = new ArrayList(); - /** - * A map of sample (dummy) items, by ID. - */ public static Map ITEM_MAP = new HashMap(); - - static { - //addItem(new ProviderItem("1", "bitmask", "https://bitmask.net/provider.json", "https://api.bitmask.net:4430/1/config/eip-service.json")); - } + /** + * Adds a new provider item to the end of the items map, and to the items list. + * @param item + */ public static void addItem(ProviderItem item) { ITEMS.add(item); ITEM_MAP.put(String.valueOf(ITEMS.size()), item); } /** - * A dummy item representing a piece of content. + * A provider item. */ public static class ProviderItem { public boolean custom = false; @@ -45,15 +44,13 @@ public class ProviderListContent { public String eip_service_json_url; public String cert_json_url; public boolean danger_on = false; - - public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) { - this.id = id; - this.name = name; - this.provider_json_url = provider_json_url; - this.eip_service_json_url = eip_service_json_url; - this.cert_json_url = cert_json_url; - } + /** + * @param name of the provider + * @param urls_file_input_stream file input stream linking with the assets url file + * @param custom if it's a new provider entered by the user or not + * @param danger_on if the user trusts completely the new provider + */ public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom, boolean danger_on) { try { @@ -78,6 +75,13 @@ public class ProviderListContent { } } + /** + * @param name of the provider + * @param provider_json_url used to download provider.json file of the provider + * @param provider_json already downloaded + * @param custom if it's a new provider entered by the user or not + * @param danger_on if the user trusts completely the new provider + */ public ProviderItem(String name, String provider_json_url, JSONObject provider_json, boolean custom, boolean danger_on) { try { -- cgit v1.2.3 From f4956bb818fb9ed04760e6de3b53b876272da5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 20 Jun 2013 16:52:43 +0200 Subject: User messages are now in string.xml Some more constants added to ConfigHelper. This solves #2908. --- README | 66 +------------------------ assets/urls/bitmask.url | 2 +- res/values/strings.xml | 14 ++++++ src/se/leap/leapclient/ConfigHelper.java | 6 ++- src/se/leap/leapclient/ConfigurationWizard.java | 16 +++--- src/se/leap/leapclient/Dashboard.java | 18 +++---- src/se/leap/leapclient/LogInDialog.java | 2 +- src/se/leap/leapclient/NewProviderDialog.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 6 +-- src/se/leap/leapclient/ProviderListContent.java | 6 +-- 10 files changed, 47 insertions(+), 93 deletions(-) mode change 100644 => 120000 README diff --git a/README b/README deleted file mode 100644 index 7d57a6e..0000000 --- a/README +++ /dev/null @@ -1,65 +0,0 @@ -Compiling -========= - -Preconditions ----------------- - -1. Android SDK installed (follow instructions from http://developer.android.com/sdk/index.html) -2. API version 16 or version installed. -2. Ant 1.6 or greater - -Instructions to compile ------------------------ - -1. cd $PROJECT_LOCATION/leap_android -2. ./compile.sh - -Postconditions --------------- - -1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists - -Running on the emulator -========================= - -Preconditions ------------------ - -1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. -3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) - -Instructions to run on the emulator ------------------------------------ - -1. cd $PROJECT_LOCATION/leap_android -1. Run script: ./run.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). - -Postconditions --------------- - -1. LEAP Android is running. - -Debugging from console -====================== - -Preconditions ------------------ - -1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. -3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). -4. jdb is installed (this program is part of OpenJDK 7) - -Instructions to debug from the console ------------------------------------ - -1. cd $PROJECT_LOCATION/leap_android -2. Run script: ./debug.sh @AVD-NAME . (avd names are the names of the files in ~/.android/avd with extension .avd). - -Postconditions --------------- - -1. LEAP Android is running. -2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". -3. You are in a jdb debuggin session. diff --git a/README b/README new file mode 120000 index 0000000..c3ca074 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.txt \ No newline at end of file diff --git a/assets/urls/bitmask.url b/assets/urls/bitmask.url index 910f040..a17a5ff 100644 --- a/assets/urls/bitmask.url +++ b/assets/urls/bitmask.url @@ -1,7 +1,7 @@ { "name" : "bitmask", "assets_json_provider" : "providers/bitmask.net_provider.json", - "json_provider" : "https://bitmask.net/provider.json", + "provider_json_url" : "https://bitmask.net/provider.json", "cert" : "https://bitmask.net/ca.crt", "json_eip_service" : "https://api.bitmask.net:4430/1/config/eip-service.json" } \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 4501ac1..804964c 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -265,6 +265,8 @@ Introduce new provider Save New provider\'s main URL + It seems your URL is well formed + It seems your URL is not well formed Introduce your username Enter your password Log in @@ -281,5 +283,17 @@ Downloading authentication certificates Error parsing provider\'s responses! Success! + You have not entered a LEAP provider URL or it is unavailable + Your anon cert has been correctly downloaded + Your anon cert was not downloaded + Install a new version of this app. + Your password is not well-formed: it should have at least 8 characters. + Authentication succeeded. + Authentication failed. + Logged out. + Didn\'t logged out. + Your own cert has been correctly downloaded. + Your own cert has incorrectly been downloaded. + \ No newline at end of file diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5838f52..cb4a550 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -40,11 +40,14 @@ public class ConfigHelper { NEW_PROVIDER_DIALOG = "logInDialog", SRP_REGISTER = "srpRegister", SRP_AUTH = "srpAuth", + M1_KEY = "M1", + M2_KEY = "M2", LOG_IN = "logIn", LOG_OUT = "logOut", DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", API_VERSION_KEY = "api_version", RESULT_KEY = "result", + RECEIVER_KEY = "receiver", PROVIDER_KEY = "provider", SERVICE_KEY = "service", ALLOWED_ANON = "allow_anonymous", @@ -68,7 +71,8 @@ public class ConfigHelper { USERNAME_KEY = "username", PASSWORD_KEY = "password", ALLOW_REGISTRATION_KEY = "allow_registration", - EIP_SERVICE_API_PATH = "config/eip-service.json" + EIP_SERVICE_API_PATH = "config/eip-service.json", + ERRORS_KEY = "errors" ; final public static String NG_1024 = diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 91b92d6..ce27942 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -105,7 +105,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.incorrectly_updated_provider_dot_json_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } @@ -122,20 +122,20 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.correctly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } @@ -236,7 +236,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, provider.danger_on); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -252,7 +252,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -282,7 +282,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -302,7 +302,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); provider_API_command.putExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index e8ea270..dd8ee33 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -224,7 +224,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } provider_API_command.putExtra(ConfigHelper.SRP_AUTH, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -249,7 +249,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } provider_API_command.putExtra(ConfigHelper.LOG_OUT, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -286,7 +286,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf method_and_parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -297,25 +297,25 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf String session_id_cookie_key = resultData.getString(ConfigHelper.SESSION_ID_COOKIE_KEY); String session_id_string = resultData.getString(ConfigHelper.SESSION_ID_KEY); setResult(RESULT_OK); - Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.succesful_authentication_message, Toast.LENGTH_LONG).show(); Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.authentication_failed_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { setResult(RESULT_OK); - Toast.makeText(getApplicationContext(), "Logged out", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.successful_log_out_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Didn't logged out", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.log_out_failed_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.successful_authed_cert_downloaded_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.authed_cert_download_failed_message, Toast.LENGTH_LONG).show(); } } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 00429d1..dcb92d8 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -40,7 +40,7 @@ public class LogInDialog extends DialogFragment { interface_with_Dashboard.authenticate(username, password); } else { password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "Your password is not well-formed: it should have at least 8 characters", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_password_message, Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 5b84ec0..678e805 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -65,10 +65,10 @@ public class NewProviderDialog extends DialogFragment { boolean danger_on = danger_checkbox.isChecked(); if(validURL(entered_url)) { interface_with_ConfigurationWizard.saveProvider(entered_url, danger_on); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); } else { url_input_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_password_message, Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index f8d730e..4dfe200 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -219,11 +219,11 @@ public class ProviderAPI extends IntentService { JSONObject session_idAndM2 = new JSONObject(); if(json_response.length() > 0) { - byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); + byte[] M2_not_trimmed = new BigInteger(json_response.getString(ConfigHelper.M2_KEY), 16).toByteArray(); Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue()); - session_idAndM2.put("M2", Util.trim(M2_not_trimmed)); + session_idAndM2.put(ConfigHelper.M2_KEY, Util.trim(M2_not_trimmed)); } return session_idAndM2; } @@ -245,7 +245,7 @@ public class ProviderAPI extends IntentService { HttpEntity responseEntity = getResponse.getEntity(); String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); - if(!json_response.isNull("errors") || json_response.has("errors")) { + if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { return new JSONObject(); } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 4ae4609..8727b16 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -60,10 +60,10 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; - provider_json_url = file_contents.getString("json_provider"); + provider_json_url = file_contents.getString(ConfigHelper.PROVIDER_JSON_URL); provider_json_filename = file_contents.getString("assets_json_provider"); eip_service_json_url = file_contents.getString("json_eip_service"); - cert_json_url = file_contents.getString("cert"); + cert_json_url = file_contents.getString(ConfigHelper.CERT_KEY); this.custom = custom; this.danger_on = danger_on; } catch (JSONException e) { @@ -89,7 +89,7 @@ public class ProviderListContent { this.name = name; this.provider_json_url = provider_json_url; this.provider_json = provider_json; - eip_service_json_url = provider_json.getString("api_uri") + "/" + provider_json.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; + eip_service_json_url = provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.EIP_SERVICE_API_PATH; cert_json_url = (String) provider_json.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; -- cgit v1.2.3 From 65e2f56a8a10877964fb9fc57963d1bf8104801a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 20 Jun 2013 17:47:07 +0200 Subject: No binary library needed. I've decided not to include any lib, but to copy the SRPParameters class to our codebase and Util.trim method to ConfigHelper. --- libs/jboss-common-client.jar | Bin 399031 -> 0 bytes libs/jboss-srp-client.jar | Bin 23248 -> 0 bytes libs/jbosssx-client.jar | Bin 140507 -> 0 bytes src/org/jboss/security/srp/SRPParameters.java | 150 ++++++++++++++++++++++++++ src/se/leap/leapclient/ConfigHelper.java | 20 ++++ src/se/leap/leapclient/LeapSRPSession.java | 69 ++++++------ src/se/leap/leapclient/ProviderAPI.java | 5 +- 7 files changed, 207 insertions(+), 37 deletions(-) delete mode 100644 libs/jboss-common-client.jar delete mode 100644 libs/jboss-srp-client.jar delete mode 100644 libs/jbosssx-client.jar create mode 100644 src/org/jboss/security/srp/SRPParameters.java diff --git a/libs/jboss-common-client.jar b/libs/jboss-common-client.jar deleted file mode 100644 index af5fb00..0000000 Binary files a/libs/jboss-common-client.jar and /dev/null differ diff --git a/libs/jboss-srp-client.jar b/libs/jboss-srp-client.jar deleted file mode 100644 index 9a64c28..0000000 Binary files a/libs/jboss-srp-client.jar and /dev/null differ diff --git a/libs/jbosssx-client.jar b/libs/jbosssx-client.jar deleted file mode 100644 index 5ad6fc8..0000000 Binary files a/libs/jbosssx-client.jar and /dev/null differ diff --git a/src/org/jboss/security/srp/SRPParameters.java b/src/org/jboss/security/srp/SRPParameters.java new file mode 100644 index 0000000..4b188cb --- /dev/null +++ b/src/org/jboss/security/srp/SRPParameters.java @@ -0,0 +1,150 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2006, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.jboss.security.srp; + +import java.io.Serializable; +import java.util.Arrays; + +import org.spongycastle.util.encoders.Base64; + +/** The RFC2945 algorithm session parameters that the client and server +agree to use. In addition to the base RFC2945 parameters, one can choose an +alternate hash algorithm for the private session key. + +@author Scott.Stark@jboss.org +@version $Revision: 57210 $ +*/ +public class SRPParameters implements Cloneable, Serializable +{ + /** The serial version ID. + * @since 1.2.4.1 + */ + private static final long serialVersionUID = 6438772808805276693L; + + /** The algorithm safe-prime modulus */ + public final byte[] N; + /** The algorithm primitive generator */ + public final byte[] g; + /** The random password salt originally used to verify the password */ + public final byte[] s; + /** The algorithm to hash the session key to produce K. To be consistent + with the RFC2945 description this must be SHA_Interleave as implemented + by the JBossSX security provider. For compatibility with earlier JBossSX + SRP releases the algorithm must be SHA_ReverseInterleave. This name is + passed to java.security.MessageDigest.getInstance(). */ + public final String hashAlgorithm; + /** The algorithm to use for any encryption of data. + */ + public final String cipherAlgorithm; + /** The cipher intialization vector bytes + */ + public byte[] cipherIV; + + /** Creates a new instance of SRPParameters */ + public SRPParameters(byte[] N, byte[] g, byte[] s) + { + this(N, g, s, "SHA_Interleave", null); + } + public SRPParameters(byte[] N, byte[] g, byte[] s, String hashAlgorithm) + { + this(N, g, s, hashAlgorithm, null); + } + public SRPParameters(byte[] N, byte[] g, byte[] s, String hashAlgorithm, + String cipherAlgorithm) + { + this(N, g, s, hashAlgorithm, cipherAlgorithm, null); + } + public SRPParameters(byte[] N, byte[] g, byte[] s, String hashAlgorithm, + String cipherAlgorithm, byte[] cipherIV) + { + this.N = N; + this.g = g; + this.s = s; + if( hashAlgorithm == null ) + hashAlgorithm = "SHA_Interleave"; + this.hashAlgorithm = hashAlgorithm; + this.cipherAlgorithm = cipherAlgorithm; + this.cipherIV = cipherIV; + } + + public Object clone() + { + Object clone = null; + try + { + clone = super.clone(); + } + catch(CloneNotSupportedException e) + { + } + return clone; + } + + public int hashCode() + { + int hashCode = hashAlgorithm.hashCode(); + for(int i = 0; i < N.length; i ++) + hashCode += N[i]; + for(int i = 0; i < g.length; i ++) + hashCode += g[i]; + for(int i = 0; i < s.length; i ++) + hashCode += s[i]; + return hashCode; + } + + public boolean equals(Object obj) + { + boolean equals = false; + if( obj instanceof SRPParameters ) + { + SRPParameters p = (SRPParameters) obj; + equals = hashAlgorithm.equals(p.hashAlgorithm); + if( equals == true ) + equals = Arrays.equals(N, p.N); + if( equals == true ) + equals = Arrays.equals(g, p.g); + if( equals == true ) + equals = Arrays.equals(s, p.s); + } + return equals; + } + + public String toString() + { + StringBuffer tmp = new StringBuffer(super.toString()); + tmp.append('{'); + tmp.append("N: "); + tmp.append(Base64.encode(N)); + tmp.append("|g: "); + tmp.append(Base64.encode(g)); + tmp.append("|s: "); + tmp.append(Base64.encode(s)); + tmp.append("|hashAlgorithm: "); + tmp.append(hashAlgorithm); + tmp.append("|cipherAlgorithm: "); + tmp.append(cipherAlgorithm); + tmp.append("|cipherIV: "); + tmp.append(cipherIV); + tmp.append('}'); + return tmp.toString(); + } +} diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index cb4a550..dd20112 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -207,6 +207,26 @@ public class ConfigHelper { return input_stream; } + /** + * Treat the input as the MSB representation of a number, + * and lop off leading zero elements. For efficiency, the + * input is simply returned if no leading zeroes are found. + * + * @param in array to be trimmed + */ + public static byte[] trim(byte[] in) { + if(in.length == 0 || in[0] != 0) + return in; + + int len = in.length; + int i = 1; + while(in[i] == 0 && i < len) + ++i; + byte[] ret = new byte[len - i]; + System.arraycopy(in, i, ret, 0, len - i); + return ret; + } + /** * Sets class scope Shared Preferences * @param shared_preferences diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index beb286d..d21ccff 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -4,9 +4,9 @@ import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Arrays; -import org.jboss.security.Util; import org.jboss.security.srp.SRPParameters; /** @@ -30,6 +30,7 @@ public class LeapSRPSession { private BigInteger a; private BigInteger A; private byte[] K; + private SecureRandom pseudoRng; /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */ private MessageDigest clientHash; /** The M2 = H(A | M | K) hash */ @@ -57,20 +58,20 @@ public class LeapSRPSession { */ public LeapSRPSession(String username, String password, SRPParameters params, byte[] abytes) { - try { - // Initialize the secure random number and message digests - Util.init(); - } - catch(NoSuchAlgorithmException e) { - } - this.params = params; this.g = new BigInteger(1, params.g); - N_bytes = Util.trim(params.N); + N_bytes = ConfigHelper.trim(params.N); this.N = new BigInteger(1, N_bytes); this.username = username; this.password = password; + try { + pseudoRng = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if( abytes != null ) { A_LEN = 8*abytes.length; /* TODO Why did they put this condition? @@ -105,15 +106,15 @@ public class LeapSRPSession { byte[] colon = {}; String encoding = "ISO-8859-1"; try { - user = Util.trim(username.getBytes(encoding)); - colon = Util.trim(":".getBytes(encoding)); - password_bytes = Util.trim(password.getBytes(encoding)); + user = ConfigHelper.trim(username.getBytes(encoding)); + colon = ConfigHelper.trim(":".getBytes(encoding)); + password_bytes = ConfigHelper.trim(password.getBytes(encoding)); } catch(UnsupportedEncodingException e) { // Use the default platform encoding - user = Util.trim(username.getBytes()); - colon = Util.trim(":".getBytes()); - password_bytes = Util.trim(password.getBytes()); + user = ConfigHelper.trim(username.getBytes()); + colon = ConfigHelper.trim(":".getBytes()); + password_bytes = ConfigHelper.trim(password.getBytes()); } // Build the hash @@ -152,7 +153,7 @@ public class LeapSRPSession { { //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa byte[] xor_digest = new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); - return Util.trim(xor_digest); + return ConfigHelper.trim(xor_digest); } /** @@ -166,11 +167,11 @@ public class LeapSRPSession { if( a == null ) { BigInteger one = BigInteger.ONE; do { - a = new BigInteger(A_LEN, Util.getPRNG()); + a = new BigInteger(A_LEN, pseudoRng); } while(a.compareTo(one) <= 0); } A = g.modPow(a, N); - Abytes = Util.trim(A.toByteArray()); + Abytes = ConfigHelper.trim(A.toByteArray()); } return Abytes; } @@ -186,7 +187,7 @@ public class LeapSRPSession { */ public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = calculatePasswordHash(username, password, Util.trim(salt_bytes)); + byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes)); this.x = new BigInteger(1, xb); // Calculate v = kg^x mod N @@ -204,36 +205,36 @@ public class LeapSRPSession { clientHash.update(xor_digest); // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); - username_digest = Util.trim(username_digest); + byte[] username_digest = newDigest().digest(ConfigHelper.trim(username.getBytes())); + username_digest = ConfigHelper.trim(username_digest); clientHash.update(username_digest); // clientHash = H(N) xor H(g) | H(U) | s - clientHash.update(Util.trim(salt_bytes)); + clientHash.update(ConfigHelper.trim(salt_bytes)); K = null; // clientHash = H(N) xor H(g) | H(U) | A - byte[] Abytes = Util.trim(A.toByteArray()); + byte[] Abytes = ConfigHelper.trim(A.toByteArray()); clientHash.update(Abytes); // clientHash = H(N) xor H(g) | H(U) | s | A | B - Bbytes = Util.trim(Bbytes); + Bbytes = ConfigHelper.trim(Bbytes); clientHash.update(Bbytes); // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); - byte[] S_bytes = Util.trim(S.toByteArray()); + byte[] S_bytes = ConfigHelper.trim(S.toByteArray()); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); - K = Util.trim(sessionDigest.digest(S_bytes)); + K = ConfigHelper.trim(sessionDigest.digest(S_bytes)); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); - byte[] M1 = Util.trim(clientHash.digest()); + byte[] M1 = ConfigHelper.trim(clientHash.digest()); // serverHash = Astr + M + K serverHash.update(Abytes); @@ -249,8 +250,8 @@ public class LeapSRPSession { * @return the parameter S */ private BigInteger calculateS(byte[] Bbytes) { - byte[] Abytes = Util.trim(A.toByteArray()); - Bbytes = Util.trim(Bbytes); + byte[] Abytes = ConfigHelper.trim(A.toByteArray()); + Bbytes = ConfigHelper.trim(Bbytes); byte[] u_bytes = getU(Abytes, Bbytes); BigInteger B = new BigInteger(1, Bbytes); @@ -270,10 +271,10 @@ public class LeapSRPSession { */ public byte[] getU(byte[] Abytes, byte[] Bbytes) { MessageDigest u_digest = newDigest(); - u_digest.update(Util.trim(Abytes)); - u_digest.update(Util.trim(Bbytes)); + u_digest.update(ConfigHelper.trim(Abytes)); + u_digest.update(ConfigHelper.trim(Bbytes)); byte[] u_digest_bytes = u_digest.digest(); - return Util.trim(new BigInteger(1, u_digest_bytes).toByteArray()); + return ConfigHelper.trim(new BigInteger(1, u_digest_bytes).toByteArray()); } /** @@ -283,8 +284,8 @@ public class LeapSRPSession { public boolean verify(byte[] M2) { // M2 = H(A | M1 | K) - M2 = Util.trim(M2); - byte[] myM2 = Util.trim(serverHash.digest()); + M2 = ConfigHelper.trim(M2); + byte[] myM2 = ConfigHelper.trim(serverHash.digest()); boolean valid = Arrays.equals(M2, myM2); return valid; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4dfe200..00d7d82 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -41,7 +41,6 @@ import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; -import org.jboss.security.Util; import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -214,7 +213,7 @@ public class ProviderAPI extends IntentService { * @throws JSONException */ private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { - HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16)); + HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); JSONObject json_response = sendToServer(put); JSONObject session_idAndM2 = new JSONObject(); @@ -223,7 +222,7 @@ public class ProviderAPI extends IntentService { Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue()); - session_idAndM2.put(ConfigHelper.M2_KEY, Util.trim(M2_not_trimmed)); + session_idAndM2.put(ConfigHelper.M2_KEY, ConfigHelper.trim(M2_not_trimmed)); } return session_idAndM2; } -- cgit v1.2.3 From 3f8e2f6569f893a49bf1819416cae792c702d370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 20 Jun 2013 18:03:05 +0200 Subject: No untracked files. Added two auxiliar files: prepareTestProviderAPI.sh is updated in feature/authGui_tests. proguard-project.txt is completely commented, but I think it may be suitable to version control. --- .gitignore | 4 ++++ prepareTestProviderAPI.sh | 15 +++++++++++++++ proguard-project.txt | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100755 prepareTestProviderAPI.sh create mode 100644 proguard-project.txt diff --git a/.gitignore b/.gitignore index 11526f8..9aa5a03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ obj bin gen +libs openvpn/.git openvpn/autom4te.cache openvpn/aclocal.m4 @@ -65,3 +66,6 @@ id.zip /hosts-for-android-emulator.bk /build-native.sh.bk /build-native.sh~ + +build.gradle +local.properties diff --git a/prepareTestProviderAPI.sh b/prepareTestProviderAPI.sh new file mode 100755 index 0000000..0eca85a --- /dev/null +++ b/prepareTestProviderAPI.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +if [ -z "$1" ] +then + echo Usage: prepareTestProviderAPI.sh \"project folder\" + exit 0; +fi + +PROJECT_FOLDER=$1 +hosts_file="hosts-for-tests" + +adb shell mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system +adb push $PROJECT_FOLDER/$hosts_file /system/etc/hosts + +echo "Pushed $PROJECT_FOLDER/$hosts_file" diff --git a/proguard-project.txt b/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} -- cgit v1.2.3