blob: 5719f884d79aee5e178ed65e29af47030a9688cd [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
19import com.android.email.SecurityPolicy.PolicySet;
Andy Stadler1ca111c2010-12-01 12:58:36 -080020import com.android.email.provider.ContentCache;
21import com.android.email.provider.EmailContent;
Andrew Stadler345fb8b2010-01-26 17:24:15 -080022import com.android.email.provider.EmailContent.Account;
23import com.android.email.provider.EmailContent.AccountColumns;
Andy Stadler1ca111c2010-12-01 12:58:36 -080024import com.android.email.provider.EmailContent.Mailbox;
25import com.android.email.provider.EmailContent.Message;
Andy Stadlera0d08052011-01-19 11:40:48 -080026import com.android.email.provider.EmailProvider;
27import com.android.email.provider.ProviderTestUtils;
Andrew Stadler345fb8b2010-01-26 17:24:15 -080028
Andy Stadlera0d08052011-01-19 11:40:48 -080029import android.app.admin.DevicePolicyManager;
Andrew Stadler345fb8b2010-01-26 17:24:15 -080030import android.content.ContentUris;
31import android.content.ContentValues;
32import android.content.Context;
Andrew Stadlerd6286082010-02-01 16:48:16 -080033import android.content.ContextWrapper;
Andrew Stadler345fb8b2010-01-26 17:24:15 -080034import android.net.Uri;
35import android.test.ProviderTestCase2;
36import android.test.suitebuilder.annotation.MediumTest;
37import android.test.suitebuilder.annotation.SmallTest;
38
39/**
40 * This is a series of unit tests for backup/restore of the SecurityPolicy class.
Marc Blank2b2b3442010-08-02 13:47:23 -070041 *
Marc Blank9b4988d2010-06-09 16:18:57 -070042 * You can run this entire test case with:
43 * runtest -c com.android.email.SecurityPolicyTests email
Andrew Stadler345fb8b2010-01-26 17:24:15 -080044 */
Marc Blank9b4988d2010-06-09 16:18:57 -070045
Andrew Stadler345fb8b2010-01-26 17:24:15 -080046@MediumTest
47public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
48
49 private Context mMockContext;
50
Andrew Stadlerd6286082010-02-01 16:48:16 -080051 private static final PolicySet EMPTY_POLICY_SET =
Andy Stadler469f2982011-01-13 13:12:55 -080052 new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, false);
Andrew Stadlerd6286082010-02-01 16:48:16 -080053
Andrew Stadler345fb8b2010-01-26 17:24:15 -080054 public SecurityPolicyTests() {
55 super(EmailProvider.class, EmailProvider.EMAIL_AUTHORITY);
56 }
57
58 @Override
59 protected void setUp() throws Exception {
60 super.setUp();
Andrew Stadlerd6286082010-02-01 16:48:16 -080061 mMockContext = new MockContext2(getMockContext(), this.mContext);
Andy Stadler1ca111c2010-12-01 12:58:36 -080062 // Invalidate all caches, since we reset the database for each test
63 ContentCache.invalidateAllCachesForTest();
Andrew Stadler345fb8b2010-01-26 17:24:15 -080064 }
65
66 /**
67 * Delete any dummy accounts we set up for this test
68 */
69 @Override
70 protected void tearDown() throws Exception {
71 super.tearDown();
72 }
73
74 /**
Makoto Onuki0fb092b2010-06-04 15:26:11 -070075 * Private context wrapper used to add back getPackageName() for these tests.
76 *
Andy Stadlera0d08052011-01-19 11:40:48 -080077 * This class also implements {@link Context} method(s) that are called during tests.
Andrew Stadlerd6286082010-02-01 16:48:16 -080078 */
79 private static class MockContext2 extends ContextWrapper {
80
81 private final Context mRealContext;
82
83 public MockContext2(Context mockContext, Context realContext) {
84 super(mockContext);
85 mRealContext = realContext;
86 }
87
88 @Override
Makoto Onuki0fb092b2010-06-04 15:26:11 -070089 public Context getApplicationContext() {
90 return this;
91 }
92
93 @Override
Andrew Stadlerd6286082010-02-01 16:48:16 -080094 public String getPackageName() {
95 return mRealContext.getPackageName();
96 }
Andy Stadlera0d08052011-01-19 11:40:48 -080097
98 @Override
99 public Object getSystemService(String name) {
100 return mRealContext.getSystemService(name);
101 }
Andrew Stadlerd6286082010-02-01 16:48:16 -0800102 }
103
104 /**
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800105 * Retrieve the security policy object, and inject the mock context so it works as expected
106 */
107 private SecurityPolicy getSecurityPolicy() {
108 SecurityPolicy sp = SecurityPolicy.getInstance(mMockContext);
109 sp.setContext(mMockContext);
110 return sp;
111 }
112
Marc Blank1d6dab22010-06-14 12:24:02 -0700113 public void testPolicySetConstructor() {
114 // We know that EMPTY_POLICY_SET doesn't generate an Exception or we wouldn't be here
115 // Try some illegal parameters
116 try {
Andy Stadler469f2982011-01-13 13:12:55 -0800117 new PolicySet(100, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0, false);
Marc Blank1d6dab22010-06-14 12:24:02 -0700118 fail("Too-long password allowed");
119 } catch (IllegalArgumentException e) {
120 }
121 try {
Andy Stadler469f2982011-01-13 13:12:55 -0800122 new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG + 1, 0, 0, false, 0, 0, 0, false);
Marc Blank1d6dab22010-06-14 12:24:02 -0700123 fail("Illegal password mode allowed");
124 } catch (IllegalArgumentException e) {
125 }
Marc Blank61911d42010-08-27 18:01:21 -0700126
Marc Blankc2638102010-08-06 19:57:05 -0700127 PolicySet ps = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0,
Andy Stadler469f2982011-01-13 13:12:55 -0800128 PolicySet.SCREEN_LOCK_TIME_MAX + 1, false, 0, 0, 0, false);
Andy Stadler6278dcd2010-09-22 12:06:41 -0700129 assertEquals(PolicySet.SCREEN_LOCK_TIME_MAX, ps.getMaxScreenLockTimeForTest());
Marc Blank61911d42010-08-27 18:01:21 -0700130
Marc Blankc2638102010-08-06 19:57:05 -0700131 ps = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE,
Andy Stadler469f2982011-01-13 13:12:55 -0800132 PolicySet.PASSWORD_MAX_FAILS_MAX + 1, 0, false, 0, 0, 0, false);
Andy Stadler6278dcd2010-09-22 12:06:41 -0700133 assertEquals(PolicySet.PASSWORD_MAX_FAILS_MAX, ps.getMaxPasswordFailsForTest());
Marc Blankc2638102010-08-06 19:57:05 -0700134 // All password related fields should be zero when password mode is NONE
135 // Illegal values for these fields should be ignored
136 ps = new PolicySet(999/*length*/, PolicySet.PASSWORD_MODE_NONE,
137 999/*fails*/, 9999/*screenlock*/, false, 999/*expir*/, 999/*history*/,
Andy Stadler469f2982011-01-13 13:12:55 -0800138 999/*complex*/, false);
Marc Blankc2638102010-08-06 19:57:05 -0700139 assertEquals(0, ps.mMinPasswordLength);
140 assertEquals(0, ps.mMaxScreenLockTime);
141 assertEquals(0, ps.mMaxPasswordFails);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800142 assertEquals(0, ps.mPasswordExpirationDays);
Marc Blankc2638102010-08-06 19:57:05 -0700143 assertEquals(0, ps.mPasswordHistory);
144 assertEquals(0, ps.mPasswordComplexChars);
Marc Blank61911d42010-08-27 18:01:21 -0700145
146 // With a simple password, we should set complex chars to zero
147 ps = new PolicySet(4/*length*/, PolicySet.PASSWORD_MODE_SIMPLE,
Andy Stadler469f2982011-01-13 13:12:55 -0800148 0, 0, false, 0, 0, 3/*complex*/, false);
Marc Blank61911d42010-08-27 18:01:21 -0700149 assertEquals(4, ps.mMinPasswordLength);
150 assertEquals(0, ps.mPasswordComplexChars);
Marc Blank1d6dab22010-06-14 12:24:02 -0700151 }
152
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800153 /**
154 * Test business logic of aggregating accounts with policies
155 */
156 public void testAggregator() {
157 SecurityPolicy sp = getSecurityPolicy();
158
Andrew Stadlerd6286082010-02-01 16:48:16 -0800159 // with no accounts, should return empty set
Marc Blank9b4988d2010-06-09 16:18:57 -0700160 assertEquals(EMPTY_POLICY_SET, sp.computeAggregatePolicy());
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800161
Andrew Stadlerd6286082010-02-01 16:48:16 -0800162 // with accounts having no security, empty set
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800163 Account a1 = ProviderTestUtils.setupAccount("no-sec-1", false, mMockContext);
164 a1.mSecurityFlags = 0;
165 a1.save(mMockContext);
166 Account a2 = ProviderTestUtils.setupAccount("no-sec-2", false, mMockContext);
167 a2.mSecurityFlags = 0;
168 a2.save(mMockContext);
Marc Blank9b4988d2010-06-09 16:18:57 -0700169 assertEquals(EMPTY_POLICY_SET, sp.computeAggregatePolicy());
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800170
171 // with a single account in security mode, should return same security as in account
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800172 // first test with partially-populated policies
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800173 Account a3 = ProviderTestUtils.setupAccount("sec-3", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800174 PolicySet p3ain = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
175 false);
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800176 p3ain.writeAccount(a3, null, true, mMockContext);
177 PolicySet p3aout = sp.computeAggregatePolicy();
178 assertNotNull(p3aout);
179 assertEquals(p3ain, p3aout);
180
181 // Repeat that test with fully-populated policies
Andy Stadler469f2982011-01-13 13:12:55 -0800182 PolicySet p3bin = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 15, 16, false, 6, 2, 3,
183 false);
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800184 p3bin.writeAccount(a3, null, true, mMockContext);
185 PolicySet p3bout = sp.computeAggregatePolicy();
186 assertNotNull(p3bout);
187 assertEquals(p3bin, p3bout);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800188
189 // add another account which mixes it up (some fields will change, others will not)
190 // pw length and pw mode - max logic - will change because larger #s here
191 // fail count and lock timer - min logic - will *not* change because larger #s here
192 // wipe required - OR logic - will *not* change here because false
Andy Stadler1ca111c2010-12-01 12:58:36 -0800193 // expiration - will not change because 0 (unspecified)
194 // max complex chars - max logic - will change
Andy Stadler469f2982011-01-13 13:12:55 -0800195 // encryption required - OR logic - will *not* change here because false
196 PolicySet p4in = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 5, 7,
197 false);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800198 Account a4 = ProviderTestUtils.setupAccount("sec-4", false, mMockContext);
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800199 p4in.writeAccount(a4, null, true, mMockContext);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800200 PolicySet p4out = sp.computeAggregatePolicy();
201 assertNotNull(p4out);
202 assertEquals(20, p4out.mMinPasswordLength);
203 assertEquals(PolicySet.PASSWORD_MODE_STRONG, p4out.mPasswordMode);
204 assertEquals(15, p4out.mMaxPasswordFails);
205 assertEquals(16, p4out.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800206 assertEquals(6, p4out.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700207 assertEquals(5, p4out.mPasswordHistory);
208 assertEquals(7, p4out.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800209 assertFalse(p4out.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800210 assertFalse(p4out.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800211
212 // add another account which mixes it up (the remaining fields will change)
213 // pw length and pw mode - max logic - will *not* change because smaller #s here
214 // fail count and lock timer - min logic - will change because smaller #s here
215 // wipe required - OR logic - will change here because true
Andy Stadler1ca111c2010-12-01 12:58:36 -0800216 // expiration time - min logic - will change because lower here
217 // history & complex chars - will not change because 0 (unspecified)
Andy Stadler469f2982011-01-13 13:12:55 -0800218 // encryption required - OR logic - will change here because true
219 PolicySet p5in = new PolicySet(4, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 1, 0, 0,
220 true);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800221 Account a5 = ProviderTestUtils.setupAccount("sec-5", false, mMockContext);
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800222 p5in.writeAccount(a5, null, true, mMockContext);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800223 PolicySet p5out = sp.computeAggregatePolicy();
224 assertNotNull(p5out);
225 assertEquals(20, p5out.mMinPasswordLength);
226 assertEquals(PolicySet.PASSWORD_MODE_STRONG, p5out.mPasswordMode);
227 assertEquals(5, p5out.mMaxPasswordFails);
228 assertEquals(6, p5out.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800229 assertEquals(1, p5out.mPasswordExpirationDays);
Andy Stadler469f2982011-01-13 13:12:55 -0800230 assertEquals(5, p5out.mPasswordHistory);
231 assertEquals(7, p5out.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800232 assertTrue(p5out.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800233 assertTrue(p5out.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800234 }
235
236 /**
237 * Make sure aggregator (and any other direct DB accessors) handle the case of upgraded
238 * accounts properly (where the security flags will be NULL instead of zero).
239 */
240 public void testNullFlags() {
241 SecurityPolicy sp = getSecurityPolicy();
242
243 Account a1 = ProviderTestUtils.setupAccount("null-sec-1", true, mMockContext);
244 ContentValues cv = new ContentValues();
245 cv.putNull(AccountColumns.SECURITY_FLAGS);
246 Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, a1.mId);
247 mMockContext.getContentResolver().update(uri, cv, null, null);
248
249 Account a2 = ProviderTestUtils.setupAccount("no-sec-2", false, mMockContext);
250 a2.mSecurityFlags = 0;
251 a2.save(mMockContext);
Marc Blank9b4988d2010-06-09 16:18:57 -0700252 assertEquals(EMPTY_POLICY_SET, sp.computeAggregatePolicy());
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800253 }
254
255 /**
256 * Make sure the fields are encoded properly for their max ranges. This is looking
257 * for any encoding mask/shift errors, which would cause bits to overflow into other fields.
258 */
259 @SmallTest
Andrew Stadlera843d402010-04-02 22:05:12 -0700260 public void testFieldIsolation() {
Andy Stadler469f2982011-01-13 13:12:55 -0800261 // Check PASSWORD_LENGTH
Marc Blankc2638102010-08-06 19:57:05 -0700262 PolicySet p = new PolicySet(PolicySet.PASSWORD_LENGTH_MAX, PolicySet.PASSWORD_MODE_SIMPLE,
Andy Stadler469f2982011-01-13 13:12:55 -0800263 0, 0, false, 0, 0 ,0, false);
Marc Blankc2638102010-08-06 19:57:05 -0700264 assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800265 assertEquals(PolicySet.PASSWORD_LENGTH_MAX, p.mMinPasswordLength);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800266 assertEquals(0, p.mMaxPasswordFails);
267 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800268 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700269 assertEquals(0, p.mPasswordHistory);
270 assertEquals(0, p.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800271 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800272 assertFalse(p.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800273
Andy Stadler469f2982011-01-13 13:12:55 -0800274 // Check PASSWORD_MODE
275 p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0, 0, false);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800276 assertEquals(PolicySet.PASSWORD_MODE_STRONG, p.mPasswordMode);
Marc Blankc2638102010-08-06 19:57:05 -0700277 assertEquals(0, p.mMinPasswordLength);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800278 assertEquals(0, p.mMaxPasswordFails);
279 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800280 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700281 assertEquals(0, p.mPasswordHistory);
282 assertEquals(0, p.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800283 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800284 assertFalse(p.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800285
Andy Stadler469f2982011-01-13 13:12:55 -0800286 // Check PASSWORD_FAILS (note, mode must be set for this to be non-zero)
Marc Blankc2638102010-08-06 19:57:05 -0700287 p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, PolicySet.PASSWORD_MAX_FAILS_MAX, 0,
Andy Stadler469f2982011-01-13 13:12:55 -0800288 false, 0, 0, 0, false);
Marc Blankc2638102010-08-06 19:57:05 -0700289 assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800290 assertEquals(0, p.mMinPasswordLength);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800291 assertEquals(PolicySet.PASSWORD_MAX_FAILS_MAX, p.mMaxPasswordFails);
292 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800293 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700294 assertEquals(0, p.mPasswordHistory);
295 assertEquals(0, p.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800296 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800297 assertFalse(p.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800298
Andy Stadler469f2982011-01-13 13:12:55 -0800299 // Check SCREEN_LOCK_TIME (note, mode must be set for this to be non-zero)
Marc Blankc2638102010-08-06 19:57:05 -0700300 p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, PolicySet.SCREEN_LOCK_TIME_MAX,
Andy Stadler469f2982011-01-13 13:12:55 -0800301 false, 0, 0, 0, false);
Marc Blankc2638102010-08-06 19:57:05 -0700302 assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800303 assertEquals(0, p.mMinPasswordLength);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800304 assertEquals(0, p.mMaxPasswordFails);
305 assertEquals(PolicySet.SCREEN_LOCK_TIME_MAX, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800306 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700307 assertEquals(0, p.mPasswordHistory);
308 assertEquals(0, p.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800309 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800310 assertFalse(p.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800311
Andy Stadler469f2982011-01-13 13:12:55 -0800312 // Check REQUIRE_REMOTE_WIPE
313 p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, true, 0, 0, 0, false);
Marc Blankc2638102010-08-06 19:57:05 -0700314 assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800315 assertEquals(0, p.mMinPasswordLength);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800316 assertEquals(0, p.mMaxPasswordFails);
317 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800318 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700319 assertEquals(0, p.mPasswordHistory);
320 assertEquals(0, p.mPasswordComplexChars);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800321 assertTrue(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800322 assertFalse(p.mRequireEncryption);
Marc Blank9b4988d2010-06-09 16:18:57 -0700323
Andy Stadler469f2982011-01-13 13:12:55 -0800324 // Check PASSWORD_EXPIRATION (note, mode must be set for this to be non-zero)
Marc Blankc2638102010-08-06 19:57:05 -0700325 p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false,
Andy Stadler469f2982011-01-13 13:12:55 -0800326 PolicySet.PASSWORD_EXPIRATION_MAX, 0, 0, false);
Marc Blankc2638102010-08-06 19:57:05 -0700327 assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
Marc Blank9b4988d2010-06-09 16:18:57 -0700328 assertEquals(0, p.mMinPasswordLength);
Marc Blank9b4988d2010-06-09 16:18:57 -0700329 assertEquals(0, p.mMaxPasswordFails);
330 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800331 assertEquals(PolicySet.PASSWORD_EXPIRATION_MAX, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700332 assertEquals(0, p.mPasswordHistory);
333 assertEquals(0, p.mPasswordComplexChars);
334 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800335 assertFalse(p.mRequireEncryption);
Marc Blank9b4988d2010-06-09 16:18:57 -0700336
Andy Stadler469f2982011-01-13 13:12:55 -0800337 // Check PASSWORD_HISTORY (note, mode must be set for this to be non-zero)
Marc Blankc2638102010-08-06 19:57:05 -0700338 p = new PolicySet(0, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0,
Andy Stadler469f2982011-01-13 13:12:55 -0800339 PolicySet.PASSWORD_HISTORY_MAX, 0, false);
Marc Blankc2638102010-08-06 19:57:05 -0700340 assertEquals(PolicySet.PASSWORD_MODE_SIMPLE, p.mPasswordMode);
Marc Blank9b4988d2010-06-09 16:18:57 -0700341 assertEquals(0, p.mMinPasswordLength);
Marc Blank9b4988d2010-06-09 16:18:57 -0700342 assertEquals(0, p.mMaxPasswordFails);
343 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800344 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700345 assertEquals(PolicySet.PASSWORD_HISTORY_MAX, p.mPasswordHistory);
346 assertEquals(0, p.mPasswordComplexChars);
347 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800348 assertFalse(p.mRequireEncryption);
Marc Blank9b4988d2010-06-09 16:18:57 -0700349
Andy Stadler469f2982011-01-13 13:12:55 -0800350 // Check PASSWORD_COMPLEX_CHARS (note, mode must be set for this to be non-zero)
Marc Blank61911d42010-08-27 18:01:21 -0700351 p = new PolicySet(0, PolicySet.PASSWORD_MODE_STRONG, 0, 0, false, 0, 0,
Andy Stadler469f2982011-01-13 13:12:55 -0800352 PolicySet.PASSWORD_COMPLEX_CHARS_MAX, false);
Marc Blank61911d42010-08-27 18:01:21 -0700353 assertEquals(PolicySet.PASSWORD_MODE_STRONG, p.mPasswordMode);
Marc Blank9b4988d2010-06-09 16:18:57 -0700354 assertEquals(0, p.mMinPasswordLength);
Marc Blank9b4988d2010-06-09 16:18:57 -0700355 assertEquals(0, p.mMaxPasswordFails);
356 assertEquals(0, p.mMaxScreenLockTime);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800357 assertEquals(0, p.mPasswordExpirationDays);
Marc Blank9b4988d2010-06-09 16:18:57 -0700358 assertEquals(0, p.mPasswordHistory);
359 assertEquals(PolicySet.PASSWORD_COMPLEX_CHARS_MAX, p.mPasswordComplexChars);
360 assertFalse(p.mRequireRemoteWipe);
Andy Stadler469f2982011-01-13 13:12:55 -0800361 assertFalse(p.mRequireEncryption);
362
363 // Check REQUIRE_ENCRYPTION
364 p = new PolicySet(0, PolicySet.PASSWORD_MODE_NONE, 0, 0, false, 0, 0, 0, true);
365 assertEquals(PolicySet.PASSWORD_MODE_NONE, p.mPasswordMode);
366 assertEquals(0, p.mMinPasswordLength);
367 assertEquals(0, p.mMaxPasswordFails);
368 assertEquals(0, p.mMaxScreenLockTime);
369 assertEquals(0, p.mPasswordExpirationDays);
370 assertEquals(0, p.mPasswordHistory);
371 assertEquals(0, p.mPasswordComplexChars);
372 assertFalse(p.mRequireRemoteWipe);
373 assertTrue(p.mRequireEncryption);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800374 }
375
376 /**
377 * Test encoding into an Account and out again
378 */
379 @SmallTest
380 public void testAccountEncoding() {
Andy Stadler469f2982011-01-13 13:12:55 -0800381 PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800382 Account a = new Account();
383 final String SYNC_KEY = "test_sync_key";
Andrew Stadler3d2b3b32010-02-05 11:10:39 -0800384 p1.writeAccount(a, SYNC_KEY, false, null);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800385 PolicySet p2 = new PolicySet(a);
386 assertEquals(p1, p2);
387 }
388
389 /**
Marc Blank9b4988d2010-06-09 16:18:57 -0700390 * Test equality. Note, the tests for inequality are poor, as each field should
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800391 * be tested individually.
392 */
393 @SmallTest
Marc Blank9b4988d2010-06-09 16:18:57 -0700394 public void testEquals() {
Andy Stadler469f2982011-01-13 13:12:55 -0800395 PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
396 PolicySet p2 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
397 PolicySet p3 = new PolicySet(2, PolicySet.PASSWORD_MODE_SIMPLE, 5, 6, true, 7, 8, 9, false);
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800398 assertTrue(p1.equals(p2));
399 assertFalse(p2.equals(p3));
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800400 }
401
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800402 /**
403 * Test the API to set/clear policy hold flags in an account
404 */
405 public void testSetClearHoldFlag() {
406 SecurityPolicy sp = getSecurityPolicy();
407
408 Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext);
409 a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL;
410 a1.save(mMockContext);
411 Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700412 a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD;
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800413 a2.save(mMockContext);
414
415 // confirm clear until set
416 Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
417 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL, a1a.mFlags);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800418 sp.setAccountHoldFlag(mMockContext, a1, true);
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800419 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1.mFlags);
420 Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
421 assertEquals(Account.FLAGS_NOTIFY_NEW_MAIL | Account.FLAGS_SECURITY_HOLD, a1b.mFlags);
422
423 // confirm set until cleared
424 Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700425 assertEquals(Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD, a2a.mFlags);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800426 sp.setAccountHoldFlag(mMockContext, a2, false);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700427 assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2.mFlags);
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800428 Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
Jim Shuma9e2ddca2010-03-16 18:08:52 -0700429 assertEquals(Account.FLAGS_VIBRATE_ALWAYS, a2b.mFlags);
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800430 }
431
Andy Stadler1ca111c2010-12-01 12:58:36 -0800432// private static class MockController extends Controller {
433// protected MockController(Context context) {
434// super(context);
435// }
436// }
Marc Blank02d59d22010-10-25 11:49:29 -0700437
Andrew Stadler2a5eeea2010-02-08 17:42:42 -0800438 /**
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800439 * Test the response to disabling DeviceAdmin status
Andy Stadler1ca111c2010-12-01 12:58:36 -0800440 *
441 * TODO: Reenable the 2nd portion of this test - it fails because it gets into the Controller
442 * and spins up an account backup on another thread.
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800443 */
444 public void testDisableAdmin() {
445 Account a1 = ProviderTestUtils.setupAccount("disable-1", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800446 PolicySet p1 = new PolicySet(10, PolicySet.PASSWORD_MODE_SIMPLE, 0, 0, false, 0, 0, 0,
447 false);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800448 p1.writeAccount(a1, "sync-key-1", true, mMockContext);
449
450 Account a2 = ProviderTestUtils.setupAccount("disable-2", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800451 PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
452 false);
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800453 p2.writeAccount(a2, "sync-key-2", true, mMockContext);
454
455 Account a3 = ProviderTestUtils.setupAccount("disable-3", false, mMockContext);
456 a3.mSecurityFlags = 0;
457 a3.mSecuritySyncKey = null;
458 a3.save(mMockContext);
459
460 SecurityPolicy sp = getSecurityPolicy();
461
462 // Confirm that "enabling" device admin does not change security status (flags & sync key)
463 PolicySet before = sp.getAggregatePolicy();
464 sp.onAdminEnabled(true); // "enabled" should not change anything
465 PolicySet after1 = sp.getAggregatePolicy();
466 assertEquals(before, after1);
467 Account a1a = Account.restoreAccountWithId(mMockContext, a1.mId);
468 assertNotNull(a1a.mSecuritySyncKey);
469 Account a2a = Account.restoreAccountWithId(mMockContext, a2.mId);
470 assertNotNull(a2a.mSecuritySyncKey);
471 Account a3a = Account.restoreAccountWithId(mMockContext, a3.mId);
472 assertNull(a3a.mSecuritySyncKey);
473
Marc Blank02d59d22010-10-25 11:49:29 -0700474 // Simulate revoke of device admin; directly call deleteSecuredAccounts, which is normally
475 // called from a background thread
Andy Stadler1ca111c2010-12-01 12:58:36 -0800476// MockController mockController = new MockController(mMockContext);
477// Controller.injectMockControllerForTest(mockController);
478// try {
479// sp.deleteSecuredAccounts(mMockContext);
480// PolicySet after2 = sp.getAggregatePolicy();
481// assertEquals(SecurityPolicy.NO_POLICY_SET, after2);
482// Account a1b = Account.restoreAccountWithId(mMockContext, a1.mId);
483// assertNull(a1b);
484// Account a2b = Account.restoreAccountWithId(mMockContext, a2.mId);
485// assertNull(a2b);
486// Account a3b = Account.restoreAccountWithId(mMockContext, a3.mId);
487// assertNull(a3b.mSecuritySyncKey);
488// } finally {
489// Controller.injectMockControllerForTest(null);
490// }
491 }
492
493 /**
494 * Test the scanner that finds expiring accounts
495 */
496 public void testFindExpiringAccount() {
497 SecurityPolicy sp = getSecurityPolicy();
498
499 Account a1 = ProviderTestUtils.setupAccount("expiring-1", true, mMockContext);
500
501 // With no expiring accounts, this should return null.
502 long nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
503 assertEquals(-1, nextExpiringAccountId);
504
505 // Add a single expiring account
506 Account a2 = ProviderTestUtils.setupAccount("expiring-2", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800507 PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
508 false);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800509 p2.writeAccount(a2, "sync-key-2", true, mMockContext);
510
511 // The expiring account should be returned
512 nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
513 assertEquals(a2.mId, nextExpiringAccountId);
514
515 // Add an account with a longer expiration
516 Account a3 = ProviderTestUtils.setupAccount("expiring-3", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800517 PolicySet p3 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 60, 0, 0,
518 false);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800519 p3.writeAccount(a3, "sync-key-3", true, mMockContext);
520
521 // The original expiring account (a2) should be returned
522 nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
523 assertEquals(a2.mId, nextExpiringAccountId);
524
525 // Add an account with a shorter expiration
526 Account a4 = ProviderTestUtils.setupAccount("expiring-4", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800527 PolicySet p4 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 15, 0, 0,
528 false);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800529 p4.writeAccount(a4, "sync-key-4", true, mMockContext);
530
531 // The new expiring account (a4) should be returned
532 nextExpiringAccountId = sp.findShortestExpiration(mMockContext);
533 assertEquals(a4.mId, nextExpiringAccountId);
534 }
535
536 /**
537 * Lightweight subclass of the Controller class allows injection of mock context
538 */
539 public static class TestController extends Controller {
540
541 protected TestController(Context providerContext, Context systemContext) {
542 super(systemContext);
543 setProviderContext(providerContext);
Marc Blank02d59d22010-10-25 11:49:29 -0700544 }
Andrew Stadleraf55e3e2010-02-16 14:33:08 -0800545 }
Andy Stadler1ca111c2010-12-01 12:58:36 -0800546
547 /**
548 * Test the scanner that wipes expiring accounts
549 */
550 public void testWipeExpiringAccounts() {
551 SecurityPolicy sp = getSecurityPolicy();
552 TestController testController = new TestController(mMockContext, getContext());
553
554 // Two accounts - a1 is normal, a2 has security (but no expiration)
555 Account a1 = ProviderTestUtils.setupAccount("expired-1", true, mMockContext);
556 Account a2 = ProviderTestUtils.setupAccount("expired-2", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800557 PolicySet p2 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 0, 0, 0,
558 false);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800559 p2.writeAccount(a2, "sync-key-2", true, mMockContext);
560
561 // Add a mailbox & messages to each account
562 long account1Id = a1.mId;
563 long account2Id = a2.mId;
564 Mailbox box1 = ProviderTestUtils.setupMailbox("box1", account1Id, true, mMockContext);
565 long box1Id = box1.mId;
566 ProviderTestUtils.setupMessage("message1", account1Id, box1Id, false, true, mMockContext);
567 ProviderTestUtils.setupMessage("message2", account1Id, box1Id, false, true, mMockContext);
568 Mailbox box2 = ProviderTestUtils.setupMailbox("box2", account2Id, true, mMockContext);
569 long box2Id = box2.mId;
570 ProviderTestUtils.setupMessage("message3", account2Id, box2Id, false, true, mMockContext);
571 ProviderTestUtils.setupMessage("message4", account2Id, box2Id, false, true, mMockContext);
572
573 // Run the expiration code - should do nothing
574 boolean wiped = sp.wipeExpiredAccounts(mMockContext, testController);
575 assertFalse(wiped);
576 // check mailboxes & messages not wiped
577 assertEquals(2, EmailContent.count(mMockContext, Account.CONTENT_URI));
578 assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
579 assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
580
581 // Add 3rd account that really expires
582 Account a3 = ProviderTestUtils.setupAccount("expired-3", false, mMockContext);
Andy Stadler469f2982011-01-13 13:12:55 -0800583 PolicySet p3 = new PolicySet(20, PolicySet.PASSWORD_MODE_STRONG, 25, 26, false, 30, 0, 0,
584 false);
Andy Stadler1ca111c2010-12-01 12:58:36 -0800585 p3.writeAccount(a3, "sync-key-3", true, mMockContext);
586
587 // Add mailbox & messages to 3rd account
588 long account3Id = a3.mId;
589 Mailbox box3 = ProviderTestUtils.setupMailbox("box3", account3Id, true, mMockContext);
590 long box3Id = box3.mId;
591 ProviderTestUtils.setupMessage("message5", account3Id, box3Id, false, true, mMockContext);
592 ProviderTestUtils.setupMessage("message6", account3Id, box3Id, false, true, mMockContext);
593
594 // check new counts
595 assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
596 assertEquals(3, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
597 assertEquals(6, EmailContent.count(mMockContext, Message.CONTENT_URI));
598
599 // Run the expiration code - wipe acct #3
600 wiped = sp.wipeExpiredAccounts(mMockContext, testController);
601 assertTrue(wiped);
602 // check new counts - account survives but data is wiped
603 assertEquals(3, EmailContent.count(mMockContext, Account.CONTENT_URI));
604 assertEquals(2, EmailContent.count(mMockContext, Mailbox.CONTENT_URI));
605 assertEquals(4, EmailContent.count(mMockContext, Message.CONTENT_URI));
606
607 // Check security hold states - only #3 should be in hold
608 Account account = Account.restoreAccountWithId(mMockContext, account1Id);
609 assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
610 account = Account.restoreAccountWithId(mMockContext, account2Id);
611 assertEquals(0, account.mFlags & Account.FLAGS_SECURITY_HOLD);
612 account = Account.restoreAccountWithId(mMockContext, account3Id);
613 assertEquals(Account.FLAGS_SECURITY_HOLD, account.mFlags & Account.FLAGS_SECURITY_HOLD);
614 }
Andy Stadlera0d08052011-01-19 11:40:48 -0800615
616 /**
617 * Test the code that clears unsupported policies
618 * TODO inject a mock DPM so we can directly control & test all cases, no matter what device
619 */
620 public void testClearUnsupportedPolicies() {
621 PolicySet p1 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
622 PolicySet p2 = new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, true);
623
624 SecurityPolicy sp = getSecurityPolicy();
625 DevicePolicyManager dpm = sp.getDPM();
626 boolean hasEncryption =
627 dpm.getStorageEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
628
629 PolicySet p1Result = sp.clearUnsupportedPolicies(p1);
630 PolicySet p2Result = sp.clearUnsupportedPolicies(p2);
631
632 // No changes expected when encryptionRequested was false
633 assertEquals(p1, p1Result);
634 if (hasEncryption) {
635 // No changes expected
636 assertEquals(p2, p2Result);
637 } else {
638 PolicySet p2Expect =
639 new PolicySet(1, PolicySet.PASSWORD_MODE_STRONG, 3, 4, true, 7, 8, 9, false);
640 assertEquals(p2Expect, p2Result);
641 }
642 }
Andrew Stadler345fb8b2010-01-26 17:24:15 -0800643}