flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.56k stars 27.33k forks source link

[local_auth] PlatformException(NotAvailable, Security credentials not available., null, null) on newer devices with no biometric hardware #105005

Closed hashirabdulbasheer closed 2 years ago

hashirabdulbasheer commented 2 years ago

local_auth plugin throws a platform exception with the message "Security credentials not available" on android 10 device that doesn't have any biometric hardware.

I faced this issue when using local_auth on a zebra device (android phone). the phone doesn't have any biometric hardware. it neither has a fingerprint scanner nor Face ID. but it has a pin set for local auth. in this case, shouldn't the local auth plugin open the pin entry screen?

I am running the example app project that is provided along with local auth android. The check biometrics button returns false. The get enrolled biometrics button returns an empty list. The authenticate button throws the exception - PlatformException(NotAvailable, Security credentials not available., null, null)

I checked the source code for local_auth_android. The issue happens when control goes into this bloc

https://github.com/flutter/plugins/blob/b0bfab678f83bebd49e9f9d0a83fe9b40774e853/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java#L187

LocalAuthPlugin.java - Line 187

   // API 29 and above
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
      authHelper =
          new AuthenticationHelper(
              lifecycle, (FragmentActivity) activity, call, completionHandler, true);
      authHelper.authenticate();
      return;
    }

This calls causes an error to be thrown in the completionHandler when run.

Is this block of code required? if biometric is not required then when why should authentication be tried again? can't it just fall over to invoking the keyguardManager.createConfirmDeviceCredentialIntent intent?

If it I comment the above code then it behaves correctly by invoking the deviceCredential intent and showing the pin screen.

Steps to Reproduce

1) Install and run the example app of local_auth_android on a android phone without fingerprint or Face ID or any biometric and running android 10. Make sure a PIN is set on the phone. 2) Click the authenticate button in the example app 3) An exception gets thrown.

Expected results: The Pin entry screen should be displayed.

Actual results: An exception gets thrown - PlatformException(NotAvailable, Security credentials not available., null, null)

flutter doctor -v
[✓] Flutter (Channel stable, 3.0.1, on macOS 12.2 21D49 darwin-x64, locale en-SA)
    • Flutter version 3.0.1 at /Users/hmdmobility/Documents/sdk/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision fb57da5f94 (11 days ago), 2022-05-19 15:50:29 -0700
    • Engine revision caaafc5604
    • Dart version 2.17.1
    • DevTools version 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
    • Android SDK at /Users/hmdmobility/Library/Android/sdk
    • Platform android-32, build-tools 32.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.8+10-b944.6916264)

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-x64     • macOS 12.2 21D49 darwin-x64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 102.0.5005.61

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
hashirabdulbasheer commented 2 years ago

A suggestion:

Is this a good idea?

If biometric is available on the device then call the AuthenticationHelper authenticate methods. Otherwise, if there is no biometric on the device then invoke the keyguardManager.createConfirmDeviceCredentialIntent intent ?

Because AuthenticationHelper authenticate fails when there in no biometric on the phone and the keyguardManager.createConfirmDeviceCredentialIntent never gets called.

danagbemava-nc commented 2 years ago

Hi @hashirabdulbasheer, thanks for filing the issue.

Can you provide the output of flutter run -v that captures the error you're facing?

Also, is this issue only on android 10?

hashirabdulbasheer commented 2 years ago

Hi @danagbemava-nc

I have attached the output of flutter run -v that captures the error in the txt file flutter_run_log_v.txt.

I am not sure about other android versions. The phone that I am using is running android 10. The phone doesn't have any other biometric. There is no fingerprint or any other biometric. I am using a PIN to authenticate.

I also tried on an emulator running android 11. It works on that. But it has a fingerprint sensor. So, not exactly the same scenario.

I don't know if this helps. But I found a similar issue reported in android bug issue tracker. Not sure if this happens due a bug in android. Here is the link to the issue: https://issuetracker.google.com/issues/142740104

flutter_run_log_v.txt

danagbemava-nc commented 2 years ago

Hi @hashirabdulbasheer, thanks for the info.

I was unable to get a device without biometric hardware so I cannot confirm this locally. I also tested with an emulator with no biometrics enrolled, but since the emulated hardware itself was present, I was unable to reproduce this issue.

I've updated the title to be generic since the code block1 is executed for android 10 and above. There's a chance this might be happening on devices android 10 and above without biometric hardware.

[1]https://github.com/flutter/plugins/blob/b0bfab678f83bebd49e9f9d0a83fe9b40774e853/packages/local_auth/local_auth_android/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java#L187-L194

Leaving this for further investigation from the team, as I do not have a device capable of confirming this.

stuartmorgan commented 2 years ago

Note from triage: there have been some other recent bugs about fallback to pin not working correctly in other cases on Android; this may be a duplicate of a larger underlying issue.

oliverbytes commented 2 years ago

I'm having the same issue on a Samsung A013G Phone. No biometric hardware and PIN is set.

hashirabdulbasheer commented 2 years ago

If it is an android issue then we can't expect a fix for it soon. For now, I have implemented a custom plugin that uses keyguardManager.createConfirmDeviceCredentialIntent in case the local_auth throws the exception. This displays the pin entry screen correctly.

It would be good if we can handle it in local_auth plugin itself. It would have solved the issue without another plugin.

But note that keyguardManager.createConfirmDeviceCredentialIntent was deprecated in api 29.

stuartmorgan commented 2 years ago

If it is an android issue then we can't expect a fix for it soon.

It is much more likely to be an issue in the plugin's handling of fallback than an issue in Android.

github-actions[bot] commented 2 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.