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.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
syncInformation.baseUrl = preferenceManager.getServerUrl();
syncInformation.baseUrl = preferenceManager.getUserCredentials().first;
syncInformation.syncUserPassword = new RandomString(16).nextString();
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
return syncInformation;

View File

@ -33,7 +33,7 @@ public class LoginActivity extends AppCompatActivity {
private PreferenceManager preferenceManager;
private ConstraintLayout constraintLayout;
private TextInputLayout serverAutomationKey;
private TextInputLayout serverAuthkey;
private TextInputLayout serverUrl;
private ProgressBar progressBar;
@ -81,7 +81,7 @@ public class LoginActivity extends AppCompatActivity {
downloadInfoButton.setOnClickListener(onLogin);
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);
}
@ -92,12 +92,12 @@ public class LoginActivity extends AppCompatActivity {
@Override
public void onClick(View v) {
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;
serverUrl.setError(null);
serverAutomationKey.setError(null);
serverAuthkey.setError(null);
if (!isValidUrl(url)) {
error = true;
@ -106,7 +106,7 @@ public class LoginActivity extends AppCompatActivity {
if (!isValidAutomationKey(authkey)) {
error = true;
serverAutomationKey.setError("Invalid automation key");
serverAuthkey.setError("Invalid automation key");
}
if (error) {
@ -145,14 +145,10 @@ public class LoginActivity extends AppCompatActivity {
@Override
public void success(Organisation organisation) {
preferenceManager.setUserOrgInfo(organisation);
// save authkey
preferenceManager.setAutomationKey(authkey);
// save url
preferenceManager.setServerUrl(url);
preferenceManager.setUserCredentials(url, authkey);
progressBar.setVisibility(View.GONE);
Intent home = new Intent(getApplicationContext(), HomeActivity.class);
startActivity(home);
finish();

View File

@ -17,6 +17,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.util.Pair;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
@ -48,7 +49,8 @@ public class ProfileActivity extends AppCompatActivity {
setContentView(R.layout.activity_profile);
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();
populateInformationViews();

View File

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

View File

@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.util.Pair;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -99,7 +100,8 @@ public class UploadActivity extends AppCompatActivity {
setContentView(R.layout.activity_upload);
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();
initViews();

View File

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

View File

@ -3,6 +3,8 @@ package lu.circl.mispbump.auxiliary;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.core.util.Pair;
import com.google.gson.Gson;
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 SERVER_URL = "server_url";
private static final String AUTOMATION_KEY = "user_automation";
private static final String USER_CREDENTIALS = "user_credentials";
private static final String USER_INFOS = "user_infos";
private static final String USER_ORG_INFOS = "user_org_infos";
@ -62,6 +62,7 @@ public class PreferenceManager {
/**
* Save downloaded MISP roles on device.
*
* @param roles {@link Role}
*/
public void setRoles(Role[] roles) {
@ -78,7 +79,8 @@ public class PreferenceManager {
* @return {@link Role}[] or null
*/
public Role[] getRoles() {
Type type = new TypeToken<Role[]>() {}.getType();
Type type = new TypeToken<Role[]>() {
}.getType();
String rolesString = preferences.getString(MISP_ROLES, "");
assert rolesString != null;
@ -209,147 +211,34 @@ public class PreferenceManager {
}
/**
* 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) {
public void setUserCredentials(String url, String authkey) {
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
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();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
} catch (NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
e.printStackTrace();
}
}
/**
* Decrypts the stored automation key and returns it.
*
* @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)) {
public Pair<String, String> getUserCredentials() {
if (!preferences.contains(USER_CREDENTIALS)) {
return null;
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, null));
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
Type type = new TypeToken<Pair<String, String>>() {}.getType();
String serializedCreds = keyStoreWrapper.decrypt(preferences.getString(USER_CREDENTIALS, ""));
return new Gson().fromJson(serializedCreds, type);
} catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
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;
@ -357,7 +246,8 @@ public class PreferenceManager {
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
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()) {
cachedUploadInformationList = new ArrayList<>();
@ -462,8 +352,8 @@ public class PreferenceManager {
public void clearAllData() {
SharedPreferences.Editor editor = preferences.edit();
clearServerUrl();
clearAutomationKey();
// clearServerUrl();
// clearAutomationKey();
clearUploadInformation();
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_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY";
public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
public static final String USER_CREDENTIALS_ALIAS = "ALIAS_USER_CREDENTIALS";
public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";