Home | History | Annotate | Download | only in parser
      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 (at) 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