Merge "Add method to return an EnforcingAdmin after checking the caller's permissions."

This commit is contained in:
Elis Elliott
2023-02-09 09:24:12 +00:00
committed by Android (Google) Code Review
4 changed files with 170 additions and 43 deletions

View File

@@ -7708,7 +7708,7 @@ package android.app.admin {
method @RequiresPermission(value=android.Manifest.permission.READ_NEARBY_STREAMING_POLICY, conditional=true) public int getNearbyAppStreamingPolicy();
method @RequiresPermission(value=android.Manifest.permission.READ_NEARBY_STREAMING_POLICY, conditional=true) public int getNearbyNotificationStreamingPolicy();
method @Deprecated @ColorInt public int getOrganizationColor(@NonNull android.content.ComponentName);
method @Nullable public CharSequence getOrganizationName(@NonNull android.content.ComponentName);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY) public CharSequence getOrganizationName(@Nullable android.content.ComponentName);
method public java.util.List<android.telephony.data.ApnSetting> getOverrideApns(@NonNull android.content.ComponentName);
method @NonNull public android.app.admin.DevicePolicyManager getParentProfileInstance(@NonNull android.content.ComponentName);
method @RequiresPermission(android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY) public int getPasswordComplexity();
@@ -7863,7 +7863,7 @@ package android.app.admin {
method public void setNetworkLoggingEnabled(@Nullable android.content.ComponentName, boolean);
method @Deprecated public void setOrganizationColor(@NonNull android.content.ComponentName, int);
method public void setOrganizationId(@NonNull String);
method public void setOrganizationName(@NonNull android.content.ComponentName, @Nullable CharSequence);
method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY) public void setOrganizationName(@Nullable android.content.ComponentName, @Nullable CharSequence);
method public void setOverrideApnsEnabled(@NonNull android.content.ComponentName, boolean);
method @NonNull public String[] setPackagesSuspended(@NonNull android.content.ComponentName, @NonNull String[], boolean);
method public void setPasswordExpirationTimeout(@NonNull android.content.ComponentName, long);

View File

@@ -18,6 +18,7 @@ package android.app.admin;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.SET_TIME;
import static android.Manifest.permission.SET_TIME_ZONE;
@@ -13485,18 +13486,24 @@ public class DevicePolicyManager {
}
/**
* Called by the device owner (since API 26) or profile owner (since API 24) to set the name of
* the organization under management.
* Called by the device owner (since API 26) or profile owner (since API 24) or, starting from
* Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
* holders of the permission
* {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY} to set the
* name of the organization under management.
*
* <p>If the organization name needs to be localized, it is the responsibility of the {@link
* DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast and set
* a new version of this string accordingly.
* <p>If the organization name needs to be localized, it is the responsibility of the caller
* to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast and set a new version of this
* string accordingly.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param admin Which {@link DeviceAdminReceiver} this request is associated with or can be
* {@code null} if accessing with a permission without association with a DeviceAdminReceiver.
* @param title The organization name or {@code null} to clear a previously set name.
* @throws SecurityException if {@code admin} is not a device or profile owner.
* @throws SecurityException if {@code admin} is not a device or profile owner or holder of the
* permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY}.
*/
public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) {
@RequiresPermission(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY)
public void setOrganizationName(@Nullable ComponentName admin, @Nullable CharSequence title) {
throwIfParentInstance("setOrganizationName");
try {
mService.setOrganizationName(admin, title);
@@ -13506,14 +13513,21 @@ public class DevicePolicyManager {
}
/**
* Called by a profile owner of a managed profile to retrieve the name of the organization under
* management.
* Called by the device owner (since API 26) or profile owner (since API 24) or, starting from
* Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
* holders of the permission
* {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY
* to retrieve the name of the organization under management.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param admin Which {@link DeviceAdminReceiver} this request is associated with or can be
* {@code null} if accessing with a permission without association with a DeviceAdminReceiver.
* @return The organization name or {@code null} if none is set.
* @throws SecurityException if {@code admin} is not a profile owner.
* @throws SecurityException if {@code admin} if {@code admin} is not a device or profile
* owner or holder of the
* permission {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY}.
*/
public @Nullable CharSequence getOrganizationName(@NonNull ComponentName admin) {
@RequiresPermission(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY)
public @Nullable CharSequence getOrganizationName(@Nullable ComponentName admin) {
throwIfParentInstance("getOrganizationName");
try {
return mService.getOrganizationName(admin);

View File

@@ -21,6 +21,7 @@ import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY;
import static android.Manifest.permission.QUERY_ADMIN_POLICY;
import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY;
import static android.Manifest.permission.SET_TIME;
@@ -15436,16 +15437,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
public void setOrganizationName(@NonNull ComponentName who, CharSequence text) {
public void setOrganizationName(@Nullable ComponentName who, CharSequence text) {
if (!mHasFeature) {
return;
}
Objects.requireNonNull(who, "ComponentName is null");
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
CallerIdentity caller = getCallerIdentity(who);
ActiveAdmin admin = null;
if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
}
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
if (!isPermissionCheckFlagEnabled()) {
admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
}
if (!TextUtils.equals(admin.organizationName, text)) {
admin.organizationName = (text == null || text.length() == 0)
? null : text.toString();
@@ -15455,20 +15467,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
public CharSequence getOrganizationName(@NonNull ComponentName who) {
public CharSequence getOrganizationName(@Nullable ComponentName who) {
if (!mHasFeature) {
return null;
}
Objects.requireNonNull(who, "ComponentName is null");
CallerIdentity caller = getCallerIdentity(who);
ActiveAdmin admin = null;
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallingUser(isManagedProfile(caller.getUserId()));
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
if (isPermissionCheckFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforceCanQueryAndGetEnforcingAdmin(
who,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
caller.getUserId());
admin = enforcingAdmin.getActiveAdmin();
} else {
Preconditions.checkCallingUser(isManagedProfile(caller.getUserId()));
Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller));
synchronized (getLockObject()) {
ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
return admin.organizationName;
synchronized (getLockObject()) {
admin = getProfileOwnerOrDeviceOwnerLocked(caller.getUserId());
}
}
return admin.organizationName;
}
/**
@@ -20092,22 +20113,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
MANAGE_DEVICE_POLICY_ACROSS_USERS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
SET_TIME,
SET_TIME_ZONE);
SET_TIME_ZONE,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY);
private static final List<String> FINANCED_DEVICE_OWNER_PERMISSIONS = List.of(
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY);
private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
List.of(
MANAGE_DEVICE_POLICY_ACROSS_USERS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
SET_TIME,
SET_TIME_ZONE);
SET_TIME_ZONE,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY);
private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS = List.of(
SET_TIME,
SET_TIME_ZONE);
private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of(
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY);
private static final HashMap<Integer, List<String>> DPC_PERMISSIONS = new HashMap<>();
{
@@ -20125,9 +20150,48 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final HashMap<String, String> CROSS_USER_PERMISSIONS =
new HashMap<>();
{
// Auto time is intrinsically global so there is no cross-user permission.
// Time and Timezone is intrinsically global so there is no cross-user permission.
CROSS_USER_PERMISSIONS.put(SET_TIME, null);
CROSS_USER_PERMISSIONS.put(SET_TIME_ZONE, null);
// Organisation identity policy will involve data of other organisations on the device and
// therefore the FULL cross-user permission is required.
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
}
/**
* Checks if the calling process has been granted permission to apply a device policy on a
* specific user.
* The given permission will be checked along with its associated cross-user permission if it
* exists and the target user is different to the calling user.
* Returns the {@link ActiveAdmin} of the caller.
*
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
* the associated cross-user permission if the caller's user is different to the target user.
*/
private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
String permission, int targetUserId) {
enforcePermission(permission, targetUserId);
return getEnforcingAdminForCaller(admin, getCallerIdentity());
}
/**
* Checks whether the calling process has been granted permission to query a device policy on
* a specific user.
* The given permission will be checked along with its associated cross-user permission if it
* exists and the target user is different to the calling user.
*
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
* the associated cross-user permission if the caller's user is different to the target user.
*/
private EnforcingAdmin enforceCanQueryAndGetEnforcingAdmin(@Nullable ComponentName admin,
String permission, int targetUserId) {
enforceCanQuery(permission, targetUserId);
return getEnforcingAdminForCaller(admin, getCallerIdentity());
}
/**
@@ -20139,7 +20203,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
* the associtated cross-user permission if the caller's user is different to the target user.
* the associated cross-user permission if the caller's user is different to the target user.
*/
private void enforcePermission(String permission, int targetUserId)
throws SecurityException {
@@ -20154,13 +20218,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
* Return whether the calling process has been granted permission to query a device policy on
* Checks whether the calling process has been granted permission to query a device policy on
* a specific user.
* The given permission will be checked along with its associated cross-user permission if it
* exists and the target user is different to the calling user.
*
* @param permission The name of the permission being checked.
* @param targetUserId The userId of the user which the caller needs permission to act on.
* @throws SecurityException if the caller has not been granted the given permission,
* the associatated cross-user permission if the caller's user is different to the target user
* the associated cross-user permission if the caller's user is different to the target user
* and if the user has not been granted {@link QUERY_ADMIN_POLICY}.
*/
private void enforceCanQuery(String permission, int targetUserId) throws SecurityException {
@@ -20225,10 +20291,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
// Check if the caller is an active admin that uses a certain policy.
if (ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
return getActiveAdminForCallerLocked(
null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
try {
return getActiveAdminForCallerLocked(
null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
} catch (SecurityException e) {
// A security exception means there is not an active admin with permission and
// therefore
return false;
}
}
return false;
}
@@ -20258,6 +20329,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
private EnforcingAdmin getEnforcingAdminForCaller(@Nullable ComponentName who,
CallerIdentity caller) {
int userId = caller.getUserId();
ActiveAdmin admin = null;
synchronized (getLockObject()) {
admin = getActiveAdminUncheckedLocked(who, userId);
}
if (isDeviceOwner(caller) || isProfileOwner(caller)) {
return EnforcingAdmin.createEnterpriseEnforcingAdmin(who, userId, admin);
}
if (getActiveAdminUncheckedLocked(who, userId) != null) {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId);
}
private boolean isPermissionCheckFlagEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_DEVICE_POLICY_MANAGER,

View File

@@ -63,6 +63,7 @@ final class EnforcingAdmin {
private Set<String> mAuthorities;
private final int mUserId;
private final boolean mIsRoleAuthority;
private final ActiveAdmin mActiveAdmin;
static EnforcingAdmin createEnforcingAdmin(@NonNull String packageName, int userId) {
Objects.requireNonNull(packageName);
@@ -73,14 +74,31 @@ final class EnforcingAdmin {
@NonNull ComponentName componentName, int userId) {
Objects.requireNonNull(componentName);
return new EnforcingAdmin(
componentName.getPackageName(), componentName, Set.of(DPC_AUTHORITY), userId);
componentName.getPackageName(), componentName, Set.of(DPC_AUTHORITY), userId,
/* activeAdmin=*/ null);
}
static EnforcingAdmin createEnterpriseEnforcingAdmin(
@NonNull ComponentName componentName, int userId, ActiveAdmin activeAdmin) {
Objects.requireNonNull(componentName);
return new EnforcingAdmin(
componentName.getPackageName(), componentName, Set.of(DPC_AUTHORITY), userId,
activeAdmin);
}
static EnforcingAdmin createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId) {
Objects.requireNonNull(componentName);
return new EnforcingAdmin(
componentName.getPackageName(), componentName, Set.of(DEVICE_ADMIN_AUTHORITY),
userId);
userId, /* activeAdmin=*/ null);
}
static EnforcingAdmin createDeviceAdminEnforcingAdmin(ComponentName componentName, int userId,
ActiveAdmin activeAdmin) {
Objects.requireNonNull(componentName);
return new EnforcingAdmin(
componentName.getPackageName(), componentName, Set.of(DEVICE_ADMIN_AUTHORITY),
userId, activeAdmin);
}
static String getRoleAuthorityOf(String roleName) {
@@ -88,7 +106,8 @@ final class EnforcingAdmin {
}
private EnforcingAdmin(
String packageName, ComponentName componentName, Set<String> authorities, int userId) {
String packageName, ComponentName componentName, Set<String> authorities, int userId,
ActiveAdmin activeAdmin) {
Objects.requireNonNull(packageName);
Objects.requireNonNull(componentName);
Objects.requireNonNull(authorities);
@@ -99,6 +118,7 @@ final class EnforcingAdmin {
mComponentName = componentName;
mAuthorities = new HashSet<>(authorities);
mUserId = userId;
mActiveAdmin = activeAdmin;
}
private EnforcingAdmin(String packageName, int userId) {
@@ -111,6 +131,7 @@ final class EnforcingAdmin {
mComponentName = null;
// authorities will be loaded when needed
mAuthorities = null;
mActiveAdmin = null;
}
private static Set<String> getRoleAuthoritiesOrDefault(String packageName, int userId) {
@@ -156,6 +177,11 @@ final class EnforcingAdmin {
return mUserId;
}
@Nullable
public ActiveAdmin getActiveAdmin() {
return mActiveAdmin;
}
/**
* For two EnforcingAdmins to be equal they must:
*
@@ -224,7 +250,7 @@ final class EnforcingAdmin {
String className = parser.getAttributeValue(/* namespace= */ null, ATTR_CLASS_NAME);
ComponentName componentName = new ComponentName(packageName, className);
Set<String> authorities = Set.of(authoritiesStr.split(ATTR_AUTHORITIES_SEPARATOR));
return new EnforcingAdmin(packageName, componentName, authorities, userId);
return new EnforcingAdmin(packageName, componentName, authorities, userId, null);
}
}