Browse Source

GMEAuth manager fixes

master
Preyea Regmi 4 years ago
parent
commit
0989bc09cb
  1. 1
      app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGateway.java
  2. 59
      app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/gateway/LoginV2Gateway.java
  3. 122
      app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java
  4. 45
      app/src/main/java/com/gmeremit/online/gmeremittance_native/security/GMEAuthManager.java
  5. 28
      app/src/main/java/com/gmeremit/online/gmeremittance_native/security/GMEAuthManagerGateway.java
  6. 36
      app/src/main/java/com/gmeremit/online/gmeremittance_native/security/model/GMEBiometricEncryptionDTO.java
  7. 50
      app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/FingerprintEnablePromptActivity.java
  8. 2
      app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/SettingsView.java

1
app/src/main/java/com/gmeremit/online/gmeremittance_native/base/PrivilegedGateway.java

@ -209,7 +209,6 @@ public abstract class PrivilegedGateway extends BaseGateway implements Privilege
@Override
public void persistSecretKeyForBiometric(String encrypted) {
Log.d("GMEAuthManager","Encrypted secret to Storage => "+encrypted);
GmeApplication.getStorage().edit().putString(PrefKeys.APP_SECRET_KEY, encrypted).apply();
}

59
app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/gateway/LoginV2Gateway.java

@ -78,63 +78,4 @@ public class LoginV2Gateway extends PrivilegedGateway implements LoginV2Interact
GmeApplication.getStorage().edit().putString(PrefKeys.USER_LOGGED_IN_STATUS, sessionId).apply();
}
public static class UserCredentialDecryptionResultDTO {
String userId;
String userPwd;
public UserCredentialDecryptionResultDTO(String userId, String userPwd) {
this.userId = userId;
this.userPwd = userPwd;
}
public String getUserId() {
return userId;
}
public String getUserPwd() {
return userPwd;
}
@Override
public String toString() {
return "UserCredentialDecryptionResultDTO{" +
"userId='" + userId + '\'' +
", userPwd='" + userPwd + '\'' +
'}';
}
}
public static class UserCredentialEncryptionResultDTO {
String userId;
String encPwd;
String encKey;
public UserCredentialEncryptionResultDTO(String userId, String encPwd, String encKey) {
this.userId = userId;
this.encPwd = encPwd;
this.encKey = encKey;
}
public String getUserId() {
return userId;
}
public String getEncPwd() {
return encPwd;
}
public String getEncKey() {
return encKey;
}
@Override
public String toString() {
return "UserCredentialEncryptionResultDTO{" +
"userId='" + userId + '\'' +
", encPwd='" + encPwd + '\'' +
", encKey='" + encKey + '\'' +
'}';
}
}
}

122
app/src/main/java/com/gmeremit/online/gmeremittance_native/loginV2/presenter/LoginV2Presenter.java

@ -10,13 +10,14 @@ import com.gmeremit.online.gmeremittance_native.loginV2.model.LoginModelV2;
import com.gmeremit.online.gmeremittance_native.security.GMEAuthManager;
import com.gmeremit.online.gmeremittance_native.security.model.GMEAuthFailedResult;
import com.gmeremit.online.gmeremittance_native.security.model.GMEAuthSuccessResult;
import com.gmeremit.online.gmeremittance_native.security.utils.SecurityUtils;
import com.gmeremit.online.gmeremittance_native.utils.Constants;
import com.gmeremit.online.gmeremittance_native.utils.https.GenericApiObserverResponse;
import io.reactivex.CompletableObserver;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterInterface, LoginV2InteractorInterface {
@ -24,13 +25,17 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
private final LoginV2ContractInterface view;
private final LoginV2Gateway gateway;
private final CompositeDisposable compositeDisposable;
private String encUserPassword;
private GMEAuthManager gmeAuthManager;
public LoginV2Presenter(LoginV2ContractInterface view, LoginV2Gateway gateway) {
this.view = view;
this.gateway = gateway;
encUserPassword = "";
gmeAuthManager = GMEAuthManager.getGmeAuthManager((AppCompatActivity) view.getContext());
compositeDisposable = new CompositeDisposable();
}
@ -45,21 +50,6 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
}
}
private void persistUserCredentialForFingerprintAuth(String userId, String pwd, LoginModelV2 loginModelV2) {
SecurityUtils.generateKey()
.flatMap(key -> Observable.zip(Observable.just(userId),
SecurityUtils.encryptUsingAES(pwd, key).subscribeOn(Schedulers.io()),
encryptByKeyStore(key).subscribeOn(Schedulers.io()),
LoginV2Gateway.UserCredentialEncryptionResultDTO::new)
).observeOn(AndroidSchedulers.mainThread())
.subscribe(new UserCredentialEncryptionResultObserver(loginModelV2));
}
private Observable<String> encryptByKeyStore(String data) {
return SecurityUtils.encryptUsingKeyStore(view.getContext(), data)
.flatMap(encKey -> Observable.just(encKey.getEncrypted()));
}
private boolean validatePassword() {
if (encUserPassword == null || encUserPassword.length() < 1) {
view.showInvalidPassword(getStringfromStringId(R.string.password_empty_error));
@ -77,16 +67,23 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
@Override
public boolean checkIfBiometricIsAvailable() {
return SecurityUtils.checkFingerPrintUsablity(view.getContext()) && gateway.isFingerPrintAuthEnabled() && gateway.getPersistedUserId() != null && gateway.getPersistedUserPwd() != null;
return gmeAuthManager.isBiometricSupportedByDevice() && gmeAuthManager.isBiometricDataAvailable() && gmeAuthManager.isBiometricEnabledOnTheApp();
}
@Override
public void onViewDestroyed() {
super.onViewDestroyed();
if(compositeDisposable!=null&&!compositeDisposable.isDisposed())
compositeDisposable.dispose();
}
@Override
public void promptForBiometricAuth() {
GMEAuthManager.getGmeAuthManager((AppCompatActivity) view.getContext()).requestBiometricAuth()
gmeAuthManager.requestBiometricAuth()
.setListener(new GMEAuthManager.GMEAuthListener() {
@Override
public void onGMEAuthSuccess(GMEAuthSuccessResult result) {
encUserPassword =result.getResult();
encUserPassword = result.getResult();
view.onLoginPerformTask(() -> loginUser(gateway.getPersistedUserId()));
}
@ -116,25 +113,26 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
@Override
public void loginUser(String userId) {
this.gateway.loginUser(gateway.getBasicAuth(view.getContext()), userId, encUserPassword)
.subscribeOn(Schedulers.io())
.flatMap(loginResponse -> {
if (loginResponse.getErrorCode().equalsIgnoreCase(Constants.SUCCESS_CODE_V2)) {
LoginModelV2 data = loginResponse.getData();
turnOffFingerprintAuthIfRequired(userId);
return gateway.saveUserInfo(data);
} else {
return Observable.error(new Exception(loginResponse.getMsg()));
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new LoginObserver(userId, encUserPassword));
compositeDisposable.add(
this.gateway.loginUser(gateway.getBasicAuth(view.getContext()), userId, encUserPassword)
.subscribeOn(Schedulers.io())
.flatMap(loginResponse -> {
if (loginResponse.getErrorCode().equalsIgnoreCase(Constants.SUCCESS_CODE_V2)) {
LoginModelV2 data = loginResponse.getData();
turnOffFingerprintAuthIfRequired(userId);
return gateway.saveUserInfo(data);
} else {
return Observable.error(new Exception(loginResponse.getMsg()));
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new LoginObserver(userId, encUserPassword)));
}
private void turnOffFingerprintAuthIfRequired(String userId) {
if (!userId.equalsIgnoreCase(gateway.getPersistedUserId())) {
gateway.turnOffFingerprintAuth(true);
gmeAuthManager.turnOfBiometric(true);
}
}
@ -156,10 +154,28 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
@Override
protected void onSuccess(LoginModelV2 loginResponse) {
if (SecurityUtils.checkFingerPrintUsablity(view.getContext()))
persistUserCredentialForFingerprintAuth(userId, encUserPassword, loginResponse);
if (gmeAuthManager.isBiometricSupportedByDevice())
gmeAuthManager.persistUserCredentialForFingerprintAuth(userId, encUserPassword)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
@Override
public void onComplete() {
onLoginSuccess();
}
@Override
public void onError(Throwable e) {
onLoginSuccess();
}
});
else {
onLoginSuccess(loginResponse);
onLoginSuccess();
}
}
@ -188,7 +204,7 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
encUserPassword = null;
}
private void onLoginSuccess(LoginModelV2 loginResponse) {
private void onLoginSuccess() {
Runnable task = null;
clearExistingFormData();
setSessionEnabled();
@ -198,34 +214,4 @@ public class LoginV2Presenter extends BasePresenter implements LoginV2PresenterI
}
public class UserCredentialEncryptionResultObserver extends DisposableObserver<LoginV2Gateway.UserCredentialEncryptionResultDTO> {
LoginModelV2 loginModelV2;
public UserCredentialEncryptionResultObserver(LoginModelV2 loginModelV2) {
this.loginModelV2 = loginModelV2;
}
@Override
public void onNext(LoginV2Gateway.UserCredentialEncryptionResultDTO userCredentialEncryptionResultDTO) {
gateway.persistSecretKeyForBiometric(userCredentialEncryptionResultDTO.getEncKey());
gateway.persistUserPwdForBiometric(userCredentialEncryptionResultDTO.getEncPwd());
gateway.persistUserIdForBiometric(userCredentialEncryptionResultDTO.getUserId());
onLoginSuccess(loginModelV2);
}
@Override
public void onError(Throwable e) {
gateway.flushBiometricData();
onLoginSuccess(loginModelV2);
}
@Override
public void onComplete() {
}
}
}

45
app/src/main/java/com/gmeremit/online/gmeremittance_native/security/GMEAuthManager.java

@ -8,11 +8,14 @@ import androidx.appcompat.app.AppCompatActivity;
import com.gmeremit.online.gmeremittance_native.GmeApplication;
import com.gmeremit.online.gmeremittance_native.base.PrefKeys;
import com.gmeremit.online.gmeremittance_native.loginV2.gateway.LoginV2Gateway;
import com.gmeremit.online.gmeremittance_native.loginV2.presenter.LoginV2Presenter;
import com.gmeremit.online.gmeremittance_native.security.auth.GMETxnOTPRequestBottomSheetDialog;
import com.gmeremit.online.gmeremittance_native.security.auth.GMEUserPasswordPromptBottomSheetDialog;
import com.gmeremit.online.gmeremittance_native.security.auth.profilescreen.GMEUserProfileChangeOTPRequestBottomSheetDialog;
import com.gmeremit.online.gmeremittance_native.security.model.GMEAuthFailedResult;
import com.gmeremit.online.gmeremittance_native.security.model.GMEAuthSuccessResult;
import com.gmeremit.online.gmeremittance_native.security.model.GMEBiometricEncryptionDTO;
import com.gmeremit.online.gmeremittance_native.security.model.GMEScreenBasedParam;
import com.gmeremit.online.gmeremittance_native.security.model.GMETxnParam;
import com.gmeremit.online.gmeremittance_native.security.utils.SecurityUtils;
@ -20,6 +23,7 @@ import com.mtramin.rxfingerprint.RxFingerprint;
import com.mtramin.rxfingerprint.data.BiometricExceptions;
import com.mtramin.rxfingerprint.data.FingerprintDecryptionResult;
import io.reactivex.Completable;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -128,6 +132,10 @@ public class GMEAuthManager {
return RxFingerprint.isAvailable(context);
}
public void turnOfBiometric(boolean action) {
gmeAuthManagerGateway.turnOffFingerprintAuth(action);
}
private void returnInvalidRequest() {
if (listener != null)
listener.onGMEAuthFailed(new GMEAuthFailedResult("Unknown auth requested.\n" + INVALID_REQUEST));
@ -165,14 +173,13 @@ public class GMEAuthManager {
if (e instanceof BiometricExceptions.BiometricAuthUserCancelledException)
listener.onGMEAuthCancelled();
else if (e instanceof BiometricExceptions.BiometricAuthNonRecoverableException) {
if(gmeTxnParam!=null&&gmeTxnParam.isFallbackAuthEnabled()) {
if (gmeTxnParam != null && gmeTxnParam.isFallbackAuthEnabled()) {
Toast.makeText(context, "Fingerprint authentication is not available at the moment. Please use the password instead", Toast.LENGTH_LONG).show();
new Handler().postDelayed(() -> showUserPasswordPrompt(), 500);
}
else
} else
listener.onGMEAuthFailed(new GMEAuthFailedResult(e.getMessage()));
} else if(e instanceof BiometricExceptions.BiometricAuthRecoverableException)
listener.onGMEAuthFailed(new GMEAuthFailedResult(e.getMessage(),true));
} else if (e instanceof BiometricExceptions.BiometricAuthRecoverableException)
listener.onGMEAuthFailed(new GMEAuthFailedResult(e.getMessage(), true));
else
listener.onGMEAuthFailed(new GMEAuthFailedResult(e.getMessage()));
}
@ -194,12 +201,38 @@ public class GMEAuthManager {
}
private Observable<String> decryptByKeyStore(String data) {
return SecurityUtils.decryptUsingKeyStore(context, data)
.map(FingerprintDecryptionResult::getDecrypted);
}
public Completable persistUserCredentialForFingerprintAuth(String userId, String pwd) {
return Completable.fromObservable(
SecurityUtils.generateKey()
.flatMap(key -> Observable.zip(Observable.just(userId),
SecurityUtils.encryptUsingAES(pwd, key).subscribeOn(Schedulers.io()),
encryptByKeyStore(key).subscribeOn(Schedulers.io()),
GMEBiometricEncryptionDTO::new)
).map(data -> {
gmeAuthManagerGateway.persistSecretKeyForBiometric(data.getEncKey());
gmeAuthManagerGateway.persistUserPwdForBiometric(data.getEncPwd());
gmeAuthManagerGateway.persistUserIdForBiometric(data.getUserId());
return true;
}).doOnError(error->{
gmeAuthManagerGateway.flushBiometricData();
})
);
}
private Observable<String> encryptByKeyStore(String data) {
return SecurityUtils.encryptUsingKeyStore(context, data)
.flatMap(encKey -> Observable.just(encKey.getEncrypted()));
}
private void showOTPTxnPrompt() {
GMETxnOTPRequestBottomSheetDialog.showPromptView(this.gmeTxnParam, new GMETxnOTPRequestBottomSheetDialog.GMETxnOTPUserSubmitListener() {
@Override

28
app/src/main/java/com/gmeremit/online/gmeremittance_native/security/GMEAuthManagerGateway.java

@ -18,4 +18,32 @@ class GMEAuthManagerGateway extends PrivilegedGateway {
public boolean isBiometricEnabledOnTheApp() {
return GmeApplication.getStorage().getBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED, false);
}
public void turnOffFingerprintAuth(boolean action) {
GmeApplication.getStorage().edit().putBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED, !action).apply();
}
public void persistUserIdForBiometric(String encrypted) {
GmeApplication.getStorage().edit().putString(PrefKeys.APP_USER_ID_SECRET_KEY, encrypted).apply();
}
public void persistUserPwdForBiometric(String encrypted) {
GmeApplication.getStorage().edit().putString(PrefKeys.APP_USER_SECRET_KEY, encrypted).apply();
}
public void persistSecretKeyForBiometric(String encrypted) {
GmeApplication.getStorage().edit().putString(PrefKeys.APP_SECRET_KEY, encrypted).apply();
}
public void flushBiometricData() {
SharedPreferences.Editor editor = GmeApplication.getStorage().edit();
editor.putString(PrefKeys.APP_USER_ID_SECRET_KEY, null);
editor.putBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED, false);
editor.putString(PrefKeys.APP_USER_SECRET_KEY, null);
editor.putString(PrefKeys.APP_SECRET_KEY, null);
editor.apply();
}
}

36
app/src/main/java/com/gmeremit/online/gmeremittance_native/security/model/GMEBiometricEncryptionDTO.java

@ -0,0 +1,36 @@
package com.gmeremit.online.gmeremittance_native.security.model;
public class GMEBiometricEncryptionDTO {
String userId;
String encPwd;
String encKey;
public GMEBiometricEncryptionDTO(String userId, String encPwd, String encKey) {
this.userId = userId;
this.encPwd = encPwd;
this.encKey = encKey;
}
public String getUserId() {
return userId;
}
public String getEncPwd() {
return encPwd;
}
public String getEncKey() {
return encKey;
}
@Override
public String toString() {
return "UserCredentialEncryptionResultDTO{" +
"userId='" + userId + '\'' +
", encPwd='" + encPwd + '\'' +
", encKey='" + encKey + '\'' +
'}';
}
}

50
app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/FingerprintEnablePromptActivity.java

@ -1,20 +1,23 @@
package com.gmeremit.online.gmeremittance_native.settings.view;
import android.content.SharedPreferences;
import android.os.Handler;
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
import com.gmeremit.online.gmeremittance_native.GmeApplication;
import com.gmeremit.online.gmeremittance_native.R;
import com.gmeremit.online.gmeremittance_native.base.BaseActivity;
import com.gmeremit.online.gmeremittance_native.base.PrefKeys;
import com.gmeremit.online.gmeremittance_native.customwidgets.CustomAlertDialog;
import com.gmeremit.online.gmeremittance_native.security.GMEAuthManager;
import com.gmeremit.online.gmeremittance_native.security.model.GMEAuthFailedResult;
import com.gmeremit.online.gmeremittance_native.security.model.GMEAuthSuccessResult;
import butterknife.BindView;
import butterknife.ButterKnife;
@ -40,6 +43,7 @@ public class FingerprintEnablePromptActivity extends BaseActivity implements Vie
TextView tv_manual;
private boolean isAnimationPlayed = false;
private GMEAuthManager gmeAuthManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -72,6 +76,7 @@ public class FingerprintEnablePromptActivity extends BaseActivity implements Vie
private void init() {
mobileBg = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_fp_prompt);
fingerBg = AnimatedVectorDrawableCompat.create(this, R.drawable.avd_fp);
gmeAuthManager= GMEAuthManager.getGmeAuthManager(this);
}
void performDefaultAction(Bundle savedInstance) {
@ -85,45 +90,32 @@ public class FingerprintEnablePromptActivity extends BaseActivity implements Vie
}
private boolean isBiometricDataAvailable() {
SharedPreferences sp = GmeApplication.getStorage();
return sp.getString(PrefKeys.APP_USER_ID_SECRET_KEY, null) != null && sp.getString(PrefKeys.APP_USER_SECRET_KEY, null) != null && sp.getString(PrefKeys.APP_SECRET_KEY, null) != null;
}
private void showFingerprintAuthDialog() {
if (isBiometricDataAvailable()) {
FingerPrintAuthPromptDialog fingerPrintAuthPromptDialog = new FingerPrintAuthPromptDialog();
fingerPrintAuthPromptDialog.setFingerprintAuthListener(true, new FingerPrintAuthPromptDialog.FingerprintAuthListener() {
@Override
public void onFingerPrintAuthenticated(boolean userAction) {
GmeApplication.getStorage().edit().putBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED, userAction).apply();
private void showFingerprintAuthDialog() {
if (gmeAuthManager.isBiometricDataAvailable()) {
gmeAuthManager.requestBiometricAuth().setListener(new GMEAuthManager.GMEAuthListener() {
@Override
public void onGMEAuthSuccess(GMEAuthSuccessResult result) {
gmeAuthManager.turnOfBiometric(false);
showToastMessage(getString(R.string.fingerprint_auth_enabled_text));
finish();
if (fingerPrintAuthPromptDialog != null)
fingerPrintAuthPromptDialog.dismiss();
}
@Override
public void onFingerPrintInvalidatedBySystem() {
public void onGMEAuthFailed(GMEAuthFailedResult failedResult) {
showToastMessage(failedResult.getFailedReason());
finish();
}
if (fingerPrintAuthPromptDialog != null)
fingerPrintAuthPromptDialog.dismiss();
@Override
public void onGMEAuthCancelled() {
new Handler().postDelayed(() -> {
GmeApplication.getStorage().edit().clear().apply();
showPopUpMessage(getString(R.string.fingerprint_changed_externally), CustomAlertDialog.AlertType.ALERT,
alert -> {
logout();
});
}, 200);
}
});
}).prompt();
if (!fingerPrintAuthPromptDialog.isAdded())
fingerPrintAuthPromptDialog.show(getSupportFragmentManager(), "FingerPrintScannerPromptDialog");
} else {
showPopUpMessage(getString(R.string.fingerprint_changed_externally), CustomAlertDialog.AlertType.ALERT,
alert -> {

2
app/src/main/java/com/gmeremit/online/gmeremittance_native/settings/view/SettingsView.java

@ -147,7 +147,7 @@ public class SettingsView extends BaseActivity implements CompoundButton.OnCheck
gmeAuthManager.requestBiometricAuth().setListener(new GMEAuthManager.GMEAuthListener() {
@Override
public void onGMEAuthSuccess(GMEAuthSuccessResult result) {
GmeApplication.getStorage().edit().putBoolean(PrefKeys.APP_FINGER_PRINT_ENABLED, isChecked).apply();
gmeAuthManager.turnOfBiometric(!isChecked);
view_fingerprint.setOnCheckedChangeListener(null);
view_fingerprint.setChecked(isChecked);
view_fingerprint.setOnCheckedChangeListener(SettingsView.this);

Loading…
Cancel
Save