summaryrefslogtreecommitdiffstats
path: root/tests/src/com/android/settings/vpn2/VpnTests.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/com/android/settings/vpn2/VpnTests.java')
-rw-r--r--tests/src/com/android/settings/vpn2/VpnTests.java420
1 files changed, 420 insertions, 0 deletions
diff --git a/tests/src/com/android/settings/vpn2/VpnTests.java b/tests/src/com/android/settings/vpn2/VpnTests.java
new file mode 100644
index 0000000..2c6963a
--- /dev/null
+++ b/tests/src/com/android/settings/vpn2/VpnTests.java
@@ -0,0 +1,420 @@
+/*
+ * 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.net.LinkAddress;
+import android.net.RouteInfo;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.security.Credentials;
+import android.security.KeyStore;
+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 junit.framework.Assert;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+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>
+ * <name></name>
+ * <type></type>
+ * <server></server>
+ * <username></username>
+ * <password></password>
+ * <dnsServers></dnsServers>
+ * <searchDomains></searchDomains>
+ * <routes></routes>
+ * <l2tpSecret></l2tpSecret>
+ * <ipsecIdentifier></ipsecIdentifier>
+ * <ipsecSecret></ipsecSecret>
+ * <ipsecUserCert></ipsecUserCert>
+ * <ipsecCaCert></ipsecCaCert>
+ * <ipsecServerCert></ipsecServerCert>
+ * </vpn>
+ * 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 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<Integer, VpnInfo> 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 <filename>'", 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<Integer, VpnInfo> 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();
+ 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() != null) {
+ tries++;
+ Thread.sleep(10 * 1000);
+ Log.v(TAG, "Wait for legacy VPN to be disconnected.");
+ }
+ Assert.assertNull("Failed to disconect VPN", mService.getLegacyVpnInfo());
+ // wait for 30 seconds after the previous VPN is disconnected.
+ sleep(30 * 1000);
+ }
+ // Create CertInstallerHelper to initialize the keystore
+ mCertHelper = new CertInstallerHelper();
+ }
+
+ 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);
+ } catch (RemoteException e) {
+ Log.e(TAG, String.format("disconnect VPN exception: %s", e.toString()));
+ }
+ }
+
+ /**
+ * Get external IP address
+ */
+ private String getIpAddress() {
+ String ip = null;
+ try {
+ HttpClient httpClient = new DefaultHttpClient();
+ HttpGet httpGet = new HttpGet(EXTERNAL_SERVER);
+ HttpResponse httpResponse = httpClient.execute(httpGet);
+ Log.i(TAG, "Response from httpget: " + httpResponse.getStatusLine().toString());
+
+ String entityStr = EntityUtils.toString(httpResponse.getEntity());
+ JSONObject json_data = new JSONObject(entityStr);
+ 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());
+ }
+ 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();
+ 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();
+ }
+
+ // 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);
+ }
+}