blob: ed264859ad5d55e0965c8b6ca070e5f24c1f24b1 [file] [log] [blame]
Andrew Stadler345fb8b2010-01-26 17:24:15 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email;
18
Ben Komalo505ac4b2011-06-21 18:16:26 -070019import android.app.admin.DevicePolicyManager;
20import android.content.Context;
21import android.content.ContextWrapper;
22import android.test.ProviderTestCase2;
23import android.test.suitebuilder.annotation.MediumTest;
24import android.test.suitebuilder.annotation.SmallTest;
25
Andy Stadler1ca111c2010-12-01 12:58:36 -080026import com.android.email.provider.ContentCache;
Marc Blank9ba506c2011-02-08 18:54:56 -080027import com.android.email.provider.EmailProvider;
28import com.android.email.provider.ProviderTestUtils;
Marc Blankf5418f12011-06-13 15:32:27 -070029import com.android.emailcommon.provider.Account;
Marc Blanka7bc0312011-02-10 10:26:56 -080030import com.android.emailcommon.provider.EmailContent;
Marc Blanka7bc0312011-02-10 10:26:56 -080031import com.android.emailcommon.provider.EmailContent.Message;
Ben Komalo53ea83e2011-05-13 17:26:27 -070032import com.android.emailcommon.provider.Mailbox;
Marc Blankaeee10e2011-04-27 17:12:06 -070033import com.android.emailcommon.provider.Policy;
34import com.android.emailcommon.service.LegacyPolicySet;
Andrew Stadler345fb8b2010-01-26 17:24:15 -080035
Andrew Stadler345fb8b2010-01-26 17:24:15 -080036/**
37 * This is a series of unit tests for backup/restore of the SecurityPolicy class.
Marc Blank2b2b3442010-08-02 13:47:23 -070038 *
Marc Blank9b4988d2010-06-09 16:18:57 -070039 * You can run this entire test case with:
40 * runtest -c com.android.email.SecurityPolicyTests email
Andrew Stadler345fb8b2010-01-26 17:24:15 -080041 */
Marc Blank9b4988d2010-06-09 16:18:57 -070042
Andrew Stadler345fb8b2010-01-26 17:24:15 -080043@MediumTest
44public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
45
46 private Context mMockContext;
Marc Blankaeee10e2011-04-27 17:12:06 -070047 private SecurityPolicy mSecurityPolicy;
Andrew Stadlerd6286082010-02-01 16:48:16 -080048
Andrew Stadler345fb8b2010-01-26 17:24:15 -080049 public SecurityPolicyTests() {
Marc Blank31d9acb2011-02-11 15:05:17 -080050 super(EmailProvider.class, EmailContent.AUTHORITY);
Andrew Stadler345fb8b2010-01-26 17:24:15 -080051 }
52
Marc Blankaeee10e2011-04-27 17:12:06 -070053 private static final Policy EMPTY_POLICY = new Policy();
54
Andrew Stadler345fb8b2010-01-26 17:24:15 -080055 @Override
56 protected void setUp() throws Exception {
57 super.setUp();
Marc Blankaeee10e2011-04-27 17:12:06 -070058 mMockContext = new MockContext2(getMockContext(), mContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -080059 // Invalidate all caches, since we reset the database for each test
Marc Blank6e418aa2011-06-18 18:03:11 -070060 ContentCache.invalidateAllCaches();
Ben Komalocb1d65c2011-07-25 16:04:07 -070061 Controller.getInstance(mMockContext).markForTest(true);
Andrew Stadler345fb8b2010-01-26 17:24:15 -080062 }
63
64 /**
65 * Delete any dummy accounts we set up for this test
66 */
67 @Override
68 protected void tearDown() throws Exception {
Ben Komalocb1d65c2011-07-25 16:04:07 -070069 Controller.getInstance(mMockContext).markForTest(false);
Andrew Stadler345fb8b2010-01-26 17:24:15 -080070 super.tearDown();
71 }
72
73 /**
Makoto Onuki0fb092b2010-06-04 15:26:11 -070074 * Private context wrapper used to add back getPackageName() for these tests.
75 *
Andy Stadlera0d08052011-01-19 11:40:48 -080076 * This class also implements {@link Context} method(s) that are called during tests.
Andrew Stadlerd6286082010-02-01 16:48:16 -080077 */
78 private static class MockContext2 extends ContextWrapper {
79
80 private final Context mRealContext;
81
82 public MockContext2(Context mockContext, Context realContext) {
83 super(mockContext);
84 mRealContext = realContext;
85 }
86
87 @Override
Makoto Onuki0fb092b2010-06-04 15:26:11 -070088 public Context getApplicationContext() {
89 return this;
90 }
91
92 @Override
Andrew Stadlerd6286082010-02-01 16:48:16 -080093 public String getPackageName() {
94 return mRealContext.getPackageName();
95 }
Andy Stadlera0d08052011-01-19 11:40:48 -080096
97 @Override
98 public Object getSystemService(String name) {
99 return mRealContext.getSystemService(name);
100 }
Andrew Stadlerd6286082010-02-01 16:48:16 -0800101 }
102
103 /**
Marc Blankaeee10e2011-04-27 17:12:06 -0700104 * Create a Policy using the arguments formerly used to create a PolicySet; this minimizes the
105 * changes needed for re-using the PolicySet unit test logic
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800106 */
Marc Blankaeee10e2011-04-27 17:12:06 -0700107 private Policy setupPolicy(int minPasswordLength, int passwordMode, int maxPasswordFails,
108 int maxScreenLockTime, boolean requireRemoteWipe, int passwordExpirationDays,
109 int passwordHistory, int passwordComplexChars, boolean requireEncryption,
Ben Komaloe76962b2011-07-01 12:34:03 -0700110 boolean dontAllowCamera)
Ben Komalod09cff02011-05-06 14:57:47 -0700111 throws IllegalArgumentException {
Marc Blankaeee10e2011-04-27 17:12:06 -0700112 Policy policy = new Policy();
113 policy.mPasswordMinLength = minPasswordLength;
114 policy.mPasswordMode = passwordMode;
115 policy.mPasswordMaxFails = maxPasswordFails;
116 policy.mMaxScreenLockTime = maxScreenLockTime;
117 policy.mRequireRemoteWipe = requireRemoteWipe;
118 policy.mPasswordExpirationDays = passwordExpirationDays;
119 policy.mPasswordHistory = passwordHistory;
120 policy.mPasswordComplexChars = passwordComplexChars;
121 policy.mRequireEncryption = requireEncryption;
Ben Komalod09cff02011-05-06 14:57:47 -0700122 policy.mDontAllowCamera = dontAllowCamera;
Marc Blankaeee10e2011-04-27 17:12:06 -0700123 return policy;
Marc Blank1d6dab22010-06-14 12:24:02 -0700124 }
125
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800126 /**
127 * Test business logic of aggregating accounts with policies
128 */
129 public void testAggregator() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700130 mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800131
Andrew Stadlerd6286082010-02-01 16:48:16 -0800132 // with no accounts, should return empty set
Marc Blankaeee10e2011-04-27 17:12:06 -0700133 assertEquals(EMPTY_POLICY, mSecurityPolicy.computeAggregatePolicy());
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800134
Andrew Stadlerd6286082010-02-01 16:48:16 -0800135 // with accounts having no security, empty set
Marc Blankaeee10e2011-04-27 17:12:06 -0700136 ProviderTestUtils.setupAccount("no-sec-1", true, mMockContext);
137 ProviderTestUtils.setupAccount("no-sec-2", true, mMockContext);
138 assertEquals(EMPTY_POLICY, mSecurityPolicy.computeAggregatePolicy());
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800139
140 // with a single account in security mode, should return same security as in account
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800141 // first test with partially-populated policies
Marc Blankaeee10e2011-04-27 17:12:06 -0700142 Account a3 = ProviderTestUtils.setupAccount("sec-3", true, mMockContext);
143 Policy p3ain = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700144 false, false);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700145 Policy.setAccountPolicy(mMockContext, a3, p3ain, null);
Marc Blankaeee10e2011-04-27 17:12:06 -0700146 Policy p3aout = mSecurityPolicy.computeAggregatePolicy();
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800147 assertNotNull(p3aout);
148 assertEquals(p3ain, p3aout);
149
150 // Repeat that test with fully-populated policies
Marc Blankaeee10e2011-04-27 17:12:06 -0700151 Policy p3bin = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3,
Ben Komaloe76962b2011-07-01 12:34:03 -0700152 false, false);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700153 Policy.setAccountPolicy(mMockContext, a3, p3bin, null);
Marc Blankaeee10e2011-04-27 17:12:06 -0700154 Policy p3bout = mSecurityPolicy.computeAggregatePolicy();
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800155 assertNotNull(p3bout);
156 assertEquals(p3bin, p3bout);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800157
158 // add another account which mixes it up (some fields will change, others will not)
159 // pw length and pw mode - max logic - will change because larger #s here
160 // fail count and lock timer - min logic - will *not* change because larger #s here
161 // wipe required - OR logic - will *not* change here because false
Andy Stadler1ca111c2010-12-01 12:58:36 -0800162 // expiration - will not change because 0 (unspecified)
163 // max complex chars - max logic - will change
Andy Stadler469f2982011-01-13 13:12:55 -0800164 // encryption required - OR logic - will *not* change here because false
Ben Komalod09cff02011-05-06 14:57:47 -0700165 // don't allow camera - OR logic - will change here because it's true
Marc Blankaeee10e2011-04-27 17:12:06 -0700166 Policy p4in = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7,
Ben Komaloe76962b2011-07-01 12:34:03 -0700167 false, true);
Marc Blankaeee10e2011-04-27 17:12:06 -0700168 Account a4 = ProviderTestUtils.setupAccount("sec-4", true, mMockContext);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700169 Policy.setAccountPolicy(mMockContext, a4, p4in, null);
Marc Blankaeee10e2011-04-27 17:12:06 -0700170 Policy p4out = mSecurityPolicy.computeAggregatePolicy();
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800171 assertNotNull(p4out);
Marc Blankaeee10e2011-04-27 17:12:06 -0700172 assertEquals(20, p4out.mPasswordMinLength);
173 assertEquals(Policy.PASSWORD_MODE_STRONG, p4out.mPasswordMode);
174 assertEquals(15, p4out.mPasswordMaxFails);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800175 assertEquals(16, p4out.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800176 assertEquals(6, p4out.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700177 assertEquals(5, p4out.mPasswordHistory);
178 assertEquals(7, p4out.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800179 assertFalse(p4out.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800180 assertFalse(p4out.mRequireEncryption);
Andy Stadler7fd14be2011-03-02 16:41:05 -0800181 assertFalse(p4out.mRequireEncryptionExternal);
Ben Komalod09cff02011-05-06 14:57:47 -0700182 assertTrue(p4out.mDontAllowCamera);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800183
184 // add another account which mixes it up (the remaining fields will change)
185 // pw length and pw mode - max logic - will *not* change because smaller #s here
186 // fail count and lock timer - min logic - will change because smaller #s here
187 // wipe required - OR logic - will change here because true
Andy Stadler1ca111c2010-12-01 12:58:36 -0800188 // expiration time - min logic - will change because lower here
189 // history & complex chars - will not change because 0 (unspecified)
Andy Stadler469f2982011-01-13 13:12:55 -0800190 // encryption required - OR logic - will change here because true
Ben Komalod09cff02011-05-06 14:57:47 -0700191 // don't allow camera - OR logic - will *not* change here because it's already true
Marc Blankaeee10e2011-04-27 17:12:06 -0700192 Policy p5in = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700193 true, false);
Marc Blankaeee10e2011-04-27 17:12:06 -0700194 Account a5 = ProviderTestUtils.setupAccount("sec-5", true, mMockContext);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700195 Policy.setAccountPolicy(mMockContext, a5, p5in, null);
Marc Blankaeee10e2011-04-27 17:12:06 -0700196 Policy p5out = mSecurityPolicy.computeAggregatePolicy();
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800197 assertNotNull(p5out);
Marc Blankaeee10e2011-04-27 17:12:06 -0700198 assertEquals(20, p5out.mPasswordMinLength);
199 assertEquals(Policy.PASSWORD_MODE_STRONG, p5out.mPasswordMode);
200 assertEquals(5, p5out.mPasswordMaxFails);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800201 assertEquals(6, p5out.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800202 assertEquals(1, p5out.mPasswordExpirationDays);
Andy Stadler469f2982011-01-13 13:12:55 -0800203 assertEquals(5, p5out.mPasswordHistory);
204 assertEquals(7, p5out.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800205 assertTrue(p5out.mRequireRemoteWipe);
Andy Stadler7fd14be2011-03-02 16:41:05 -0800206 assertFalse(p5out.mRequireEncryptionExternal);
Ben Komalod09cff02011-05-06 14:57:47 -0700207 assertTrue(p5out.mDontAllowCamera);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800208 }
209
Ben Komalo505ac4b2011-06-21 18:16:26 -0700210 private long assertAccountPolicyConsistent(long accountId, long oldKey) {
211 Account account = Account.restoreAccountWithId(mMockContext, accountId);
212 long policyKey = account.mPolicyKey;
213
214 assertTrue(policyKey > 0);
215
216 // Found a policy. Ensure it matches.
217 Policy policy = Policy.restorePolicyWithId(mMockContext, policyKey);
218 assertNotNull(policy);
219 assertEquals(account.mPolicyKey, policy.mId);
220 assertEquals(
221 accountId,
222 Policy.getAccountIdWithPolicyKey(mMockContext, policy.mId));
223
224 // Assert the old one isn't there.
225 if (oldKey > 0) {
226 assertNull("old policy not cleaned up",
227 Policy.restorePolicyWithId(mMockContext, oldKey));
228 }
229
230 return policyKey;
231 }
232
233 @SmallTest
234 public void testSettingAccountPolicy() {
235 Account account = ProviderTestUtils.setupAccount("testaccount", true, mMockContext);
236 long accountId = account.mId;
237 Policy initial = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700238 false, false);
Ben Komalo505ac4b2011-06-21 18:16:26 -0700239 Policy.setAccountPolicy(mMockContext, accountId, initial, null);
240
241 long oldKey = assertAccountPolicyConsistent(account.mId, 0);
242
243 Policy updated = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700244 false, false);
Ben Komalo505ac4b2011-06-21 18:16:26 -0700245 Policy.setAccountPolicy(mMockContext, accountId, updated, null);
246 oldKey = assertAccountPolicyConsistent(account.mId, oldKey);
247
248 // Remove the policy
249 Policy.clearAccountPolicy(
250 mMockContext, Account.restoreAccountWithId(mMockContext, accountId));
251 assertNull("old policy not cleaned up",
252 Policy.restorePolicyWithId(mMockContext, oldKey));
253 }
254
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800255 /**
Marc Blank9b4988d2010-06-09 16:18:57 -0700256 * Test equality. Note, the tests for inequality are poor, as each field should
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800257 * be tested individually.
258 */
259 @SmallTest
Marc Blank9b4988d2010-06-09 16:18:57 -0700260 public void testEquals() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700261 Policy p1 =
Ben Komaloe76962b2011-07-01 12:34:03 -0700262 setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
Marc Blankaeee10e2011-04-27 17:12:06 -0700263 Policy p2 =
Ben Komaloe76962b2011-07-01 12:34:03 -0700264 setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
Marc Blankaeee10e2011-04-27 17:12:06 -0700265 Policy p3 =
Ben Komaloe76962b2011-07-01 12:34:03 -0700266 setupPolicy(2, Policy.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false, false);
Ben Komalod09cff02011-05-06 14:57:47 -0700267 Policy p4 =
Ben Komaloe76962b2011-07-01 12:34:03 -0700268 setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, true);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800269 assertTrue(p1.equals(p2));
270 assertFalse(p2.equals(p3));
Ben Komalod09cff02011-05-06 14:57:47 -0700271 assertFalse(p1.equals(p4));
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800272 }
273
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800274 /**
275 * Test the API to set/clear policy hold flags in an account
276 */
277 public void testSetClearHoldFlag() {
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800278 Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext);
279 a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL;
280 a1.save(mMockContext);
281 Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700282 a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD;
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800283 a2.save(mMockContext);
284
285 // confirm clear until set
286 Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
287 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL, a1a.mFlags);
Marc Blankaeee10e2011-04-27 17:12:06 -0700288 SecurityPolicy.setAccountHoldFlag(mMockContext, a1, true);
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800289 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1.mFlags);
290 Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
291 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1b.mFlags);
292
293 // confirm set until cleared
294 Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700295 assertEquals(Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD, a2a.mFlags);
Marc Blankaeee10e2011-04-27 17:12:06 -0700296 SecurityPolicy.setAccountHoldFlag(mMockContext, a2, false);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700297 assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2.mFlags);
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800298 Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700299 assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2b.mFlags);
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800300 }
301
302 /**
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800303 * Test the response to disabling DeviceAdmin status
304 */
305 public void testDisableAdmin() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700306 Account a1 = ProviderTestUtils.setupAccount("disable-1", true, mMockContext);
307 Policy p1 = setupPolicy(10, Policy.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700308 false, false);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700309 Policy.setAccountPolicy(mMockContext, a1, p1, "security-sync-key-1");
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800310
Marc Blankaeee10e2011-04-27 17:12:06 -0700311 Account a2 = ProviderTestUtils.setupAccount("disable-2", true, mMockContext);
312 Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700313 false, false);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700314 Policy.setAccountPolicy(mMockContext, a2, p2, "security-sync-key-2");
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800315
Marc Blankaeee10e2011-04-27 17:12:06 -0700316 Account a3 = ProviderTestUtils.setupAccount("disable-3", true, mMockContext);
317 Policy.clearAccountPolicy(mMockContext, a3);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800318
Marc Blankaeee10e2011-04-27 17:12:06 -0700319 mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800320
Marc Blankaeee10e2011-04-27 17:12:06 -0700321 // Confirm that "enabling" device admin does not change security status (policy & sync key)
322 Policy before = mSecurityPolicy.getAggregatePolicy();
323 mSecurityPolicy.onAdminEnabled(true); // "enabled" should not change anything
324 Policy after1 = mSecurityPolicy.getAggregatePolicy();
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800325 assertEquals(before, after1);
326 Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
327 assertNotNull(a1a.mSecuritySyncKey);
Marc Blankaeee10e2011-04-27 17:12:06 -0700328 assertTrue(a1a.mPolicyKey > 0);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800329 Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
330 assertNotNull(a2a.mSecuritySyncKey);
Marc Blankaeee10e2011-04-27 17:12:06 -0700331 assertTrue(a2a.mPolicyKey > 0);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800332 Account a3a = Account.restoreAccountWithId(mMockContext, a3.mId);
333 assertNull(a3a.mSecuritySyncKey);
Marc Blankaeee10e2011-04-27 17:12:06 -0700334 assertTrue(a3a.mPolicyKey == 0);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800335
Marc Blank4e4aba92011-07-18 17:33:38 -0700336 mSecurityPolicy.deleteSecuredAccounts(mMockContext);
337 Policy after2 = mSecurityPolicy.getAggregatePolicy();
338 assertEquals(EMPTY_POLICY, after2);
339 Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
340 assertNull(a1b);
341 Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
342 assertNull(a2b);
343 Account a3b = Account.restoreAccountWithId(mMockContext, a3.mId);
344 assertNull(a3b.mSecuritySyncKey);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800345 }
346
347 /**
348 * Test the scanner that finds expiring accounts
349 */
350 public void testFindExpiringAccount() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700351 ProviderTestUtils.setupAccount("expiring-1", true, mMockContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800352
353 // With no expiring accounts, this should return null.
Andy Stadler7fd14be2011-03-02 16:41:05 -0800354 long nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800355 assertEquals(-1, nextExpiringAccountId);
356
357 // Add a single expiring account
Marc Blankaeee10e2011-04-27 17:12:06 -0700358 Account a2 =
359 ProviderTestUtils.setupAccount("expiring-2", true, mMockContext);
360 Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700361 false, true);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700362 Policy.setAccountPolicy(mMockContext, a2, p2, null);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800363
364 // The expiring account should be returned
Andy Stadler7fd14be2011-03-02 16:41:05 -0800365 nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800366 assertEquals(a2.mId, nextExpiringAccountId);
367
368 // Add an account with a longer expiration
Marc Blankaeee10e2011-04-27 17:12:06 -0700369 Account a3 = ProviderTestUtils.setupAccount("expiring-3", true, mMockContext);
370 Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700371 false, true);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700372 Policy.setAccountPolicy(mMockContext, a3, p3, null);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800373
374 // The original expiring account (a2) should be returned
Andy Stadler7fd14be2011-03-02 16:41:05 -0800375 nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800376 assertEquals(a2.mId, nextExpiringAccountId);
377
378 // Add an account with a shorter expiration
Marc Blankaeee10e2011-04-27 17:12:06 -0700379 Account a4 = ProviderTestUtils.setupAccount("expiring-4", true, mMockContext);
380 Policy p4 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700381 false, true);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700382 Policy.setAccountPolicy(mMockContext, a4, p4, null);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800383
384 // The new expiring account (a4) should be returned
Andy Stadler7fd14be2011-03-02 16:41:05 -0800385 nextExpiringAccountId = SecurityPolicy.findShortestExpiration(mMockContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800386 assertEquals(a4.mId, nextExpiringAccountId);
387 }
388
389 /**
390 * Lightweight subclass of the Controller class allows injection of mock context
391 */
392 public static class TestController extends Controller {
Andy Stadler1ca111c2010-12-01 12:58:36 -0800393 protected TestController(Context providerContext, Context systemContext) {
394 super(systemContext);
395 setProviderContext(providerContext);
Ben Komalocb1d65c2011-07-25 16:04:07 -0700396 markForTest(true);
Marc Blank02d59d22010-10-25 11:49:29 -0700397 }
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800398 }
Andy Stadler1ca111c2010-12-01 12:58:36 -0800399
400 /**
401 * Test the scanner that wipes expiring accounts
402 */
403 public void testWipeExpiringAccounts() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700404 mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800405 TestController testController = new TestController(mMockContext, getContext());
406
407 // Two accounts - a1 is normal, a2 has security (but no expiration)
408 Account a1 = ProviderTestUtils.setupAccount("expired-1", true, mMockContext);
Marc Blankaeee10e2011-04-27 17:12:06 -0700409 Account a2 = ProviderTestUtils.setupAccount("expired-2", true, mMockContext);
410 Policy p2 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700411 false, true);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700412 Policy.setAccountPolicy(mMockContext, a2, p2, null);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800413
414 // Add a mailbox & messages to each account
415 long account1Id = a1.mId;
416 long account2Id = a2.mId;
417 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
418 long box1Id = box1.mId;
419 ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mMockContext);
420 ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, true, mMockContext);
421 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account2Id, true, mMockContext);
422 long box2Id = box2.mId;
423 ProviderTestUtils.setupMessage("message3", account2Id, box2Id, false, true, mMockContext);
424 ProviderTestUtils.setupMessage("message4", account2Id, box2Id, false, true, mMockContext);
425
426 // Run the expiration code - should do nothing
Marc Blankaeee10e2011-04-27 17:12:06 -0700427 boolean wiped = SecurityPolicy.wipeExpiredAccounts(mMockContext, testController);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800428 assertFalse(wiped);
429 // check mailboxes & messages not wiped
430 assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI));
431 assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
432 assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
433
434 // Add 3rd account that really expires
Marc Blankaeee10e2011-04-27 17:12:06 -0700435 Account a3 = ProviderTestUtils.setupAccount("expired-3", true, mMockContext);
436 Policy p3 = setupPolicy(20, Policy.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
Ben Komaloe76962b2011-07-01 12:34:03 -0700437 false, true);
Marc Blankfae5ebb2011-05-25 15:04:53 -0700438 Policy.setAccountPolicy(mMockContext, a3, p3, null);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800439
440 // Add mailbox & messages to 3rd account
441 long account3Id = a3.mId;
442 Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account3Id, true, mMockContext);
443 long box3Id = box3.mId;
444 ProviderTestUtils.setupMessage("message5", account3Id, box3Id, false, true, mMockContext);
445 ProviderTestUtils.setupMessage("message6", account3Id, box3Id, false, true, mMockContext);
446
447 // check new counts
448 assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
449 assertEquals(3, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
450 assertEquals(6, EmailContent.count(mMockContext, Message.CONTENT_URI));
451
452 // Run the expiration code - wipe acct #3
Marc Blankaeee10e2011-04-27 17:12:06 -0700453 wiped = SecurityPolicy.wipeExpiredAccounts(mMockContext, testController);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800454 assertTrue(wiped);
455 // check new counts - account survives but data is wiped
456 assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
457 assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
458 assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
459
460 // Check security hold states - only #3 should be in hold
461 Account account = Account.restoreAccountWithId(mMockContext, account1Id);
462 assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
463 account = Account.restoreAccountWithId(mMockContext, account2Id);
464 assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
465 account = Account.restoreAccountWithId(mMockContext, account3Id);
466 assertEquals(Account.FLAGS_SECURITY_HOLD, account.mFlags & Account.FLAGS_SECURITY_HOLD);
467 }
Andy Stadlera0d08052011-01-19 11:40:48 -0800468
469 /**
470 * Test the code that clears unsupported policies
471 * TODO inject a mock DPM so we can directly control & test all cases, no matter what device
472 */
473 public void testClearUnsupportedPolicies() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700474 Policy p1 =
Ben Komaloe76962b2011-07-01 12:34:03 -0700475 setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false, false);
Marc Blankaeee10e2011-04-27 17:12:06 -0700476 Policy p2 =
Ben Komaloe76962b2011-07-01 12:34:03 -0700477 setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true, false);
Andy Stadlera0d08052011-01-19 11:40:48 -0800478
Marc Blankaeee10e2011-04-27 17:12:06 -0700479 mSecurityPolicy = SecurityPolicy.getInstance(mMockContext);
480 DevicePolicyManager dpm = mSecurityPolicy.getDPM();
Andy Stadlera0d08052011-01-19 11:40:48 -0800481 boolean hasEncryption =
482 dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
483
Marc Blankaeee10e2011-04-27 17:12:06 -0700484 Policy p1Result = mSecurityPolicy.clearUnsupportedPolicies(p1);
485 Policy p2Result = mSecurityPolicy.clearUnsupportedPolicies(p2);
Andy Stadlera0d08052011-01-19 11:40:48 -0800486
Ben Komaloe76962b2011-07-01 12:34:03 -0700487 // No changes expected when encryptionRequested was false
Andy Stadlera0d08052011-01-19 11:40:48 -0800488 assertEquals(p1, p1Result);
489 if (hasEncryption) {
490 // No changes expected
491 assertEquals(p2, p2Result);
492 } else {
Andy Stadler7fd14be2011-03-02 16:41:05 -0800493 // If encryption is unsupported, encryption policy bits are cleared
Marc Blankaeee10e2011-04-27 17:12:06 -0700494 Policy policyExpect =
495 setupPolicy(1, Policy.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false,
Ben Komaloe76962b2011-07-01 12:34:03 -0700496 false);
Andy Stadler7fd14be2011-03-02 16:41:05 -0800497 assertEquals(policyExpect, p2Result);
Andy Stadlera0d08052011-01-19 11:40:48 -0800498 }
499 }
Andy Stadler22759ba2011-03-16 09:48:08 -0700500
501 /**
502 * Test the code that converts from exchange-style quality to DPM/Lockscreen style quality.
503 */
504 public void testGetDPManagerPasswordQuality() {
Marc Blankaeee10e2011-04-27 17:12:06 -0700505 // Policy.PASSWORD_MODE_NONE -> DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
506 Policy p1 = setupPolicy(0, Policy.PASSWORD_MODE_NONE,
Ben Komaloe76962b2011-07-01 12:34:03 -0700507 0, 0, false, 0, 0, 0, false, false);
Andy Stadler22759ba2011-03-16 09:48:08 -0700508 assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
509 p1.getDPManagerPasswordQuality());
510
511 // PASSWORD_MODE_SIMPLE -> PASSWORD_QUALITY_NUMERIC
Marc Blankaeee10e2011-04-27 17:12:06 -0700512 Policy p2 = setupPolicy(4, Policy.PASSWORD_MODE_SIMPLE,
Ben Komaloe76962b2011-07-01 12:34:03 -0700513 0, 0, false, 0, 0, 0, false, false);
Andy Stadler22759ba2011-03-16 09:48:08 -0700514 assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
515 p2.getDPManagerPasswordQuality());
516
517 // PASSWORD_MODE_STRONG -> PASSWORD_QUALITY_ALPHANUMERIC
Marc Blankaeee10e2011-04-27 17:12:06 -0700518 Policy p3 = setupPolicy(4, Policy.PASSWORD_MODE_STRONG,
Ben Komaloe76962b2011-07-01 12:34:03 -0700519 0, 0, false, 0, 0, 0, false, false);
Andy Stadler22759ba2011-03-16 09:48:08 -0700520 assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
521 p3.getDPManagerPasswordQuality());
522
523 // PASSWORD_MODE_STRONG + complex chars -> PASSWORD_QUALITY_COMPLEX
Marc Blankaeee10e2011-04-27 17:12:06 -0700524 Policy p4 = setupPolicy(4, Policy.PASSWORD_MODE_STRONG,
Ben Komaloe76962b2011-07-01 12:34:03 -0700525 0, 0, false, 0, 0 , 2, false, false);
Andy Stadler22759ba2011-03-16 09:48:08 -0700526 assertEquals(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX,
527 p4.getDPManagerPasswordQuality());
528 }
Marc Blankaeee10e2011-04-27 17:12:06 -0700529
530 private boolean policySetEqualsPolicy(PolicySet ps, Policy policy) {
531 if ((ps.mPasswordMode >> LegacyPolicySet.PASSWORD_MODE_SHIFT) != policy.mPasswordMode) {
532 return false;
533 }
534 if (ps.mMinPasswordLength != policy.mPasswordMinLength) return false;
535 if (ps.mPasswordComplexChars != policy.mPasswordComplexChars) return false;
536 if (ps.mPasswordHistory != policy.mPasswordHistory) return false;
537 if (ps.mPasswordExpirationDays != policy.mPasswordExpirationDays) return false;
538 if (ps.mMaxPasswordFails != policy.mPasswordMaxFails) return false;
539 if (ps.mMaxScreenLockTime != policy.mMaxScreenLockTime) return false;
540 if (ps.mRequireRemoteWipe != policy.mRequireRemoteWipe) return false;
541 if (ps.mRequireEncryption != policy.mRequireEncryption) return false;
542 if (ps.mRequireEncryptionExternal != policy.mRequireEncryptionExternal) return false;
543 return true;
544 }
545
546 public void testPolicyFlagsToPolicy() {
547 // Policy flags; the three sets included here correspond to policies for three test
548 // accounts that, between them, use all of the possible policies
549 long flags = 67096612L;
550 PolicySet ps = new PolicySet(flags);
551 Policy policy = LegacyPolicySet.flagsToPolicy(flags);
552 assertTrue(policySetEqualsPolicy(ps, policy));
553 flags = 52776591691846L;
554 ps = new PolicySet(flags);
555 policy = LegacyPolicySet.flagsToPolicy(flags);
556 assertTrue(policySetEqualsPolicy(ps, policy));
557 flags = 1689605957029924L;
558 ps = new PolicySet(flags);
559 policy = LegacyPolicySet.flagsToPolicy(flags);
560 assertTrue(policySetEqualsPolicy(ps, policy));
561 }
562
563 /**
564 * The old PolicySet class fields and constructor; we use this to test conversion to the
565 * new Policy table scheme
566 */
567 private static class PolicySet {
568 private final int mMinPasswordLength;
569 private final int mPasswordMode;
570 private final int mMaxPasswordFails;
571 private final int mMaxScreenLockTime;
572 private final boolean mRequireRemoteWipe;
573 private final int mPasswordExpirationDays;
574 private final int mPasswordHistory;
575 private final int mPasswordComplexChars;
576 private final boolean mRequireEncryption;
577 private final boolean mRequireEncryptionExternal;
578
579 /**
580 * Create from values encoded in an account flags int
581 */
582 private PolicySet(long flags) {
583 mMinPasswordLength = (int) ((flags & LegacyPolicySet.PASSWORD_LENGTH_MASK)
584 >> LegacyPolicySet.PASSWORD_LENGTH_SHIFT);
585 mPasswordMode =
586 (int) (flags & LegacyPolicySet.PASSWORD_MODE_MASK);
587 mMaxPasswordFails = (int) ((flags & LegacyPolicySet.PASSWORD_MAX_FAILS_MASK)
588 >> LegacyPolicySet.PASSWORD_MAX_FAILS_SHIFT);
589 mMaxScreenLockTime = (int) ((flags & LegacyPolicySet.SCREEN_LOCK_TIME_MASK)
590 >> LegacyPolicySet.SCREEN_LOCK_TIME_SHIFT);
591 mRequireRemoteWipe = 0 != (flags & LegacyPolicySet.REQUIRE_REMOTE_WIPE);
592 mPasswordExpirationDays = (int) ((flags & LegacyPolicySet.PASSWORD_EXPIRATION_MASK)
593 >> LegacyPolicySet.PASSWORD_EXPIRATION_SHIFT);
594 mPasswordHistory = (int) ((flags & LegacyPolicySet.PASSWORD_HISTORY_MASK)
595 >> LegacyPolicySet.PASSWORD_HISTORY_SHIFT);
596 mPasswordComplexChars = (int) ((flags & LegacyPolicySet.PASSWORD_COMPLEX_CHARS_MASK)
597 >> LegacyPolicySet.PASSWORD_COMPLEX_CHARS_SHIFT);
598 mRequireEncryption = 0 != (flags & LegacyPolicySet.REQUIRE_ENCRYPTION);
599 mRequireEncryptionExternal = 0 != (flags & LegacyPolicySet.REQUIRE_ENCRYPTION_EXTERNAL);
600 }
601 }
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800602}