summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--emailcommon/src/com/android/emailcommon/service/PolicySet.java23
-rw-r--r--src/com/android/email/SecurityPolicy.java38
-rw-r--r--tests/src/com/android/email/SecurityPolicyTests.java136
3 files changed, 146 insertions, 51 deletions
diff --git a/emailcommon/src/com/android/emailcommon/service/PolicySet.java b/emailcommon/src/com/android/emailcommon/service/PolicySet.java
index 8b983e94e..2bc3ee9d0 100644
--- a/emailcommon/src/com/android/emailcommon/service/PolicySet.java
+++ b/emailcommon/src/com/android/emailcommon/service/PolicySet.java
@@ -63,8 +63,10 @@ public class PolicySet implements Parcelable {
private static final int PASSWORD_COMPLEX_CHARS_SHIFT = 44;
private static final long PASSWORD_COMPLEX_CHARS_MASK = 31L << PASSWORD_COMPLEX_CHARS_SHIFT;
public static final int PASSWORD_COMPLEX_CHARS_MAX = 31;
- // bit 49: requires device encryption
+ // bit 49: requires device encryption (internal)
private static final long REQUIRE_ENCRYPTION = 1L << 49;
+ // bit 50: requires external storage encryption
+ private static final long REQUIRE_ENCRYPTION_EXTERNAL = 1L << 50;
/* Convert days to mSec (used for password expiration) */
private static final long DAYS_TO_MSEC = 24 * 60 * 60 * 1000;
@@ -80,6 +82,7 @@ public class PolicySet implements Parcelable {
public final int mPasswordHistory;
public final int mPasswordComplexChars;
public final boolean mRequireEncryption;
+ public final boolean mRequireEncryptionExternal;
public int getMinPasswordLengthForTest() {
return mMinPasswordLength;
@@ -105,6 +108,10 @@ public class PolicySet implements Parcelable {
return mRequireEncryption;
}
+ public boolean isRequireEncryptionExternalForTest() {
+ return mRequireEncryptionExternal;
+ }
+
/**
* Create from raw values.
* @param minPasswordLength (0=not enforced)
@@ -115,12 +122,14 @@ public class PolicySet implements Parcelable {
* @param passwordExpirationDays in days (0=not enforced)
* @param passwordHistory (0=not enforced)
* @param passwordComplexChars (0=not enforced)
+ * @param requireEncryption
+ * @param requireEncryptionExternal
* @throws IllegalArgumentException for illegal arguments.
*/
public PolicySet(int minPasswordLength, int passwordMode, int maxPasswordFails,
int maxScreenLockTime, boolean requireRemoteWipe, int passwordExpirationDays,
- int passwordHistory, int passwordComplexChars, boolean requireEncryption)
- throws IllegalArgumentException {
+ int passwordHistory, int passwordComplexChars, boolean requireEncryption,
+ boolean requireEncryptionExternal) throws IllegalArgumentException {
// If we're not enforcing passwords, make sure we clean up related values, since EAS
// can send non-zero values for any or all of these
if (passwordMode == PASSWORD_MODE_NONE) {
@@ -171,6 +180,7 @@ public class PolicySet implements Parcelable {
mPasswordHistory = passwordHistory;
mPasswordComplexChars = passwordComplexChars;
mRequireEncryption = requireEncryption;
+ mRequireEncryptionExternal = requireEncryptionExternal;
}
/**
@@ -201,6 +211,7 @@ public class PolicySet implements Parcelable {
mPasswordComplexChars =
(int) ((flags & PASSWORD_COMPLEX_CHARS_MASK) >> PASSWORD_COMPLEX_CHARS_SHIFT);
mRequireEncryption = 0 != (flags & REQUIRE_ENCRYPTION);
+ mRequireEncryptionExternal = 0 != (flags & REQUIRE_ENCRYPTION_EXTERNAL);
}
/**
@@ -305,6 +316,7 @@ public class PolicySet implements Parcelable {
dest.writeInt(mPasswordHistory);
dest.writeInt(mPasswordComplexChars);
dest.writeInt(mRequireEncryption ? 1 : 0);
+ dest.writeInt(mRequireEncryptionExternal ? 1 : 0);
}
/**
@@ -320,6 +332,7 @@ public class PolicySet implements Parcelable {
mPasswordHistory = in.readInt();
mPasswordComplexChars = in.readInt();
mRequireEncryption = in.readInt() == 1;
+ mRequireEncryptionExternal = in.readInt() == 1;
}
@Override
@@ -339,6 +352,7 @@ public class PolicySet implements Parcelable {
flags |= (long)mPasswordExpirationDays << PASSWORD_EXPIRATION_SHIFT;
flags |= (long)mPasswordComplexChars << PASSWORD_COMPLEX_CHARS_SHIFT;
if (mRequireEncryption) flags |= REQUIRE_ENCRYPTION;
+ if (mRequireEncryptionExternal) flags |= REQUIRE_ENCRYPTION_EXTERNAL;
return flags;
}
@@ -350,7 +364,8 @@ public class PolicySet implements Parcelable {
+ " pw-expiration=" + mPasswordExpirationDays
+ " pw-history=" + mPasswordHistory
+ " pw-complex-chars=" + mPasswordComplexChars
- + " require-encryption=" + mRequireEncryption + "}";
+ + " require-encryption=" + mRequireEncryption
+ + " require-encryptionExternal=" + mRequireEncryptionExternal + "}";
}
}
diff --git a/src/com/android/email/SecurityPolicy.java b/src/com/android/email/SecurityPolicy.java
index 2af2ef0a1..7734b82f1 100644
--- a/src/com/android/email/SecurityPolicy.java
+++ b/src/com/android/email/SecurityPolicy.java
@@ -33,6 +33,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
+import android.os.Environment;
import android.util.Log;
/**
@@ -48,7 +49,7 @@ public class SecurityPolicy {
private PolicySet mAggregatePolicy;
/* package */ static final PolicySet NO_POLICY_SET =
- new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false);
+ new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false, false);
/**
* This projection on Account is for scanning/reading
@@ -105,6 +106,7 @@ public class SecurityPolicy {
* password expiration take the min (strongest mode)
* password complex chars take the max (strongest mode)
* encryption take the max (logical or)
+ * encryption (external) take the max (logical or)
*
* @return a policy representing the strongest aggregate. If no policy sets are defined,
* a lightweight "nothing required" policy will be returned. Never null.
@@ -121,6 +123,7 @@ public class SecurityPolicy {
int passwordExpirationDays = Integer.MAX_VALUE;
int passwordComplexChars = Integer.MIN_VALUE;
boolean requireEncryption = false;
+ boolean requireEncryptionExternal = false;
Cursor c = mContext.getContentResolver().query(Account.CONTENT_URI,
ACCOUNT_SECURITY_PROJECTION, Account.SECURITY_NONZERO_SELECTION, null, null);
@@ -150,6 +153,7 @@ public class SecurityPolicy {
}
requireRemoteWipe |= p.mRequireRemoteWipe;
requireEncryption |= p.mRequireEncryption;
+ requireEncryptionExternal |= p.mRequireEncryptionExternal;
policiesFound = true;
}
}
@@ -168,7 +172,7 @@ public class SecurityPolicy {
return new PolicySet(minPasswordLength, passwordMode, maxPasswordFails,
maxScreenLockTime, requireRemoteWipe, passwordExpirationDays, passwordHistory,
- passwordComplexChars, requireEncryption);
+ passwordComplexChars, requireEncryption, requireEncryptionExternal);
} else {
return NO_POLICY_SET;
}
@@ -229,6 +233,13 @@ public class SecurityPolicy {
return false;
}
}
+ if (policies.mRequireEncryptionExternal) {
+ // At this time, we only support "external encryption" when it is provided by virtue
+ // of emulating the external storage inside an encrypted device.
+ if (!policies.mRequireEncryption) return false;
+ if (Environment.isExternalStorageRemovable()) return false;
+ if (!Environment.isExternalStorageEmulated()) return false;
+ }
return true;
}
@@ -254,7 +265,19 @@ public class SecurityPolicy {
result = new PolicySet(policies.mMinPasswordLength, policies.mPasswordMode,
policies.mMaxPasswordFails, policies.mMaxScreenLockTime,
policies.mRequireRemoteWipe, policies.mPasswordExpirationDays,
- policies.mPasswordHistory, policies.mPasswordComplexChars, false);
+ policies.mPasswordHistory, policies.mPasswordComplexChars, false, false);
+ }
+ }
+ // At this time, we only support "external encryption" when it is provided by virtue
+ // of emulating the external storage inside an encrypted device.
+ if (policies.mRequireEncryptionExternal) {
+ if (Environment.isExternalStorageRemovable()
+ || !Environment.isExternalStorageEmulated()) {
+ // 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, false);
}
}
return result;
@@ -375,6 +398,11 @@ public class SecurityPolicy {
reasons |= INACTIVE_NEED_ENCRYPTION;
}
}
+ // TODO: If we ever support external storage encryption as a first-class feature,
+ // it will need to be checked here. For now, if there is a policy request for
+ // external storage encryption, it's sufficient that we've activated internal
+ // storage encryption.
+
// password failures are counted locally - no test required here
// no check required for remote wipe (it's supported, if we're the admin)
@@ -415,6 +443,10 @@ public class SecurityPolicy {
dpm.setPasswordMinimumNonLetter(mAdminName, policies.mPasswordComplexChars);
// encryption required
dpm.setStorageEncryption(mAdminName, policies.mRequireEncryption);
+ // TODO: If we ever support external storage encryption as a first-class feature,
+ // it will need to be set here. For now, if there is a policy request for
+ // external storage encryption, it's sufficient that we've activated internal
+ // storage encryption.
}
}
diff --git a/tests/src/com/android/email/SecurityPolicyTests.java b/tests/src/com/android/email/SecurityPolicyTests.java
index 82fa5844d..0536139ed 100644
--- a/tests/src/com/android/email/SecurityPolicyTests.java
+++ b/tests/src/com/android/email/SecurityPolicyTests.java
@@ -49,7 +49,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
private Context mMockContext;
private static final PolicySet EMPTY_POLICY_SET =
- new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false);
+ new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false, false);
public SecurityPolicyTests() {
super(EmailProvider.class, EmailContent.AUTHORITY);
@@ -114,28 +114,29 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// We know that EMPTY_POLICY_SET doesn't generate an Exception or we wouldn't be here
// Try some illegal parameters
try {
- new PolicySet(100, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false);
+ new PolicySet(100, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false, false);
fail("Too-long password allowed");
} catch (IllegalArgumentException e) {
}
try {
- new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG + 1, 0, 0, false, 0, 0, 0, false);
+ new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG + 1, 0, 0, false, 0, 0, 0, false,
+ false);
fail("Illegal password mode allowed");
} catch (IllegalArgumentException e) {
}
PolicySet ps = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0,
- PolicySet.SCREEN_LOCK_TIME_MAX + 1, false, 0, 0, 0, false);
+ PolicySet.SCREEN_LOCK_TIME_MAX + 1, false, 0, 0, 0, false, false);
assertEquals(PolicySet.SCREEN_LOCK_TIME_MAX, ps.getMaxScreenLockTimeForTest());
ps = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE,
- PolicySet.PASSWORD_MAX_FAILS_MAX + 1, 0, false, 0, 0, 0, false);
+ PolicySet.PASSWORD_MAX_FAILS_MAX + 1, 0, false, 0, 0, 0, false, false);
assertEquals(PolicySet.PASSWORD_MAX_FAILS_MAX, ps.getMaxPasswordFailsForTest());
// All password related fields should be zero when password mode is NONE
// Illegal values for these fields should be ignored
ps = new PolicySet(999/*length*/, PolicySet.PASSWORD_MODE_NONE,
999/*fails*/, 9999/*screenlock*/, false, 999/*expir*/, 999/*history*/,
- 999/*complex*/, false);
+ 999/*complex*/, false, false);
assertEquals(0, ps.mMinPasswordLength);
assertEquals(0, ps.mMaxScreenLockTime);
assertEquals(0, ps.mMaxPasswordFails);
@@ -145,7 +146,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// With a simple password, we should set complex chars to zero
ps = new PolicySet(4/*length*/, PolicySet.PASSWORD_MODE_SIMPLE,
- 0, 0, false, 0, 0, 3/*complex*/, false);
+ 0, 0, false, 0, 0, 3/*complex*/, false, false);
assertEquals(4, ps.mMinPasswordLength);
assertEquals(0, ps.mPasswordComplexChars);
}
@@ -172,7 +173,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// first test with partially-populated policies
Account a3 = ProviderTestUtils.setupAccount("sec-3", false, mMockContext);
PolicySet p3ain = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
- false);
+ false, false);
p3ain.writeAccount(a3, null, true, mMockContext);
PolicySet p3aout = sp.computeAggregatePolicy();
assertNotNull(p3aout);
@@ -180,7 +181,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// Repeat that test with fully-populated policies
PolicySet p3bin = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3,
- false);
+ false, false);
p3bin.writeAccount(a3, null, true, mMockContext);
PolicySet p3bout = sp.computeAggregatePolicy();
assertNotNull(p3bout);
@@ -193,8 +194,9 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// expiration - will not change because 0 (unspecified)
// max complex chars - max logic - will change
// encryption required - OR logic - will *not* change here because false
+ // encryption external req'd - OR logic - will *not* change here because false
PolicySet p4in = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7,
- false);
+ false, false);
Account a4 = ProviderTestUtils.setupAccount("sec-4", false, mMockContext);
p4in.writeAccount(a4, null, true, mMockContext);
PolicySet p4out = sp.computeAggregatePolicy();
@@ -208,6 +210,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(7, p4out.mPasswordComplexChars);
assertFalse(p4out.mRequireRemoteWipe);
assertFalse(p4out.mRequireEncryption);
+ assertFalse(p4out.mRequireEncryptionExternal);
// add another account which mixes it up (the remaining fields will change)
// pw length and pw mode - max logic - will *not* change because smaller #s here
@@ -216,8 +219,9 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// expiration time - min logic - will change because lower here
// history & complex chars - will not change because 0 (unspecified)
// encryption required - OR logic - will change here because true
+ // encryption external req'd - OR logic - will *not* change here because false
PolicySet p5in = new PolicySet(4, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0,
- true);
+ true, false);
Account a5 = ProviderTestUtils.setupAccount("sec-5", false, mMockContext);
p5in.writeAccount(a5, null, true, mMockContext);
PolicySet p5out = sp.computeAggregatePolicy();
@@ -230,7 +234,17 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(5, p5out.mPasswordHistory);
assertEquals(7, p5out.mPasswordComplexChars);
assertTrue(p5out.mRequireRemoteWipe);
- assertTrue(p5out.mRequireEncryption);
+ assertFalse(p5out.mRequireEncryptionExternal);
+
+ // add another account that continues to mutate fields
+ // encryption external req'd - OR logic - will change here because true
+ PolicySet p6in = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0,
+ false, true);
+ Account a6 = ProviderTestUtils.setupAccount("sec-6", false, mMockContext);
+ p6in.writeAccount(a6, null, true, mMockContext);
+ PolicySet p6out = sp.computeAggregatePolicy();
+ assertNotNull(p6out);
+ assertTrue(p6out.mRequireEncryptionExternal);
}
/**
@@ -260,7 +274,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
public void testFieldIsolation() {
// Check PASSWORD_LENGTH
PolicySet p = new PolicySet(PolicySet.PASSWORD_LENGTH_MAX, PolicySet.PASSWORD_MODE_SIMPLE,
- 0, 0, false, 0, 0 ,0, false);
+ 0, 0, false, 0, 0 ,0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(PolicySet.PASSWORD_LENGTH_MAX, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -270,9 +284,10 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check PASSWORD_MODE
- p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0, 0, false);
+ p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0, 0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_STRONG, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -282,10 +297,11 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check PASSWORD_FAILS (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, PolicySet.PASSWORD_MAX_FAILS_MAX, 0,
- false, 0, 0, 0, false);
+ false, 0, 0, 0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(PolicySet.PASSWORD_MAX_FAILS_MAX, p.mMaxPasswordFails);
@@ -295,10 +311,11 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check SCREEN_LOCK_TIME (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, PolicySet.SCREEN_LOCK_TIME_MAX,
- false, 0, 0, 0, false);
+ false, 0, 0, 0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -308,9 +325,10 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check REQUIRE_REMOTE_WIPE
- p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, true, 0, 0, 0, false);
+ p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, true, 0, 0, 0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -320,10 +338,11 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertTrue(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check PASSWORD_EXPIRATION (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false,
- PolicySet.PASSWORD_EXPIRATION_MAX, 0, 0, false);
+ PolicySet.PASSWORD_EXPIRATION_MAX, 0, 0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -333,10 +352,11 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check PASSWORD_HISTORY (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0,
- PolicySet.PASSWORD_HISTORY_MAX, 0, false);
+ PolicySet.PASSWORD_HISTORY_MAX, 0, false, false);
assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -346,10 +366,11 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check PASSWORD_COMPLEX_CHARS (note, mode must be set for this to be non-zero)
p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0,
- PolicySet.PASSWORD_COMPLEX_CHARS_MAX, false);
+ PolicySet.PASSWORD_COMPLEX_CHARS_MAX, false, false);
assertEquals(PolicySet.PASSWORD_MODE_STRONG, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -359,9 +380,10 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(PolicySet.PASSWORD_COMPLEX_CHARS_MAX, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertFalse(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
// Check REQUIRE_ENCRYPTION
- p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, true);
+ p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, true, false);
assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
assertEquals(0, p.mMinPasswordLength);
assertEquals(0, p.mMaxPasswordFails);
@@ -371,6 +393,20 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
assertEquals(0, p.mPasswordComplexChars);
assertFalse(p.mRequireRemoteWipe);
assertTrue(p.mRequireEncryption);
+ assertFalse(p.mRequireEncryptionExternal);
+
+ // Check REQUIRE_ENCRYPTION_EXTERNAL
+ p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false, true);
+ assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
+ assertEquals(0, p.mMinPasswordLength);
+ assertEquals(0, p.mMaxPasswordFails);
+ assertEquals(0, p.mMaxScreenLockTime);
+ assertEquals(0, p.mPasswordExpirationDays);
+ assertEquals(0, p.mPasswordHistory);
+ assertEquals(0, p.mPasswordComplexChars);
+ assertFalse(p.mRequireRemoteWipe);
+ assertFalse(p.mRequireEncryption);
+ assertTrue(p.mRequireEncryptionExternal);
}
/**
@@ -378,7 +414,8 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
*/
@SmallTest
public void testAccountEncoding() {
- PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
+ PolicySet p1 =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
Account a = new Account();
final String SYNC_KEY = "test_sync_key";
p1.writeAccount(a, SYNC_KEY, false, null);
@@ -392,9 +429,12 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
*/
@SmallTest
public void testEquals() {
- 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, false);
- PolicySet p3 = new PolicySet(2, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false);
+ PolicySet p1 =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
+ PolicySet p2 =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
+ PolicySet p3 =
+ new PolicySet(2, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false, false);
assertTrue(p1.equals(p2));
assertFalse(p2.equals(p3));
}
@@ -444,12 +484,12 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
public void testDisableAdmin() {
Account a1 = ProviderTestUtils.setupAccount("disable-1", false, mMockContext);
PolicySet p1 = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
- false);
+ false, false);
p1.writeAccount(a1, "sync-key-1", true, mMockContext);
Account a2 = ProviderTestUtils.setupAccount("disable-2", false, mMockContext);
PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
- false);
+ false, false);
p2.writeAccount(a2, "sync-key-2", true, mMockContext);
Account a3 = ProviderTestUtils.setupAccount("disable-3", false, mMockContext);
@@ -494,42 +534,40 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
* Test the scanner that finds expiring accounts
*/
public void testFindExpiringAccount() {
- SecurityPolicy sp = getSecurityPolicy();
-
Account a1 = ProviderTestUtils.setupAccount("expiring-1", true, mMockContext);
// With no expiring accounts, this should return null.
- long nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
+ long nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
assertEquals(-1, nextExpiringAccountId);
// Add a single expiring account
Account a2 = ProviderTestUtils.setupAccount("expiring-2", false, mMockContext);
PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
- false);
+ false, false);
p2.writeAccount(a2, "sync-key-2", true, mMockContext);
// The expiring account should be returned
- nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
+ nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
assertEquals(a2.mId, nextExpiringAccountId);
// Add an account with a longer expiration
Account a3 = ProviderTestUtils.setupAccount("expiring-3", false, mMockContext);
PolicySet p3 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0,
- false);
+ false, false);
p3.writeAccount(a3, "sync-key-3", true, mMockContext);
// The original expiring account (a2) should be returned
- nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
+ nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
assertEquals(a2.mId, nextExpiringAccountId);
// Add an account with a shorter expiration
Account a4 = ProviderTestUtils.setupAccount("expiring-4", false, mMockContext);
PolicySet p4 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0,
- false);
+ false, false);
p4.writeAccount(a4, "sync-key-4", true, mMockContext);
// The new expiring account (a4) should be returned
- nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
+ nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
assertEquals(a4.mId, nextExpiringAccountId);
}
@@ -555,7 +593,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
Account a1 = ProviderTestUtils.setupAccount("expired-1", true, mMockContext);
Account a2 = ProviderTestUtils.setupAccount("expired-2", false, mMockContext);
PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
- false);
+ false, false);
p2.writeAccount(a2, "sync-key-2", true, mMockContext);
// Add a mailbox & messages to each account
@@ -581,7 +619,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
// Add 3rd account that really expires
Account a3 = ProviderTestUtils.setupAccount("expired-3", false, mMockContext);
PolicySet p3 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
- false);
+ false, false);
p3.writeAccount(a3, "sync-key-3", true, mMockContext);
// Add mailbox & messages to 3rd account
@@ -618,8 +656,12 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
* 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);
+ PolicySet p1 =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
+ PolicySet p2 =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true, false);
+ PolicySet p3 =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, true);
SecurityPolicy sp = getSecurityPolicy();
DevicePolicyManager dpm = sp.getDPM();
@@ -628,16 +670,22 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
PolicySet p1Result = sp.clearUnsupportedPolicies(p1);
PolicySet p2Result = sp.clearUnsupportedPolicies(p2);
+ PolicySet p3Result = sp.clearUnsupportedPolicies(p3);
- // No changes expected when encryptionRequested was false
+ // No changes expected when encryptionRequested bits were false
assertEquals(p1, p1Result);
if (hasEncryption) {
// No changes expected
+ // NOTE: TODO: Modify to check for external encryption cleared on devices that
+ // won't support it (e.g. having only unencrypted, removable storage.)
assertEquals(p2, p2Result);
+ assertEquals(p3, p3Result);
} else {
- PolicySet p2Expect =
- new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
- assertEquals(p2Expect, p2Result);
+ // If encryption is unsupported, encryption policy bits are cleared
+ PolicySet policyExpect =
+ new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
+ assertEquals(policyExpect, p2Result);
+ assertEquals(policyExpect, p3Result);
}
}
}