blob: eba2dffaa44b7a236a8410201c7912ff5246111a [file] [log] [blame]
tturney1bdf77d2015-12-28 17:46:13 -08001#!/usr/bin/env python3.4
Ang Li73697b32015-12-03 00:41:53 +00002#
tturney1bdf77d2015-12-28 17:46:13 -08003# Copyright 2016 - The Android Open Source Project
Ang Li73697b32015-12-03 00:41:53 +00004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import pprint
Ang Li8e767182015-12-09 17:29:24 -080018import random
Ang Li73697b32015-12-03 00:41:53 +000019import time
20
Ang Lic2d45212016-03-10 18:38:53 -080021from acts import asserts
Ang Li82522812016-06-02 13:57:21 -070022from acts import base_test
23from acts import signals
24from acts.test_utils.wifi import wifi_test_utils as wutils
Ang Lic2d45212016-03-10 18:38:53 -080025
Ang Lie8ed2b32015-12-11 12:30:20 -080026WifiEnums = wutils.WifiEnums
Ang Li73697b32015-12-03 00:41:53 +000027
28# EAP Macros
29EAP = WifiEnums.Eap
30EapPhase2 = WifiEnums.EapPhase2
Ang Li73697b32015-12-03 00:41:53 +000031# Enterprise Config Macros
32Ent = WifiEnums.Enterprise
Ang Li73697b32015-12-03 00:41:53 +000033
Ang Li73697b32015-12-03 00:41:53 +000034
Ang Li81549052016-06-09 18:51:14 -070035class WifiEnterpriseTest(base_test.BaseTestClass):
Ang Li73697b32015-12-03 00:41:53 +000036 def __init__(self, controllers):
Ang Li82522812016-06-02 13:57:21 -070037 base_test.BaseTestClass.__init__(self, controllers)
Ang Li81549052016-06-09 18:51:14 -070038 self.tests = ("test_eap_connect", "test_eap_connect_negative", )
Ang Li73697b32015-12-03 00:41:53 +000039
40 def setup_class(self):
41 self.dut = self.android_devices[0]
Ang Li8e767182015-12-09 17:29:24 -080042 wutils.wifi_test_device_init(self.dut)
Ang Li81549052016-06-09 18:51:14 -070043 # If running in a setup with attenuators, set attenuation on all
44 # channels to zero.
45 if getattr(self, "attenuators", []):
46 for a in self.attenuators:
47 a.set_atten(0)
Ang Li73697b32015-12-03 00:41:53 +000048 required_userparam_names = (
Ang Li81549052016-06-09 18:51:14 -070049 "ca_cert", "client_cert", "client_key", "passpoint_ca_cert",
50 "passpoint_client_cert", "passpoint_client_key", "eap_identity",
51 "eap_password", "invalid_ca_cert", "invalid_client_cert",
52 "invalid_client_key", "fqdn", "provider_friendly_name", "realm",
53 "ssid_peap0", "ssid_peap1", "ssid_tls", "ssid_ttls", "ssid_pwd",
54 "ssid_sim", "ssid_aka", "ssid_aka_prime", "ssid_passpoint",
55 "device_password", "ping_addr")
Ang Li5cd6d3c2016-02-01 11:29:14 -080056 self.unpack_userparams(required_userparam_names,
Ang Li82522812016-06-02 13:57:21 -070057 roaming_consortium_ids=None,
58 plmn=None)
Ang Li73697b32015-12-03 00:41:53 +000059 # Default configs for EAP networks.
Ang Li82522812016-06-02 13:57:21 -070060 self.config_peap0 = {
Ang Li73697b32015-12-03 00:41:53 +000061 Ent.EAP: EAP.PEAP,
62 Ent.CA_CERT: self.ca_cert,
63 Ent.IDENTITY: self.eap_identity,
64 Ent.PASSWORD: self.eap_password,
65 Ent.PHASE2: EapPhase2.MSCHAPV2,
Ang Li82522812016-06-02 13:57:21 -070066 WifiEnums.SSID_KEY: self.ssid_peap0
Ang Li73697b32015-12-03 00:41:53 +000067 }
Ang Li82522812016-06-02 13:57:21 -070068 self.config_peap1 = dict(self.config_peap0)
69 self.config_peap1[WifiEnums.SSID_KEY] = self.ssid_peap1
Ang Li73697b32015-12-03 00:41:53 +000070 self.config_tls = {
71 Ent.EAP: EAP.TLS,
72 Ent.CA_CERT: self.ca_cert,
73 WifiEnums.SSID_KEY: self.ssid_tls,
74 Ent.CLIENT_CERT: self.client_cert,
75 Ent.PRIVATE_KEY_ID: self.client_key,
76 Ent.IDENTITY: self.eap_identity,
77 }
78 self.config_ttls = {
79 Ent.EAP: EAP.TTLS,
80 Ent.CA_CERT: self.ca_cert,
81 Ent.IDENTITY: self.eap_identity,
82 Ent.PASSWORD: self.eap_password,
83 Ent.PHASE2: EapPhase2.MSCHAPV2,
84 WifiEnums.SSID_KEY: self.ssid_ttls
85 }
Ang Li82522812016-06-02 13:57:21 -070086 self.config_pwd = {
87 Ent.EAP: EAP.PWD,
88 Ent.IDENTITY: self.eap_identity,
89 Ent.PASSWORD: self.eap_password,
90 WifiEnums.SSID_KEY: self.ssid_pwd
91 }
Ang Li73697b32015-12-03 00:41:53 +000092 self.config_sim = {
93 Ent.EAP: EAP.SIM,
94 WifiEnums.SSID_KEY: self.ssid_sim,
95 }
Ang Li82522812016-06-02 13:57:21 -070096 self.config_aka = {
97 Ent.EAP: EAP.AKA,
98 WifiEnums.SSID_KEY: self.ssid_aka,
99 }
100 self.config_aka_prime = {
101 Ent.EAP: EAP.AKA_PRIME,
102 WifiEnums.SSID_KEY: self.ssid_aka_prime,
103 }
Ang Li73697b32015-12-03 00:41:53 +0000104
105 # Base config for passpoint networks.
106 self.config_passpoint = {
107 Ent.FQDN: self.fqdn,
108 Ent.FRIENDLY_NAME: self.provider_friendly_name,
109 Ent.REALM: self.realm,
110 Ent.CA_CERT: self.passpoint_ca_cert
111 }
Ang Li82522812016-06-02 13:57:21 -0700112 if self.plmn:
Ang Li73697b32015-12-03 00:41:53 +0000113 self.config_passpoint[Ent.PLMN] = self.plmn
Ang Li82522812016-06-02 13:57:21 -0700114 if self.roaming_consortium_ids:
Ang Li81549052016-06-09 18:51:14 -0700115 self.config_passpoint[
116 Ent.ROAMING_IDS] = self.roaming_consortium_ids
Ang Li73697b32015-12-03 00:41:53 +0000117
118 # Default configs for passpoint networks.
119 self.config_passpoint_tls = dict(self.config_tls)
120 self.config_passpoint_tls.update(self.config_passpoint)
121 self.config_passpoint_tls[Ent.CLIENT_CERT] = self.passpoint_client_cert
Ang Li81549052016-06-09 18:51:14 -0700122 self.config_passpoint_tls[
123 Ent.PRIVATE_KEY_ID] = self.passpoint_client_key
Ang Li73697b32015-12-03 00:41:53 +0000124 del self.config_passpoint_tls[WifiEnums.SSID_KEY]
125 self.config_passpoint_ttls = dict(self.config_ttls)
126 self.config_passpoint_ttls.update(self.config_passpoint)
127 del self.config_passpoint_ttls[WifiEnums.SSID_KEY]
128 # Set screen lock password so ConfigStore is unlocked.
Ang Lia9d188f2016-02-17 18:03:01 -0800129 self.dut.droid.setDevicePassword(self.device_password)
Ang Li73697b32015-12-03 00:41:53 +0000130
131 def teardown_class(self):
Ang Li8e767182015-12-09 17:29:24 -0800132 wutils.reset_wifi(self.dut)
Ang Lia9d188f2016-02-17 18:03:01 -0800133 self.dut.droid.disableDevicePassword()
134 self.dut.ed.clear_all_events()
Ang Li73697b32015-12-03 00:41:53 +0000135
136 def setup_test(self):
Ang Lia9d188f2016-02-17 18:03:01 -0800137 self.dut.droid.wifiStartTrackingStateChange()
138 self.dut.droid.wakeLockAcquireBright()
139 self.dut.droid.wakeUpNow()
Ang Li8e767182015-12-09 17:29:24 -0800140 wutils.reset_wifi(self.dut)
Ang Lia9d188f2016-02-17 18:03:01 -0800141 self.dut.ed.clear_all_events()
Ang Li73697b32015-12-03 00:41:53 +0000142
143 def teardown_test(self):
Ang Lia9d188f2016-02-17 18:03:01 -0800144 self.dut.droid.wakeLockRelease()
145 self.dut.droid.goToSleepNow()
146 self.dut.droid.wifiStopTrackingStateChange()
Ang Li73697b32015-12-03 00:41:53 +0000147
Ang Li20377aa2016-02-26 13:19:51 -0800148 def on_fail(self, test_name, begin_time):
149 self.dut.cat_adb_log(test_name, begin_time)
150
Ang Li73697b32015-12-03 00:41:53 +0000151 """Helper Functions"""
152
153 def eap_negative_connect_logic(self, config, ad):
154 """Tries to connect to an enterprise network with invalid credentials
155 and expect a failure.
156
157 Args:
158 config: A dict representing an invalid EAP credential.
159
160 Returns:
161 True if connection failed as expected, False otherwise.
162 """
Ang Li82522812016-06-02 13:57:21 -0700163 with asserts.assert_raises(signals.TestFailure, extras=config):
164 verdict = wutils.eap_connect(config, ad)
165 asserts.explicit_pass("Connection failed as expected.")
Ang Li73697b32015-12-03 00:41:53 +0000166
167 def expand_config_by_phase2(self, config):
168 """Take an enterprise config and generate a list of configs, each with
169 a different phase2 auth type.
170
171 Args:
172 config: A dict representing enterprise config.
173
174 Returns
175 A list of enterprise configs.
176 """
177 results = []
178 for phase2_type in EapPhase2:
179 # Skip a special case for passpoint TTLS.
180 if Ent.FQDN in config and phase2_type == EapPhase2.GTC:
181 continue
182 c = dict(config)
183 c[Ent.PHASE2] = phase2_type
184 results.append(c)
185 return results
186
187 def gen_eap_configs(self):
188 """Generates configurations for different EAP authentication types.
189
190 Returns:
191 A list of dicts each representing an EAP configuration.
192 """
Ang Li81549052016-06-09 18:51:14 -0700193 configs = [self.config_tls, self.config_pwd, self.config_sim,
194 self.config_aka, self.config_aka_prime]
Ang Li8e767182015-12-09 17:29:24 -0800195 configs += wutils.expand_enterprise_config_by_phase2(self.config_ttls)
Ang Li82522812016-06-02 13:57:21 -0700196 configs += wutils.expand_enterprise_config_by_phase2(self.config_peap0)
197 configs += wutils.expand_enterprise_config_by_phase2(self.config_peap1)
Ang Li73697b32015-12-03 00:41:53 +0000198 return configs
199
200 def gen_passpoint_configs(self):
201 """Generates passpoint configurations for different EAP authentication
202 types.
203
204 Returns:
205 A list of dicts each representing an EAP configuration for
206 passpoint networks.
207 """
208 configs = [self.config_passpoint_tls]
Ang Li81549052016-06-09 18:51:14 -0700209 configs += wutils.expand_enterprise_config_by_phase2(
210 self.config_passpoint_ttls)
Ang Li73697b32015-12-03 00:41:53 +0000211 return configs
212
213 def gen_negative_configs(self, configs, neg_params):
214 """Generic function used to generate negative configs.
215
216 For all the valid configurations, if a param in the neg_params also
217 exists in a config, a copy of the config is made with an invalid value
218 of the param.
219
220 Args:
221 configs: A list of valid configurations.
222 neg_params: A dict that has all the invalid values.
223
224 Returns:
225 A list of invalid configurations generated based on the valid
226 configurations. Each invalid configuration has a different invalid
227 field.
228 """
229 results = []
230 for c in configs:
231 for k, v in neg_params.items():
232 # Skip negative test for TLS's identity field since it's not
233 # used for auth.
234 if c[Ent.EAP] == EAP.TLS and k == Ent.IDENTITY:
235 continue
236 if k in c:
237 nc = dict(c)
238 nc[k] = v
239 nc["invalid_field"] = k
240 results.append(nc)
241 return results
242
243 def gen_negative_eap_configs(self):
244 """Generates invalid configurations for different EAP authentication
245 types.
246
247 For all the valid EAP configurations, if a param that is part of the
248 authentication info exists in a config, a copy of the config is made
249 with an invalid value of the param.
250
251 Returns:
252 A list of dicts each representing an invalid EAP configuration.
253 """
254 neg_params = {
255 Ent.CLIENT_CERT: self.invalid_client_cert,
256 Ent.CA_CERT: self.invalid_ca_cert,
257 Ent.PRIVATE_KEY_ID: self.invalid_client_key,
258 Ent.IDENTITY: "fake_identity",
259 Ent.PASSWORD: "wrong_password"
260 }
261 configs = self.gen_eap_configs()
262 return self.gen_negative_configs(configs, neg_params)
263
264 def gen_negative_passpoint_configs(self):
265 """Generates invalid configurations for different EAP authentication
266 types with passpoint support.
267
268 Returns:
269 A list of dicts each representing an invalid EAP configuration
270 with passpoint fields.
271 """
272 neg_params = {
273 Ent.CLIENT_CERT: self.invalid_client_cert,
274 Ent.CA_CERT: self.invalid_ca_cert,
275 Ent.PRIVATE_KEY_ID: self.invalid_client_key,
276 Ent.IDENTITY: "fake_identity",
277 Ent.PASSWORD: "wrong_password",
278 Ent.FQDN: "fake_fqdn",
279 Ent.REALM: "where_no_one_has_gone_before",
280 Ent.PLMN: "fake_plmn",
281 Ent.ROAMING_IDS: [1234567890, 9876543210]
282 }
283 configs = self.gen_passpoint_configs()
284 return self.gen_negative_configs(configs, neg_params)
285
286 def gen_eap_test_name(self, config, ad):
287 """Generates a test case name based on an EAP configuration.
288
289 Args:
290 config: A dict representing an EAP credential.
291 ad: Discarded. This is here because name function signature needs
292 to be consistent with logic function signature for generated
293 test cases.
294
295 Returns:
296 A string representing the name of a generated EAP test case.
297 """
Ang Li82522812016-06-02 13:57:21 -0700298 eap_name = config[Ent.EAP].name
299 if "peap0" in config[WifiEnums.SSID_KEY].lower():
300 eap_name = "PEAP0"
301 if "peap1" in config[WifiEnums.SSID_KEY].lower():
302 eap_name = "PEAP1"
303 name = "test_connect-%s" % eap_name
Ang Li73697b32015-12-03 00:41:53 +0000304 if Ent.PHASE2 in config:
305 name += "-{}".format(config[Ent.PHASE2].name)
306 return name
307
308 def gen_passpoint_test_name(self, config, ad):
309 """Generates a test case name based on an EAP passpoint configuration.
310
311 Args:
312 config: A dict representing an EAP passpoint credential.
313 ad: Discarded. This is here because name function signature needs
314 to be consistent with logic function signature for generated
315 test cases.
316
317 Returns:
318 A string representing the name of a generated EAP passpoint connect
319 test case.
320 """
321 name = self.gen_eap_test_name(config, ad)
322 name = name.replace("connect", "passpoint_connect")
323 return name
324
325 """Tests"""
Ang Li81549052016-06-09 18:51:14 -0700326
Ang Li82522812016-06-02 13:57:21 -0700327 @signals.generated_test
Ang Li73697b32015-12-03 00:41:53 +0000328 def test_eap_connect(self):
329 """Test connecting to enterprise networks of different authentication
330 types.
331
332 The authentication types tested are:
333 EAP-TLS
334 EAP-PEAP with different phase2 types.
335 EAP-TTLS with different phase2 types.
336
337 Procedures:
338 For each enterprise wifi network
339 1. Connect to the network.
340 2. Send a GET request to a website and check response.
341
342 Expect:
343 Successful connection and Internet access through the enterprise
344 networks.
345 """
346 eap_configs = self.gen_eap_configs()
Ang Li81549052016-06-09 18:51:14 -0700347 self.log.info("Testing %d different configs.", len(eap_configs))
Ang Li8e767182015-12-09 17:29:24 -0800348 random.shuffle(eap_configs)
Ang Li81549052016-06-09 18:51:14 -0700349 failed = self.run_generated_testcases(wutils.eap_connect,
350 eap_configs,
351 args=(self.dut, ),
352 name_func=self.gen_eap_test_name)
353 asserts.assert_equal(
354 len(failed), 0, "The following configs failed EAP connect test: %s"
355 % pprint.pformat(failed))
Ang Li73697b32015-12-03 00:41:53 +0000356
Ang Li82522812016-06-02 13:57:21 -0700357 @signals.generated_test
Ang Li73697b32015-12-03 00:41:53 +0000358 def test_eap_connect_negative(self):
359 """Test connecting to enterprise networks.
360
361 Procedures:
362 For each enterprise wifi network
363 1. Connect to the network with invalid credentials.
364
365 Expect:
366 Fail to establish connection.
367 """
368 neg_eap_configs = self.gen_negative_eap_configs()
Ang Li81549052016-06-09 18:51:14 -0700369 self.log.info("Testing %d different configs.", len(neg_eap_configs))
Ang Li8e767182015-12-09 17:29:24 -0800370 random.shuffle(neg_eap_configs)
Ang Li81549052016-06-09 18:51:14 -0700371
Ang Li73697b32015-12-03 00:41:53 +0000372 def name_gen(config, ad):
373 name = self.gen_eap_test_name(config, ad)
374 name += "-with_wrong-{}".format(config["invalid_field"])
375 return name
Ang Li81549052016-06-09 18:51:14 -0700376
377 failed = self.run_generated_testcases(self.eap_negative_connect_logic,
378 neg_eap_configs,
379 args=(self.dut, ),
380 name_func=name_gen)
Ang Li73697b32015-12-03 00:41:53 +0000381 msg = ("The following configs failed negative EAP connect test: %s" %
382 pprint.pformat(failed))
Ang Li82522812016-06-02 13:57:21 -0700383 asserts.assert_equal(len(failed), 0, msg)
Ang Li73697b32015-12-03 00:41:53 +0000384
Ang Li82522812016-06-02 13:57:21 -0700385 @signals.generated_test
Ang Li73697b32015-12-03 00:41:53 +0000386 def test_passpoint_connect(self):
387 """Test connecting to enterprise networks of different authentication
388 types with passpoint support.
389
390 The authentication types tested are:
391 EAP-TLS
392 EAP-TTLS with MSCHAPV2 as phase2.
393
394 Procedures:
395 For each enterprise wifi network
396 1. Connect to the network.
397 2. Send a GET request to a website and check response.
398
399 Expect:
400 Successful connection and Internet access through the enterprise
401 networks with passpoint support.
402 """
Ang Lic2d45212016-03-10 18:38:53 -0800403 asserts.skip_if(not self.dut.droid.wifiIsPasspointSupported(),
Ang Li81549052016-06-09 18:51:14 -0700404 "Passpoint is not supported on device %s" %
405 self.dut.model)
Ang Li73697b32015-12-03 00:41:53 +0000406 passpoint_configs = self.gen_passpoint_configs()
Ang Li81549052016-06-09 18:51:14 -0700407 self.log.info("Testing %d different configs.", len(passpoint_configs))
Ang Li8e767182015-12-09 17:29:24 -0800408 random.shuffle(passpoint_configs)
Ang Li73697b32015-12-03 00:41:53 +0000409 failed = self.run_generated_testcases(
Ang Li8e767182015-12-09 17:29:24 -0800410 wutils.eap_connect,
Ang Li73697b32015-12-03 00:41:53 +0000411 passpoint_configs,
Ang Li81549052016-06-09 18:51:14 -0700412 args=(self.dut, ),
Ang Li73697b32015-12-03 00:41:53 +0000413 name_func=self.gen_passpoint_test_name)
Ang Li81549052016-06-09 18:51:14 -0700414 asserts.assert_equal(
415 len(failed), 0,
416 "The following configs failed passpoint connect test: %s" %
417 pprint.pformat(failed))
Ang Li73697b32015-12-03 00:41:53 +0000418
Ang Li82522812016-06-02 13:57:21 -0700419 @signals.generated_test
Ang Li73697b32015-12-03 00:41:53 +0000420 def test_passpoint_connect_negative(self):
421 """Test connecting to enterprise networks.
422
423 Procedures:
424 For each enterprise wifi network
425 1. Connect to the network with invalid credentials.
426
427 Expect:
428 Fail to establish connection.
429 """
Ang Lic2d45212016-03-10 18:38:53 -0800430 asserts.skip_if(not self.dut.droid.wifiIsPasspointSupported(),
Ang Li81549052016-06-09 18:51:14 -0700431 "Passpoint is not supported on device %s" %
432 self.dut.model)
Ang Li73697b32015-12-03 00:41:53 +0000433 neg_passpoint_configs = self.gen_negative_passpoint_configs()
Ang Li81549052016-06-09 18:51:14 -0700434 self.log.info("Testing %d different configs.",
435 len(neg_passpoint_configs))
Ang Li8e767182015-12-09 17:29:24 -0800436 random.shuffle(neg_passpoint_configs)
Ang Li81549052016-06-09 18:51:14 -0700437
Ang Li73697b32015-12-03 00:41:53 +0000438 def name_gen(config, ad):
439 name = self.gen_passpoint_test_name(config, ad)
440 name += "-with_wrong-{}".format(config["invalid_field"])
441 return name
Ang Li81549052016-06-09 18:51:14 -0700442
443 failed = self.run_generated_testcases(self.eap_negative_connect_logic,
444 neg_passpoint_configs,
445 args=(self.dut, ),
446 name_func=name_gen)
447 asserts.assert_equal(
448 len(failed), 0,
449 "The following configs failed negative passpoint connect test: %s"
450 % pprint.pformat(failed))