From 2ffeffcec24df0c0720ebc02624b60f4939a2e54 Mon Sep 17 00:00:00 2001 From: Tamas Toth Date: Fri, 26 Jul 2024 14:44:20 +0200 Subject: [PATCH] NEVISACCESSAPP-6057: Introduce authenticator allow list - Added allowed list of authenticators in the `ApplicationModule`. - Added `AuthenticatorValidator`. --- .../configuration/ConfigurationProvider.kt | 7 +- .../ConfigurationProviderImpl.kt | 7 +- .../exampleapp/dagger/ApplicationModule.kt | 69 ++++++++-- .../domain/interaction/AccountSelectorImpl.kt | 24 ++-- .../AuthenticationAuthenticatorSelector.kt | 16 --- ...AuthenticationAuthenticatorSelectorImpl.kt | 88 ------------- .../interaction/AuthenticatorSelectorImpl.kt | 116 +++++++++++++++++ .../interaction/BiometricUserVerifierImpl.kt | 10 +- .../DevicePasscodeUserVerifierImpl.kt | 10 +- .../FingerprintUserVerifierImpl.kt | 14 +-- .../domain/interaction/PinChangerImpl.kt | 14 ++- .../domain/interaction/PinEnrollerImpl.kt | 11 +- .../domain/interaction/PinUserVerifierImpl.kt | 13 +- .../RegistrationAuthenticatorSelector.kt | 16 --- .../RegistrationAuthenticatorSelectorImpl.kt | 118 ------------------ .../validation/AuthenticatorValidator.kt | 39 ++++++ .../validation/AuthenticatorValidatorImpl.kt | 94 ++++++++++++++ .../AuthCloudRegistrationViewModel.kt | 25 ++-- .../nevis/exampleapp/ui/home/HomeViewModel.kt | 43 ++++--- .../ui/outOfBand/OutOfBandViewModel.kt | 29 +++-- .../ui/qrReader/QrReaderViewModel.kt | 45 +++---- .../selectAccount/SelectAccountViewModel.kt | 28 +++-- .../SelectAuthenticatorNavigationParameter.kt | 9 +- .../UserNamePasswordLoginViewModel.kt | 27 ++-- gradle.properties | 4 +- 25 files changed, 474 insertions(+), 402 deletions(-) delete mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelector.kt delete mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelectorImpl.kt create mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticatorSelectorImpl.kt delete mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelector.kt delete mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelectorImpl.kt create mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidator.kt create mode 100644 app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidatorImpl.kt diff --git a/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProvider.kt b/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProvider.kt index 486a44f..87df3b7 100644 --- a/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProvider.kt +++ b/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProvider.kt @@ -24,5 +24,10 @@ interface ConfigurationProvider { * The [Configuration] object related to the environment. */ val configuration: Configuration + + /** + * The list of allowed authenticators. + */ + val authenticatorAllowlist: List //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProviderImpl.kt b/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProviderImpl.kt index cad5d89..f74ad2f 100644 --- a/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProviderImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/common/configuration/ConfigurationProviderImpl.kt @@ -9,9 +9,10 @@ package ch.nevis.exampleapp.common.configuration import ch.nevis.mobile.sdk.api.Configuration /** - * Default implementation of [ConfigurationProvider] abstract class. + * Default implementation of [ConfigurationProvider] interface. */ class ConfigurationProviderImpl( override val environment: Environment, - override val configuration: Configuration -) : ConfigurationProvider \ No newline at end of file + override val configuration: Configuration, + override val authenticatorAllowlist: List +) : ConfigurationProvider diff --git a/app/src/main/java/ch/nevis/exampleapp/dagger/ApplicationModule.kt b/app/src/main/java/ch/nevis/exampleapp/dagger/ApplicationModule.kt index f9a38f8..e11912b 100644 --- a/app/src/main/java/ch/nevis/exampleapp/dagger/ApplicationModule.kt +++ b/app/src/main/java/ch/nevis/exampleapp/dagger/ApplicationModule.kt @@ -23,12 +23,19 @@ import ch.nevis.exampleapp.domain.deviceInformation.DeviceInformationFactoryImpl import ch.nevis.exampleapp.domain.interaction.* import ch.nevis.exampleapp.domain.log.SdkLogger import ch.nevis.exampleapp.domain.log.SdkLoggerImpl +import ch.nevis.exampleapp.domain.validation.AuthenticatorValidator +import ch.nevis.exampleapp.domain.validation.AuthenticatorValidatorImpl import ch.nevis.exampleapp.ui.navigation.NavigationDispatcher import ch.nevis.exampleapp.ui.navigation.NavigationDispatcherImpl import ch.nevis.mobile.sdk.api.Configuration +import ch.nevis.mobile.sdk.api.localdata.Authenticator.BIOMETRIC_AUTHENTICATOR_AAID +import ch.nevis.mobile.sdk.api.localdata.Authenticator.DEVICE_PASSCODE_AUTHENTICATOR_AAID +import ch.nevis.mobile.sdk.api.localdata.Authenticator.FINGERPRINT_AUTHENTICATOR_AAID +import ch.nevis.mobile.sdk.api.localdata.Authenticator.PIN_AUTHENTICATOR_AAID import ch.nevis.mobile.sdk.api.operation.pin.PinChanger import ch.nevis.mobile.sdk.api.operation.pin.PinEnroller import ch.nevis.mobile.sdk.api.operation.selection.AccountSelector +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier @@ -41,6 +48,7 @@ import dagger.hilt.components.SingletonComponent import retrofit2.Retrofit import retrofit2.converter.gson.GsonConverterFactory import java.net.URI +import javax.inject.Named import javax.inject.Singleton /** @@ -50,6 +58,20 @@ import javax.inject.Singleton @InstallIn(SingletonComponent::class) class ApplicationModule { + //region Constants + companion object { + /** + * The unique name of authenticator selector implementation for Registration operation. + */ + const val REGISTRATION_AUTHENTICATOR_SELECTOR = "REGISTRATION_AUTHENTICATOR_SELECTOR" + + /** + * The unique name of authenticator selector implementation for Authentication operation. + */ + const val AUTHENTICATION_AUTHENTICATOR_SELECTOR = "AUTHENTICATION_AUTHENTICATOR_SELECTOR" + } + //endregion + //region Configuration @Suppress("DEPRECATION") @SuppressLint("PackageManagerGetSignatures") @@ -90,12 +112,21 @@ class ApplicationModule { .build() } + @Provides + fun provideAuthenticatorAllowlist(): List = listOf( + PIN_AUTHENTICATOR_AAID, + FINGERPRINT_AUTHENTICATOR_AAID, + BIOMETRIC_AUTHENTICATOR_AAID, + DEVICE_PASSCODE_AUTHENTICATOR_AAID + ) + @Provides @Singleton fun provideConfigurationProvider(application: Application): ConfigurationProvider = ConfigurationProviderImpl( Environment.AUTHENTICATION_CLOUD, - provideAuthenticationCloudConfiguration(application) + provideAuthenticationCloudConfiguration(application), + provideAuthenticatorAllowlist() ) //endregion @@ -131,6 +162,12 @@ class ApplicationModule { fun provideSettings(@ApplicationContext context: Context): Settings = SettingsImpl(context) //endregion + //region Validation + @Provides + @Singleton + fun provideAuthenticatorValidator(): AuthenticatorValidator = AuthenticatorValidatorImpl() + //endregion + //region Interaction @Provides fun provideBiometricUserVerifier(navigationDispatcher: NavigationDispatcher): BiometricUserVerifier = @@ -152,23 +189,35 @@ class ApplicationModule { AccountSelectorImpl(navigationDispatcher, errorHandler) @Provides - fun provideAuthenticationAuthenticatorSelector( + @Named(REGISTRATION_AUTHENTICATOR_SELECTOR) + fun provideRegistrationAuthenticatorSelector( + configurationProvider: ConfigurationProvider, navigationDispatcher: NavigationDispatcher, + authenticatorValidator: AuthenticatorValidator, settings: Settings - ): AuthenticationAuthenticatorSelector = - AuthenticationAuthenticatorSelectorImpl( + ): AuthenticatorSelector = + AuthenticatorSelectorImpl( + configurationProvider, navigationDispatcher, - settings + authenticatorValidator, + settings, + AuthenticatorSelectorOperation.REGISTRATION ) @Provides - fun provideRegistrationAuthenticatorSelector( + @Named(AUTHENTICATION_AUTHENTICATOR_SELECTOR) + fun provideAuthenticationAuthenticatorSelector( + configurationProvider: ConfigurationProvider, navigationDispatcher: NavigationDispatcher, + authenticatorValidator: AuthenticatorValidator, settings: Settings - ): RegistrationAuthenticatorSelector = - RegistrationAuthenticatorSelectorImpl( + ): AuthenticatorSelector = + AuthenticatorSelectorImpl( + configurationProvider, navigationDispatcher, - settings + authenticatorValidator, + settings, + AuthenticatorSelectorOperation.AUTHENTICATION ) @Provides @@ -204,4 +253,4 @@ class ApplicationModule { .addConverterFactory(GsonConverterFactory.create()) .build() //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AccountSelectorImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AccountSelectorImpl.kt index d67ab66..bac1084 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AccountSelectorImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AccountSelectorImpl.kt @@ -21,10 +21,10 @@ import ch.nevis.mobile.sdk.api.operation.selection.AccountSelector import timber.log.Timber /** - * Default implementation of [AccountSelector] interface. It checks the set and - * transaction confirmation data in received [AccountSelectionContext] object and decides + * Default implementation of [AccountSelector] interface. It checks the [Account] set and + * transaction confirmation data received in the [AccountSelectionContext] object and decides * if the next step is transaction confirmation or account selection. As an addition it also showcases - * how to skip account selection if the received account list set only one element. + * how to skip account selection if the received account list set has only one element. */ class AccountSelectorImpl( @@ -42,28 +42,28 @@ class AccountSelectorImpl( //region AccountSelector override fun selectAccount( - accountSelectionContext: AccountSelectionContext, - accountSelectionHandler: AccountSelectionHandler + context: AccountSelectionContext, + handler: AccountSelectionHandler ) { Timber.asTree() .sdk("Please select one of the received available accounts!") try { - val accounts = validAccounts(accountSelectionContext) + val accounts = validAccounts(context) if (accounts.isEmpty()) { throw BusinessException.accountsNotFound() } val transactionConfirmationData = - accountSelectionContext.transactionConfirmationData().orElse(null) + context.transactionConfirmationData().orElse(null) transactionConfirmationData?.also { navigationDispatcher.requestNavigation( NavigationGraphDirections.actionGlobalTransactionConfirmationFragment( TransactionConfirmationNavigationParameter( Operation.OUT_OF_BAND_AUTHENTICATION, - accountSelectionContext.accounts(), + context.accounts(), it.decodeToString(), - accountSelectionHandler + handler ) ) ) @@ -71,14 +71,14 @@ class AccountSelectorImpl( if (accounts.size == 1) { Timber.asTree() .sdk("One account found, performing automatic selection!") - accountSelectionHandler.username(accounts.first().username()) + handler.username(accounts.first().username()) } else { navigationDispatcher.requestNavigation( NavigationGraphDirections.actionGlobalSelectAccountFragment( SelectAccountNavigationParameter( Operation.OUT_OF_BAND_AUTHENTICATION, - accountSelectionContext.accounts(), - accountSelectionHandler + context.accounts(), + handler ) ) ) diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelector.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelector.kt deleted file mode 100644 index ba084b6..0000000 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelector.kt +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Nevis Mobile Authentication SDK Example App - * - * Copyright © 2023. Nevis Security AG. All rights reserved. - */ - -package ch.nevis.exampleapp.domain.interaction - -import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector - -/** - * Marker interface declaration for [AuthenticatorSelector] implementations those are used during - * authentication operations. This interface is created to ease Dagger Hilt injection of [AuthenticatorSelector] - * implementations. - */ -interface AuthenticationAuthenticatorSelector : AuthenticatorSelector \ No newline at end of file diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelectorImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelectorImpl.kt deleted file mode 100644 index 6fda602..0000000 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticationAuthenticatorSelectorImpl.kt +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Nevis Mobile Authentication SDK Example App - * - * Copyright © 2023. Nevis Security AG. All rights reserved. - */ - -package ch.nevis.exampleapp.domain.interaction - -import ch.nevis.exampleapp.NavigationGraphDirections -import ch.nevis.exampleapp.common.settings.Settings -import ch.nevis.exampleapp.domain.model.operation.Operation -import ch.nevis.exampleapp.domain.util.isUserEnrolled -import ch.nevis.exampleapp.domain.util.titleResId -import ch.nevis.exampleapp.logging.sdk -import ch.nevis.exampleapp.ui.navigation.NavigationDispatcher -import ch.nevis.exampleapp.ui.selectAuthenticator.model.AuthenticatorItem -import ch.nevis.exampleapp.ui.selectAuthenticator.parameter.SelectAuthenticatorNavigationParameter -import ch.nevis.mobile.sdk.api.localdata.Authenticator -import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionContext -import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionHandler -import timber.log.Timber - -/** - * Default implementation of [AuthenticationAuthenticatorSelector] interface. It collects registered - * and hardware supported authenticators for an authentication operation and navigates to Select - * Authenticator view. - */ -class AuthenticationAuthenticatorSelectorImpl( - - /** - * An instance of a [NavigationDispatcher] interface implementation. - */ - private val navigationDispatcher: NavigationDispatcher, - - /** - * An instance of a [Settings] interface implementation. - */ - private val settings: Settings -) : AuthenticationAuthenticatorSelector { - - //region AuthenticatorSelector - override fun selectAuthenticator( - authenticatorSelectionContext: AuthenticatorSelectionContext, - authenticatorSelectionHandler: AuthenticatorSelectionHandler - ) { - Timber.asTree() - .sdk("Please select one of the received available authenticators!") - - val authenticatorItems = authenticatorSelectionContext.authenticators().mapNotNull { - mapForAuthentication(it, authenticatorSelectionContext) - }.toSet() - - navigationDispatcher.requestNavigation( - NavigationGraphDirections.actionGlobalSelectAuthenticatorFragment( - SelectAuthenticatorNavigationParameter( - Operation.AUTHENTICATION, - authenticatorItems, - authenticatorSelectionHandler - ) - ) - ) - } - //endregion - - //region Private Interface - private fun mapForAuthentication( - authenticator: Authenticator, - context: AuthenticatorSelectionContext - ): AuthenticatorItem? { - Timber.d("Checking if authenticator %s is eligible for authentication.", authenticator.aaid()) - return if (authenticator.registration() - .isRegistered(context.account().username()) && authenticator.isSupportedByHardware - ) { - AuthenticatorItem( - authenticator.aaid(), - context.isPolicyCompliant(authenticator.aaid()), - authenticator.isUserEnrolled( - context.account().username(), - settings.allowClass2Sensors - ), - authenticator.titleResId() - ) - } else { - null - } - } - //endregion -} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticatorSelectorImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticatorSelectorImpl.kt new file mode 100644 index 0000000..fd01e30 --- /dev/null +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/AuthenticatorSelectorImpl.kt @@ -0,0 +1,116 @@ +/** + * Nevis Mobile Authentication SDK Example App + * + * Copyright © 2024. Nevis Security AG. All rights reserved. + */ + +package ch.nevis.exampleapp.domain.interaction + +import ch.nevis.exampleapp.NavigationGraphDirections +import ch.nevis.exampleapp.common.configuration.ConfigurationProvider +import ch.nevis.exampleapp.common.settings.Settings +import ch.nevis.exampleapp.domain.util.isUserEnrolled +import ch.nevis.exampleapp.domain.util.titleResId +import ch.nevis.exampleapp.domain.validation.AuthenticatorValidator +import ch.nevis.exampleapp.logging.sdk +import ch.nevis.exampleapp.ui.navigation.NavigationDispatcher +import ch.nevis.exampleapp.ui.selectAuthenticator.model.AuthenticatorItem +import ch.nevis.exampleapp.ui.selectAuthenticator.parameter.SelectAuthenticatorNavigationParameter +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionContext +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionHandler +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector +import timber.log.Timber + +/** + * Supported operations during authenticator selection. + */ +enum class AuthenticatorSelectorOperation { + + /** + * Registration operation. + */ + REGISTRATION, + + /** + * Authentication operation. + */ + AUTHENTICATION, +} + +/** + * Default implementation of [AuthenticatorSelector] interface. + */ +class AuthenticatorSelectorImpl( + /** + * An instance of a [ConfigurationProvider] implementation. + */ + private val configurationProvider: ConfigurationProvider, + + /** + * An instance of a [NavigationDispatcher] interface implementation. + */ + private val navigationDispatcher: NavigationDispatcher, + + /** + * An instance of an [AuthenticatorValidator] interface implementation. + */ + private val authenticatorValidator: AuthenticatorValidator, + + /** + * An instance of a [Settings] interface implementation. + */ + private val settings: Settings, + + /** + * The current operation. + */ + private val operation: AuthenticatorSelectorOperation +) : AuthenticatorSelector { + override fun selectAuthenticator( + context: AuthenticatorSelectionContext, + handler: AuthenticatorSelectionHandler + ) { + Timber.asTree().sdk("Please select one of the received available authenticators!") + + val authenticators = when (operation) { + AuthenticatorSelectorOperation.REGISTRATION -> { + authenticatorValidator.validateForRegistration( + context, + configurationProvider.authenticatorAllowlist + ) + } + AuthenticatorSelectorOperation.AUTHENTICATION -> { + authenticatorValidator.validateForAuthentication( + context, + configurationProvider.authenticatorAllowlist + ) + } + } + + if (authenticators.isEmpty()) { + Timber.e("No available authenticators found. Cancelling authenticator selection.") + return handler.cancel() + } + + val authenticatorItems = authenticators.map { + AuthenticatorItem( + it.aaid(), + context.isPolicyCompliant(it.aaid()), + it.isUserEnrolled( + context.account().username(), + settings.allowClass2Sensors + ), + it.titleResId() + ) + }.toSet() + + navigationDispatcher.requestNavigation( + NavigationGraphDirections.actionGlobalSelectAuthenticatorFragment( + SelectAuthenticatorNavigationParameter( + authenticatorItems, + handler + ) + ) + ) + } +} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/BiometricUserVerifierImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/BiometricUserVerifierImpl.kt index 49b6b51..41066b6 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/BiometricUserVerifierImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/BiometricUserVerifierImpl.kt @@ -31,16 +31,16 @@ class BiometricUserVerifierImpl( //region BiometricUserVerifier override fun verifyBiometric( - biometricUserVerificationContext: BiometricUserVerificationContext, - biometricUserVerificationHandler: BiometricUserVerificationHandler + context: BiometricUserVerificationContext, + handler: BiometricUserVerificationHandler ) { Timber.asTree().sdk("Please start biometric user verification.") navigationDispatcher.requestNavigation( NavigationGraphDirections.actionGlobalVerifyUserFragment( VerifyUserNavigationParameter( VerifyUserViewMode.BIOMETRIC, - biometricUserVerificationContext.authenticator().titleResId(), - biometricUserVerificationHandler = biometricUserVerificationHandler + context.authenticator().titleResId(), + biometricUserVerificationHandler = handler ) ) ) @@ -51,4 +51,4 @@ class BiometricUserVerifierImpl( .sdk("Valid credentials provided during biometric verification.") } //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/DevicePasscodeUserVerifierImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/DevicePasscodeUserVerifierImpl.kt index 4d9c5ce..211ce7e 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/DevicePasscodeUserVerifierImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/DevicePasscodeUserVerifierImpl.kt @@ -31,16 +31,16 @@ class DevicePasscodeUserVerifierImpl( //region DevicePasscodeUserVerifier override fun verifyDevicePasscode( - devicePasscodeUserVerificationContext: DevicePasscodeUserVerificationContext, - devicePasscodeUserVerificationHandler: DevicePasscodeUserVerificationHandler + context: DevicePasscodeUserVerificationContext, + handler: DevicePasscodeUserVerificationHandler ) { Timber.asTree().sdk("Please start device passcode user verification.") navigationDispatcher.requestNavigation( NavigationGraphDirections.actionGlobalVerifyUserFragment( VerifyUserNavigationParameter( VerifyUserViewMode.DEVICE_PASSCODE, - devicePasscodeUserVerificationContext.authenticator().titleResId(), - devicePasscodeUserVerificationHandler = devicePasscodeUserVerificationHandler + context.authenticator().titleResId(), + devicePasscodeUserVerificationHandler = handler ) ) ) @@ -51,4 +51,4 @@ class DevicePasscodeUserVerifierImpl( .sdk("Valid credentials provided during device passcode verification.") } //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/FingerprintUserVerifierImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/FingerprintUserVerifierImpl.kt index 09f4c43..7d1c457 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/FingerprintUserVerifierImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/FingerprintUserVerifierImpl.kt @@ -31,10 +31,10 @@ class FingerprintUserVerifierImpl( //region FingerprintUserVerifier override fun verifyFingerprint( - fingerprintUserVerificationContext: FingerprintUserVerificationContext, - fingerprintUserVerificationHandler: FingerprintUserVerificationHandler + context: FingerprintUserVerificationContext, + handler: FingerprintUserVerificationHandler ) { - if (fingerprintUserVerificationContext.lastRecoverableError().isPresent) { + if (context.lastRecoverableError().isPresent) { Timber.asTree().sdk("Fingerprint user verification failed. Please try again.") } else { Timber.asTree().sdk("Please start fingerprint user verification.") @@ -44,9 +44,9 @@ class FingerprintUserVerifierImpl( NavigationGraphDirections.actionGlobalVerifyUserFragment( VerifyUserNavigationParameter( VerifyUserViewMode.FINGERPRINT, - fingerprintUserVerificationContext.authenticator().titleResId(), - fingerprintUserVerificationHandler = fingerprintUserVerificationHandler, - fingerprintUserVerificationError = fingerprintUserVerificationContext.lastRecoverableError() + context.authenticator().titleResId(), + fingerprintUserVerificationHandler = handler, + fingerprintUserVerificationError = context.lastRecoverableError() .orElse(null) ) ) @@ -58,4 +58,4 @@ class FingerprintUserVerifierImpl( .sdk("Valid credentials provided during fingerprint verification.") } //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinChangerImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinChangerImpl.kt index 61cd3f3..895f0b8 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinChangerImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinChangerImpl.kt @@ -28,8 +28,11 @@ class PinChangerImpl( */ private val navigationDispatcher: NavigationDispatcher ) : PinChanger { - override fun changePin(pinChangeContext: PinChangeContext, pinChangeHandler: PinChangeHandler) { - if (pinChangeContext.lastRecoverableError().isPresent) { + override fun changePin( + context: PinChangeContext, + handler: PinChangeHandler + ) { + if (context.lastRecoverableError().isPresent) { Timber.asTree().sdk("PIN change failed. Please try again.") } else { Timber.asTree().sdk("Please start PIN change.") @@ -39,10 +42,9 @@ class PinChangerImpl( NavigationGraphDirections.actionGlobalPinFragment( PinNavigationParameter( PinViewMode.CHANGE_PIN, - pinChangeContext.authenticatorProtectionStatus(), - lastRecoverableError = pinChangeContext.lastRecoverableError() - .orElse(null), - pinChangeHandler = pinChangeHandler + context.authenticatorProtectionStatus(), + lastRecoverableError = context.lastRecoverableError().orElse(null), + pinChangeHandler = handler ) ) ) diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinEnrollerImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinEnrollerImpl.kt index 04c5b06..8148358 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinEnrollerImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinEnrollerImpl.kt @@ -30,10 +30,10 @@ class PinEnrollerImpl( //region PinEnroller override fun enrollPin( - pinEnrollmentContext: PinEnrollmentContext, - pinEnrollmentHandler: PinEnrollmentHandler + context: PinEnrollmentContext, + handler: PinEnrollmentHandler ) { - if (pinEnrollmentContext.lastRecoverableError().isPresent) { + if (context.lastRecoverableError().isPresent) { Timber.asTree().sdk("PIN enrollment failed. Please try again.") } else { Timber.asTree().sdk("Please start PIN enrollment.") @@ -43,9 +43,8 @@ class PinEnrollerImpl( NavigationGraphDirections.actionGlobalPinFragment( PinNavigationParameter( PinViewMode.ENROLL_PIN, - lastRecoverableError = pinEnrollmentContext.lastRecoverableError() - .orElse(null), - pinEnrollmentHandler = pinEnrollmentHandler + lastRecoverableError = context.lastRecoverableError().orElse(null), + pinEnrollmentHandler = handler ) ) ) diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinUserVerifierImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinUserVerifierImpl.kt index 49877af..472b10b 100644 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinUserVerifierImpl.kt +++ b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/PinUserVerifierImpl.kt @@ -31,10 +31,10 @@ class PinUserVerifierImpl( //region PinUserVerifier override fun verifyPin( - pinUserVerificationContext: PinUserVerificationContext, - pinUserVerificationHandler: PinUserVerificationHandler + context: PinUserVerificationContext, + handler: PinUserVerificationHandler ) { - if (pinUserVerificationContext.lastRecoverableError().isPresent) { + if (context.lastRecoverableError().isPresent) { Timber.asTree().sdk("PIN user verification failed. Please try again.") } else { Timber.asTree().sdk("Please start PIN user verification.") @@ -44,10 +44,9 @@ class PinUserVerifierImpl( NavigationGraphDirections.actionGlobalPinFragment( PinNavigationParameter( PinViewMode.VERIFY_PIN, - pinAuthenticatorProtectionStatus = pinUserVerificationContext.authenticatorProtectionStatus(), - lastRecoverableError = pinUserVerificationContext.lastRecoverableError() - .orElse(null), - pinUserVerificationHandler = pinUserVerificationHandler + pinAuthenticatorProtectionStatus = context.authenticatorProtectionStatus(), + lastRecoverableError = context.lastRecoverableError().orElse(null), + pinUserVerificationHandler = handler ) ) ) diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelector.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelector.kt deleted file mode 100644 index fb49692..0000000 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelector.kt +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Nevis Mobile Authentication SDK Example App - * - * Copyright © 2023. Nevis Security AG. All rights reserved. - */ - -package ch.nevis.exampleapp.domain.interaction - -import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector - -/** - * Marker interface declaration for [AuthenticatorSelector] implementations those are used during - * registration operations. This interface is created to ease Dagger Hilt injection of [AuthenticatorSelector] - * implementations. - */ -interface RegistrationAuthenticatorSelector : AuthenticatorSelector \ No newline at end of file diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelectorImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelectorImpl.kt deleted file mode 100644 index b940c73..0000000 --- a/app/src/main/java/ch/nevis/exampleapp/domain/interaction/RegistrationAuthenticatorSelectorImpl.kt +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Nevis Mobile Authentication SDK Example App - * - * Copyright © 2023. Nevis Security AG. All rights reserved. - */ - -package ch.nevis.exampleapp.domain.interaction - -import ch.nevis.exampleapp.NavigationGraphDirections -import ch.nevis.exampleapp.common.settings.Settings -import ch.nevis.exampleapp.domain.model.operation.Operation -import ch.nevis.exampleapp.domain.util.isUserEnrolled -import ch.nevis.exampleapp.domain.util.titleResId -import ch.nevis.exampleapp.logging.sdk -import ch.nevis.exampleapp.ui.navigation.NavigationDispatcher -import ch.nevis.exampleapp.ui.selectAuthenticator.model.AuthenticatorItem -import ch.nevis.exampleapp.ui.selectAuthenticator.parameter.SelectAuthenticatorNavigationParameter -import ch.nevis.mobile.sdk.api.localdata.Authenticator -import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionContext -import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionHandler -import timber.log.Timber - -/** - * Default implementation of [RegistrationAuthenticatorSelector] interface. It collects non-registered, - * hardware supported, policy compliant authenticators for an registration operation and navigates to Select - * Authenticator view. - */ -class RegistrationAuthenticatorSelectorImpl( - - /** - * An instance of a [NavigationDispatcher] interface implementation. - */ - private val navigationDispatcher: NavigationDispatcher, - - /** - * An instance of a [Settings] interface implementation. - */ - private val settings: Settings -) : RegistrationAuthenticatorSelector { - - //region RegistrationAuthenticatorSelector - override fun selectAuthenticator( - authenticatorSelectionContext: AuthenticatorSelectionContext, - authenticatorSelectionHandler: AuthenticatorSelectionHandler - ) { - Timber.asTree() - .sdk("Please select one of the received available authenticators!") - - val authenticatorItems = authenticatorSelectionContext.authenticators().mapNotNull { - mapForRegistration(it, authenticatorSelectionContext) - }.toSet() - - navigationDispatcher.requestNavigation( - NavigationGraphDirections.actionGlobalSelectAuthenticatorFragment( - SelectAuthenticatorNavigationParameter( - Operation.REGISTRATION, - authenticatorItems, - authenticatorSelectionHandler - ) - ) - ) - } - //endregion - - //region Private Interface - private fun mapForRegistration( - authenticator: Authenticator, - context: AuthenticatorSelectionContext - ): AuthenticatorItem? { - Timber.d("Checking if authenticator %s is eligible for registration.", authenticator.aaid()) - val username = context.account().username() - val authenticators = context.authenticators() - - val biometricRegistered = authenticators.any { - it.aaid() == Authenticator.BIOMETRIC_AUTHENTICATOR_AAID && - it.registration().isRegistered(username) - } - - val canRegisterBiometric = authenticators.any { - it.aaid() == Authenticator.BIOMETRIC_AUTHENTICATOR_AAID && - context.isPolicyCompliant(it.aaid()) && - it.isSupportedByHardware - } - - val canRegisterFingerprint = authenticators.any { - it.aaid() == Authenticator.FINGERPRINT_AUTHENTICATOR_AAID && - context.isPolicyCompliant(it.aaid()) && - it.isSupportedByHardware - } - - // If biometric can be registered (or is already registered), or if we cannot - // register fingerprint, do not propose to register fingerprint (we favor biometric over fingerprint). - if ((canRegisterBiometric || biometricRegistered || !canRegisterFingerprint) && - authenticator.aaid() == Authenticator.FINGERPRINT_AUTHENTICATOR_AAID - ) { - return null - } - - // Do not display: - // - policy non-compliant authenticators (this includes already registered authenticators) - // - not hardware supported authenticators. - // - not OS supported authenticators. - return if (authenticator.isSupportedByHardware && authenticator.isSupportedByOs && context.isPolicyCompliant(authenticator.aaid())) { - AuthenticatorItem( - authenticator.aaid(), - true, - authenticator.isUserEnrolled( - context.account().username(), - settings.allowClass2Sensors - ), - authenticator.titleResId() - ) - } else { - null - } - } - //endregion -} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidator.kt b/app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidator.kt new file mode 100644 index 0000000..78c1fba --- /dev/null +++ b/app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidator.kt @@ -0,0 +1,39 @@ +/** + * Nevis Mobile Authentication SDK Example App + * + * Copyright © 2024. Nevis Security AG. All rights reserved. + */ + +package ch.nevis.exampleapp.domain.validation + +import ch.nevis.mobile.sdk.api.localdata.Authenticator +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionContext + +/** + * Interface declaration for validating list of authenticators for different operations. + */ +interface AuthenticatorValidator { + /** + * Validates authenticators for registration operation. + * + * @param context The context holding the authenticators to validate. + * @param authenticatorAllowlist List of allowlisted authenticators. + * @return List of allowed authenticators. + */ + fun validateForRegistration( + context: AuthenticatorSelectionContext, + authenticatorAllowlist: List + ): Set + + /** + * Validates authenticators for authentication operation. + * + * @param context The context holding the authenticators to validate. + * @param authenticatorAllowlist List of allowlisted authenticators. + * @return List of allowed authenticators. + */ + fun validateForAuthentication( + context: AuthenticatorSelectionContext, + authenticatorAllowlist: List + ): Set +} diff --git a/app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidatorImpl.kt b/app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidatorImpl.kt new file mode 100644 index 0000000..7fddfa8 --- /dev/null +++ b/app/src/main/java/ch/nevis/exampleapp/domain/validation/AuthenticatorValidatorImpl.kt @@ -0,0 +1,94 @@ +/** + * Nevis Mobile Authentication SDK Example App + * + * Copyright © 2024. Nevis Security AG. All rights reserved. + */ + +package ch.nevis.exampleapp.domain.validation + +import ch.nevis.mobile.sdk.api.localdata.Authenticator +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionContext + +/** + * Default implementation of [AuthenticatorValidator] interface. + */ +class AuthenticatorValidatorImpl : AuthenticatorValidator { + //region AuthenticatorValidator + override fun validateForRegistration( + context: AuthenticatorSelectionContext, + authenticatorAllowlist: List + ): Set { + return context.authenticators() + .filter { authenticatorAllowlist.contains(it.aaid()) } + .filter { + // Do not display: + // - policy non-compliant authenticators (this includes already registered authenticators) + // - not hardware supported authenticators. + // - not OS supported authenticators. + // - prefer Biometrics authenticator on Android + it.isSupportedByHardware && + it.isSupportedByOs && + context.isPolicyCompliant(it.aaid()) && + filterFingerprintIfNecessary(context, it) + }.toSet() + } + + override fun validateForAuthentication( + context: AuthenticatorSelectionContext, + authenticatorAllowlist: List + ): Set { + return context.authenticators() + .filter { authenticatorAllowlist.contains(it.aaid()) } + .filter { + // Do not display: + // - non-registered authenticators + // - not hardware supported authenticators + it.registration().isRegistered(context.account().username()) && + it.isSupportedByHardware + }.toSet() + } + //endregion + + //region Private Interface + private fun filterFingerprintIfNecessary( + context: AuthenticatorSelectionContext, + authenticator: Authenticator + ): Boolean { + if (authenticator.aaid() != Authenticator.FINGERPRINT_AUTHENTICATOR_AAID) { + return true + } + + var isBiometricsRegistered = false + var canRegisterBiometrics = false + var canRegisterFingerprint = false + context.authenticators().forEach { + if (it.aaid() == Authenticator.BIOMETRIC_AUTHENTICATOR_AAID && + it.registration().isRegistered(context.account().username()) + ) { + isBiometricsRegistered = true + } + + if (it.aaid() == Authenticator.BIOMETRIC_AUTHENTICATOR_AAID && + context.isPolicyCompliant(it.aaid()) && + it.isSupportedByHardware + ) { + canRegisterBiometrics = true + } + + if (it.aaid() == Authenticator.FINGERPRINT_AUTHENTICATOR_AAID && + context.isPolicyCompliant(it.aaid()) && + it.isSupportedByHardware + ) { + canRegisterFingerprint = true + } + } + + // If biometric can be registered (or is already registered), or if we + // cannot register fingerprint, do not propose to register fingerprint + // (we favor biometric over fingerprint). + return !isBiometricsRegistered && + !canRegisterBiometrics && + canRegisterFingerprint + } + //endregion +} diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/authCloudRegistration/AuthCloudRegistrationViewModel.kt b/app/src/main/java/ch/nevis/exampleapp/ui/authCloudRegistration/AuthCloudRegistrationViewModel.kt index a8e4d53..dab9287 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/authCloudRegistration/AuthCloudRegistrationViewModel.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/authCloudRegistration/AuthCloudRegistrationViewModel.kt @@ -9,21 +9,23 @@ package ch.nevis.exampleapp.ui.authCloudRegistration import ch.nevis.exampleapp.NavigationGraphDirections import ch.nevis.exampleapp.common.error.ErrorHandler import ch.nevis.exampleapp.common.settings.Settings +import ch.nevis.exampleapp.dagger.ApplicationModule import ch.nevis.exampleapp.domain.client.ClientProvider import ch.nevis.exampleapp.domain.deviceInformation.DeviceInformationFactory import ch.nevis.exampleapp.domain.interaction.OnErrorImpl -import ch.nevis.exampleapp.domain.interaction.RegistrationAuthenticatorSelector import ch.nevis.exampleapp.domain.model.error.BusinessException import ch.nevis.exampleapp.domain.model.operation.Operation import ch.nevis.exampleapp.ui.base.BaseViewModel import ch.nevis.exampleapp.ui.navigation.NavigationDispatcher import ch.nevis.exampleapp.ui.result.parameter.ResultNavigationParameter import ch.nevis.mobile.sdk.api.operation.pin.PinEnroller +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import javax.inject.Named /** * View model implementation of Auth Cloud API Registration view. @@ -51,29 +53,30 @@ class AuthCloudRegistrationViewModel @Inject constructor( private val settings: Settings, /** - * An instance of a [BiometricUserVerifier] interface implementation. + * An instance of an [AuthenticatorSelector] interface implementation used during registration. */ - private val biometricUserVerifier: BiometricUserVerifier, + @Named(ApplicationModule.REGISTRATION_AUTHENTICATOR_SELECTOR) + private val authenticatorSelector: AuthenticatorSelector, /** - * An instance of a [DevicePasscodeUserVerifier] interface implementation. + * An instance of a [PinEnroller] interface implementation. */ - private val devicePasscodeUserVerifier: DevicePasscodeUserVerifier, + private val pinEnroller: PinEnroller, /** - * An instance of a [FingerprintUserVerifier] interface implementation. + * An instance of a [BiometricUserVerifier] interface implementation. */ - private val fingerprintUserVerifier: FingerprintUserVerifier, + private val biometricUserVerifier: BiometricUserVerifier, /** - * An instance of a [PinEnroller] interface implementation. + * An instance of a [DevicePasscodeUserVerifier] interface implementation. */ - private val pinEnroller: PinEnroller, + private val devicePasscodeUserVerifier: DevicePasscodeUserVerifier, /** - * An instance of a [RegistrationAuthenticatorSelector] interface implementation. + * An instance of a [FingerprintUserVerifier] interface implementation. */ - private val authenticatorSelector: RegistrationAuthenticatorSelector, + private val fingerprintUserVerifier: FingerprintUserVerifier, /** * An instance of an [ErrorHandler] interface implementation. Received errors will be passed to this error diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/home/HomeViewModel.kt b/app/src/main/java/ch/nevis/exampleapp/ui/home/HomeViewModel.kt index a52fb61..6289d63 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/home/HomeViewModel.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/home/HomeViewModel.kt @@ -13,11 +13,10 @@ import ch.nevis.exampleapp.common.configuration.ConfigurationProvider import ch.nevis.exampleapp.common.configuration.Environment import ch.nevis.exampleapp.common.error.ErrorHandler import ch.nevis.exampleapp.common.settings.Settings +import ch.nevis.exampleapp.dagger.ApplicationModule import ch.nevis.exampleapp.domain.client.ClientProvider import ch.nevis.exampleapp.domain.deviceInformation.DeviceInformationFactory -import ch.nevis.exampleapp.domain.interaction.AuthenticationAuthenticatorSelector import ch.nevis.exampleapp.domain.interaction.OnErrorImpl -import ch.nevis.exampleapp.domain.interaction.RegistrationAuthenticatorSelector import ch.nevis.exampleapp.domain.model.error.BusinessException import ch.nevis.exampleapp.domain.model.error.MobileAuthenticationClientException import ch.nevis.exampleapp.domain.model.operation.Operation @@ -32,6 +31,7 @@ import ch.nevis.mobile.sdk.api.localdata.Authenticator import ch.nevis.mobile.sdk.api.operation.OperationError import ch.nevis.mobile.sdk.api.operation.pin.PinEnroller import ch.nevis.mobile.sdk.api.operation.selection.AccountSelector +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier @@ -42,6 +42,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import javax.inject.Inject +import javax.inject.Named import kotlin.coroutines.resume /** @@ -81,24 +82,26 @@ class HomeViewModel @Inject constructor( deviceInformationFactory: DeviceInformationFactory, /** - * An instance of a [AccountSelector] interface implementation. + * An instance of an [AccountSelector] interface implementation. */ accountSelector: AccountSelector, /** - * An instance of a [BiometricUserVerifier] interface implementation. + * An instance of an [AuthenticatorSelector] interface implementation used during registration. */ - biometricUserVerifier: BiometricUserVerifier, + @Named(ApplicationModule.REGISTRATION_AUTHENTICATOR_SELECTOR) + registrationAuthenticatorSelector: AuthenticatorSelector, /** - * An instance of a [DevicePasscodeUserVerifier] interface implementation. + * An instance of an [AuthenticatorSelector] interface implementation used during authentication. */ - devicePasscodeUserVerifier: DevicePasscodeUserVerifier, + @Named(ApplicationModule.AUTHENTICATION_AUTHENTICATOR_SELECTOR) + authenticationAuthenticatorSelector: AuthenticatorSelector, /** - * An instance of a [FingerprintUserVerifier] interface implementation. + * An instance of a [PinEnroller] interface implementation. */ - fingerprintUserVerifier: FingerprintUserVerifier, + pinEnroller: PinEnroller, /** * An instance of a [PinUserVerifier] interface implementation. @@ -106,19 +109,19 @@ class HomeViewModel @Inject constructor( pinUserVerifier: PinUserVerifier, /** - * An instance of a [PinEnroller] interface implementation. + * An instance of a [BiometricUserVerifier] interface implementation. */ - pinEnroller: PinEnroller, + biometricUserVerifier: BiometricUserVerifier, /** - * An instance of a [AuthenticationAuthenticatorSelector] interface implementation. + * An instance of a [DevicePasscodeUserVerifier] interface implementation. */ - authenticationAuthenticatorSelector: AuthenticationAuthenticatorSelector, + devicePasscodeUserVerifier: DevicePasscodeUserVerifier, /** - * An instance of a [RegistrationAuthenticatorSelector] interface implementation. + * An instance of a [FingerprintUserVerifier] interface implementation. */ - registrationAuthenticatorSelector: RegistrationAuthenticatorSelector, + fingerprintUserVerifier: FingerprintUserVerifier, /** * An instance of an [ErrorHandler] interface implementation. Received errors will be passed to this error @@ -131,13 +134,13 @@ class HomeViewModel @Inject constructor( navigationDispatcher, settings, accountSelector, + registrationAuthenticatorSelector, + authenticationAuthenticatorSelector, + pinEnroller, + pinUserVerifier, biometricUserVerifier, devicePasscodeUserVerifier, fingerprintUserVerifier, - pinUserVerifier, - pinEnroller, - authenticationAuthenticatorSelector, - registrationAuthenticatorSelector, errorHandler ) { @@ -344,4 +347,4 @@ class HomeViewModel @Inject constructor( } } //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/outOfBand/OutOfBandViewModel.kt b/app/src/main/java/ch/nevis/exampleapp/ui/outOfBand/OutOfBandViewModel.kt index 8d93689..ef49f75 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/outOfBand/OutOfBandViewModel.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/outOfBand/OutOfBandViewModel.kt @@ -11,9 +11,7 @@ import ch.nevis.exampleapp.common.error.ErrorHandler import ch.nevis.exampleapp.common.settings.Settings import ch.nevis.exampleapp.domain.client.ClientProvider import ch.nevis.exampleapp.domain.deviceInformation.DeviceInformationFactory -import ch.nevis.exampleapp.domain.interaction.AuthenticationAuthenticatorSelector import ch.nevis.exampleapp.domain.interaction.OnErrorImpl -import ch.nevis.exampleapp.domain.interaction.RegistrationAuthenticatorSelector import ch.nevis.exampleapp.domain.model.error.BusinessException import ch.nevis.exampleapp.domain.model.operation.Operation import ch.nevis.exampleapp.ui.base.BaseViewModel @@ -24,6 +22,7 @@ import ch.nevis.mobile.sdk.api.operation.outofband.OutOfBandPayload import ch.nevis.mobile.sdk.api.operation.outofband.OutOfBandRegistration import ch.nevis.mobile.sdk.api.operation.pin.PinEnroller import ch.nevis.mobile.sdk.api.operation.selection.AccountSelector +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier @@ -61,19 +60,19 @@ abstract class OutOfBandViewModel( private val accountSelector: AccountSelector, /** - * An instance of a [BiometricUserVerifier] interface implementation. + * An instance of a [AuthenticatorSelector] interface implementation. */ - private val biometricUserVerifier: BiometricUserVerifier, + private val registrationAuthenticatorSelector: AuthenticatorSelector, /** - * An instance of a [DevicePasscodeUserVerifier] interface implementation. + * An instance of a [AuthenticatorSelector] interface implementation. */ - private val devicePasscodeUserVerifier: DevicePasscodeUserVerifier, + private val authenticationAuthenticatorSelector: AuthenticatorSelector, /** - * An instance of a [FingerprintUserVerifier] interface implementation. + * An instance of a [PinEnroller] interface implementation. */ - private val fingerprintUserVerifier: FingerprintUserVerifier, + private val pinEnroller: PinEnroller, /** * An instance of a [PinUserVerifier] interface implementation. @@ -81,19 +80,19 @@ abstract class OutOfBandViewModel( private val pinUserVerifier: PinUserVerifier, /** - * An instance of a [PinEnroller] interface implementation. + * An instance of a [BiometricUserVerifier] interface implementation. */ - private val pinEnroller: PinEnroller, + private val biometricUserVerifier: BiometricUserVerifier, /** - * An instance of a [AuthenticationAuthenticatorSelector] interface implementation. + * An instance of a [DevicePasscodeUserVerifier] interface implementation. */ - private val authenticationAuthenticatorSelector: AuthenticationAuthenticatorSelector, + private val devicePasscodeUserVerifier: DevicePasscodeUserVerifier, /** - * An instance of a [RegistrationAuthenticatorSelector] interface implementation. + * An instance of a [FingerprintUserVerifier] interface implementation. */ - private val registrationAuthenticatorSelector: RegistrationAuthenticatorSelector, + private val fingerprintUserVerifier: FingerprintUserVerifier, /** * An instance of an [ErrorHandler] interface implementation. Received errors will be passed to this error @@ -199,4 +198,4 @@ abstract class OutOfBandViewModel( .execute() } //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/qrReader/QrReaderViewModel.kt b/app/src/main/java/ch/nevis/exampleapp/ui/qrReader/QrReaderViewModel.kt index 80f40a8..e690c77 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/qrReader/QrReaderViewModel.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/qrReader/QrReaderViewModel.kt @@ -8,20 +8,21 @@ package ch.nevis.exampleapp.ui.qrReader import ch.nevis.exampleapp.common.error.ErrorHandler import ch.nevis.exampleapp.common.settings.Settings +import ch.nevis.exampleapp.dagger.ApplicationModule import ch.nevis.exampleapp.domain.client.ClientProvider import ch.nevis.exampleapp.domain.deviceInformation.DeviceInformationFactory -import ch.nevis.exampleapp.domain.interaction.AuthenticationAuthenticatorSelector -import ch.nevis.exampleapp.domain.interaction.RegistrationAuthenticatorSelector import ch.nevis.exampleapp.ui.navigation.NavigationDispatcher import ch.nevis.exampleapp.ui.outOfBand.OutOfBandViewModel import ch.nevis.mobile.sdk.api.operation.pin.PinEnroller import ch.nevis.mobile.sdk.api.operation.selection.AccountSelector +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.PinUserVerifier import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import javax.inject.Named /** * View model implementation of QR Reader view. @@ -50,24 +51,26 @@ class QrReaderViewModel @Inject constructor( deviceInformationFactory: DeviceInformationFactory, /** - * An instance of a [AccountSelector] interface implementation. + * An instance of an [AccountSelector] interface implementation. */ accountSelector: AccountSelector, /** - * An instance of a [BiometricUserVerifier] interface implementation. + * An instance of an [AuthenticatorSelector] interface implementation used during registration. */ - biometricUserVerifier: BiometricUserVerifier, + @Named(ApplicationModule.REGISTRATION_AUTHENTICATOR_SELECTOR) + registrationAuthenticatorSelector: AuthenticatorSelector, /** - * An instance of a [DevicePasscodeUserVerifier] interface implementation. + * An instance of a [AuthenticatorSelector] interface implementation used during authentication. */ - devicePasscodeUserVerifier: DevicePasscodeUserVerifier, + @Named(ApplicationModule.AUTHENTICATION_AUTHENTICATOR_SELECTOR) + authenticationAuthenticatorSelector: AuthenticatorSelector, /** - * An instance of a [FingerprintUserVerifier] interface implementation. + * An instance of a [PinEnroller] interface implementation. */ - fingerprintUserVerifier: FingerprintUserVerifier, + pinEnroller: PinEnroller, /** * An instance of a [PinUserVerifier] interface implementation. @@ -75,22 +78,22 @@ class QrReaderViewModel @Inject constructor( pinUserVerifier: PinUserVerifier, /** - * An instance of a [PinEnroller] interface implementation. + * An instance of a [BiometricUserVerifier] interface implementation. */ - pinEnroller: PinEnroller, + biometricUserVerifier: BiometricUserVerifier, /** - * An instance of a [AuthenticationAuthenticatorSelector] interface implementation. + * An instance of a [DevicePasscodeUserVerifier] interface implementation. */ - authenticationAuthenticatorSelector: AuthenticationAuthenticatorSelector, + devicePasscodeUserVerifier: DevicePasscodeUserVerifier, /** - * An instance of a [RegistrationAuthenticatorSelector] interface implementation. + * An instance of a [FingerprintUserVerifier] interface implementation. */ - registrationAuthenticatorSelector: RegistrationAuthenticatorSelector, + fingerprintUserVerifier: FingerprintUserVerifier, /** - * An instance of a [ErrorHandler] implementation. Received errors will be passed to this error + * An instance of an [ErrorHandler] implementation. Received errors will be passed to this error * handler instance. */ errorHandler: ErrorHandler @@ -100,12 +103,12 @@ class QrReaderViewModel @Inject constructor( navigationDispatcher, settings, accountSelector, + registrationAuthenticatorSelector, + authenticationAuthenticatorSelector, + pinEnroller, + pinUserVerifier, biometricUserVerifier, devicePasscodeUserVerifier, fingerprintUserVerifier, - pinUserVerifier, - pinEnroller, - authenticationAuthenticatorSelector, - registrationAuthenticatorSelector, errorHandler -) \ No newline at end of file +) diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/selectAccount/SelectAccountViewModel.kt b/app/src/main/java/ch/nevis/exampleapp/ui/selectAccount/SelectAccountViewModel.kt index 252babe..0034fab 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/selectAccount/SelectAccountViewModel.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/selectAccount/SelectAccountViewModel.kt @@ -8,8 +8,8 @@ package ch.nevis.exampleapp.ui.selectAccount import ch.nevis.exampleapp.NavigationGraphDirections import ch.nevis.exampleapp.common.error.ErrorHandler +import ch.nevis.exampleapp.dagger.ApplicationModule import ch.nevis.exampleapp.domain.client.ClientProvider -import ch.nevis.exampleapp.domain.interaction.AuthenticationAuthenticatorSelector import ch.nevis.exampleapp.domain.interaction.OnErrorImpl import ch.nevis.exampleapp.domain.model.error.BusinessException import ch.nevis.exampleapp.domain.model.operation.Operation @@ -19,13 +19,14 @@ import ch.nevis.exampleapp.ui.result.parameter.ResultNavigationParameter import ch.nevis.exampleapp.ui.selectAccount.parameter.SelectAccountNavigationParameter import ch.nevis.mobile.sdk.api.operation.pin.PinChanger import ch.nevis.mobile.sdk.api.operation.selection.AccountSelectionHandler -import ch.nevis.mobile.sdk.api.operation.selection.AccountSelector +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.PinUserVerifier import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import javax.inject.Named /** * View model implementation for Select Account view. @@ -43,6 +44,17 @@ class SelectAccountViewModel @Inject constructor( */ private val navigationDispatcher: NavigationDispatcher, + /** + * An instance of an [AuthenticatorSelector] interface implementation used during authentication. + */ + @Named(ApplicationModule.AUTHENTICATION_AUTHENTICATOR_SELECTOR) + private val authenticatorSelector: AuthenticatorSelector, + + /** + * An instance of a [PinUserVerifier] interface implementation. + */ + private val pinUserVerifier: PinUserVerifier, + /** * An instance of a [BiometricUserVerifier] interface implementation. */ @@ -63,16 +75,6 @@ class SelectAccountViewModel @Inject constructor( */ private val pinChanger: PinChanger, - /** - * An instance of a [PinUserVerifier] interface implementation. - */ - private val pinUserVerifier: PinUserVerifier, - - /** - * An instance of a [AccountSelector] interface implementation. - */ - private val authenticatorSelector: AuthenticationAuthenticatorSelector, - /** * An instance of an [ErrorHandler] interface implementation. Received errors will be passed to this error * handler instance. @@ -219,4 +221,4 @@ class SelectAccountViewModel @Inject constructor( accountSelectionHandler = null } //endregion -} \ No newline at end of file +} diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/selectAuthenticator/parameter/SelectAuthenticatorNavigationParameter.kt b/app/src/main/java/ch/nevis/exampleapp/ui/selectAuthenticator/parameter/SelectAuthenticatorNavigationParameter.kt index c2ac222..6dd21de 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/selectAuthenticator/parameter/SelectAuthenticatorNavigationParameter.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/selectAuthenticator/parameter/SelectAuthenticatorNavigationParameter.kt @@ -9,7 +9,6 @@ package ch.nevis.exampleapp.ui.selectAuthenticator.parameter import ch.nevis.exampleapp.domain.model.operation.Operation import ch.nevis.exampleapp.ui.base.model.NavigationParameter import ch.nevis.exampleapp.ui.selectAuthenticator.model.AuthenticatorItem -import ch.nevis.mobile.sdk.api.localdata.Authenticator import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelectionHandler import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize @@ -19,12 +18,6 @@ import kotlinx.parcelize.Parcelize */ @Parcelize data class SelectAuthenticatorNavigationParameter( - - /** - * The operation type the authenticator selection was requested for. - */ - val operation: Operation, - /** * The list of available authenticator items the user can select from. */ @@ -38,4 +31,4 @@ data class SelectAuthenticatorNavigationParameter( */ @IgnoredOnParcel val authenticatorSelectionHandler: AuthenticatorSelectionHandler? = null -) : NavigationParameter \ No newline at end of file +) : NavigationParameter diff --git a/app/src/main/java/ch/nevis/exampleapp/ui/userNamePasswordLogin/UserNamePasswordLoginViewModel.kt b/app/src/main/java/ch/nevis/exampleapp/ui/userNamePasswordLogin/UserNamePasswordLoginViewModel.kt index afd1afa..1e61046 100644 --- a/app/src/main/java/ch/nevis/exampleapp/ui/userNamePasswordLogin/UserNamePasswordLoginViewModel.kt +++ b/app/src/main/java/ch/nevis/exampleapp/ui/userNamePasswordLogin/UserNamePasswordLoginViewModel.kt @@ -10,10 +10,10 @@ import androidx.lifecycle.viewModelScope import ch.nevis.exampleapp.NavigationGraphDirections import ch.nevis.exampleapp.common.error.ErrorHandler import ch.nevis.exampleapp.common.settings.Settings +import ch.nevis.exampleapp.dagger.ApplicationModule import ch.nevis.exampleapp.domain.client.ClientProvider import ch.nevis.exampleapp.domain.deviceInformation.DeviceInformationFactory import ch.nevis.exampleapp.domain.interaction.OnErrorImpl -import ch.nevis.exampleapp.domain.interaction.RegistrationAuthenticatorSelector import ch.nevis.exampleapp.domain.model.error.BusinessException import ch.nevis.exampleapp.domain.model.operation.Operation import ch.nevis.exampleapp.retrofit.LoginEndPoint @@ -23,6 +23,7 @@ import ch.nevis.exampleapp.ui.result.parameter.ResultNavigationParameter import ch.nevis.mobile.sdk.api.authorization.AuthorizationProvider.CookieAuthorizationProvider import ch.nevis.mobile.sdk.api.authorization.Cookie import ch.nevis.mobile.sdk.api.operation.pin.PinEnroller +import ch.nevis.mobile.sdk.api.operation.selection.AuthenticatorSelector import ch.nevis.mobile.sdk.api.operation.userverification.BiometricUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.DevicePasscodeUserVerifier import ch.nevis.mobile.sdk.api.operation.userverification.FingerprintUserVerifier @@ -32,6 +33,7 @@ import retrofit2.Retrofit import timber.log.Timber import java.net.PasswordAuthentication import javax.inject.Inject +import javax.inject.Named /** * View model implementation of UserName and Password Login view. @@ -44,7 +46,7 @@ class UserNamePasswordLoginViewModel @Inject constructor( private val clientProvider: ClientProvider, /** - * An [Retrofit] instance. + * A [Retrofit] instance. */ private val retrofit: Retrofit, @@ -64,29 +66,30 @@ class UserNamePasswordLoginViewModel @Inject constructor( private val settings: Settings, /** - * An instance of a [BiometricUserVerifier] interface implementation. + * An instance of an [AuthenticatorSelector] interface implementation used during registration. */ - private val biometricUserVerifier: BiometricUserVerifier, + @Named(ApplicationModule.REGISTRATION_AUTHENTICATOR_SELECTOR) + private val authenticatorSelector: AuthenticatorSelector, /** - * An instance of a [DevicePasscodeUserVerifier] interface implementation. + * An instance of a [PinEnroller] interface implementation. */ - private val devicePasscodeUserVerifier: DevicePasscodeUserVerifier, + private val pinEnroller: PinEnroller, /** - * An instance of a [FingerprintUserVerifier] interface implementation. + * An instance of a [BiometricUserVerifier] interface implementation. */ - private val fingerprintUserVerifier: FingerprintUserVerifier, + private val biometricUserVerifier: BiometricUserVerifier, /** - * An instance of a [PinEnroller] interface implementation. + * An instance of a [DevicePasscodeUserVerifier] interface implementation. */ - private val pinEnroller: PinEnroller, + private val devicePasscodeUserVerifier: DevicePasscodeUserVerifier, /** - * An instance of a [RegistrationAuthenticatorSelector] interface implementation. + * An instance of a [FingerprintUserVerifier] interface implementation. */ - private val authenticatorSelector: RegistrationAuthenticatorSelector, + private val fingerprintUserVerifier: FingerprintUserVerifier, /** * An instance of an [ErrorHandler] interface implementation. Received errors will be passed to this error diff --git a/gradle.properties b/gradle.properties index 8c893fd..011de8f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,6 +22,6 @@ kotlin.code.style=official # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -VERSION_NAME=3.6.1 +VERSION_NAME=3.7.0 VERSION_CODE=1 -NEVIS_MOBILE_AUTHENTICATION_SDK_VERSION=3.6.+ \ No newline at end of file +NEVIS_MOBILE_AUTHENTICATION_SDK_VERSION=3.7.+