Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f49794b5 authored by Andrew Scull's avatar Andrew Scull
Browse files

LSS: pass secret to AuthSecret HAL when no credential

If there was once a credential, a secret will have been enrolled. When
the credential is removed, that secret is still enrolled but still needs
to be derived. This adds that derivation in the case that the secret is
enrolled by the user doesn't have a credential.

Bug: 77942316
Test: runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests
Change-Id: I099a9537ab0739830a234b5f4f3721f4e8476571
parent 26c25f00
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -584,10 +584,43 @@ public class LockSettingsService extends ILockSettings.Stub {
                if (mUserManager.getUserInfo(userId).isManagedProfile()) {
                    tieManagedProfileLockIfNecessary(userId, null);
                }

                // If the user doesn't have a credential, try and derive their secret for the
                // AuthSecret HAL. The secret will have been enrolled if the user previously set a
                // credential and still needs to be passed to the HAL once that credential is
                // removed.
                if (mUserManager.getUserInfo(userId).isPrimary() && !isUserSecure(userId)) {
                    tryDeriveAuthTokenForUnsecuredPrimaryUser(userId);
                }
            }
        });
    }

    private void tryDeriveAuthTokenForUnsecuredPrimaryUser(@UserIdInt int userId) {
        synchronized (mSpManager) {
            // Make sure the user has a synthetic password to derive
            if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
                return;
            }

            try {
                final long handle = getSyntheticPasswordHandleLocked(userId);
                final String noCredential = null;
                AuthenticationResult result =
                        mSpManager.unwrapPasswordBasedSyntheticPassword(
                                getGateKeeperService(), handle, noCredential, userId, null);
                if (result.authToken != null) {
                    Slog.i(TAG, "Retrieved auth token for user " + userId);
                    onAuthTokenKnownForUser(userId, result.authToken);
                } else {
                    Slog.e(TAG, "Auth token not available for user " + userId);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Failure retrieving auth token", e);
            }
        }
    }

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
+3 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.app.IActivityManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
@@ -102,7 +103,8 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase {
        LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);

        mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager,
                mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class));
                mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
                mock(KeyguardManager.class));
        mStorage = new LockSettingsStorageTestable(mContext,
                new File(getContext().getFilesDir(), "locksettings"));
        File storageDir = mStorage.mStorageDir;
+2 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
@@ -79,7 +80,7 @@ public class LockSettingsStorageTests extends AndroidTestCase {

        MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager,
                mock(NotificationManager.class), mock(DevicePolicyManager.class),
                mock(StorageManager.class), mock(TrustManager.class));
                mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class));
        mStorage = new LockSettingsStorageTestable(context,
                new File(getContext().getFilesDir(), "locksettings"));
        mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
+7 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.locksettings;

import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
@@ -32,16 +33,19 @@ public class MockLockSettingsContext extends ContextWrapper {
    private DevicePolicyManager mDevicePolicyManager;
    private StorageManager mStorageManager;
    private TrustManager mTrustManager;
    private KeyguardManager mKeyguardManager;

    public MockLockSettingsContext(Context base, UserManager userManager,
            NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
            StorageManager storageManager, TrustManager trustManager) {
            StorageManager storageManager, TrustManager trustManager,
            KeyguardManager keyguardManager) {
        super(base);
        mUserManager = userManager;
        mNotificationManager = notificationManager;
        mDevicePolicyManager = devicePolicyManager;
        mStorageManager = storageManager;
        mTrustManager = trustManager;
        mKeyguardManager = keyguardManager;
    }

    @Override
@@ -56,6 +60,8 @@ public class MockLockSettingsContext extends ContextWrapper {
            return mStorageManager;
        } else if (TRUST_SERVICE.equals(name)) {
            return mTrustManager;
        } else if (KEYGUARD_SERVICE.equals(name)) {
            return mKeyguardManager;
        } else {
            throw new RuntimeException("System service not mocked: " + name);
        }
+32 −0
Original line number Diff line number Diff line
@@ -217,6 +217,38 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
        verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
    }

    public void testNoSyntheticPasswordOrCredentialDoesNotPassAuthSecret() throws RemoteException {
        // Setting null doesn't create a synthetic password
        initializeCredentialUnderSP(null, PRIMARY_USER_ID);

        reset(mAuthSecretService);
        mService.onUnlockUser(PRIMARY_USER_ID);
        mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
        verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
    }

    public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException {
        final String PASSWORD = "passwordForASyntheticPassword";
        initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);

        reset(mAuthSecretService);
        mService.onUnlockUser(PRIMARY_USER_ID);
        mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
        verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
    }

    public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException {
        final String PASSWORD = "getASyntheticPassword";
        initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID);
        mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD,
                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);

        reset(mAuthSecretService);
        mService.onUnlockUser(PRIMARY_USER_ID);
        mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler
        verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class));
    }

    public void testManagedProfileUnifiedChallengeMigration() throws RemoteException {
        final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd";
        disableSyntheticPassword();