From 0b72a722edacfd790178a2a6183bb985656b2887 Mon Sep 17 00:00:00 2001 From: Michal Karpinski Date: Tue, 21 Jun 2016 15:05:53 +0100 Subject: [PATCH] Fingerprint Strong auth timeout Allows PO and DO configure strong auth timeout for fingerprint. Bug: 31430135 Change-Id: Ie6451d49aa95527adc3720d9a2a0848f58940510 (cherry picked from commit 8f010dd25d18151cc47accc7d853b4f8f7fe8491) --- .../app/admin/DevicePolicyManager.java | 80 +++++++++++++++++++ .../app/admin/IDevicePolicyManager.aidl | 3 + .../keyguard/KeyguardUpdateMonitor.java | 11 +-- .../DevicePolicyManagerService.java | 73 +++++++++++++++++ 4 files changed, 160 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 688876cb3891c..6ee848557ed61 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -416,6 +416,14 @@ public class DevicePolicyManager { */ public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3; + /** + * Default and maximum timeout in milliseconds after which unlocking with weak auth times out, + * i.e. the user has to use a strong authentication method like password, PIN or pattern. + * + * @hide + */ + public static final long DEFAULT_STRONG_AUTH_TIMEOUT_MS = 72 * 60 * 60 * 1000; // 72h + /** * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that * allows a mobile device management application or NFC programmer application which starts @@ -2335,6 +2343,78 @@ public class DevicePolicyManager { return 0; } + /** + * Called by a device/profile owner to set the timeout after which unlocking with secondary, non + * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong + * authentication method like password, pin or pattern. + * + *

This timeout is used internally to reset the timer to require strong auth again after + * specified timeout each time it has been successfully used. + * + *

Fingerprint can also be disabled altogether using {@link #KEYGUARD_DISABLE_FINGERPRINT}. + * + *

Trust agents can also be disabled altogether using {@link #KEYGUARD_DISABLE_TRUST_AGENTS}. + * + *

The calling device admin must be a device or profile owner. If it is not, + * a {@link SecurityException} will be thrown. + * + *

This method can be called on the {@link DevicePolicyManager} instance returned by + * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent + * profile. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param timeoutMs The new timeout, after which the user will have to unlock with strong + * authentication method. If the timeout is lower than 1 hour (minimum) or higher than + * 72 hours (default and maximum) an {@link IllegalArgumentException} is thrown. + * + * @throws SecurityException if {@code admin} is not a device or profile owner. + * @throws IllegalArgumentException if the timeout is lower than 1 hour (minimum) or higher than + * 72 hours (default and maximum) + * + * @hide + */ + public void setRequiredStrongAuthTimeout(@NonNull ComponentName admin, + long timeoutMs) { + if (mService != null) { + try { + mService.setRequiredStrongAuthTimeout(admin, timeoutMs, mParentInstance); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Determine for how long the user will be able to use secondary, non strong auth for + * authentication, since last strong method authentication (password, pin or pattern) was used. + * After the returned timeout the user is required to use strong authentication method. + * + *

This method can be called on the {@link DevicePolicyManager} instance + * returned by {@link #getParentProfileInstance(ComponentName)} in order to retrieve + * restrictions on the parent profile. + * + * @param admin The name of the admin component to check, or {@code null} to aggregate + * accross all participating admins. + * @return The timeout or default timeout if not configured + * + * @hide + */ + public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) { + return getRequiredStrongAuthTimeout(admin, myUserId()); + } + + /** @hide per-user version */ + public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin, @UserIdInt int userId) { + if (mService != null) { + try { + return mService.getRequiredStrongAuthTimeout(admin, userId, mParentInstance); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return DEFAULT_STRONG_AUTH_TIMEOUT_MS; + } + /** * Make the device lock immediately, as if the lock screen timeout has expired at the point of * this call. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 1036f0499a544..dde1efe69ec9d 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -82,6 +82,9 @@ interface IDevicePolicyManager { long getMaximumTimeToLock(in ComponentName who, int userHandle, boolean parent); long getMaximumTimeToLockForUserAndProfiles(int userHandle); + void setRequiredStrongAuthTimeout(in ComponentName who, long timeMs, boolean parent); + long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent); + void lockNow(boolean parent); void wipeData(int flags); diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index dccb1a9214899..60d9c39a6d233 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -111,12 +111,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; - /** - * Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a - * strong auth method like password, PIN or pattern. - */ - private static final long FINGERPRINT_UNLOCK_TIMEOUT_MS = 72 * 60 * 60 * 1000; - // Callback messages private static final int MSG_TIME_UPDATE = 301; private static final int MSG_BATTERY_UPDATE = 302; @@ -608,7 +602,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private void scheduleStrongAuthTimeout() { - long when = SystemClock.elapsedRealtime() + FINGERPRINT_UNLOCK_TIMEOUT_MS; + final DevicePolicyManager dpm = + (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + long when = SystemClock.elapsedRealtime() + dpm.getRequiredStrongAuthTimeout(null, + sCurrentUser); Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT); intent.putExtra(USER_ID, sCurrentUser); PendingIntent sender = PendingIntent.getBroadcast(mContext, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 777c0b35e4be3..6976b28abec0f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -309,6 +309,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000; + /** + * Minimum timeout in milliseconds after which unlocking with weak auth times out, + * i.e. the user has to use a strong authentication method like password, PIN or pattern. + */ + private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h + final Context mContext; final Injector mInjector; final IPackageManager mIPackageManager; @@ -550,6 +556,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_PERMITTED_IMES = "permitted-imes"; private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe"; private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock"; + private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout"; private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter"; private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols"; private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric"; @@ -604,6 +611,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0; long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK; + long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS; + static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0; int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE; @@ -753,6 +762,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_VALUE, Long.toString(maximumTimeToUnlock)); out.endTag(null, TAG_MAX_TIME_TO_UNLOCK); } + if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { + out.startTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT); + out.attribute(null, ATTR_VALUE, Long.toString(strongAuthUnlockTimeout)); + out.endTag(null, TAG_STRONG_AUTH_UNLOCK_TIMEOUT); + } if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { out.startTag(null, TAG_MAX_FAILED_PASSWORD_WIPE); out.attribute(null, ATTR_VALUE, Integer.toString(maximumFailedPasswordsForWipe)); @@ -967,6 +981,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { maximumTimeToUnlock = Long.parseLong( parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) { + strongAuthUnlockTimeout = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) { maximumFailedPasswordsForWipe = Integer.parseInt( parser.getAttributeValue(null, ATTR_VALUE)); @@ -1218,6 +1235,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { pw.println(minimumPasswordNonLetter); pw.print(prefix); pw.print("maximumTimeToUnlock="); pw.println(maximumTimeToUnlock); + pw.print(prefix); pw.print("strongAuthUnlockTimeout="); + pw.println(strongAuthUnlockTimeout); pw.print(prefix); pw.print("maximumFailedPasswordsForWipe="); pw.println(maximumFailedPasswordsForWipe); pw.print(prefix); pw.print("specifiesGlobalProxy="); @@ -4222,6 +4241,60 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return time; } + @Override + public void setRequiredStrongAuthTimeout(ComponentName who, long timeoutMs, + boolean parent) { + if (!mHasFeature) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + Preconditions.checkArgument(timeoutMs >= MINIMUM_STRONG_AUTH_TIMEOUT_MS, + "Timeout must not be lower than the minimum strong auth timeout."); + Preconditions.checkArgument(timeoutMs <= DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS, + "Timeout must not be higher than the default strong auth timeout."); + + final int userHandle = mInjector.userHandleGetCallingUserId(); + synchronized (this) { + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, parent); + if (ap.strongAuthUnlockTimeout != timeoutMs) { + ap.strongAuthUnlockTimeout = timeoutMs; + saveSettingsLocked(userHandle); + } + } + } + + /** + * Return a single admin's strong auth unlock timeout or minimum value (strictest) of all + * admins if who is null. + * Returns default timeout if not configured. + */ + @Override + public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) { + if (!mHasFeature) { + return DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS; + } + enforceFullCrossUsersPermission(userId); + synchronized (this) { + if (who != null) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent); + return admin != null ? Math.max(admin.strongAuthUnlockTimeout, + MINIMUM_STRONG_AUTH_TIMEOUT_MS) + : DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS; + } + + // Return the strictest policy across all participating admins. + List admins = getActiveAdminsForLockscreenPoliciesLocked(userId, parent); + + long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS; + for (int i = 0; i < admins.size(); i++) { + strongAuthUnlockTimeout = Math.min(admins.get(i).strongAuthUnlockTimeout, + strongAuthUnlockTimeout); + } + return Math.max(strongAuthUnlockTimeout, MINIMUM_STRONG_AUTH_TIMEOUT_MS); + } + } + @Override public void lockNow(boolean parent) { if (!mHasFeature) {