forcedotcom / SalesforceMobileSDK-Android

Android SDK for Salesforce

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

App crash due to UserAccount Being Null in Biometric Authentication Manager

adriduttaheb opened this issue · comments

Please fill out the following details:

  1. Version of Mobile SDK Used: 11.0.0
  2. Issue found in Native App or Hybrid App: Native App
  3. OS Version: 12, 13, 14 (possibly all versions, these are the ones on record)
  4. Device: Any Android Devices
  5. Steps to reproduce: Intermittent bug, Open app after the user is already logged in.
  6. Actual behavior: When the user opens the app from background after successful login, the app crashes with the error message, and repeatedly crashes afterwards.
  7. Expected Behavior: User shouldn't crash when they open the app from the background.
  8. Error Log:
    Caused by java.lang.NullPointerException: userAccount must not be null
    at com.salesforce.androidsdk.security.BiometricAuthenticationManager.shouldLock(BiometricAuthenticationManager.kt:55)
    at com.salesforce.androidsdk.security.AppLockManager.onAppForegrounded(AppLockManager.kt:47)
    at com.salesforce.androidsdk.app.SalesforceSDKManager.onAppForegrounded(SalesforceSDKManager.java:1474)
    at java.lang.reflect.Method.invoke(Method.java)
    at androidx.lifecycle.ClassesInfoCache$MethodReference.invokeCallback(ClassesInfoCache.java:222)
    at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeMethodsForEvent(ClassesInfoCache.java:199)
    at androidx.lifecycle.ClassesInfoCache$CallbackInfo.invokeCallbacks(ClassesInfoCache.java:190)
    at androidx.lifecycle.ReflectiveGenericLifecycleObserver.onStateChanged(ReflectiveGenericLifecycleObserver.java:40)
    at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.kt:314)
    at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.kt:192)
    at com.salesforce.androidsdk.app.SalesforceSDKManager.lambda$new$0$com-salesforce-androidsdk-app-SalesforceSDKManager(SalesforceSDKManager.java:292)
    at com.salesforce.androidsdk.app.SalesforceSDKManager$$ExternalSyntheticLambda0.run(:2)
    at android.os.Handler.handleCallback(Handler.java:978)
    at android.os.Handler.dispatchMessage(Handler.java:104)
    at android.os.Looper.loopOnce(Looper.java:238)
    at android.os.Looper.loop(Looper.java:357)
    at android.app.ActivityThread.main(ActivityThread.java:8090)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026)

Hello,
For the above error, it seems like the kotlin class BiometricAuthenticationManager is calling the UserAccountManager java class, but BiometricAuthenticationManager is expecting a non null return type from UserAccountManager.

In UserAccountManager.buildUserAccount(), this seems to be the only conditional returning a null value, which is causing the crash:

if (authToken == null || instanceServer == null || userId == null || orgId == null) {
	return null;
}

Would it be possible to logout the user when this occurs, instead of causing a crash?

Hello @adriduttaheb. I can try to take a look at this, but the scenario you describe should not be possible. The line before we attempt buildUserAccount(account) is val account = SalesforceSDKManager.getInstance().userAccountManager.currentAccount ?: return false.

userId and orgId are checked before account is returned so somehow either authToken or instanceServer have become null. Are you setting either of those values somehow?

We are not setting authToken or instanceServer to null manually. However, I believe our company has a policy to revoke authtokens after a certain duration, would that cause authToken to become null?

I'm not sure what might cause instanceServer to become null, but our stores sometimes have poor connectivity, so is that something that can impact it?

Also, I'm trying out solution to prevent the crash:
val userAccount = SalesforceSDKManager.getInstance().userAccountManager.buildUserAccount(account) ?: return false

I don't have too much experience working with the sdk, so do you know if this would lead to any security risks?

Hi @adriduttaheb, I will look into this when I get some time because I am not sure how this state is possible. It is possible that revoking the auth token but that still seems odd. What good does revoking the auth token do if the SDK will use the refresh token to get a new auth token on the next API call?

If your app is not using the Biometric Authentication feature (set with a custom attribute on the connected app) the code change you proposed is harmless.