1 /*
2  * Copyright 2016, 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 package com.android.managedprovisioning.parser;
17 
18 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
19 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE;
20 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
21 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
22 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE;
23 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM;
24 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER;
25 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION;
26 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
27 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM;
28 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE;
29 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME;
30 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR;
31 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION;
32 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE;
33 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN;
34 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PAC_URL;
35 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD;
36 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_BYPASS;
37 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_HOST;
38 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT;
39 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE;
40 import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID;
41 import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
42 import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
43 import static com.android.managedprovisioning.TestUtils.createTestAdminExtras;
44 import static com.android.managedprovisioning.parser.MessageParser.EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM;
45 import static com.android.managedprovisioning.parser.MessageParser.EXTRA_PROVISIONING_STARTED_BY_TRUSTED_SOURCE;
46 
47 import android.accounts.Account;
48 import android.app.admin.DevicePolicyManager;
49 import android.content.ComponentName;
50 import android.content.Context;
51 import android.content.Intent;
52 import android.nfc.NdefMessage;
53 import android.nfc.NdefRecord;
54 import android.nfc.NfcAdapter;
55 import android.os.PersistableBundle;
56 import android.test.AndroidTestCase;
57 import android.test.suitebuilder.annotation.SmallTest;
58 import android.util.Base64;
59 
60 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException;
61 import com.android.managedprovisioning.common.Utils;
62 import com.android.managedprovisioning.model.PackageDownloadInfo;
63 import com.android.managedprovisioning.model.ProvisioningParams;
64 import com.android.managedprovisioning.model.WifiInfo;
65 
66 import java.io.ByteArrayOutputStream;
67 import java.util.Locale;
68 import java.util.Properties;
69 
70 import org.mockito.Mock;
71 import org.mockito.MockitoAnnotations;
72 
73 /** Tests for {@link PropertiesProvisioningDataParser} */
74 @SmallTest
75 public class PropertiesProvisioningDataParserTest extends AndroidTestCase {
76     private static final String TEST_PACKAGE_NAME = "com.afwsamples.testdpc";
77     private static final ComponentName TEST_COMPONENT_NAME =
78             ComponentName.unflattenFromString(
79                     "com.afwsamples.testdpc/com.afwsamples.testdpc.DeviceAdminReceiver");
80     private static final long TEST_LOCAL_TIME = 1456939524713L;
81     private static final Locale TEST_LOCALE = Locale.UK;
82     private static final String TEST_TIME_ZONE = "GMT";
83     private static final Integer TEST_MAIN_COLOR = 65280;
84     private static final boolean TEST_STARTED_BY_TRUSTED_SOURCE = true;
85     private static final boolean TEST_LEAVE_ALL_SYSTEM_APP_ENABLED = true;
86     private static final boolean TEST_SKIP_ENCRYPTION = true;
87     private static final boolean TEST_SKIP_USER_SETUP = true;
88     private static final Account TEST_ACCOUNT_TO_MIGRATE =
89             new Account("user@gmail.com", "com.google");
90 
91     // Wifi info
92     private static final String TEST_SSID = "TestWifi";
93     private static final boolean TEST_HIDDEN = true;
94     private static final String TEST_SECURITY_TYPE = "WPA2";
95     private static final String TEST_PASSWORD = "GoogleRock";
96     private static final String TEST_PROXY_HOST = "testhost.com";
97     private static final int TEST_PROXY_PORT = 7689;
98     private static final String TEST_PROXY_BYPASS_HOSTS = "http://host1.com;https://host2.com";
99     private static final String TEST_PAC_URL = "pac.test.com";
100     private static final WifiInfo TEST_WIFI_INFO = WifiInfo.Builder.builder()
101             .setSsid(TEST_SSID)
102             .setHidden(TEST_HIDDEN)
103             .setSecurityType(TEST_SECURITY_TYPE)
104             .setPassword(TEST_PASSWORD)
105             .setProxyHost(TEST_PROXY_HOST)
106             .setProxyPort(TEST_PROXY_PORT)
107             .setProxyBypassHosts(TEST_PROXY_BYPASS_HOSTS)
108             .setPacUrl(TEST_PAC_URL)
109             .build();
110 
111     // Device admin package download info
112     private static final String TEST_DOWNLOAD_LOCATION =
113             "http://example/dpc.apk";
114     private static final String TEST_COOKIE_HEADER =
115             "Set-Cookie: sessionToken=foobar; Expires=Thu, 18 Feb 2016 23:59:59 GMT";
116     private static final byte[] TEST_PACKAGE_CHECKSUM = new byte[] { '1', '2', '3', '4', '5' };
117     private static final byte[] TEST_SIGNATURE_CHECKSUM = new byte[] { '5', '4', '3', '2', '1' };
118     private static final int TEST_MIN_SUPPORT_VERSION = 17689;
119     private static final PackageDownloadInfo TEST_DOWNLOAD_INFO =
120             PackageDownloadInfo.Builder.builder()
121                     .setLocation(TEST_DOWNLOAD_LOCATION)
122                     .setCookieHeader(TEST_COOKIE_HEADER)
123                     .setPackageChecksum(TEST_PACKAGE_CHECKSUM)
124                     .setSignatureChecksum(TEST_SIGNATURE_CHECKSUM)
125                     .setMinVersion(TEST_MIN_SUPPORT_VERSION)
126                     .build();
127 
128     @Mock
129     private Context mContext;
130 
131     private PropertiesProvisioningDataParser mPropertiesProvisioningDataParser;
132 
133     @Override
setUp()134     public void setUp() {
135         // this is necessary for mockito to work
136         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
137 
138         MockitoAnnotations.initMocks(this);
139 
140         mPropertiesProvisioningDataParser = new PropertiesProvisioningDataParser(new Utils());
141     }
142 
testParse_nfcProvisioningIntent()143     public void testParse_nfcProvisioningIntent() throws Exception {
144         // GIVEN a NFC provisioning intent with all supported data.
145         Properties props = new Properties();
146         ByteArrayOutputStream stream = new ByteArrayOutputStream();
147         props.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, TEST_PACKAGE_NAME);
148         props.setProperty(
149                 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
150                 TEST_COMPONENT_NAME.flattenToString());
151         setTestWifiInfo(props);
152         setTestTimeTimeZoneAndLocale(props);
153         setTestDeviceAdminDownload(props);
154         // GIVEN this intent requested to support SHA1 package checksum.
155         props.setProperty(
156                 EXTRA_PROVISIONING_DEVICE_ADMIN_SUPPORT_SHA1_PACKAGE_CHECKSUM,
157                 Boolean.toString(true));
158         props.setProperty(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, getTestAdminExtrasString());
159         props.setProperty(
160                 EXTRA_PROVISIONING_SKIP_ENCRYPTION,
161                 Boolean.toString(TEST_SKIP_ENCRYPTION));
162         // GIVEN main color is supplied even though it is not supported in NFC provisioning.
163         props.setProperty(EXTRA_PROVISIONING_MAIN_COLOR, Integer.toString(TEST_MAIN_COLOR));
164 
165         props.store(stream, "NFC provisioning intent" /* data description */);
166 
167         NdefRecord record = NdefRecord.createMime(
168                 DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC,
169                 stream.toByteArray());
170         NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record});
171 
172         Intent intent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED)
173                 .setType(MIME_TYPE_PROVISIONING_NFC)
174                 .putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg});
175 
176         // WHEN the intent is parsed by the parser.
177         ProvisioningParams params = mPropertiesProvisioningDataParser.parse(intent, mContext);
178 
179 
180         // THEN ProvisionParams is constructed as expected.
181         assertEquals(
182                 ProvisioningParams.Builder.builder()
183                         // THEN NFC provisioning is translated to ACTION_PROVISION_MANAGED_DEVICE
184                         // action.
185                         .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE)
186                         .setDeviceAdminComponentName(TEST_COMPONENT_NAME)
187                         .setDeviceAdminPackageName(TEST_PACKAGE_NAME)
188                         .setDeviceAdminDownloadInfo(
189                                 PackageDownloadInfo.Builder.builder()
190                                         .setLocation(TEST_DOWNLOAD_LOCATION)
191                                         .setCookieHeader(TEST_COOKIE_HEADER)
192                                         .setPackageChecksum(TEST_PACKAGE_CHECKSUM)
193                                         .setSignatureChecksum(TEST_SIGNATURE_CHECKSUM)
194                                         .setMinVersion(TEST_MIN_SUPPORT_VERSION)
195                                         // THEN it supports SHA1 package checksum.
196                                         .setPackageChecksumSupportsSha1(true)
197                                         .build())
198                         .setLocalTime(TEST_LOCAL_TIME)
199                         .setLocale(TEST_LOCALE)
200                         .setTimeZone(TEST_TIME_ZONE)
201                         // THEN main color is not supported in NFC intent.
202                         .setMainColor(null)
203                         .setSkipEncryption(TEST_SKIP_ENCRYPTION)
204                         .setWifiInfo(TEST_WIFI_INFO)
205                         .setAdminExtrasBundle(getTestAdminExtrasPersistableBundle())
206                         .setStartedByTrustedSource(true)
207                         .build(),
208                 params);
209     }
210 
testParse_OtherIntentsThrowsException()211     public void testParse_OtherIntentsThrowsException() {
212         // GIVEN a managed device provisioning intent and some extras.
213         Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE)
214                 .putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, TEST_PACKAGE_NAME)
215                 .putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, TEST_COMPONENT_NAME)
216                 .putExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION, TEST_SKIP_ENCRYPTION)
217                 .putExtra(EXTRA_PROVISIONING_MAIN_COLOR, TEST_MAIN_COLOR)
218                 .putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, TEST_ACCOUNT_TO_MIGRATE);
219 
220         try {
221             // WHEN the intent is parsed by the parser.
222             ProvisioningParams params = mPropertiesProvisioningDataParser.parse(intent, mContext);
223             fail("PropertiesProvisioningDataParser doesn't support intent other than NFC. "
224                     + "IllegalProvisioningArgumentException should be thrown");
225         } catch (IllegalProvisioningArgumentException e) {
226             // THEN IllegalProvisioningArgumentException is thrown.
227         }
228     }
229 
setTestWifiInfo(Properties props)230     private static Properties setTestWifiInfo(Properties props) {
231         props.setProperty(EXTRA_PROVISIONING_WIFI_SSID, TEST_SSID);
232         props.setProperty(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, TEST_SECURITY_TYPE);
233         props.setProperty(EXTRA_PROVISIONING_WIFI_PASSWORD, TEST_PASSWORD);
234         props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_HOST, TEST_PROXY_HOST);
235         props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS, TEST_PROXY_BYPASS_HOSTS);
236         props.setProperty(EXTRA_PROVISIONING_WIFI_PAC_URL, TEST_PAC_URL);
237         props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_PORT, Integer.toString(TEST_PROXY_PORT));
238         props.setProperty(EXTRA_PROVISIONING_WIFI_HIDDEN, Boolean.toString(TEST_HIDDEN));
239         return props;
240     }
241 
setTestTimeTimeZoneAndLocale(Properties props)242     private static Properties setTestTimeTimeZoneAndLocale(Properties props) {
243         props.setProperty(EXTRA_PROVISIONING_LOCAL_TIME, Long.toString(TEST_LOCAL_TIME));
244         props.setProperty(EXTRA_PROVISIONING_TIME_ZONE, TEST_TIME_ZONE);
245         props.setProperty(EXTRA_PROVISIONING_LOCALE, MessageParser.localeToString(TEST_LOCALE));
246         return props;
247     }
248 
setTestDeviceAdminDownload(Properties props)249     private static Properties setTestDeviceAdminDownload(Properties props) {
250         props.setProperty(
251                 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE,
252                 Integer.toString(TEST_MIN_SUPPORT_VERSION));
253         props.setProperty(
254                 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION,
255                 TEST_DOWNLOAD_LOCATION);
256         props.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER,
257                 TEST_COOKIE_HEADER);
258         props.setProperty(
259                 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM,
260                 Base64.encodeToString(TEST_PACKAGE_CHECKSUM,
261                         Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP));
262         props.setProperty(
263                 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM,
264                 Base64.encodeToString(TEST_SIGNATURE_CHECKSUM,
265                         Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP));
266         return props;
267     }
268 
getTestAdminExtrasString()269     private static String getTestAdminExtrasString() throws Exception {
270         Properties props = new Properties();
271         ByteArrayOutputStream stream = new ByteArrayOutputStream();
272 
273         PersistableBundle bundle = getTestAdminExtrasPersistableBundle();
274         for (String key : bundle.keySet()) {
275             props.setProperty(key, bundle.getString(key));
276         }
277         props.store(stream, "ADMIN_EXTRAS_BUNDLE" /* data description */);
278 
279         return stream.toString();
280     }
281 
getTestAdminExtrasPersistableBundle()282     private static PersistableBundle getTestAdminExtrasPersistableBundle() {
283         PersistableBundle bundle = new PersistableBundle();
284         bundle.putString("key1", "val1");
285         bundle.putString("key2", "val2");
286         bundle.putString("key3", "val3");
287         return bundle;
288     }
289 }
290