Skip to content

Commit

Permalink
[WIP] refactor auth to allow multiple user pins
Browse files Browse the repository at this point in the history
  • Loading branch information
LZRS committed Mar 1, 2024
1 parent e08fd0e commit 81e8fb2
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ constructor(
accounts.find { it.name == username && it.type == authConfiguration.accountType }

val currentAccount =
secureSharedPreference.retrieveCredentials()?.let { cred ->
secureSharedPreference.retrieveSessionCredentials()?.let { cred ->
accounts.find { it.name == cred.username && it.type == authConfiguration.accountType }
}
if (currentAccount != null) {
Expand All @@ -231,8 +231,6 @@ constructor(
val currentUserRoles = getRolesList(currentAccessToken)
val secondUserRoles = getRolesList(oAuthResponse.accessToken)

// todo: verify requirements (with pm/tpm) on comparing match for user permission roles,
// also which roles to compare
// todo: optimise
val allMatching = currentUserRoles.all { secondUserRoles.contains(it) }
if (!allMatching) throw IllegalAccessException("Unauthorized")
Expand All @@ -247,7 +245,10 @@ constructor(
setAuthToken(newAccount, AUTH_TOKEN_TYPE, oAuthResponse.accessToken)
}
// Save credentials
secureSharedPreference.saveCredentials(username, password)
secureSharedPreference.apply {
saveMultiCredentials(username, password)
saveSessionUsername(username)
}
}
}

Expand All @@ -272,18 +273,16 @@ constructor(
}

fun validateSavedLoginCredentials(username: String, enteredPassword: CharArray): Boolean {
val credentials = secureSharedPreference.retrieveCredentials()
return if (username.equals(credentials?.username, ignoreCase = true)) {
val generatedHash =
enteredPassword.toPasswordHash(Base64.getDecoder().decode(credentials!!.salt))
generatedHash == credentials.passwordHash
} else {
false
}
val usernameCredential = secureSharedPreference.retrieveCredentials(username)
return if (usernameCredential != null){
val usernameGeneratedHash = enteredPassword.toPasswordHash(Base64.getDecoder().decode(
usernameCredential.salt))
usernameGeneratedHash == usernameCredential.passwordHash
} else false
}

fun findAccount(): Account? {
val credentials = secureSharedPreference.retrieveCredentials()
val credentials = secureSharedPreference.retrieveSessionCredentials()
return accountManager.getAccountsByType(authConfiguration.accountType).find {
it.name == credentials?.username
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class SecureSharedPreference @Inject constructor(@ApplicationContext val context
private fun getMasterKey() =
MasterKey.Builder(context).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()

fun saveCredentials(username: String, password: CharArray) {
@Deprecated("") private fun saveCredentials(username: String, password: CharArray) {
val randomSaltBytes = get256RandomBytes()

secureSharedPreferences.edit {
Expand All @@ -61,17 +61,70 @@ class SecureSharedPreference @Inject constructor(@ApplicationContext val context
clearPasswordInMemory(password)
}

fun saveMultiCredentials(username: String, password: CharArray){
val randomSaltBytes = get256RandomBytes()

secureSharedPreferences.apply {

edit {
putString(
"${username}_${SharedPreferenceKey.LOGIN_CREDENTIAL_KEY.name}",
AuthCredentials(
username = username,
salt = Base64.getEncoder().encodeToString(randomSaltBytes),
passwordHash = password.toPasswordHash(randomSaltBytes),
)
.encodeJson(),
)

putStringSet(SharedPreferenceKey.LOGIN_USERS.name, retrieveLoggedInUsernames() + username)
}
}

saveCredentials(username, password)

clearPasswordInMemory(password)
}

fun saveSessionUsername(username: String) = secureSharedPreferences.edit {
putString(SharedPreferenceKey.LOGIN_SESSION_USER.name, username)
}

fun retrieveLoggedInUsernames(): Set<String> = secureSharedPreferences.getStringSet(SharedPreferenceKey.LOGIN_USERS.name, emptySet())!!


@Deprecated("")
fun deleteCredentials() =
secureSharedPreferences.edit { remove(SharedPreferenceKey.LOGIN_CREDENTIAL_KEY.name) }

fun retrieveSessionUsername() = retrieveCredentials()?.username
fun deleteCredentials(username: String) = secureSharedPreferences.apply {
val users = retrieveLoggedInUsernames()
edit {
remove("${username}_${SharedPreferenceKey.LOGIN_CREDENTIAL_KEY.name}")
putStringSet(SharedPreferenceKey.LOGIN_USERS.name, users - username)
}
}

fun retrieveCredentials(): AuthCredentials? =
// fun retrieveSessionUsername() = retrieveCredentials()?.username

fun retrieveSessionUsername() = secureSharedPreferences.getString(SharedPreferenceKey.LOGIN_SESSION_USER.name, null)

fun retrieveSessionUsername(username: String) = retrieveCredentials(username)?.username

@Deprecated("") fun retrieveCredentials(): AuthCredentials? =
secureSharedPreferences
.getString(SharedPreferenceKey.LOGIN_CREDENTIAL_KEY.name, null)
?.decodeJson<AuthCredentials>()

fun saveSessionPin(pin: CharArray) {
fun retrieveSessionCredentials(): AuthCredentials? =
retrieveSessionUsername()?.let { retrieveCredentials(it) }

fun retrieveCredentials(username: String): AuthCredentials? =
secureSharedPreferences
.getString("${username}_${SharedPreferenceKey.LOGIN_CREDENTIAL_KEY.name}", null)
?.decodeJson<AuthCredentials>()

@Deprecated("") private fun saveSessionPin(pin: CharArray) {
val randomSaltBytes = get256RandomBytes()
secureSharedPreferences.edit {
putString(
Expand All @@ -82,17 +135,40 @@ class SecureSharedPreference @Inject constructor(@ApplicationContext val context
}
}

fun saveSessionPin(username: String, pin: CharArray){
val randomSaltBytes = get256RandomBytes()
val hash = pin.toPasswordHash(randomSaltBytes)

secureSharedPreferences.edit {
putString("${username}_${SharedPreferenceKey.LOGIN_PIN_SALT.name}", Base64.getEncoder().encodeToString(randomSaltBytes))

putString("${username}_${SharedPreferenceKey.LOGIN_PIN_KEY.name}", hash)
}

saveSessionPin(pin)
}

fun retrieveSessionUserSalt(username: String) = secureSharedPreferences.getString("${username}_${SharedPreferenceKey.LOGIN_PIN_SALT.name}", null)

fun retrieveSessionUserPin(username: String) = secureSharedPreferences.getString("${username}_${SharedPreferenceKey.LOGIN_PIN_KEY.name}", null)

@VisibleForTesting fun get256RandomBytes() = 256.getRandomBytesOfSize()

fun retrievePinSalt() =
@Deprecated("") fun retrievePinSalt() =
secureSharedPreferences.getString(SharedPreferenceKey.LOGIN_PIN_SALT.name, null)

fun retrieveSessionPin() =
@Deprecated("") fun retrieveSessionPin() =
secureSharedPreferences.getString(SharedPreferenceKey.LOGIN_PIN_KEY.name, null)

fun deleteSessionPin() =
@Deprecated("") fun deleteSessionPin() =
secureSharedPreferences.edit { remove(SharedPreferenceKey.LOGIN_PIN_KEY.name) }

fun deleteSessionPin(username: String) =
secureSharedPreferences.edit {
remove("${username}_${SharedPreferenceKey.LOGIN_PIN_KEY.name}")
remove("${username}_${SharedPreferenceKey.LOGIN_PIN_SALT.name}")
}

/** This method resets/clears all existing values in the shared preferences synchronously */
fun resetSharedPrefs() = secureSharedPreferences.edit { clear() }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ enum class SharedPreferenceKey {
LOGIN_CREDENTIAL_KEY,
LOGIN_PIN_KEY,
LOGIN_PIN_SALT,
LOGIN_USERS,
LOGIN_SESSION_USER,
LAST_OFFSET,
USER_INFO,
CARE_TEAM,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,24 @@ constructor(
}
}

fun onPinVerified(username:String, validPin: Boolean){
viewModelScope.launch(dispatcherProvider.io()) {
secureSharedPreference.saveSessionUsername(username)
onPinVerified(validPin)
}
}

fun onShowPinError(showError: Boolean) {
pinUiState.value = pinUiState.value.copy(showProgressBar = false)
_showError.postValue(showError)
}

fun onSetPin(newPin: CharArray) {
viewModelScope.launch(dispatcherProvider.io()) {
val username = secureSharedPreference.retrieveSessionUsername()

pinUiState.value = pinUiState.value.copy(showProgressBar = true)
secureSharedPreference.saveSessionPin(newPin)
secureSharedPreference.saveSessionPin(username!!, newPin)
pinUiState.value = pinUiState.value.copy(showProgressBar = false)
}

Expand Down Expand Up @@ -150,4 +159,21 @@ constructor(
onPinVerified(validPin)
}
}

fun pinLogin(username: String, enteredPin: CharArray, callback: (Boolean) -> Unit) {
viewModelScope.launch(dispatcherProvider.io()) {
pinUiState.value = pinUiState.value.copy(showProgressBar = true)

val storedPinHash = secureSharedPreference.retrieveSessionUserPin(username)
val salt = secureSharedPreference.retrieveSessionUserSalt(username)
val generatedHash = enteredPin.toPasswordHash(Base64.getDecoder().decode(salt))
val validPin = generatedHash == storedPinHash

if (validPin) clearPasswordInMemory(enteredPin)

callback.invoke(validPin)

onPinVerified(validPin)
}
}
}

0 comments on commit 81e8fb2

Please sign in to comment.