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

Commit b85646d5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Wipe device when COPE PO max password attemps exceeded"

parents 1b883e21 a5b15b25
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -3730,6 +3730,11 @@ public class DevicePolicyManager {
     * requires that you request both {@link DeviceAdminInfo#USES_POLICY_WATCH_LOGIN} and
     * {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}}.
     * <p>
     * When this policy is set by a device owner, profile owner of an organization-owned device or
     * an admin on the primary user, the device will be factory reset after too many incorrect
     * password attempts. When set by a profile owner or an admin on a secondary user or a managed
     * profile, only the corresponding user or profile will be wiped.
     * <p>
     * To implement any other policy (e.g. wiping data for a particular application only, erasing or
     * revoking credentials, or reporting the failure to a server), you should implement
     * {@link DeviceAdminReceiver#onPasswordFailed(Context, android.content.Intent)} instead. Do not
@@ -3798,10 +3803,12 @@ public class DevicePolicyManager {
    }
    /**
     * Returns the profile with the smallest maximum failed passwords for wipe,
     * for the given user. So for primary user, it might return the primary or
     * a managed profile. For a secondary user, it would be the same as the
     * user passed in.
     * Returns the user that will be wiped first when too many failed attempts are made to unlock
     * user {@code userHandle}. That user is either the same as {@code userHandle} or belongs to the
     * same profile group. When there is no such policy, returns {@code UserHandle.USER_NULL}.
     * E.g. managed profile user may be wiped as a result of failed primary profile password
     * attempts when using unified challenge. Primary user may be wiped as a result of failed
     * password attempts on the managed profile on an organization-owned device.
     * @hide Used only by Keyguard
     */
    @RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
+16 −4
Original line number Diff line number Diff line
@@ -5343,7 +5343,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        synchronized (getLockObject()) {
            ActiveAdmin admin = getAdminWithMinimumFailedPasswordsForWipeLocked(
                    userHandle, parent);
            return admin != null ? admin.getUserHandle().getIdentifier() : UserHandle.USER_NULL;
            return admin != null ? getUserIdToWipeForFailedPasswords(admin) : UserHandle.USER_NULL;
        }
    }
@@ -5354,7 +5354,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
     *   <li>this user and all profiles that don't have their own challenge otherwise.
     * </ul>
     * <p>If the policy for the primary and any other profile are equal, it returns the admin for
     * the primary profile.
     * the primary profile. Policy of a PO on an organization-owned device applies to the primary
     * profile.
     * Returns {@code null} if no participating admin has that policy set.
     */
    private ActiveAdmin getAdminWithMinimumFailedPasswordsForWipeLocked(
@@ -5373,7 +5374,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            }
            // We always favor the primary profile if several profiles have the same value set.
            int userId = admin.getUserHandle().getIdentifier();
            final int userId = getUserIdToWipeForFailedPasswords(admin);
            if (count == 0 ||
                    count > admin.maximumFailedPasswordsForWipe ||
                    (count == admin.maximumFailedPasswordsForWipe &&
@@ -7170,7 +7171,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        if (wipeData && strictestAdmin != null) {
            final int userId = strictestAdmin.getUserHandle().getIdentifier();
            final int userId = getUserIdToWipeForFailedPasswords(strictestAdmin);
            Slog.i(LOG_TAG, "Max failed password attempts policy reached for admin: "
                    + strictestAdmin.info.getComponent().flattenToShortString()
                    + ". Calling wipeData for user " + userId);
@@ -7201,6 +7202,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    /**
     * Returns which user should be wiped if this admin's maximum filed password attempts policy is
     * violated.
     */
    private int getUserIdToWipeForFailedPasswords(ActiveAdmin admin) {
        final int userId = admin.getUserHandle().getIdentifier();
        final ComponentName component = admin.info.getComponent();
        return isProfileOwnerOfOrganizationOwnedDevice(component, userId)
                ? getProfileParentId(userId) : userId;
    }
    @Override
    public void reportSuccessfulPasswordAttempt(int userHandle) {
        enforceFullCrossUsersPermission(userHandle);
+81 −2
Original line number Diff line number Diff line
@@ -4535,6 +4535,86 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                .removeUserEvenWhenDisallowed(anyInt());
    }

    public void testMaximumFailedDevicePasswordAttemptsReachedOrgOwnedManagedProfile()
            throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        configureProfileOwnerOfOrgOwnedDevice(admin1, MANAGED_PROFILE_USER_ID);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(admin1));
        assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(null));

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);

        assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM));
        // Check that primary will be wiped as a result of failed primary user unlock attempts.
        assertEquals(UserHandle.USER_SYSTEM,
                dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM));

        // Failed password attempts on the parent user are taken into account, as there isn't a
        // separate work challenge.
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);
        dpm.reportFailedPasswordAttempt(UserHandle.USER_SYSTEM);

        // For managed profile on an organization owned device, the whole device should be wiped.
        verify(getServices().recoverySystem).rebootWipeUserData(
                /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
                /*wipeEuicc=*/ eq(false));
    }

    public void testMaximumFailedProfilePasswordAttemptsReachedOrgOwnedManagedProfile()
            throws Exception {
        final int MANAGED_PROFILE_USER_ID = 15;
        final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(MANAGED_PROFILE_USER_ID, 19436);
        addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1);

        // Even if the caller is the managed profile, the current user is the user 0
        when(getServices().iactivityManager.getCurrentUser())
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));

        doReturn(true).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID);

        // Configure separate challenge.
        configureProfileOwnerOfOrgOwnedDevice(admin1, MANAGED_PROFILE_USER_ID);

        mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
        dpm.setMaximumFailedPasswordsForWipe(admin1, 3);

        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
        mContext.callerPermissions.add(permission.BIND_DEVICE_ADMIN);

        assertEquals(0, dpm.getMaximumFailedPasswordsForWipe(null, UserHandle.USER_SYSTEM));
        assertEquals(3, dpm.getMaximumFailedPasswordsForWipe(null, MANAGED_PROFILE_USER_ID));
        // Check that the policy is not affecting primary profile challenge.
        assertEquals(UserHandle.USER_NULL,
                dpm.getProfileWithMinimumFailedPasswordsForWipe(UserHandle.USER_SYSTEM));
        // Check that primary will be wiped as a result of failed profile unlock attempts.
        assertEquals(UserHandle.USER_SYSTEM,
                dpm.getProfileWithMinimumFailedPasswordsForWipe(MANAGED_PROFILE_USER_ID));

        // Simulate three failed attempts at solving the separate challenge.
        dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID);
        dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID);
        dpm.reportFailedPasswordAttempt(MANAGED_PROFILE_USER_ID);

        // For managed profile on an organization owned device, the whole device should be wiped.
        verify(getServices().recoverySystem).rebootWipeUserData(
                /*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
                /*wipeEuicc=*/ eq(false));
    }

    public void testGetPermissionGrantState() throws Exception {
        final String permission = "some.permission";
        final String app1 = "com.example.app1";
@@ -5770,8 +5850,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        when(getServices().userManager.getProfileParent(eq(UserHandle.of(userId))))
                .thenReturn(UserHandle.SYSTEM);
        final long ident = mServiceContext.binder.clearCallingIdentity();
        mServiceContext.binder.callingUid =
                UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
        mServiceContext.binder.callingUid = UserHandle.getUid(userId, DpmMockContext.SYSTEM_UID);

        configureContextForAccess(mServiceContext, true);
        runAsCaller(mServiceContext, dpms, dpm -> {