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));
        }
Example #2
0
        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();
            }
        }
Example #6
0
        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);
        }
Example #7
0
        /// <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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }