From 13e64c9c102f45aea11fa859f4e77d59b180bf5a Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Mon, 7 Aug 2017 10:56:32 +0200 Subject: [PATCH] Remove old VPN tests which instrumented Settings This is not actually a Settings test and never was, it just used Settings as a convenient delivery mechanism for system-level privileges. Tests for the Settings app should only check that the Settings app is behaving within its remit, ie. showing system server state and making the appropriate calls to set up a connection when certain UI elements are pressed. Also since the test relies heavily on off-device state it makes a lot more sense to run as a hostside test and have the same test code responsible for pushing certificates and network configs to the device instead of including manual instructions. For an end-to-end legacy VPN test see ACTS: https://android.googlesource.com/platform/tools/test/connectivity/+/master/acts/tests/google/net/LegacyVpnTest.py For an end-to-end app VPN test see CTS hostside: https://android.googlesource.com/platform/cts/+/master/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AlwaysOnVpnTest.java Test: make Settings Change-Id: Ia105c3ebd2fa5064adc4422bd3d77c3abba55634 Fix: 64040865 --- .../settings/vpn2/CertInstallerHelper.java | 223 --------- .../com/android/settings/vpn2/VpnInfo.java | 65 --- .../settings/vpn2/VpnProfileParser.java | 246 ---------- .../com/android/settings/vpn2/VpnTests.java | 446 ------------------ 4 files changed, 980 deletions(-) delete mode 100644 tests/app/src/com/android/settings/vpn2/CertInstallerHelper.java delete mode 100644 tests/app/src/com/android/settings/vpn2/VpnInfo.java delete mode 100644 tests/app/src/com/android/settings/vpn2/VpnProfileParser.java delete mode 100644 tests/app/src/com/android/settings/vpn2/VpnTests.java diff --git a/tests/app/src/com/android/settings/vpn2/CertInstallerHelper.java b/tests/app/src/com/android/settings/vpn2/CertInstallerHelper.java deleted file mode 100644 index fa2638ff995..00000000000 --- a/tests/app/src/com/android/settings/vpn2/CertInstallerHelper.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.vpn2; - -import android.os.Environment; -import android.security.Credentials; -import android.security.KeyStore; -import android.util.Log; - -import com.android.internal.net.VpnProfile; -import com.android.org.bouncycastle.asn1.ASN1InputStream; -import com.android.org.bouncycastle.asn1.ASN1Sequence; -import com.android.org.bouncycastle.asn1.DEROctetString; -import com.android.org.bouncycastle.asn1.x509.BasicConstraints; - -import junit.framework.Assert; - -import libcore.io.Streams; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.KeyStore.PasswordProtection; -import java.security.KeyStore.PrivateKeyEntry; -import java.security.PrivateKey; -import java.security.UnrecoverableEntryException; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; - -/** - * Certificate installer helper to extract information from a provided file - * and install certificates to keystore. - */ -public class CertInstallerHelper { - private static final String TAG = "CertInstallerHelper"; - /* Define a password to unlock keystore after it is reset */ - private static final String CERT_STORE_PASSWORD = "password"; - private final int mUid = KeyStore.UID_SELF; - private PrivateKey mUserKey; // private key - private X509Certificate mUserCert; // user certificate - private List mCaCerts = new ArrayList(); - private KeyStore mKeyStore = KeyStore.getInstance(); - - /** - * Unlock keystore and set password - */ - public CertInstallerHelper() { - mKeyStore.reset(); - mKeyStore.onUserPasswordChanged(CERT_STORE_PASSWORD); - } - - private void extractCertificate(String certFile, String password) { - InputStream in = null; - final byte[] raw; - java.security.KeyStore keystore = null; - try { - // Read .p12 file from SDCARD and extract with password - in = new FileInputStream(new File( - Environment.getExternalStorageDirectory(), certFile)); - raw = Streams.readFully(in); - - keystore = java.security.KeyStore.getInstance("PKCS12"); - PasswordProtection passwordProtection = new PasswordProtection(password.toCharArray()); - keystore.load(new ByteArrayInputStream(raw), passwordProtection.getPassword()); - - // Install certificates and private keys - Enumeration aliases = keystore.aliases(); - if (!aliases.hasMoreElements()) { - Assert.fail("key store failed to put in keychain"); - } - ArrayList aliasesList = Collections.list(aliases); - // The keystore is initialized for each test case, there will - // be only one alias in the keystore - Assert.assertEquals(1, aliasesList.size()); - String alias = aliasesList.get(0); - java.security.KeyStore.Entry entry = keystore.getEntry(alias, passwordProtection); - Log.d(TAG, "extracted alias = " + alias + ", entry=" + entry.getClass()); - - if (entry instanceof PrivateKeyEntry) { - Assert.assertTrue(installFrom((PrivateKeyEntry) entry)); - } - } catch (IOException e) { - Assert.fail("Failed to read certficate: " + e); - } catch (KeyStoreException e) { - Log.e(TAG, "failed to extract certificate" + e); - } catch (NoSuchAlgorithmException e) { - Log.e(TAG, "failed to extract certificate" + e); - } catch (CertificateException e) { - Log.e(TAG, "failed to extract certificate" + e); - } catch (UnrecoverableEntryException e) { - Log.e(TAG, "failed to extract certificate" + e); - } - finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - Log.e(TAG, "close FileInputStream error: " + e); - } - } - } - } - - /** - * Extract private keys, user certificates and ca certificates - */ - private synchronized boolean installFrom(PrivateKeyEntry entry) { - mUserKey = entry.getPrivateKey(); - mUserCert = (X509Certificate) entry.getCertificate(); - - Certificate[] certs = entry.getCertificateChain(); - Log.d(TAG, "# certs extracted = " + certs.length); - mCaCerts = new ArrayList(certs.length); - for (Certificate c : certs) { - X509Certificate cert = (X509Certificate) c; - if (isCa(cert)) { - mCaCerts.add(cert); - } - } - Log.d(TAG, "# ca certs extracted = " + mCaCerts.size()); - return true; - } - - private boolean isCa(X509Certificate cert) { - try { - byte[] asn1EncodedBytes = cert.getExtensionValue("2.5.29.19"); - if (asn1EncodedBytes == null) { - return false; - } - DEROctetString derOctetString = (DEROctetString) - new ASN1InputStream(asn1EncodedBytes).readObject(); - byte[] octets = derOctetString.getOctets(); - ASN1Sequence sequence = (ASN1Sequence) - new ASN1InputStream(octets).readObject(); - return BasicConstraints.getInstance(sequence).isCA(); - } catch (IOException e) { - return false; - } - } - - /** - * Extract certificate from the given file, and install it to keystore - * @param name certificate name - * @param certFile .p12 file which includes certificates - * @param password password to extract the .p12 file - */ - public void installCertificate(VpnProfile profile, String certFile, String password) { - // extract private keys, certificates from the provided file - extractCertificate(certFile, password); - // install certificate to the keystore - int flags = KeyStore.FLAG_ENCRYPTED; - try { - if (mUserKey != null) { - Log.v(TAG, "has private key"); - String key = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; - byte[] value = mUserKey.getEncoded(); - - if (!mKeyStore.importKey(key, value, mUid, flags)) { - Log.e(TAG, "Failed to install " + key + " as user " + mUid); - return; - } - Log.v(TAG, "install " + key + " as user " + mUid + " is successful"); - } - - if (mUserCert != null) { - String certName = Credentials.USER_CERTIFICATE + profile.ipsecUserCert; - byte[] certData = Credentials.convertToPem(mUserCert); - - if (!mKeyStore.put(certName, certData, mUid, flags)) { - Log.e(TAG, "Failed to install " + certName + " as user " + mUid); - return; - } - Log.v(TAG, "install " + certName + " as user" + mUid + " is successful."); - } - - if (!mCaCerts.isEmpty()) { - String caListName = Credentials.CA_CERTIFICATE + profile.ipsecCaCert; - X509Certificate[] caCerts = mCaCerts.toArray(new X509Certificate[mCaCerts.size()]); - byte[] caListData = Credentials.convertToPem(caCerts); - - if (!mKeyStore.put(caListName, caListData, mUid, flags)) { - Log.e(TAG, "Failed to install " + caListName + " as user " + mUid); - return; - } - Log.v(TAG, " install " + caListName + " as user " + mUid + " is successful"); - } - } catch (CertificateEncodingException e) { - Log.e(TAG, "Exception while convert certificates to pem " + e); - throw new AssertionError(e); - } catch (IOException e) { - Log.e(TAG, "IOException while convert to pem: " + e); - } - } - - public int getUid() { - return mUid; - } -} diff --git a/tests/app/src/com/android/settings/vpn2/VpnInfo.java b/tests/app/src/com/android/settings/vpn2/VpnInfo.java deleted file mode 100644 index ab7fb0f3d07..00000000000 --- a/tests/app/src/com/android/settings/vpn2/VpnInfo.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.vpn2; - -import com.android.internal.net.VpnProfile; - -/** - * Wrapper for VPN Profile and associated certificate files - */ -public class VpnInfo { - // VPN Profile - private VpnProfile mVpnProfile; - // Certificate file in PC12 format for user certificates and private keys - private String mCertificateFile = null; - // Password to extract certificates from the file - private String mPassword = null; - - public VpnInfo(VpnProfile vpnProfile, String certFile, String password) { - mVpnProfile = vpnProfile; - mCertificateFile = certFile; - mPassword = password; - } - - public VpnInfo(VpnProfile vpnProfile) { - mVpnProfile = vpnProfile; - } - - public void setVpnProfile(VpnProfile vpnProfile) { - mVpnProfile = vpnProfile; - } - - public void setCertificateFile(String certFile) { - mCertificateFile = certFile; - } - - public void setPassword(String password) { - mPassword = password; - } - - public VpnProfile getVpnProfile() { - return mVpnProfile; - } - - public String getCertificateFile() { - return mCertificateFile; - } - - public String getPassword() { - return mPassword; - } -} diff --git a/tests/app/src/com/android/settings/vpn2/VpnProfileParser.java b/tests/app/src/com/android/settings/vpn2/VpnProfileParser.java deleted file mode 100644 index 51c2550eb1d..00000000000 --- a/tests/app/src/com/android/settings/vpn2/VpnProfileParser.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.vpn2; - -import android.util.Log; - -import com.android.internal.net.VpnProfile; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Parse VPN profiles from an XML file - */ -public class VpnProfileParser { - private final static String TAG = "VpnProfileParser"; - private static Map mVpnPool = new HashMap(); - - static DefaultHandler mHandler = new DefaultHandler() { - boolean name; - boolean type; - boolean server; - boolean username; - boolean password; - boolean dnsServers; - boolean searchDomains; - boolean routes; - boolean mppe; - boolean l2tpSecret; - boolean ipsecIdentifier; - boolean ipsecSecret; - boolean ipsecUserCert; - boolean ipsecCaCert; - boolean ipsecServerCert; - boolean certFile; - boolean certFilePassword; - VpnProfile profile = null; - VpnInfo vpnInfo = null; - - - @Override - public void startElement(String uri, String localName, String tagName, - Attributes attributes) throws SAXException { - if (tagName.equalsIgnoreCase("vpn")) { - //create a new VPN profile - profile = new VpnProfile(Long.toHexString(System.currentTimeMillis())); - vpnInfo = new VpnInfo(profile); - } - if (tagName.equalsIgnoreCase("name")) { - name = true; - } - if (tagName.equalsIgnoreCase("type")) { - type = true; - } - if (tagName.equalsIgnoreCase("server")) { - server = true; - } - if (tagName.equalsIgnoreCase("username")) { - username = true; - } - if (tagName.equalsIgnoreCase("password")) { - password = true; - } - if (tagName.equalsIgnoreCase("dnsServers")) { - dnsServers = true; - } - if (tagName.equalsIgnoreCase("searchDomains")) { - searchDomains = true; - } - if (tagName.equalsIgnoreCase("mppe")) { - mppe = true; - } - if (tagName.equalsIgnoreCase("l2tpSecret")) { - l2tpSecret = true; - } - if (tagName.equalsIgnoreCase("ipsecIdentifier")) { - ipsecIdentifier = true; - } - if (tagName.equalsIgnoreCase("ipsecSecret")) { - ipsecSecret = true; - } - if (tagName.equalsIgnoreCase("ipsecUserCert")) { - ipsecUserCert = true; - } - if (tagName.equalsIgnoreCase("ipsecCaCert")) { - ipsecCaCert = true; - } - if (tagName.equalsIgnoreCase("ipsecServerCert")) { - ipsecServerCert = true; - } - if (tagName.equalsIgnoreCase("routes")) { - routes = true; - } - if (tagName.equalsIgnoreCase("cert-file")) { - certFile = true; - } - if (tagName.equalsIgnoreCase("cert-file-password")) { - certFilePassword = true; - } - } - - @Override - public void endElement(String uri, String localName, String tagName) throws SAXException { - if (tagName.equalsIgnoreCase("vpn")) { - mVpnPool.put(profile.type, vpnInfo); - } - } - - @Override - public void characters(char ch[], int start, int length) throws SAXException { - String strValue = new String(ch, start, length); - if (name) { - profile.name = strValue; - name = false; - } - if (type) { - int t = getVpnProfileType(strValue); - if (t < 0) { - throw new SAXException("not a valid VPN type"); - } else { - profile.type = t; - } - type = false; - } - if (server) { - profile.server = strValue; - server = false; - } - if (username) { - profile.username = strValue; - username = false; - } - if (password) { - profile.password = strValue; - password = false; - } - if (dnsServers) { - profile.dnsServers = strValue; - dnsServers = false; - } - if (searchDomains) { - profile.searchDomains = strValue; - searchDomains = false; - } - if (mppe) { - profile.mppe = Boolean.valueOf(strValue); - mppe = false; - } - if (l2tpSecret) { - profile.l2tpSecret = strValue; - l2tpSecret = false; - } - if (ipsecIdentifier) { - profile.ipsecIdentifier = strValue; - ipsecIdentifier = false; - } - if (ipsecSecret) { - profile.ipsecSecret = strValue; - ipsecSecret = false; - } - if (ipsecUserCert) { - profile.ipsecUserCert = strValue; - ipsecUserCert = false; - } - if (ipsecCaCert) { - profile.ipsecCaCert = strValue; - ipsecCaCert = false; - } - if (ipsecServerCert) { - profile.ipsecServerCert = strValue; - ipsecServerCert = false; - } - if (routes) { - profile.routes = strValue; - routes = false; - } - if (certFile) { - vpnInfo.setCertificateFile(strValue); - certFile = false; - } - if (certFilePassword) { - vpnInfo.setPassword(strValue); - certFilePassword = false; - } - } - - private int getVpnProfileType(String type) { - if (type.equalsIgnoreCase("TYPE_PPTP")) { - return VpnProfile.TYPE_PPTP; - } else if (type.equalsIgnoreCase("TYPE_L2TP_IPSEC_PSK")) { - return VpnProfile.TYPE_L2TP_IPSEC_PSK; - } else if (type.equalsIgnoreCase("TYPE_L2TP_IPSEC_RSA")) { - return VpnProfile.TYPE_L2TP_IPSEC_RSA; - } else if (type.equalsIgnoreCase("TYPE_IPSEC_XAUTH_PSK")) { - return VpnProfile.TYPE_IPSEC_XAUTH_PSK; - } else if (type.equalsIgnoreCase("TYPE_IPSEC_XAUTH_RSA")) { - return VpnProfile.TYPE_IPSEC_XAUTH_RSA; - } else if (type.equalsIgnoreCase("TYPE_IPSEC_HYBRID_RSA")) { - return VpnProfile.TYPE_IPSEC_HYBRID_RSA; - } else { - Log.v(TAG, "Invalid VPN type: " + type); - return -1; - } - } - }; - - public static Map parse(InputStream in) { - try { - SAXParserFactory factory = SAXParserFactory.newInstance(); - SAXParser saxParser = factory.newSAXParser(); - saxParser.parse(in, mHandler); - } catch (SAXException e) { - Log.e(TAG, "Parse vpn profile exception: " + e.toString()); - } catch (IOException e) { - Log.e(TAG, "Parse vpn profile exception: " + e.toString()); - } catch (ParserConfigurationException e) { - Log.e(TAG, "Parse vpn profile exception: " + e.toString()); - } finally { - return mVpnPool; - } - } -} diff --git a/tests/app/src/com/android/settings/vpn2/VpnTests.java b/tests/app/src/com/android/settings/vpn2/VpnTests.java deleted file mode 100644 index 11e82655c69..00000000000 --- a/tests/app/src/com/android/settings/vpn2/VpnTests.java +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.vpn2; - -import android.content.Context; -import android.net.IConnectivityManager; -import android.os.Bundle; -import android.os.Environment; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; -import android.security.Credentials; -import android.security.KeyStore; -import android.security.NetworkSecurityPolicy; -import android.test.InstrumentationTestCase; -import android.test.InstrumentationTestRunner; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.internal.net.LegacyVpnInfo; -import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnProfile; - -import java.net.HttpURLConnection; -import java.net.URL; -import junit.framework.Assert; - -import libcore.io.Streams; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.UnknownHostException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; - -/** - * Legacy VPN connection tests - * - * To run the test, use command: - * adb shell am instrument -e class com.android.settings.vpn2.VpnTests -e profile foo.xml - * -w com.android.settings.tests/android.test.InstrumentationTestRunner - * - * VPN profiles are saved in an xml file and will be loaded through {@link VpnProfileParser}. - * Push the profile (foo.xml) to the external storage, e.g adb push foo.xml /sdcard/ before running - * the above command. - * - * A typical profile looks like the following: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * VPN types include: TYPE_PPTP, TYPE_L2TP_IPSEC_PSK, TYPE_L2TP_IPSEC_RSA, - * TYPE_IPSEC_XAUTH_PSK, TYPE_IPSEC_XAUTH_RSA, TYPE_IPSEC_HYBRID_RSA - */ -public class VpnTests extends InstrumentationTestCase { - private static final String TAG = "VpnTests"; - /* Maximum time to wait for VPN connection */ - private static final long MAX_CONNECTION_TIME = 5 * 60 * 1000; - private static final long VPN_STAY_TIME = 60 * 1000; - private static final int MAX_DISCONNECTION_TRIES = 3; - private static final String EXTERNAL_SERVER = - "http://ip2country.sourceforge.net/ip2c.php?format=JSON"; - private static final String VPN_INTERFACE = "ppp0"; - private final IConnectivityManager mService = IConnectivityManager.Stub - .asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - private Map mVpnInfoPool = null; - private Context mContext; - private CertInstallerHelper mCertHelper = null; - private KeyStore mKeyStore = KeyStore.getInstance(); - private String mPreviousIpAddress = null; - private boolean DEBUG = false; - - @Override - protected void setUp() throws Exception { - super.setUp(); - InputStream in = null; - InstrumentationTestRunner mRunner = (InstrumentationTestRunner)getInstrumentation(); - mContext = mRunner.getContext(); - Bundle arguments = mRunner.getArguments(); - String PROFILE_NAME = arguments.getString("profile"); - Assert.assertNotNull("Push profile to external storage and load with" - + "'-e profile '", PROFILE_NAME); - File profileFile = new File(Environment.getExternalStorageDirectory(), PROFILE_NAME); - in = new FileInputStream(profileFile); - mVpnInfoPool = VpnProfileParser.parse(in); - Assert.assertNotNull("no VPN profiles are parsed", mVpnInfoPool); - if (DEBUG) { - Log.v(TAG, "print out the vpn profiles"); - for (Map.Entry profileEntrySet: mVpnInfoPool.entrySet()) { - VpnInfo vpnInfo = profileEntrySet.getValue(); - printVpnProfile(vpnInfo.getVpnProfile()); - if (vpnInfo.getCertificateFile() != null) { - Log.d(TAG, "certificate file for this vpn is " + vpnInfo.getCertificateFile()); - } - if (vpnInfo.getPassword() != null) { - Log.d(TAG, "password for the certificate file is: " + vpnInfo.getPassword()); - } - } - } - // disconnect existing vpn if there is any - LegacyVpnInfo oldVpn = mService.getLegacyVpnInfo(UserHandle.myUserId()); - if (oldVpn != null) { - Log.v(TAG, "disconnect legacy VPN"); - disconnect(); - // wait till the legacy VPN is disconnected. - int tries = 0; - while (tries < MAX_DISCONNECTION_TRIES && - mService.getLegacyVpnInfo(UserHandle.myUserId()) != null) { - tries++; - Thread.sleep(10 * 1000); - Log.v(TAG, "Wait for legacy VPN to be disconnected."); - } - Assert.assertNull("Failed to disconect VPN", - mService.getLegacyVpnInfo(UserHandle.myUserId())); - // wait for 30 seconds after the previous VPN is disconnected. - sleep(30 * 1000); - } - // Create CertInstallerHelper to initialize the keystore - mCertHelper = new CertInstallerHelper(); - } - - @Override - protected void tearDown() throws Exception { - sleep(VPN_STAY_TIME); - super.tearDown(); - } - - private void printVpnProfile(VpnProfile profile) { - Log.v(TAG, "profile: "); - Log.v(TAG, "key: " + profile.key); - Log.v(TAG, "name: " + profile.name); - Log.v(TAG, "type: " + profile.type); - Log.v(TAG, "server: " + profile.server); - Log.v(TAG, "username: " + profile.username); - Log.v(TAG, "password: " + profile.password); - Log.v(TAG, "dnsServers: " + profile.dnsServers); - Log.v(TAG, "searchDomains: " + profile.searchDomains); - Log.v(TAG, "routes: " + profile.routes); - Log.v(TAG, "mppe: " + profile.mppe); - Log.v(TAG, "l2tpSecret: " + profile.l2tpSecret); - Log.v(TAG, "ipsecIdentifier: " + profile.ipsecIdentifier); - Log.v(TAG, "ipsecSecret: " + profile.ipsecSecret); - Log.v(TAG, "ipsecUserCert: " + profile.ipsecUserCert); - Log.v(TAG, "ipsecCaCert: " + profile.ipsecCaCert); - Log.v(TAG, "ipsecServerCert: " + profile.ipsecServerCert); - } - - private void printKeyStore(VpnProfile profile) { - // print out the information from keystore - String privateKey = ""; - String userCert = ""; - String caCert = ""; - String serverCert = ""; - if (!profile.ipsecUserCert.isEmpty()) { - privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; - byte[] value = mKeyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert); - userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); - } - if (!profile.ipsecCaCert.isEmpty()) { - byte[] value = mKeyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert); - caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); - } - if (!profile.ipsecServerCert.isEmpty()) { - byte[] value = mKeyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert); - serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); - } - Log.v(TAG, "privateKey: \n" + ((privateKey == null) ? "" : privateKey)); - Log.v(TAG, "userCert: \n" + ((userCert == null) ? "" : userCert)); - Log.v(TAG, "caCert: \n" + ((caCert == null) ? "" : caCert)); - Log.v(TAG, "serverCert: \n" + ((serverCert == null) ? "" : serverCert)); - } - - /** - * Connect legacy VPN - */ - private void connect(VpnProfile profile) throws Exception { - try { - mService.startLegacyVpn(profile); - } catch (IllegalStateException e) { - fail(String.format("start legacy vpn: %s failed: %s", profile.name, e.toString())); - } - } - - /** - * Disconnect legacy VPN - */ - private void disconnect() throws Exception { - try { - mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, UserHandle.myUserId()); - } catch (RemoteException e) { - Log.e(TAG, String.format("disconnect VPN exception: %s", e.toString())); - } - } - - /** - * Get external IP address - */ - private String getIpAddress() { - String ip = null; - HttpURLConnection urlConnection = null; - // TODO: Rewrite this test to use an HTTPS URL. - // Because this test uses cleartext HTTP, the network security policy of this app needs to - // be temporarily relaxed to permit such traffic. - NetworkSecurityPolicy networkSecurityPolicy = NetworkSecurityPolicy.getInstance(); - boolean cleartextTrafficPermittedBeforeTest = - networkSecurityPolicy.isCleartextTrafficPermitted(); - networkSecurityPolicy.setCleartextTrafficPermitted(true); - try { - URL url = new URL(EXTERNAL_SERVER); - urlConnection = (HttpURLConnection) url.openConnection(); - Log.i(TAG, "Response from httpget: " + urlConnection.getResponseCode()); - - InputStream is = urlConnection.getInputStream(); - String response; - try { - response = new String(Streams.readFully(is), StandardCharsets.UTF_8); - } finally { - is.close(); - } - - JSONObject json_data = new JSONObject(response); - ip = json_data.getString("ip"); - Log.v(TAG, "json_data: " + ip); - } catch (IllegalArgumentException e) { - Log.e(TAG, "exception while getting external IP: " + e.toString()); - } catch (IOException e) { - Log.e(TAG, "IOException while getting IP: " + e.toString()); - } catch (JSONException e) { - Log.e(TAG, "exception while creating JSONObject: " + e.toString()); - } finally { - networkSecurityPolicy.setCleartextTrafficPermitted(cleartextTrafficPermittedBeforeTest); - if (urlConnection != null) { - urlConnection.disconnect(); - } - } - return ip; - } - - /** - * Verify the vpn connection by checking the VPN state and external IP - */ - private void validateVpnConnection(VpnProfile profile) throws Exception { - validateVpnConnection(profile, false); - } - - /** - * Verify the vpn connection by checking the VPN state, external IP or ping test - */ - private void validateVpnConnection(VpnProfile profile, boolean pingTestFlag) throws Exception { - LegacyVpnInfo legacyVpnInfo = mService.getLegacyVpnInfo(UserHandle.myUserId()); - Assert.assertTrue(legacyVpnInfo != null); - - long start = System.currentTimeMillis(); - while (((System.currentTimeMillis() - start) < MAX_CONNECTION_TIME) && - (legacyVpnInfo.state != LegacyVpnInfo.STATE_CONNECTED)) { - Log.v(TAG, "vpn state: " + legacyVpnInfo.state); - sleep(10 * 1000); - legacyVpnInfo = mService.getLegacyVpnInfo(UserHandle.myUserId()); - } - - // the vpn state should be CONNECTED - Assert.assertTrue(legacyVpnInfo.state == LegacyVpnInfo.STATE_CONNECTED); - if (pingTestFlag) { - Assert.assertTrue(pingTest(profile.server)); - } else { - String curIpAddress = getIpAddress(); - // the outgoing IP address should be the same as the VPN server address - Assert.assertEquals(profile.server, curIpAddress); - } - } - - private boolean pingTest(String server) { - final long PING_TIMER = 3 * 60 * 1000; // 3 minutes - if (server == null || server.isEmpty()) { - return false; - } - long startTime = System.currentTimeMillis(); - while ((System.currentTimeMillis() - startTime) < PING_TIMER) { - try { - Log.v(TAG, "Start ping test, ping " + server); - Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + server); - int status = p.waitFor(); - if (status == 0) { - // if any of the ping test is successful, return true - return true; - } - } catch (UnknownHostException e) { - Log.e(TAG, "Ping test Fail: Unknown Host"); - } catch (IOException e) { - Log.e(TAG, "Ping test Fail: IOException"); - } catch (InterruptedException e) { - Log.e(TAG, "Ping test Fail: InterruptedException"); - } - } - // ping test timeout - return false; - } - - /** - * Install certificates from a file loaded in external stroage on the device - * @param profile vpn profile - * @param fileName certificate file name - * @param password password to extract certificate file - */ - private void installCertificatesFromFile(VpnProfile profile, String fileName, String password) - throws Exception { - if (profile == null || fileName == null || password == null) { - throw new Exception ("vpn profile, certificate file name and password can not be null"); - } - - int curUid = mContext.getUserId(); - mCertHelper.installCertificate(profile, fileName, password); - - if (DEBUG) { - printKeyStore(profile); - } - } - - private void sleep(long time) { - try { - Thread.sleep(time); - } catch (InterruptedException e) { - Log.e(TAG, "interrupted: " + e.toString()); - } - } - - /** - * Test PPTP VPN connection - */ - @LargeTest - public void testPPTPConnection() throws Exception { - mPreviousIpAddress = getIpAddress(); - VpnInfo curVpnInfo = mVpnInfoPool.get(VpnProfile.TYPE_PPTP); - VpnProfile vpnProfile = curVpnInfo.getVpnProfile(); - connect(vpnProfile); - validateVpnConnection(vpnProfile); - } - - /** - * Test L2TP/IPSec PSK VPN connection - */ - @LargeTest - public void testL2tpIpsecPskConnection() throws Exception { - mPreviousIpAddress = getIpAddress(); - VpnInfo curVpnInfo = mVpnInfoPool.get(VpnProfile.TYPE_L2TP_IPSEC_PSK); - VpnProfile vpnProfile = curVpnInfo.getVpnProfile(); - connect(vpnProfile); - validateVpnConnection(vpnProfile); - } - - /** - * Test L2TP/IPSec RSA VPN connection - */ - @LargeTest - public void testL2tpIpsecRsaConnection() throws Exception { - mPreviousIpAddress = getIpAddress(); - VpnInfo curVpnInfo = mVpnInfoPool.get(VpnProfile.TYPE_L2TP_IPSEC_RSA); - VpnProfile vpnProfile = curVpnInfo.getVpnProfile(); - if (DEBUG) { - printVpnProfile(vpnProfile); - } - String certFile = curVpnInfo.getCertificateFile(); - String password = curVpnInfo.getPassword(); - installCertificatesFromFile(vpnProfile, certFile, password); - connect(vpnProfile); - validateVpnConnection(vpnProfile); - } - - /** - * Test IPSec Xauth RSA VPN connection - */ - @LargeTest - public void testIpsecXauthRsaConnection() throws Exception { - mPreviousIpAddress = getIpAddress(); - VpnInfo curVpnInfo = mVpnInfoPool.get(VpnProfile.TYPE_IPSEC_XAUTH_RSA); - VpnProfile vpnProfile = curVpnInfo.getVpnProfile(); - if (DEBUG) { - printVpnProfile(vpnProfile); - } - String certFile = curVpnInfo.getCertificateFile(); - String password = curVpnInfo.getPassword(); - installCertificatesFromFile(vpnProfile, certFile, password); - connect(vpnProfile); - validateVpnConnection(vpnProfile); - } - - /** - * Test IPSec Xauth PSK VPN connection - */ - @LargeTest - public void testIpsecXauthPskConnection() throws Exception { - VpnInfo curVpnInfo = mVpnInfoPool.get(VpnProfile.TYPE_IPSEC_XAUTH_PSK); - VpnProfile vpnProfile = curVpnInfo.getVpnProfile(); - if (DEBUG) { - printVpnProfile(vpnProfile); - } - connect(vpnProfile); - validateVpnConnection(vpnProfile, true); - } - - /** - * Test IPSec Hybrid RSA VPN connection - */ - @LargeTest - public void testIpsecHybridRsaConnection() throws Exception { - mPreviousIpAddress = getIpAddress(); - VpnInfo curVpnInfo = mVpnInfoPool.get(VpnProfile.TYPE_IPSEC_HYBRID_RSA); - VpnProfile vpnProfile = curVpnInfo.getVpnProfile(); - if (DEBUG) { - printVpnProfile(vpnProfile); - } - connect(vpnProfile); - validateVpnConnection(vpnProfile); - } -}