public void EnableBiometrics(Action <bool> callback) { var passwordStorage = new PasswordStorageManager(this); var executor = ContextCompat.GetMainExecutor(this); var authCallback = new AuthenticationCallback(); authCallback.Success += async(_, result) => { try { var password = await SecureStorageWrapper.GetDatabasePassword(); passwordStorage.Store(password, result.CryptoObject.Cipher); } catch (Exception e) { Logger.Error(e); callback(false); return; } callback(true); }; authCallback.Failed += delegate { callback(false); }; authCallback.Error += delegate { // Do something, probably callback(false); }; var prompt = new BiometricPrompt(this, executor, authCallback); var promptInfo = new BiometricPrompt.PromptInfo.Builder() .SetTitle(GetString(Resource.String.setupBiometricUnlock)) .SetNegativeButtonText(GetString(Resource.String.cancel)) .SetConfirmationRequired(false) .SetAllowedAuthenticators(BiometricManager.Authenticators.BiometricStrong) .Build(); Cipher cipher; try { cipher = passwordStorage.GetEncryptionCipher(); } catch (Exception e) { Logger.Error(e); passwordStorage.Clear(); callback(false); return; } prompt.Authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher)); }
public FingerprintService( FragmentActivity fragmentActivity, Context applicationContext, IObservable <Unit> applicationActivated, CoreDispatcher dispatcher, IScheduler backgroundScheduler, FuncAsync <BiometricPrompt.PromptInfo> promptInfoBuilder) { fragmentActivity.Validation().NotNull(nameof(fragmentActivity)); applicationActivated.Validation().NotNull(nameof(applicationActivated)); backgroundScheduler.Validation().NotNull(nameof(backgroundScheduler)); _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); _promptInfoBuilder = promptInfoBuilder ?? throw new ArgumentNullException(nameof(promptInfoBuilder)); var executor = ContextCompat.GetMainExecutor(applicationContext); var callback = new AuthenticationCallback(OnAuthenticationSucceeded, OnAuthenticationFailed, OnAuthenticationError); _BiometricPrompt = new BiometricPrompt(fragmentActivity, executor, callback); _BiometricManager = BiometricManager.From(Application.Context); _keyStore = KeyStore.GetInstance(ANDROID_KEYSTORE); _keyStore.Load(null); _canAuthenticate = applicationActivated .ObserveOn(backgroundScheduler) .StartWith(backgroundScheduler, Unit.Default) .Select(_ => _BiometricManager.CanAuthenticate()) .Replay(1, backgroundScheduler) .RefCount(); }
public void Authenticate(Func <Task> action, string title) { try { switch (BiometricManager.From(_context).CanAuthenticate()) { case BiometricManager.BiometricSuccess: var biometricPrompt = new BiometricPrompt(MainActivity, ContextCompat.GetMainExecutor(_context), GetBiometricAuthenticationCallback(action)); var promptInfo = new BiometricPrompt.PromptInfo.Builder() .SetTitle(title == null ? "Biometric login for Falcon" : $"{title}...") .SetNegativeButtonText("Cancel") .Build(); biometricPrompt.Authenticate(promptInfo); return; case BiometricManager.BiometricErrorHwUnavailable: Tools.DisplayAlert(message: "Biometric hardware is currently unavailable. Try again later."); return; case BiometricManager.BiometricErrorNoneEnrolled: Tools.DisplayAlert(message: "The device does not have any biometrics enrolled. Please make sure you have set up any available biometrics in your phone Settings."); return; default: return; } } catch (Exception ex) { //DisplayAlertError("Something went wrong while using biometric authentication."); } }
protected override async Task <FingerprintAuthenticationResult> NativeAuthenticateAsync(AuthenticationRequestConfiguration authRequestConfig, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(authRequestConfig.Title)) { throw new ArgumentException("Title must not be null or empty on Android.", nameof(authRequestConfig.Title)); } if (!(CrossFingerprint.CurrentActivity is FragmentActivity)) { throw new InvalidOperationException($"Expected current activity to be '{typeof(FragmentActivity).FullName}' but was '{CrossFingerprint.CurrentActivity?.GetType().FullName}'. " + "You need to use AndroidX. Have you installed Xamarin.AndroidX.Migration in your Android App project!?"); } try { var cancel = string.IsNullOrWhiteSpace(authRequestConfig.CancelTitle) ? Application.Context.GetString(Android.Resource.String.Cancel) : authRequestConfig.CancelTitle; var handler = new AuthenticationHandler(); var builder = new BiometricPrompt.PromptInfo.Builder() .SetTitle(authRequestConfig.Title) .SetConfirmationRequired(authRequestConfig.ConfirmationRequired) .SetDescription(authRequestConfig.Reason); if (authRequestConfig.AllowAlternativeAuthentication) { // It's not allowed to allow alternative auth & set the negative button builder = builder.SetDeviceCredentialAllowed(authRequestConfig.AllowAlternativeAuthentication); } else { builder = builder.SetNegativeButtonText(cancel); } var info = builder.Build(); var executor = Executors.NewSingleThreadExecutor(); var activity = (FragmentActivity)CrossFingerprint.CurrentActivity; using var dialog = new BiometricPrompt(activity, executor, handler); await using (cancellationToken.Register(() => dialog.CancelAuthentication())) { dialog.Authenticate(info); var result = await handler.GetTask(); TryReleaseLifecycleObserver(activity, dialog); return(result); } } catch (Exception e) { return(new FingerprintAuthenticationResult { Status = FingerprintAuthenticationResultStatus.UnknownError, ErrorMessage = e.Message }); } }
private void ShowBiometricPrompt() { var executor = ContextCompat.GetMainExecutor(Context); var passwordStorage = new PasswordStorageManager(Context); var callback = new AuthenticationCallback(); callback.Succeeded += (_, result) => { string password; try { password = passwordStorage.Fetch(result.CryptoObject.Cipher); } catch (Exception e) { Logger.Error(e); Toast.MakeText(Context, Resource.String.genericError, ToastLength.Short); return; } UnlockAttempted?.Invoke(this, password); }; callback.Failed += delegate { FocusPasswordText(); }; callback.Errored += (_, result) => { Toast.MakeText(Context, result.Message, ToastLength.Short).Show(); FocusPasswordText(); }; _prompt = new BiometricPrompt(this, executor, callback); var promptInfo = new BiometricPrompt.PromptInfo.Builder() .SetTitle(GetString(Resource.String.unlock)) .SetSubtitle(GetString(Resource.String.unlockBiometricsMessage)) .SetNegativeButtonText(GetString(Resource.String.cancel)) .SetConfirmationRequired(false) .SetAllowedAuthenticators(BiometricManager.Authenticators.BiometricStrong) .Build(); try { var cipher = passwordStorage.GetDecryptionCipher(); _prompt.Authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher)); } catch (Exception e) { Logger.Error(e); _canUseBiometrics = false; _useBiometricsButton.Enabled = false; FocusPasswordText(); } }
public void StartListening(BiometricPrompt.AuthenticationCallback callback) { Kp2aLog.Log("Fingerprint: StartListening "); var executor = Executors.NewSingleThreadExecutor(); _biometricPrompt = new BiometricPrompt(_activity, executor, callback); BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder() .SetTitle(_activity.GetString(AppNames.AppNameResource)) .SetSubtitle(_activity.GetString(Resource.String.unlock_database_title)) .SetNegativeButtonText(_activity.GetString(Android.Resource.String.Cancel)) .SetConfirmationRequired(false) .Build(); _biometricPrompt.Authenticate(promptInfo, _cryptoObject); }
/// <summary> /// Initializes a new instance of the <see cref="BiometryService" /> class. /// </summary> /// <param name="fragmentActivity"></param> /// <param name="dispatcher"></param> /// <param name="promptInfoBuilder"></param> /// <param name="authenticators"></param> public BiometryService( FragmentActivity fragmentActivity, CoreDispatcher dispatcher, FuncAsync <BiometricPrompt.PromptInfo> promptInfoBuilder) { fragmentActivity.Validation().NotNull(nameof(fragmentActivity)); _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); _promptInfoBuilder = promptInfoBuilder ?? throw new ArgumentNullException(nameof(promptInfoBuilder)); _applicationContext = Application.Context; var executor = ContextCompat.GetMainExecutor(_applicationContext); var callback = new AuthenticationCallback(OnAuthenticationSucceeded, OnAuthenticationFailed, OnAuthenticationError); _biometricPrompt = new BiometricPrompt(fragmentActivity, executor, callback); _biometricManager = BiometricManager.From(_applicationContext); _keyStore = KeyStore.GetInstance(ANDROID_KEYSTORE); _keyStore.Load(null); }
private void ShowBiometricPrompt(Java.Security.Signature signature) { // Create biometric prompt var activity = MainActivity.FormsContext; var negativeButtonListener = new DialogInterfaceOnClickListener(() => { // Do something here. }); biometricPrompt = new BiometricPrompt.Builder(activity) .SetDescription("Never Been Easier") .SetTitle("Biometric Prompt Authentication") .SetSubtitle("Please allow Xamarin Life to authenticate") .SetNegativeButton("Cancel", activity.MainExecutor, negativeButtonListener) .Build(); // Show biometric prompt var cancellationSignal = new CancellationSignal(); var authenticationCallback = GetAuthenticationCallback(); biometricPrompt.Authenticate(new BiometricPrompt.CryptoObject(signature), cancellationSignal, activity.MainExecutor, authenticationCallback); }
public void Authenticate(string userId, Action onSuccess, Action onFailure) { OnSuccess = onSuccess; OnFailure = onFailure; if (IsBiometricPromptEnabled) { newCancelSignal = new Android.OS.CancellationSignal(); prompt = new BiometricPrompt.Builder(CrossCurrentActivity.Current.Activity) .SetTitle("ManageGo") .SetSubtitle("Fingerprint Login") .SetDescription($"Place finger on the home button to log in as {userId}") .SetNegativeButton("CANCEL", CrossCurrentActivity.Current.Activity.MainExecutor, new DialogListener(this)).Build(); prompt.Authenticate(newCancelSignal, CrossCurrentActivity.Current.Activity.MainExecutor, new BiometricCallback(this)); } else { cancellationSignal = new Android.Support.V4.OS.CancellationSignal(); var callback = new SimpleAuthCallbacks(this); FingerprintManager.Authenticate(null, 0, cancellationSignal, callback, null); } }
/// <summary> /// Removes the lifecycle observer that is set by the BiometricPrompt from the lifecycleOwner. /// See: https://stackoverflow.com/a/59637670/1489968 /// TODO: The new implementation of BiometricPrompt doesn't use this mechanism anymore. Recheck this code after Xamarin.AndroidX.Biometric has been updated. /// </summary> /// <param name="lifecycleOwner">Lifecycle owner where the observer was added.</param> /// <param name="dialog">Used BiometricPrompt</param> private static void TryReleaseLifecycleObserver(ILifecycleOwner lifecycleOwner, BiometricPrompt dialog) { var promptClass = Java.Lang.Class.FromType(dialog.GetType()); var fields = promptClass.GetDeclaredFields(); var lifecycleObserverField = fields?.FirstOrDefault(f => f.Name == "mLifecycleObserver"); if (lifecycleObserverField is null) { return; } lifecycleObserverField.Accessible = true; var lastLifecycleObserver = lifecycleObserverField.Get(dialog).JavaCast <ILifecycleObserver>(); var lifecycle = lifecycleOwner.Lifecycle; if (lastLifecycleObserver is null || lifecycle is null) { return; } lifecycle.RemoveObserver(lastLifecycleObserver); }