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 */ 16package com.android.managedprovisioning.parser; 17 18import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 19import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; 20import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE; 21import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME; 22import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE; 23import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM; 24import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER; 25import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION; 26import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; 27import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM; 28import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCALE; 29import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_LOCAL_TIME; 30import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_MAIN_COLOR; 31import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION; 32import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TIME_ZONE; 33import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_HIDDEN; 34import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PAC_URL; 35import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD; 36import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_BYPASS; 37import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_HOST; 38import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PROXY_PORT; 39import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE; 40import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID; 41import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC; 42import static org.mockito.Mockito.when; 43 44import android.accounts.Account; 45import android.app.admin.DevicePolicyManager; 46import android.content.ComponentName; 47import android.content.Context; 48import android.content.Intent; 49import android.nfc.NdefMessage; 50import android.nfc.NdefRecord; 51import android.nfc.NfcAdapter; 52import android.os.PersistableBundle; 53import android.test.AndroidTestCase; 54import android.test.suitebuilder.annotation.SmallTest; 55import android.util.Base64; 56import com.android.managedprovisioning.common.IllegalProvisioningArgumentException; 57import com.android.managedprovisioning.common.ManagedProvisioningSharedPreferences; 58import com.android.managedprovisioning.common.StoreUtils; 59import com.android.managedprovisioning.common.Utils; 60import com.android.managedprovisioning.model.PackageDownloadInfo; 61import com.android.managedprovisioning.model.ProvisioningParams; 62import com.android.managedprovisioning.model.WifiInfo; 63import java.io.ByteArrayOutputStream; 64import java.util.Locale; 65import java.util.Properties; 66import org.mockito.Mock; 67import org.mockito.MockitoAnnotations; 68 69/** Tests for {@link PropertiesProvisioningDataParser} */ 70@SmallTest 71public 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 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 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 .setIsNfc(true) 208 .build(), 209 params); 210 } 211 212 public void testParse_OtherIntentsThrowsException() { 213 // GIVEN a managed device provisioning intent and some extras. 214 Intent intent = new Intent(ACTION_PROVISION_MANAGED_DEVICE) 215 .putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, TEST_PACKAGE_NAME) 216 .putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, TEST_COMPONENT_NAME) 217 .putExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION, TEST_SKIP_ENCRYPTION) 218 .putExtra(EXTRA_PROVISIONING_MAIN_COLOR, TEST_MAIN_COLOR) 219 .putExtra(EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE, TEST_ACCOUNT_TO_MIGRATE); 220 221 try { 222 // WHEN the intent is parsed by the parser. 223 ProvisioningParams params = mPropertiesProvisioningDataParser.parse(intent); 224 fail("PropertiesProvisioningDataParser doesn't support intent other than NFC. " 225 + "IllegalProvisioningArgumentException should be thrown"); 226 } catch (IllegalProvisioningArgumentException e) { 227 // THEN IllegalProvisioningArgumentException is thrown. 228 } 229 } 230 231 public void testGetFirstNdefRecord_nullNdefMessages() { 232 // GIVEN nfc intent with no ndef messages 233 Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED); 234 // WHEN getting first ndef record 235 // THEN it should return null 236 assertNull(PropertiesProvisioningDataParser.getFirstNdefRecord(nfcIntent)); 237 } 238 239 public void testGetFirstNdefRecord_noNfcMimeType() { 240 // GIVEN nfc intent with no ndf message with a record with a valid mime type. 241 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 242 NdefRecord record = NdefRecord.createMime(INVALID_MIME_TYPE, stream.toByteArray()); 243 NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record}); 244 Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED) 245 .setType(MIME_TYPE_PROVISIONING_NFC) 246 .putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg}); 247 // WHEN getting first ndef record 248 // THEN it should return null 249 assertNull(PropertiesProvisioningDataParser.getFirstNdefRecord(nfcIntent)); 250 } 251 252 public void testGetFirstNdefRecord() { 253 // GIVEN nfc intent with valid ndf message with a record with mime type nfc. 254 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 255 NdefRecord record = NdefRecord.createMime( 256 DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, 257 stream.toByteArray()); 258 NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record}); 259 Intent nfcIntent = new Intent(NfcAdapter.ACTION_NDEF_DISCOVERED) 260 .setType(MIME_TYPE_PROVISIONING_NFC) 261 .putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg}); 262 // WHEN getting first ndef record 263 // THEN valid record should be returned 264 assertEquals(PropertiesProvisioningDataParser.getFirstNdefRecord(nfcIntent), record); 265 } 266 267 private static Properties setTestWifiInfo(Properties props) { 268 props.setProperty(EXTRA_PROVISIONING_WIFI_SSID, TEST_SSID); 269 props.setProperty(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, TEST_SECURITY_TYPE); 270 props.setProperty(EXTRA_PROVISIONING_WIFI_PASSWORD, TEST_PASSWORD); 271 props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_HOST, TEST_PROXY_HOST); 272 props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_BYPASS, TEST_PROXY_BYPASS_HOSTS); 273 props.setProperty(EXTRA_PROVISIONING_WIFI_PAC_URL, TEST_PAC_URL); 274 props.setProperty(EXTRA_PROVISIONING_WIFI_PROXY_PORT, Integer.toString(TEST_PROXY_PORT)); 275 props.setProperty(EXTRA_PROVISIONING_WIFI_HIDDEN, Boolean.toString(TEST_HIDDEN)); 276 return props; 277 } 278 279 private static Properties setTestTimeTimeZoneAndLocale(Properties props) { 280 props.setProperty(EXTRA_PROVISIONING_LOCAL_TIME, Long.toString(TEST_LOCAL_TIME)); 281 props.setProperty(EXTRA_PROVISIONING_TIME_ZONE, TEST_TIME_ZONE); 282 props.setProperty(EXTRA_PROVISIONING_LOCALE, StoreUtils.localeToString(TEST_LOCALE)); 283 return props; 284 } 285 286 private static Properties setTestDeviceAdminDownload(Properties props) { 287 props.setProperty( 288 EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE, 289 Integer.toString(TEST_MIN_SUPPORT_VERSION)); 290 props.setProperty( 291 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION, 292 TEST_DOWNLOAD_LOCATION); 293 props.setProperty(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER, 294 TEST_COOKIE_HEADER); 295 props.setProperty( 296 EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, 297 Base64.encodeToString(TEST_PACKAGE_CHECKSUM, 298 Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP)); 299 props.setProperty( 300 EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, 301 Base64.encodeToString(TEST_SIGNATURE_CHECKSUM, 302 Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP)); 303 return props; 304 } 305 306 private static String getTestAdminExtrasString() throws Exception { 307 Properties props = new Properties(); 308 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 309 310 PersistableBundle bundle = getTestAdminExtrasPersistableBundle(); 311 for (String key : bundle.keySet()) { 312 props.setProperty(key, bundle.getString(key)); 313 } 314 props.store(stream, "ADMIN_EXTRAS_BUNDLE" /* data description */); 315 316 return stream.toString(); 317 } 318 319 private static PersistableBundle getTestAdminExtrasPersistableBundle() { 320 PersistableBundle bundle = new PersistableBundle(); 321 bundle.putString("key1", "val1"); 322 bundle.putString("key2", "val2"); 323 bundle.putString("key3", "val3"); 324 return bundle; 325 } 326} 327