From 0f481cba38582b7830f0849b8b39b49f87d8c7bb Mon Sep 17 00:00:00 2001 From: Adam Velebil Date: Tue, 18 Apr 2023 12:43:48 +0200 Subject: [PATCH 1/2] fix OathSession "remembered" unlock --- .../yubico/authenticator/oath/OathManager.kt | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt b/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt index f00271b5d..bf4641ce0 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt @@ -63,6 +63,7 @@ import kotlinx.coroutines.* import kotlinx.serialization.encodeToString import java.net.URI import java.util.concurrent.Executors +import java.util.concurrent.atomic.AtomicBoolean import kotlin.coroutines.suspendCoroutine typealias OathAction = (Result) -> Unit @@ -100,6 +101,7 @@ class OathManager( @TargetApi(Build.VERSION_CODES.M) private fun createKeyStoreProviderM(): KeyProvider = KeyStoreProvider() + private var unlockOnConnect = AtomicBoolean(true) private var pendingAction: OathAction? = null private var refreshJob: Job? = null private var addToAny = false @@ -241,8 +243,7 @@ class OathManager( override suspend fun processYubiKey(device: YubiKeyDevice) { try { device.withConnection { connection -> - val session = YubiKitOathSession(connection) - + val session = getOathSession(connection) val previousId = oathViewModel.sessionState.value?.deviceId if (session.deviceId == previousId && device is NfcYubiKeyDevice) { // Run any pending action @@ -414,7 +415,7 @@ class OathManager( currentPassword: String?, newPassword: String, ): String = - useOathSession("Set password") { session -> + useOathSession("Set password", unlock = false) { session -> if (session.isAccessKeySet) { if (currentPassword == null) { throw Exception("Must provide current password to be able to change it") @@ -599,6 +600,29 @@ class OathManager( return false // the unlock did not work, session is locked } + /** + * Returns a [YubiKitOathSession] for the [connection]. + * The session will be unlocked if [unlockOnConnect] is true. + * + * Generally we always want to try to unlock the session and that is why the variable + * [unlockOnConnect] is also reset to true. + * + * Currently, only setPassword and unsetPassword will not unlock the session. + * + * @param connection the device SmartCard connection + * @return a [YubiKitOathSession] which is unlocked or locked based on an internal parameter + */ + private fun getOathSession(connection: SmartCardConnection) : YubiKitOathSession { + val session = YubiKitOathSession(connection) + + if (!unlockOnConnect.compareAndSet(false, true)) { + tryToUnlockOathSession(session) + } + + return session + } + + private fun calculateOathCodes(session: YubiKitOathSession): Map { val isUsbKey = appViewModel.connectedYubiKey.value != null var timestamp = System.currentTimeMillis() @@ -626,37 +650,30 @@ class OathManager( unlock: Boolean = true, action: (YubiKitOathSession) -> T ): T { + + // callers can decide whether the session should be unlocked first + unlockOnConnect.set(unlock) return appViewModel.connectedYubiKey.value?.let { - useOathSessionUsb(it, unlock, action) - } ?: useOathSessionNfc(title, unlock, action) + useOathSessionUsb(it, action) + } ?: useOathSessionNfc(title, action) } private suspend fun useOathSessionUsb( device: UsbYubiKeyDevice, - unlock: Boolean = true, block: (YubiKitOathSession) -> T ): T = device.withConnection { - val session = YubiKitOathSession(it) - if (unlock) { - tryToUnlockOathSession(session) - } - block(session) + block(getOathSession(it)) } private suspend fun useOathSessionNfc( title: String, - unlock: Boolean = true, block: (YubiKitOathSession) -> T ): T { try { val result = suspendCoroutine { outer -> pendingAction = { outer.resumeWith(runCatching { - val session = it.value - if (unlock) { - tryToUnlockOathSession(session) - } - block.invoke(session) + block.invoke(it.value) }) } dialogManager.showDialog(Icon.NFC, "Tap your key", title) { From ae93f39345bcbc47aebb232dfd07d702e7cda1e3 Mon Sep 17 00:00:00 2001 From: Adam Velebil Date: Tue, 18 Apr 2023 13:20:27 +0200 Subject: [PATCH 2/2] use val --- .../main/kotlin/com/yubico/authenticator/oath/OathManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt b/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt index bf4641ce0..d67333116 100644 --- a/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt +++ b/android/app/src/main/kotlin/com/yubico/authenticator/oath/OathManager.kt @@ -101,7 +101,7 @@ class OathManager( @TargetApi(Build.VERSION_CODES.M) private fun createKeyStoreProviderM(): KeyProvider = KeyStoreProvider() - private var unlockOnConnect = AtomicBoolean(true) + private val unlockOnConnect = AtomicBoolean(true) private var pendingAction: OathAction? = null private var refreshJob: Job? = null private var addToAny = false