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 org.mockito.Mockito.when; 43 44 import android.accounts.Account; 45 import android.app.admin.DevicePolicyManager; 46 import android.content.ComponentName; 47 import android.content.Context; 48 import android.content.Intent; 49 import android.nfc.NdefMessage; 50 import android.nfc.NdefRecord; 51 import android.nfc.NfcAdapter; 52 import android.os.PersistableBundle; 53 import android.test.AndroidTestCase; 54 import android.test.suitebuilder.annotation.SmallTest; 55 import android.util.Base64; 56 import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 57 import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 58 import com.android.managedprovisioning.common.StoreUtils; 59 import com.android.managedprovisioning.common.Utils; 60 import com.android.managedprovisioning.model.PackageDownloadInfo; 61 import com.android.managedprovisioning.model.ProvisioningParams; 62 import com.android.managedprovisioning.model.WifiInfo; 63 import java.io.ByteArrayOutputStream; 64 import java.util.Locale; 65 import java.util.Properties; 66 import org.mockito.Mock; 67 import org.mockito.MockitoAnnotations; 68 69 /** Tests for {@link PropertiesProvisioningDataParser} */ 70 @SmallTest 71 public class PropertiesProvisioningDataParserTest extends AndroidTestCase { 72 private static final String TEST_PACKAGE_NAME = "com.afwsamples.testdpc"; 73 private static final ComponentName TEST_COMPONENT_NAME = 74 ComponentName.unflattenFromString( 75 "com.afwsamples.testdpc/com.afwsamples.testdpc.DeviceAdminReceiver"); 76 private static final long TEST_LOCAL_TIME = 1456939524713L; 77 private static final Locale TEST_LOCALE = Locale.UK; 78 private static final String TEST_TIME_ZONE = "GMT"; 79 private static final Integer TEST_MAIN_COLOR = 65280; 80 private static final boolean TEST_STARTED_BY_TRUSTED_SOURCE = true; 81 private static final boolean TEST_LEAVE_ALL_SYSTEM_APP_ENABLED = true; 82 private static final boolean TEST_SKIP_ENCRYPTION = true; 83 private static final boolean TEST_SKIP_USER_SETUP = true; 84 private static final long TEST_PROVISIONING_ID = 2000L; 85 private static final Account TEST_ACCOUNT_TO_MIGRATE = 86 new Account("user@gmail.com", "com.google"); 87 private static final String INVALID_MIME_TYPE = "invalid-mime-type"; 88 89 // Wifi info 90 private static final String TEST_SSID = "TestWifi"; 91 private static final boolean TEST_HIDDEN = true; 92 private static final String TEST_SECURITY_TYPE = "WPA2"; 93 private static final String TEST_PASSWORD = "GoogleRock"; 94 private static final String TEST_PROXY_HOST = "testhost.com"; 95 private static final int TEST_PROXY_PORT = 7689; 96 private static final String TEST_PROXY_BYPASS_HOSTS = "http://host1.com;https://host2.com"; 97 private static final String TEST_PAC_URL = "pac.test.com"; 98 private static final WifiInfo TEST_WIFI_INFO = WifiInfo.Builder.builder() 99 .setSsid(TEST_SSID) 100 .setHidden(TEST_HIDDEN) 101 .setSecurityType(TEST_SECURITY_TYPE) 102 .setPassword(TEST_PASSWORD) 103 .setProxyHost(TEST_PROXY_HOST) 104 .setProxyPort(TEST_PROXY_PORT) 105 .setProxyBypassHosts(TEST_PROXY_BYPASS_HOSTS) 106 .setPacUrl(TEST_PAC_URL) 107 .build(); 108 109 // Device admin package download info 110 private static final String TEST_DOWNLOAD_LOCATION = 111 "http://example/dpc.apk"; 112 private static final String TEST_COOKIE_HEADER = 113 "Set-Cookie: sessionToken=foobar; Expires=Thu, 18 Feb 2016 23:59:59 GMT"; 114 private static final byte[] TEST_PACKAGE_CHECKSUM = new byte[] { '1', '2', '3', '4', '5' }; 115 private static final byte[] TEST_SIGNATURE_CHECKSUM = new byte[] { '5', '4', '3', '2', '1' }; 116 private static final int TEST_MIN_SUPPORT_VERSION = 17689; 117 private static final PackageDownloadInfo TEST_DOWNLOAD_INFO = 118 PackageDownloadInfo.Builder.builder() 119 .setLocation(TEST_DOWNLOAD_LOCATION) 120 .setCookieHeader(TEST_COOKIE_HEADER) 121 .setPackageChecksum(TEST_PACKAGE_CHECKSUM) 122 .setSignatureChecksum(TEST_SIGNATURE_CHECKSUM) 123 .setMinVersion(TEST_MIN_SUPPORT_VERSION) 124 .build(); 125 126 @Mock 127 private Context mContext; 128 129 @Mock 130 private ManagedProvisioningSharedPreferences mSharedPreferences; 131 132 private PropertiesProvisioningDataParser mPropertiesProvisioningDataParser; 133 134 @Override setUp()135 public void setUp() { 136 // this is necessary for mockito to work 137 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 138 139 MockitoAnnotations.initMocks(this); 140 141 when(mSharedPreferences.incrementAndGetProvisioningId()).thenReturn(TEST_PROVISIONING_ID); 142 mPropertiesProvisioningDataParser = new PropertiesProvisioningDataParser(mContext, 143 new Utils(), mSharedPreferences); 144 } 145 testParse_nfcProvisioningIntent()146 public void testParse_nfcProvisioningIntent() throws Exception { 147 // GIVEN a NFC provisioning intent with all supported data. 148 Properties props = new Properties(); 149 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 150 props.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, TEST_PACKAGE_NAME); 151 props.setProperty( 152 EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, 153 TEST_COMPONENT_NAME.flattenToString()); 154 setTestWifiInfo(props); 155 setTestTimeTimeZoneAndLocale(props); 156 setTestDeviceAdminDownload(props); 157 props.setProperty(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, getTestAdminExtrasString()); 158 props.setProperty( 159 EXTRA_PROVISIONING_SKIP_ENCRYPTION, 160 Boolean.toString(TEST_SKIP_ENCRYPTION)); 161 // GIVEN main color is supplied even though it is not supported in NFC provisioning. 162 props.setProperty(EXTRA_PROVISIONING_MAIN_COLOR, Integer.toString(TEST_MAIN_COLOR)); 163 164 props.store(stream, "NFC provisioning intent" /* data description */); 165 166 NdefRecord record = NdefRecord.createMime( 167 DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, 168 stream.toByteArray()); 169 NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record}); 170 171 Intent intent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED) 172 .setType(MIME_TYPE_PROVISIONING_NFC) 173 .putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg}); 174 175 // WHEN the intent is parsed by the parser. 176 ProvisioningParams params = mPropertiesProvisioningDataParser.parse(intent); 177 178 179 // THEN ProvisionParams is constructed as expected. 180 assertEquals( 181 ProvisioningParams.Builder.builder() 182 // THEN NFC provisioning is translated to ACTION_PROVISION_MANAGED_DEVICE 183 // action. 184 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE) 185 .setDeviceAdminComponentName(TEST_COMPONENT_NAME) 186 .setDeviceAdminPackageName(TEST_PACKAGE_NAME) 187 .setProvisioningId(TEST_PROVISIONING_ID) 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); 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 testGetFirstNdefRecord_nullNdefMessages()230 public void testGetFirstNdefRecord_nullNdefMessages() { 231 // GIVEN nfc intent with no ndef messages 232 Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED); 233 // WHEN getting first ndef record 234 // THEN it should return null 235 assertNull(PropertiesProvisioningDataParser.getFirstNdefRecord(nfcIntent)); 236 } 237 testGetFirstNdefRecord_noNfcMimeType()238 public void testGetFirstNdefRecord_noNfcMimeType() { 239 // GIVEN nfc intent with no ndf message with a record with a valid mime type. 240 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 241 NdefRecord record = NdefRecord.createMime(INVALID_MIME_TYPE, stream.toByteArray()); 242 NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record}); 243 Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED) 244 .setType(MIME_TYPE_PROVISIONING_NFC) 245 .putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg}); 246 // WHEN getting first ndef record 247 // THEN it should return null 248 assertNull(PropertiesProvisioningDataParser.getFirstNdefRecord(nfcIntent)); 249 } 250 testGetFirstNdefRecord()251 public void testGetFirstNdefRecord() { 252 // GIVEN nfc intent with valid ndf message with a record with mime type nfc. 253 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 254 NdefRecord record = NdefRecord.createMime( 255 DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, 256 stream.toByteArray()); 257 NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record}); 258 Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED) 259 .setType(MIME_TYPE_PROVISIONING_NFC) 260 .putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg}); 261 // WHEN getting first ndef record 262 // THEN valid record should be returned 263 assertEquals(PropertiesProvisioningDataParser.getFirstNdefRecord(nfcIntent), record); 264 } 265 setTestWifiInfo(Properties props)266 private static Properties setTestWifiInfo(Properties props) { 267 props.setProperty(EXTRA_PROVISIONING_WIFI_SSID, TEST_SSID); 268 props.setProperty(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, TEST_SECURITY_TYPE); 269 props.setProperty(EXTRA_PROVISIONING_WIFI_PASSWORD, TEST_PASSWORD); 270 props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_HOST, TEST_PROXY_HOST); 271 props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS, TEST_PROXY_BYPASS_HOSTS); 272 props.setProperty(EXTRA_PROVISIONING_WIFI_PAC_URL, TEST_PAC_URL); 273 props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_PORT, Integer.toString(TEST_PROXY_PORT)); 274 props.setProperty(EXTRA_PROVISIONING_WIFI_HIDDEN, Boolean.toString(TEST_HIDDEN)); 275 return props; 276 } 277 setTestTimeTimeZoneAndLocale(Properties props)278 private static Properties setTestTimeTimeZoneAndLocale(Properties props) { 279 props.setProperty(EXTRA_PROVISIONING_LOCAL_TIME, Long.toString(TEST_LOCAL_TIME)); 280 props.setProperty(EXTRA_PROVISIONING_TIME_ZONE, TEST_TIME_ZONE); 281 props.setProperty(EXTRA_PROVISIONING_LOCALE, StoreUtils.localeToString(TEST_LOCALE)); 282 return props; 283 } 284 setTestDeviceAdminDownload(Properties props)285 private static Properties setTestDeviceAdminDownload(Properties props) { 286 props.setProperty( 287 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 288 Integer.toString(TEST_MIN_SUPPORT_VERSION)); 289 props.setProperty( 290 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, 291 TEST_DOWNLOAD_LOCATION); 292 props.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER, 293 TEST_COOKIE_HEADER); 294 props.setProperty( 295 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, 296 Base64.encodeToString(TEST_PACKAGE_CHECKSUM, 297 Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP)); 298 props.setProperty( 299 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, 300 Base64.encodeToString(TEST_SIGNATURE_CHECKSUM, 301 Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP)); 302 return props; 303 } 304 getTestAdminExtrasString()305 private static String getTestAdminExtrasString() throws Exception { 306 Properties props = new Properties(); 307 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 308 309 PersistableBundle bundle = getTestAdminExtrasPersistableBundle(); 310 for (String key : bundle.keySet()) { 311 props.setProperty(key, bundle.getString(key)); 312 } 313 props.store(stream, "ADMIN_EXTRAS_BUNDLE" /* data description */); 314 315 return stream.toString(); 316 } 317 getTestAdminExtrasPersistableBundle()318 private static PersistableBundle getTestAdminExtrasPersistableBundle() { 319 PersistableBundle bundle = new PersistableBundle(); 320 bundle.putString("key1", "val1"); 321 bundle.putString("key2", "val2"); 322 bundle.putString("key3", "val3"); 323 return bundle; 324 } 325 } 326