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 (at) 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 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 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 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 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 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 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 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 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