Properly handle unsupported encryption policy

* This fixes the case of:
  * a device that does *not* support device encryption
  * connecting to an account that *does* require device encryption
  * but also supports "non-provisioned devices" (making the encryption
    requirement optional.)
* Added unit test

Bug: 3367191
Change-Id: I894e68c4119a102dad02d2e0815fccdae1e87189
This commit is contained in:
Andy Stadler 2011-01-19 11:40:48 -08:00
parent 985155fddd
commit a0d080558f
4 changed files with 80 additions and 7 deletions

View File

@ -187,7 +187,7 @@ public class SecurityPolicy {
/**
* Get the dpm. This mainly allows us to make some utility calls without it, for testing.
*/
private synchronized DevicePolicyManager getDPM() {
/* package */ synchronized DevicePolicyManager getDPM() {
if (mDPM == null) {
mDPM = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
}
@ -216,7 +216,7 @@ public class SecurityPolicy {
/**
* API: Query if the proposed set of policies are supported on the device.
*
* @param policies requested
* @param policies the polices that were requested
* @return boolean if supported
*/
public boolean isSupported(PolicySet policies) {
@ -232,6 +232,34 @@ public class SecurityPolicy {
return true;
}
/**
* API: Remove any unsupported policies
*
* This is used when we have a set of polices that have been requested, but the server
* is willing to allow unsupported policies to be considered optional.
*
* @param policies the polices that were requested
* @return the same PolicySet if all are supported; A replacement PolicySet if any
* unsupported policies were removed
*/
public PolicySet clearUnsupportedPolicies(PolicySet policies) {
PolicySet result = policies;
// IMPLEMENTATION: At this time, the only policy which might not be supported is
// encryption (which requires low-level systems support). Other policies are fully
// supported by the framework and do not need to be checked.
if (policies.mRequireEncryption) {
int encryptionStatus = getDPM().getStorageEncryptionStatus();
if (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED) {
// Make new PolicySet w/o encryption
result = new PolicySet(policies.mMinPasswordLength, policies.mPasswordMode,
policies.mMaxPasswordFails, policies.mMaxScreenLockTime,
policies.mRequireRemoteWipe, policies.mPasswordExpirationDays,
policies.mPasswordHistory, policies.mPasswordComplexChars, false);
}
}
return result;
}
/**
* API: Query used to determine if a given policy is "active" (the device is operating at
* the required security level).

View File

@ -1527,7 +1527,12 @@ public class EasSyncService extends AbstractSyncService {
String policyKey = acknowledgeProvision(pp.getPolicyKey(),
PROVISION_STATUS_PARTIAL);
// Return either the parser (success) or null (failure)
return (policyKey != null) ? pp : null;
if (policyKey != null) {
pp.clearUnsupportedPolicies();
return pp;
} else {
return null;
}
}
}
}
@ -2190,7 +2195,7 @@ public class EasSyncService extends AbstractSyncService {
/**
* Common code to sync E+PIM data
*
* @param target, an EasMailbox, EasContacts, or EasCalendar object
* @param target an EasMailbox, EasContacts, or EasCalendar object
*/
public void sync(AbstractSyncAdapter target) throws IOException {
Mailbox mailbox = target.mMailbox;

View File

@ -60,6 +60,12 @@ public class ProvisionParser extends Parser {
return (mPolicySet != null) && mIsSupportable;
}
public void clearUnsupportedPolicies() {
mPolicySet = SecurityPolicy.getInstance(mService.mContext)
.clearUnsupportedPolicies(mPolicySet);
mIsSupportable = true;
}
private void parseProvisionDocWbxml() throws IOException {
int minPasswordLength = 0;
int passwordMode = PolicySet.PASSWORD_MODE_NONE;

View File

@ -19,13 +19,14 @@ package com.android.email;
import com.android.email.SecurityPolicy.PolicySet;
import com.android.email.provider.ContentCache;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.AccountColumns;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.Message;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import android.app.admin.DevicePolicyManager;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
@ -73,7 +74,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
/**
* Private context wrapper used to add back getPackageName() for these tests.
*
* This class also implements {@link Context} method(s) that is called during tests.
* This class also implements {@link Context} method(s) that are called during tests.
*/
private static class MockContext2 extends ContextWrapper {
@ -93,6 +94,11 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
public String getPackageName() {
return mRealContext.getPackageName();
}
@Override
public Object getSystemService(String name) {
return mRealContext.getSystemService(name);
}
}
/**
@ -606,4 +612,32 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
account = Account.restoreAccountWithId(mMockContext, account3Id);
assertEquals(Account.FLAGS_SECURITY_HOLD, account.mFlags & Account.FLAGS_SECURITY_HOLD);
}
/**
* Test the code that clears unsupported policies
* TODO inject a mock DPM so we can directly control & test all cases, no matter what device
*/
public void testClearUnsupportedPolicies() {
PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
PolicySet p2 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true);
SecurityPolicy sp = getSecurityPolicy();
DevicePolicyManager dpm = sp.getDPM();
boolean hasEncryption =
dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
PolicySet p1Result = sp.clearUnsupportedPolicies(p1);
PolicySet p2Result = sp.clearUnsupportedPolicies(p2);
// No changes expected when encryptionRequested was false
assertEquals(p1, p1Result);
if (hasEncryption) {
// No changes expected
assertEquals(p2, p2Result);
} else {
PolicySet p2Expect =
new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
assertEquals(p2Expect, p2Result);
}
}
}