| #!/usr/bin/env python3.4 |
| # |
| # Copyright 2016 - 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. |
| |
| import pprint |
| import random |
| import time |
| |
| from acts import asserts |
| from acts import base_test |
| from acts import signals |
| from acts.test_utils.wifi import wifi_test_utils as wutils |
| |
| WifiEnums = wutils.WifiEnums |
| |
| # EAP Macros |
| EAP = WifiEnums.Eap |
| EapPhase2 = WifiEnums.EapPhase2 |
| # Enterprise Config Macros |
| Ent = WifiEnums.Enterprise |
| |
| class WifiEnterpriseTest(base_test.BaseTestClass): |
| |
| def __init__(self, controllers): |
| base_test.BaseTestClass.__init__(self, controllers) |
| self.tests = ( |
| "test_eap_connect", |
| "test_eap_connect_negative", |
| ) |
| |
| def setup_class(self): |
| self.dut = self.android_devices[0] |
| wutils.wifi_test_device_init(self.dut) |
| required_userparam_names = ( |
| "ca_cert", |
| "client_cert", |
| "client_key", |
| "passpoint_ca_cert", |
| "passpoint_client_cert", |
| "passpoint_client_key", |
| "eap_identity", |
| "eap_password", |
| "invalid_ca_cert", |
| "invalid_client_cert", |
| "invalid_client_key", |
| "fqdn", |
| "provider_friendly_name", |
| "realm", |
| "ssid_peap0", |
| "ssid_peap1", |
| "ssid_tls", |
| "ssid_ttls", |
| "ssid_pwd", |
| "ssid_sim", |
| "ssid_aka", |
| "ssid_aka_prime", |
| "ssid_passpoint", |
| "device_password", |
| "ping_addr" |
| ) |
| self.unpack_userparams(required_userparam_names, |
| roaming_consortium_ids=None, |
| plmn=None) |
| # Default configs for EAP networks. |
| self.config_peap0 = { |
| Ent.EAP: EAP.PEAP, |
| Ent.CA_CERT: self.ca_cert, |
| Ent.IDENTITY: self.eap_identity, |
| Ent.PASSWORD: self.eap_password, |
| Ent.PHASE2: EapPhase2.MSCHAPV2, |
| WifiEnums.SSID_KEY: self.ssid_peap0 |
| } |
| self.config_peap1 = dict(self.config_peap0) |
| self.config_peap1[WifiEnums.SSID_KEY] = self.ssid_peap1 |
| self.config_tls = { |
| Ent.EAP: EAP.TLS, |
| Ent.CA_CERT: self.ca_cert, |
| WifiEnums.SSID_KEY: self.ssid_tls, |
| Ent.CLIENT_CERT: self.client_cert, |
| Ent.PRIVATE_KEY_ID: self.client_key, |
| Ent.IDENTITY: self.eap_identity, |
| } |
| self.config_ttls = { |
| Ent.EAP: EAP.TTLS, |
| Ent.CA_CERT: self.ca_cert, |
| Ent.IDENTITY: self.eap_identity, |
| Ent.PASSWORD: self.eap_password, |
| Ent.PHASE2: EapPhase2.MSCHAPV2, |
| WifiEnums.SSID_KEY: self.ssid_ttls |
| } |
| self.config_pwd = { |
| Ent.EAP: EAP.PWD, |
| Ent.IDENTITY: self.eap_identity, |
| Ent.PASSWORD: self.eap_password, |
| WifiEnums.SSID_KEY: self.ssid_pwd |
| } |
| self.config_sim = { |
| Ent.EAP: EAP.SIM, |
| WifiEnums.SSID_KEY: self.ssid_sim, |
| } |
| self.config_aka = { |
| Ent.EAP: EAP.AKA, |
| WifiEnums.SSID_KEY: self.ssid_aka, |
| } |
| self.config_aka_prime = { |
| Ent.EAP: EAP.AKA_PRIME, |
| WifiEnums.SSID_KEY: self.ssid_aka_prime, |
| } |
| |
| # Base config for passpoint networks. |
| self.config_passpoint = { |
| Ent.FQDN: self.fqdn, |
| Ent.FRIENDLY_NAME: self.provider_friendly_name, |
| Ent.REALM: self.realm, |
| Ent.CA_CERT: self.passpoint_ca_cert |
| } |
| if self.plmn: |
| self.config_passpoint[Ent.PLMN] = self.plmn |
| if self.roaming_consortium_ids: |
| self.config_passpoint[Ent.ROAMING_IDS] = self.roaming_consortium_ids |
| |
| # Default configs for passpoint networks. |
| self.config_passpoint_tls = dict(self.config_tls) |
| self.config_passpoint_tls.update(self.config_passpoint) |
| self.config_passpoint_tls[Ent.CLIENT_CERT] = self.passpoint_client_cert |
| self.config_passpoint_tls[Ent.PRIVATE_KEY_ID] = self.passpoint_client_key |
| del self.config_passpoint_tls[WifiEnums.SSID_KEY] |
| self.config_passpoint_ttls = dict(self.config_ttls) |
| self.config_passpoint_ttls.update(self.config_passpoint) |
| del self.config_passpoint_ttls[WifiEnums.SSID_KEY] |
| # Set screen lock password so ConfigStore is unlocked. |
| self.dut.droid.setDevicePassword(self.device_password) |
| |
| def teardown_class(self): |
| wutils.reset_wifi(self.dut) |
| self.dut.droid.disableDevicePassword() |
| self.dut.ed.clear_all_events() |
| |
| def setup_test(self): |
| self.dut.droid.wifiStartTrackingStateChange() |
| self.dut.droid.wakeLockAcquireBright() |
| self.dut.droid.wakeUpNow() |
| wutils.reset_wifi(self.dut) |
| self.dut.ed.clear_all_events() |
| |
| def teardown_test(self): |
| self.dut.droid.wakeLockRelease() |
| self.dut.droid.goToSleepNow() |
| self.dut.droid.wifiStopTrackingStateChange() |
| |
| def on_fail(self, test_name, begin_time): |
| self.dut.cat_adb_log(test_name, begin_time) |
| |
| """Helper Functions""" |
| |
| def eap_negative_connect_logic(self, config, ad): |
| """Tries to connect to an enterprise network with invalid credentials |
| and expect a failure. |
| |
| Args: |
| config: A dict representing an invalid EAP credential. |
| |
| Returns: |
| True if connection failed as expected, False otherwise. |
| """ |
| with asserts.assert_raises(signals.TestFailure, extras=config): |
| verdict = wutils.eap_connect(config, ad) |
| asserts.explicit_pass("Connection failed as expected.") |
| |
| def expand_config_by_phase2(self, config): |
| """Take an enterprise config and generate a list of configs, each with |
| a different phase2 auth type. |
| |
| Args: |
| config: A dict representing enterprise config. |
| |
| Returns |
| A list of enterprise configs. |
| """ |
| results = [] |
| for phase2_type in EapPhase2: |
| # Skip a special case for passpoint TTLS. |
| if Ent.FQDN in config and phase2_type == EapPhase2.GTC: |
| continue |
| c = dict(config) |
| c[Ent.PHASE2] = phase2_type |
| results.append(c) |
| return results |
| |
| def gen_eap_configs(self): |
| """Generates configurations for different EAP authentication types. |
| |
| Returns: |
| A list of dicts each representing an EAP configuration. |
| """ |
| configs = [self.config_tls, |
| self.config_pwd, |
| self.config_sim, |
| self.config_aka, |
| self.config_aka_prime] |
| configs += wutils.expand_enterprise_config_by_phase2(self.config_ttls) |
| configs += wutils.expand_enterprise_config_by_phase2(self.config_peap0) |
| configs += wutils.expand_enterprise_config_by_phase2(self.config_peap1) |
| return configs |
| |
| def gen_passpoint_configs(self): |
| """Generates passpoint configurations for different EAP authentication |
| types. |
| |
| Returns: |
| A list of dicts each representing an EAP configuration for |
| passpoint networks. |
| """ |
| configs = [self.config_passpoint_tls] |
| configs += wutils.expand_enterprise_config_by_phase2(self.config_passpoint_ttls) |
| return configs |
| |
| def gen_negative_configs(self, configs, neg_params): |
| """Generic function used to generate negative configs. |
| |
| For all the valid configurations, if a param in the neg_params also |
| exists in a config, a copy of the config is made with an invalid value |
| of the param. |
| |
| Args: |
| configs: A list of valid configurations. |
| neg_params: A dict that has all the invalid values. |
| |
| Returns: |
| A list of invalid configurations generated based on the valid |
| configurations. Each invalid configuration has a different invalid |
| field. |
| """ |
| results = [] |
| for c in configs: |
| for k, v in neg_params.items(): |
| # Skip negative test for TLS's identity field since it's not |
| # used for auth. |
| if c[Ent.EAP] == EAP.TLS and k == Ent.IDENTITY: |
| continue |
| if k in c: |
| nc = dict(c) |
| nc[k] = v |
| nc["invalid_field"] = k |
| results.append(nc) |
| return results |
| |
| def gen_negative_eap_configs(self): |
| """Generates invalid configurations for different EAP authentication |
| types. |
| |
| For all the valid EAP configurations, if a param that is part of the |
| authentication info exists in a config, a copy of the config is made |
| with an invalid value of the param. |
| |
| Returns: |
| A list of dicts each representing an invalid EAP configuration. |
| """ |
| neg_params = { |
| Ent.CLIENT_CERT: self.invalid_client_cert, |
| Ent.CA_CERT: self.invalid_ca_cert, |
| Ent.PRIVATE_KEY_ID: self.invalid_client_key, |
| Ent.IDENTITY: "fake_identity", |
| Ent.PASSWORD: "wrong_password" |
| } |
| configs = self.gen_eap_configs() |
| return self.gen_negative_configs(configs, neg_params) |
| |
| def gen_negative_passpoint_configs(self): |
| """Generates invalid configurations for different EAP authentication |
| types with passpoint support. |
| |
| Returns: |
| A list of dicts each representing an invalid EAP configuration |
| with passpoint fields. |
| """ |
| neg_params = { |
| Ent.CLIENT_CERT: self.invalid_client_cert, |
| Ent.CA_CERT: self.invalid_ca_cert, |
| Ent.PRIVATE_KEY_ID: self.invalid_client_key, |
| Ent.IDENTITY: "fake_identity", |
| Ent.PASSWORD: "wrong_password", |
| Ent.FQDN: "fake_fqdn", |
| Ent.REALM: "where_no_one_has_gone_before", |
| Ent.PLMN: "fake_plmn", |
| Ent.ROAMING_IDS: [1234567890, 9876543210] |
| } |
| configs = self.gen_passpoint_configs() |
| return self.gen_negative_configs(configs, neg_params) |
| |
| def gen_eap_test_name(self, config, ad): |
| """Generates a test case name based on an EAP configuration. |
| |
| Args: |
| config: A dict representing an EAP credential. |
| ad: Discarded. This is here because name function signature needs |
| to be consistent with logic function signature for generated |
| test cases. |
| |
| Returns: |
| A string representing the name of a generated EAP test case. |
| """ |
| eap_name = config[Ent.EAP].name |
| if "peap0" in config[WifiEnums.SSID_KEY].lower(): |
| eap_name = "PEAP0" |
| if "peap1" in config[WifiEnums.SSID_KEY].lower(): |
| eap_name = "PEAP1" |
| name = "test_connect-%s" % eap_name |
| if Ent.PHASE2 in config: |
| name += "-{}".format(config[Ent.PHASE2].name) |
| return name |
| |
| def gen_passpoint_test_name(self, config, ad): |
| """Generates a test case name based on an EAP passpoint configuration. |
| |
| Args: |
| config: A dict representing an EAP passpoint credential. |
| ad: Discarded. This is here because name function signature needs |
| to be consistent with logic function signature for generated |
| test cases. |
| |
| Returns: |
| A string representing the name of a generated EAP passpoint connect |
| test case. |
| """ |
| name = self.gen_eap_test_name(config, ad) |
| name = name.replace("connect", "passpoint_connect") |
| return name |
| |
| """Tests""" |
| @signals.generated_test |
| def test_eap_connect(self): |
| """Test connecting to enterprise networks of different authentication |
| types. |
| |
| The authentication types tested are: |
| EAP-TLS |
| EAP-PEAP with different phase2 types. |
| EAP-TTLS with different phase2 types. |
| |
| Procedures: |
| For each enterprise wifi network |
| 1. Connect to the network. |
| 2. Send a GET request to a website and check response. |
| |
| Expect: |
| Successful connection and Internet access through the enterprise |
| networks. |
| """ |
| eap_configs = self.gen_eap_configs() |
| self.log.info("Testing %d different configs." % len(eap_configs)) |
| random.shuffle(eap_configs) |
| failed = self.run_generated_testcases( |
| wutils.eap_connect, |
| eap_configs, |
| args=(self.dut,), |
| name_func=self.gen_eap_test_name) |
| msg = ("The following configs failed EAP connect test: %s" % |
| pprint.pformat(failed)) |
| asserts.assert_equal(len(failed), 0, msg) |
| |
| @signals.generated_test |
| def test_eap_connect_negative(self): |
| """Test connecting to enterprise networks. |
| |
| Procedures: |
| For each enterprise wifi network |
| 1. Connect to the network with invalid credentials. |
| |
| Expect: |
| Fail to establish connection. |
| """ |
| neg_eap_configs = self.gen_negative_eap_configs() |
| self.log.info("Testing %d different configs." % len(neg_eap_configs)) |
| random.shuffle(neg_eap_configs) |
| def name_gen(config, ad): |
| name = self.gen_eap_test_name(config, ad) |
| name += "-with_wrong-{}".format(config["invalid_field"]) |
| return name |
| failed = self.run_generated_testcases( |
| self.eap_negative_connect_logic, |
| neg_eap_configs, |
| args=(self.dut,), |
| name_func=name_gen) |
| msg = ("The following configs failed negative EAP connect test: %s" % |
| pprint.pformat(failed)) |
| asserts.assert_equal(len(failed), 0, msg) |
| |
| @signals.generated_test |
| def test_passpoint_connect(self): |
| """Test connecting to enterprise networks of different authentication |
| types with passpoint support. |
| |
| The authentication types tested are: |
| EAP-TLS |
| EAP-TTLS with MSCHAPV2 as phase2. |
| |
| Procedures: |
| For each enterprise wifi network |
| 1. Connect to the network. |
| 2. Send a GET request to a website and check response. |
| |
| Expect: |
| Successful connection and Internet access through the enterprise |
| networks with passpoint support. |
| """ |
| asserts.skip_if(not self.dut.droid.wifiIsPasspointSupported(), |
| "Passpoint is not supported on device %s" % self.dut.model) |
| passpoint_configs = self.gen_passpoint_configs() |
| self.log.info("Testing %d different configs." % len(passpoint_configs)) |
| random.shuffle(passpoint_configs) |
| failed = self.run_generated_testcases( |
| wutils.eap_connect, |
| passpoint_configs, |
| args=(self.dut,), |
| name_func=self.gen_passpoint_test_name) |
| msg = ("The following configs failed passpoint connect test: %s" % |
| pprint.pformat(failed)) |
| asserts.assert_equal(len(failed), 0, msg) |
| |
| @signals.generated_test |
| def test_passpoint_connect_negative(self): |
| """Test connecting to enterprise networks. |
| |
| Procedures: |
| For each enterprise wifi network |
| 1. Connect to the network with invalid credentials. |
| |
| Expect: |
| Fail to establish connection. |
| """ |
| asserts.skip_if(not self.dut.droid.wifiIsPasspointSupported(), |
| "Passpoint is not supported on device %s" % self.dut.model) |
| neg_passpoint_configs = self.gen_negative_passpoint_configs() |
| self.log.info("Testing %d different configs." % len(neg_passpoint_configs)) |
| random.shuffle(neg_passpoint_configs) |
| def name_gen(config, ad): |
| name = self.gen_passpoint_test_name(config, ad) |
| name += "-with_wrong-{}".format(config["invalid_field"]) |
| return name |
| failed = self.run_generated_testcases( |
| self.eap_negative_connect_logic, |
| neg_passpoint_configs, |
| args=(self.dut,), |
| name_func=name_gen) |
| msg = ("The following configs failed negative passpoint connect test: " |
| "%s") % pprint.pformat(failed) |
| asserts.assert_equal(len(failed), 0, msg) |