simplified credentials saving and loading

check if credentials set AND user info downloaded for login
pull/5/head
Felix Prahl-Kamps 2019-07-23 14:58:07 +02:00
parent abe0fb7cb5
commit 91546087d0
8 changed files with 46 additions and 155 deletions

View File

@ -118,7 +118,7 @@ public class ExchangeActivity extends AppCompatActivity {
SyncInformation syncInformation = new SyncInformation(); SyncInformation syncInformation = new SyncInformation();
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation(); syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
syncInformation.syncUserAuthkey = new RandomString(40).nextString(); syncInformation.syncUserAuthkey = new RandomString(40).nextString();
syncInformation.baseUrl = preferenceManager.getServerUrl(); syncInformation.baseUrl = preferenceManager.getUserCredentials().first;
syncInformation.syncUserPassword = new RandomString(16).nextString(); syncInformation.syncUserPassword = new RandomString(16).nextString();
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email; syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
return syncInformation; return syncInformation;

View File

@ -33,7 +33,7 @@ public class LoginActivity extends AppCompatActivity {
private PreferenceManager preferenceManager; private PreferenceManager preferenceManager;
private ConstraintLayout constraintLayout; private ConstraintLayout constraintLayout;
private TextInputLayout serverAutomationKey; private TextInputLayout serverAuthkey;
private TextInputLayout serverUrl; private TextInputLayout serverUrl;
private ProgressBar progressBar; private ProgressBar progressBar;
@ -81,7 +81,7 @@ public class LoginActivity extends AppCompatActivity {
downloadInfoButton.setOnClickListener(onLogin); downloadInfoButton.setOnClickListener(onLogin);
serverUrl = findViewById(R.id.login_server_url); serverUrl = findViewById(R.id.login_server_url);
serverAutomationKey = findViewById(R.id.login_automation_key); serverAuthkey = findViewById(R.id.login_automation_key);
progressBar = findViewById(R.id.login_progressbar); progressBar = findViewById(R.id.login_progressbar);
} }
@ -92,12 +92,12 @@ public class LoginActivity extends AppCompatActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString(); final String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString();
final String authkey = Objects.requireNonNull(serverAutomationKey.getEditText()).getText().toString(); final String authkey = Objects.requireNonNull(serverAuthkey.getEditText()).getText().toString();
boolean error = false; boolean error = false;
serverUrl.setError(null); serverUrl.setError(null);
serverAutomationKey.setError(null); serverAuthkey.setError(null);
if (!isValidUrl(url)) { if (!isValidUrl(url)) {
error = true; error = true;
@ -106,7 +106,7 @@ public class LoginActivity extends AppCompatActivity {
if (!isValidAutomationKey(authkey)) { if (!isValidAutomationKey(authkey)) {
error = true; error = true;
serverAutomationKey.setError("Invalid automation key"); serverAuthkey.setError("Invalid automation key");
} }
if (error) { if (error) {
@ -145,14 +145,10 @@ public class LoginActivity extends AppCompatActivity {
@Override @Override
public void success(Organisation organisation) { public void success(Organisation organisation) {
preferenceManager.setUserOrgInfo(organisation); preferenceManager.setUserOrgInfo(organisation);
preferenceManager.setUserCredentials(url, authkey);
// save authkey
preferenceManager.setAutomationKey(authkey);
// save url
preferenceManager.setServerUrl(url);
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
Intent home = new Intent(getApplicationContext(), HomeActivity.class); Intent home = new Intent(getApplicationContext(), HomeActivity.class);
startActivity(home); startActivity(home);
finish(); finish();

View File

@ -17,6 +17,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.util.Pair;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
@ -48,7 +49,8 @@ public class ProfileActivity extends AppCompatActivity {
setContentView(R.layout.activity_profile); setContentView(R.layout.activity_profile);
preferenceManager = PreferenceManager.getInstance(this); preferenceManager = PreferenceManager.getInstance(this);
mispRestClient = MispRestClient.getInstance(preferenceManager.getServerUrl(), preferenceManager.getAuthKey()); Pair<String, String> credentials = preferenceManager.getUserCredentials();
mispRestClient = MispRestClient.getInstance(credentials.first, credentials.second);
init(); init();
populateInformationViews(); populateInformationViews();

View File

@ -2,12 +2,10 @@ package lu.circl.mispbump.activities;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import lu.circl.mispbump.auxiliary.PreferenceManager; import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.models.restModels.User;
/** /**
* Starts either the login or home activity. * Starts either the login or home activity.
@ -32,7 +30,6 @@ public class StartUpActivity extends AppCompatActivity {
private boolean isUserLoggedIn() { private boolean isUserLoggedIn() {
PreferenceManager preferenceManager = PreferenceManager.getInstance(this); PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
User user = preferenceManager.getUserInfo(); return preferenceManager.getUserCredentials() != null && preferenceManager.getUserInfo() != null;
return user != null;
} }
} }

View File

@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.util.Pair;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -99,7 +100,8 @@ public class UploadActivity extends AppCompatActivity {
setContentView(R.layout.activity_upload); setContentView(R.layout.activity_upload);
preferenceManager = PreferenceManager.getInstance(UploadActivity.this); preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
restClient = MispRestClient.getInstance(preferenceManager.getServerUrl(), preferenceManager.getAuthKey()); Pair<String, String> credentials = preferenceManager.getUserCredentials();
restClient = MispRestClient.getInstance(credentials.first, credentials.second);
parseExtra(); parseExtra();
initViews(); initViews();

View File

@ -61,12 +61,12 @@ public class MispRestClient {
return instance; return instance;
} }
public void initMispRestInterface(String url, String authkey) { private void initMispRestInterface(String url, String authkey) {
try { try {
Retrofit retrofit = new Retrofit.Builder() Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url) .baseUrl(url)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.client(getCustomClient(true, false, authkey)) .client(getCustomClient(true, true, authkey))
.build(); .build();
mispRestInterface = retrofit.create(MispRestInterface.class); mispRestInterface = retrofit.create(MispRestInterface.class);
@ -370,7 +370,7 @@ public class MispRestClient {
if (response.body() != null) { if (response.body() != null) {
callback.success(response.body().organisation); callback.success(response.body().organisation);
} else { } else {
callback.failure("Response body was nul"); callback.failure("Response was empty");
} }
} }
} }
@ -410,7 +410,6 @@ public class MispRestClient {
@Override @Override
public void onResponse(@NonNull Call<List<MispOrganisation>> call, @NonNull Response<List<MispOrganisation>> response) { public void onResponse(@NonNull Call<List<MispOrganisation>> call, @NonNull Response<List<MispOrganisation>> response) {
if (!response.isSuccessful()) { if (!response.isSuccessful()) {
// TODO handle
return; return;
} }
@ -606,6 +605,12 @@ public class MispRestClient {
return "Server is not available (no route to host)"; return "Server is not available (no route to host)";
} }
try {
throw new Exception(t);
} catch (Exception e) {
e.printStackTrace();
}
return t.getMessage(); return t.getMessage();
} }

View File

@ -3,6 +3,8 @@ package lu.circl.mispbump.auxiliary;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import androidx.core.util.Pair;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@ -28,9 +30,7 @@ public class PreferenceManager {
private static final String PREFERENCES_FILE = "user_settings"; private static final String PREFERENCES_FILE = "user_settings";
private static final String SERVER_URL = "server_url"; private static final String USER_CREDENTIALS = "user_credentials";
private static final String AUTOMATION_KEY = "user_automation";
private static final String USER_INFOS = "user_infos"; private static final String USER_INFOS = "user_infos";
private static final String USER_ORG_INFOS = "user_org_infos"; private static final String USER_ORG_INFOS = "user_org_infos";
@ -62,6 +62,7 @@ public class PreferenceManager {
/** /**
* Save downloaded MISP roles on device. * Save downloaded MISP roles on device.
*
* @param roles {@link Role} * @param roles {@link Role}
*/ */
public void setRoles(Role[] roles) { public void setRoles(Role[] roles) {
@ -78,7 +79,8 @@ public class PreferenceManager {
* @return {@link Role}[] or null * @return {@link Role}[] or null
*/ */
public Role[] getRoles() { public Role[] getRoles() {
Type type = new TypeToken<Role[]>() {}.getType(); Type type = new TypeToken<Role[]>() {
}.getType();
String rolesString = preferences.getString(MISP_ROLES, ""); String rolesString = preferences.getString(MISP_ROLES, "");
assert rolesString != null; assert rolesString != null;
@ -209,147 +211,34 @@ public class PreferenceManager {
} }
/** public void setUserCredentials(String url, String authkey) {
* Encrypts the automation key and stores it in preferences.
*
* @param automationKey key entered in {@link lu.circl.mispbump.activities.LoginActivity}
*/
public void setAutomationKey(String automationKey) {
try { try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS); KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
SharedPreferences.Editor editor = preferences.edit(); SharedPreferences.Editor editor = preferences.edit();
editor.putString(AUTOMATION_KEY, keyStoreWrapper.encrypt(automationKey)); editor.putString(USER_CREDENTIALS, keyStoreWrapper.encrypt(new Gson().toJson(new Pair<>(url, authkey))));
editor.apply(); editor.apply();
} catch (NoSuchPaddingException e) { } catch (NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
/** public Pair<String, String> getUserCredentials() {
* Decrypts the stored automation key and returns it. if (!preferences.contains(USER_CREDENTIALS)) {
*
* @return decrypted automation key associated with the current user. If no user exists an empty
* String is returned.
*/
public String getAuthKey() {
if (!preferences.contains(AUTOMATION_KEY)) {
return "";
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(AUTOMATION_KEY, ""));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return "";
}
/**
* Delete the key to decrypt this entry and the entry itself.
*/
public void clearAutomationKey() {
// remove the key from KeyStore
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
editor.remove(AUTOMATION_KEY);
editor.apply();
}
/**
* Encrypts the server url and stores it in preferences.
*
* @param serverUrl url of the corresponding misp instance
*/
public void setServerUrl(String serverUrl) {
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(SERVER_URL, keyStoreWrapper.encrypt(serverUrl));
editor.apply();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
/**
* Decrypts the stored server url and returns it
*
* @return decrypted misp instance url
*/
public String getServerUrl() {
if (!preferences.contains(SERVER_URL)) {
return null; return null;
} }
try { try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS); KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, null)); Type type = new TypeToken<Pair<String, String>>() {}.getType();
String serializedCreds = keyStoreWrapper.decrypt(preferences.getString(USER_CREDENTIALS, ""));
} catch (NoSuchPaddingException e) { return new Gson().fromJson(serializedCreds, type);
e.printStackTrace(); } catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace(); e.printStackTrace();
} }
return null; return null;
} }
/**
* Delete the key to decrypt this entry and the entry itself.
*/
public void clearServerUrl() {
// remove the key from KeyStore
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
editor.remove(SERVER_URL);
editor.apply();
}
private List<UploadInformation> cachedUploadInformationList; private List<UploadInformation> cachedUploadInformationList;
@ -357,7 +246,8 @@ public class PreferenceManager {
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS); KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null); String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
Type type = new TypeToken<List<UploadInformation>>() {}.getType(); Type type = new TypeToken<List<UploadInformation>>() {
}.getType();
if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) { if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) {
cachedUploadInformationList = new ArrayList<>(); cachedUploadInformationList = new ArrayList<>();
@ -462,8 +352,8 @@ public class PreferenceManager {
public void clearAllData() { public void clearAllData() {
SharedPreferences.Editor editor = preferences.edit(); SharedPreferences.Editor editor = preferences.edit();
clearServerUrl(); // clearServerUrl();
clearAutomationKey(); // clearAutomationKey();
clearUploadInformation(); clearUploadInformation();
editor.clear(); editor.clear();

View File

@ -29,8 +29,7 @@ public class KeyStoreWrapper {
public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO"; public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO";
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO"; public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY"; public static final String USER_CREDENTIALS_ALIAS = "ALIAS_USER_CREDENTIALS";
public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION"; public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore"; private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";