Relax device admin policies when accounts deleted

If an account is deleted, immediately recompute the aggregate
security policy, and apply it immediately.

When applying policies, handle "no policy" case by releasing device admin
status entirely.
This commit is contained in:
Andrew Stadler 2010-02-09 11:01:01 -08:00
parent 34716bb6f9
commit 50d1610c43
4 changed files with 54 additions and 27 deletions

View File

@ -63,6 +63,9 @@ public class AccountBackupRestore {
if (restored) {
// after restoring accounts, register services appropriately
Log.w(Email.LOG_TAG, "Register services after restoring accounts");
// update security profile
SecurityPolicy.getInstance(context).updatePolicies(-1);
// enable/disable other email services as necessary
Email.setServicesEnabled(context);
ExchangeUtils.startExchangeService(context);
}

View File

@ -35,6 +35,7 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
/**
* Utility functions to support reading and writing security policies
@ -178,6 +179,16 @@ public class SecurityPolicy {
}
}
/**
* Return updated aggregate policy, from cached value if possible
*/
public synchronized PolicySet getAggregatePolicy() {
if (mAggregatePolicy == null) {
mAggregatePolicy = computeAggregatePolicy();
}
return mAggregatePolicy;
}
/**
* Get the dpm. This mainly allows us to make some utility calls without it, for testing.
*/
@ -217,12 +228,23 @@ public class SecurityPolicy {
/**
* API: Report that policies may have been updated due to rewriting values in an Account.
* @param accountId the account that has been updated
* @param accountId the account that has been updated, -1 if unknown/deleted
*/
public synchronized void updatePolicies(long accountId) {
mAggregatePolicy = null;
}
/**
* API: Report that policies may have been updated *and* the caller vouches that the
* change is a reduction in policies. This forces an immediate change to device state.
* Typically used when deleting accounts, although we may use it for server-side policy
* rollbacks.
*/
public void reducePolicies() {
updatePolicies(-1);
setActivePolicies();
}
/**
* API: Query used to determine if a given policy is "active" (the device is operating at
* the required security level).
@ -237,21 +259,16 @@ public class SecurityPolicy {
* @return true if the policies are active, false if not active
*/
public boolean isActive(PolicySet policies) {
// select aggregate set if needed
if (policies == null) {
policies = getAggregatePolicy();
}
// quick check for the "empty set" of no policies
if (policies == NO_POLICY_SET) {
return true;
}
DevicePolicyManager dpm = getDPM();
if (dpm.isAdminActive(mAdminName)) {
// select aggregate set if needed
if (policies == null) {
synchronized (this) {
if (mAggregatePolicy == null) {
mAggregatePolicy = computeAggregatePolicy();
}
policies = mAggregatePolicy;
}
}
// quick check for the "empty set" of no policies
if (policies == NO_POLICY_SET) {
return true;
}
// check each policy explicitly
if (policies.mMinPasswordLength > 0) {
if (dpm.getPasswordMinimumLength(mAdminName) < policies.mMinPasswordLength) {
@ -283,19 +300,18 @@ public class SecurityPolicy {
}
/**
* Set the requested security level based on the aggregate set of requests
* Set the requested security level based on the aggregate set of requests.
* If the set is empty, we release our device administration. If the set is non-empty,
* we only proceed if we are already active as an admin.
*/
public void setActivePolicies() {
DevicePolicyManager dpm = getDPM();
if (dpm.isAdminActive(mAdminName)) {
// compute aggregate set if needed
PolicySet policies;
synchronized (this) {
if (mAggregatePolicy == null) {
mAggregatePolicy = computeAggregatePolicy();
}
policies = mAggregatePolicy;
}
// compute aggregate set of policies
PolicySet policies = getAggregatePolicy();
// if empty set, detach from policy manager
if (policies == NO_POLICY_SET) {
dpm.removeActiveAdmin(mAdminName);
} else if (dpm.isAdminActive(mAdminName)) {
// set each policy in the policy manager
// password mode & length
dpm.setPasswordQuality(mAdminName, policies.getDPManagerPasswordQuality());
@ -416,12 +432,15 @@ public class SecurityPolicy {
}
/**
* API: Remote wipe (from server). This is final, there is no confirmation.
* API: Remote wipe (from server). This is final, there is no confirmation. It will only
* return to the caller if there is an unexpected failure.
*/
public void remoteWipe(long accountId) {
public void remoteWipe() {
DevicePolicyManager dpm = getDPM();
if (dpm.isAdminActive(mAdminName)) {
dpm.wipeData(0);
} else {
Log.d(Email.LOG_TAG, "Could not remote wipe because not device admin.");
}
}

View File

@ -20,6 +20,7 @@ import com.android.email.AccountBackupRestore;
import com.android.email.Controller;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.SecurityPolicy;
import com.android.email.Utility;
import com.android.email.activity.setup.AccountSettings;
import com.android.email.activity.setup.AccountSetupBasics;
@ -426,6 +427,8 @@ public class AccountFolderList extends ListActivity implements OnItemClickListen
AccountFolderList.this.getContentResolver().delete(uri, null, null);
// Update the backup (side copy) of the accounts
AccountBackupRestore.backupAccounts(AccountFolderList.this);
// Release or relax device administration, if relevant
SecurityPolicy.getInstance(AccountFolderList.this).reducePolicies();
} catch (Exception e) {
// Ignore
}

View File

@ -19,6 +19,7 @@ package com.android.exchange;
import com.android.email.AccountBackupRestore;
import com.android.email.Email;
import com.android.email.SecurityPolicy;
import com.android.email.mail.MessagingException;
import com.android.email.mail.store.TrustManagerFactory;
import com.android.email.provider.EmailContent;
@ -1283,9 +1284,10 @@ public class SyncManager extends Service implements Runnable {
accountsDeleted = true;
}
}
// If we changed the list of accounts, refresh the backup
// If we changed the list of accounts, refresh the backup & security settings
if (accountsDeleted) {
AccountBackupRestore.backupAccounts(getContext());
SecurityPolicy.getInstance(context).reducePolicies();
}
}