blob: 625926ceb6ecd71a718a19ebc95052f2665562a8 [file] [log] [blame]
Ang Li73697b32015-12-03 00:41:53 +00001#!/usr/bin/python3.4
2#
3# Copyright 2015 - The Android Open Source Project
4#
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 Li8e767182015-12-09 17:29:24 -080021import acts.base_test
22import acts.signals.generated_test as generated_test
23import acts.test_utils.wifi_test_utils as wutils
24import acts.test_utils.wifi_test_utils.WifiEnums as WifiEnums
Ang Li73697b32015-12-03 00:41:53 +000025
26# EAP Macros
27EAP = WifiEnums.Eap
28EapPhase2 = WifiEnums.EapPhase2
29
30# Enterprise Config Macros
31Ent = WifiEnums.Enterprise
Ang Li73697b32015-12-03 00:41:53 +000032
Ang Li8e767182015-12-09 17:29:24 -080033class WifiEnterpriseTest(acts.base_test.BaseTestClass):
Ang Li73697b32015-12-03 00:41:53 +000034
35 def __init__(self, controllers):
36 BaseTestClass.__init__(self, controllers)
37 self.tests = (
38 "test_eap_connect",
39 "test_eap_connect_negative",
40 # "test_passpoint_connect",
41 # "test_passpoint_connect_negative"
42 )
43
44 def setup_class(self):
45 self.dut = self.android_devices[0]
Ang Li8e767182015-12-09 17:29:24 -080046 wutils.wifi_test_device_init(self.dut)
Ang Li73697b32015-12-03 00:41:53 +000047 required_userparam_names = (
48 "ca_cert",
49 "client_cert",
50 "client_key",
51 "passpoint_ca_cert",
52 "passpoint_client_cert",
53 "passpoint_client_key",
54 "eap_identity",
55 "eap_password",
56 "invalid_ca_cert",
57 "invalid_client_cert",
58 "invalid_client_key",
59 "fqdn",
60 "provider_friendly_name",
61 "realm",
62 "ssid_peap",
63 "ssid_tls",
64 "ssid_ttls",
65 "ssid_sim",
66 "ssid_passpoint",
67 "device_password",
68 "ping_addr"
69 )
70 optional_userparam_names = (
71 "roaming_consortium_ids",
72 "plmn"
73 )
74 assert self.unpack_userparams(required_userparam_names,
75 opt_param_names = optional_userparam_names)
76 # Default configs for EAP networks.
77 self.config_peap = {
78 Ent.EAP: EAP.PEAP,
79 Ent.CA_CERT: self.ca_cert,
80 Ent.IDENTITY: self.eap_identity,
81 Ent.PASSWORD: self.eap_password,
82 Ent.PHASE2: EapPhase2.MSCHAPV2,
83 WifiEnums.SSID_KEY: self.ssid_peap
84 }
85 self.config_tls = {
86 Ent.EAP: EAP.TLS,
87 Ent.CA_CERT: self.ca_cert,
88 WifiEnums.SSID_KEY: self.ssid_tls,
89 Ent.CLIENT_CERT: self.client_cert,
90 Ent.PRIVATE_KEY_ID: self.client_key,
91 Ent.IDENTITY: self.eap_identity,
92 }
93 self.config_ttls = {
94 Ent.EAP: EAP.TTLS,
95 Ent.CA_CERT: self.ca_cert,
96 Ent.IDENTITY: self.eap_identity,
97 Ent.PASSWORD: self.eap_password,
98 Ent.PHASE2: EapPhase2.MSCHAPV2,
99 WifiEnums.SSID_KEY: self.ssid_ttls
100 }
101 self.config_sim = {
102 Ent.EAP: EAP.SIM,
103 WifiEnums.SSID_KEY: self.ssid_sim,
104 }
105
106 # Base config for passpoint networks.
107 self.config_passpoint = {
108 Ent.FQDN: self.fqdn,
109 Ent.FRIENDLY_NAME: self.provider_friendly_name,
110 Ent.REALM: self.realm,
111 Ent.CA_CERT: self.passpoint_ca_cert
112 }
113 if hasattr(self, "plmn"):
114 self.config_passpoint[Ent.PLMN] = self.plmn
115 if hasattr(self, "roaming_consortium_ids"):
116 self.config_passpoint[Ent.ROAMING_IDS] = self.roaming_consortium_ids
117
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
122 self.config_passpoint_tls[Ent.PRIVATE_KEY_ID] = self.passpoint_client_key
123 del self.config_passpoint_tls[WifiEnums.SSID_KEY]
124 self.config_passpoint_ttls = dict(self.config_ttls)
125 self.config_passpoint_ttls.update(self.config_passpoint)
126 del self.config_passpoint_ttls[WifiEnums.SSID_KEY]
127 # Set screen lock password so ConfigStore is unlocked.
128 self.droid.setDevicePassword(self.device_password)
129 return True
130
131 def teardown_class(self):
Ang Li8e767182015-12-09 17:29:24 -0800132 wutils.reset_wifi(self.dut)
Ang Li73697b32015-12-03 00:41:53 +0000133 self.droid.disableDevicePassword()
134 self.ed.clear_all_events()
135
136 def setup_test(self):
137 self.droid.wifiStartTrackingStateChange()
138 self.droid.wakeLockAcquireBright()
139 self.droid.wakeUpNow()
Ang Li8e767182015-12-09 17:29:24 -0800140 wutils.reset_wifi(self.dut)
Ang Li73697b32015-12-03 00:41:53 +0000141 self.ed.clear_all_events()
142 return True
143
144 def teardown_test(self):
145 self.droid.wakeLockRelease()
146 self.droid.goToSleepNow()
147 self.droid.wifiStopTrackingStateChange()
148
149 """Helper Functions"""
150
151 def eap_negative_connect_logic(self, config, ad):
152 """Tries to connect to an enterprise network with invalid credentials
153 and expect a failure.
154
155 Args:
156 config: A dict representing an invalid EAP credential.
157
158 Returns:
159 True if connection failed as expected, False otherwise.
160 """
Ang Li8e767182015-12-09 17:29:24 -0800161 verdict = wutils.eap_connect(config, ad)
Ang Li73697b32015-12-03 00:41:53 +0000162 self.assert_true(not verdict, "Connection should have failed.")
163 self.log.info("Connection failed as expected.")
164 return True
165
166 def expand_config_by_phase2(self, config):
167 """Take an enterprise config and generate a list of configs, each with
168 a different phase2 auth type.
169
170 Args:
171 config: A dict representing enterprise config.
172
173 Returns
174 A list of enterprise configs.
175 """
176 results = []
177 for phase2_type in EapPhase2:
178 # Skip a special case for passpoint TTLS.
179 if Ent.FQDN in config and phase2_type == EapPhase2.GTC:
180 continue
181 c = dict(config)
182 c[Ent.PHASE2] = phase2_type
183 results.append(c)
184 return results
185
186 def gen_eap_configs(self):
187 """Generates configurations for different EAP authentication types.
188
189 Returns:
190 A list of dicts each representing an EAP configuration.
191 """
192 configs = [self.config_tls]
193 # self.config_sim
Ang Li8e767182015-12-09 17:29:24 -0800194 configs += wutils.expand_enterprise_config_by_phase2(self.config_ttls)
195 configs += wutils.expand_enterprise_config_by_phase2(self.config_peap)
Ang Li73697b32015-12-03 00:41:53 +0000196 return configs
197
198 def gen_passpoint_configs(self):
199 """Generates passpoint configurations for different EAP authentication
200 types.
201
202 Returns:
203 A list of dicts each representing an EAP configuration for
204 passpoint networks.
205 """
206 configs = [self.config_passpoint_tls]
Ang Li8e767182015-12-09 17:29:24 -0800207 configs += wutils.expand_enterprise_config_by_phase2(self.config_passpoint_ttls)
Ang Li73697b32015-12-03 00:41:53 +0000208 return configs
209
210 def gen_negative_configs(self, configs, neg_params):
211 """Generic function used to generate negative configs.
212
213 For all the valid configurations, if a param in the neg_params also
214 exists in a config, a copy of the config is made with an invalid value
215 of the param.
216
217 Args:
218 configs: A list of valid configurations.
219 neg_params: A dict that has all the invalid values.
220
221 Returns:
222 A list of invalid configurations generated based on the valid
223 configurations. Each invalid configuration has a different invalid
224 field.
225 """
226 results = []
227 for c in configs:
228 for k, v in neg_params.items():
229 # Skip negative test for TLS's identity field since it's not
230 # used for auth.
231 if c[Ent.EAP] == EAP.TLS and k == Ent.IDENTITY:
232 continue
233 if k in c:
234 nc = dict(c)
235 nc[k] = v
236 nc["invalid_field"] = k
237 results.append(nc)
238 return results
239
240 def gen_negative_eap_configs(self):
241 """Generates invalid configurations for different EAP authentication
242 types.
243
244 For all the valid EAP configurations, if a param that is part of the
245 authentication info exists in a config, a copy of the config is made
246 with an invalid value of the param.
247
248 Returns:
249 A list of dicts each representing an invalid EAP configuration.
250 """
251 neg_params = {
252 Ent.CLIENT_CERT: self.invalid_client_cert,
253 Ent.CA_CERT: self.invalid_ca_cert,
254 Ent.PRIVATE_KEY_ID: self.invalid_client_key,
255 Ent.IDENTITY: "fake_identity",
256 Ent.PASSWORD: "wrong_password"
257 }
258 configs = self.gen_eap_configs()
259 return self.gen_negative_configs(configs, neg_params)
260
261 def gen_negative_passpoint_configs(self):
262 """Generates invalid configurations for different EAP authentication
263 types with passpoint support.
264
265 Returns:
266 A list of dicts each representing an invalid EAP configuration
267 with passpoint fields.
268 """
269 neg_params = {
270 Ent.CLIENT_CERT: self.invalid_client_cert,
271 Ent.CA_CERT: self.invalid_ca_cert,
272 Ent.PRIVATE_KEY_ID: self.invalid_client_key,
273 Ent.IDENTITY: "fake_identity",
274 Ent.PASSWORD: "wrong_password",
275 Ent.FQDN: "fake_fqdn",
276 Ent.REALM: "where_no_one_has_gone_before",
277 Ent.PLMN: "fake_plmn",
278 Ent.ROAMING_IDS: [1234567890, 9876543210]
279 }
280 configs = self.gen_passpoint_configs()
281 return self.gen_negative_configs(configs, neg_params)
282
283 def gen_eap_test_name(self, config, ad):
284 """Generates a test case name based on an EAP configuration.
285
286 Args:
287 config: A dict representing an EAP credential.
288 ad: Discarded. This is here because name function signature needs
289 to be consistent with logic function signature for generated
290 test cases.
291
292 Returns:
293 A string representing the name of a generated EAP test case.
294 """
295 name = "test_connect-%s" % config[Ent.EAP].name
296 if Ent.PHASE2 in config:
297 name += "-{}".format(config[Ent.PHASE2].name)
298 return name
299
300 def gen_passpoint_test_name(self, config, ad):
301 """Generates a test case name based on an EAP passpoint configuration.
302
303 Args:
304 config: A dict representing an EAP passpoint credential.
305 ad: Discarded. This is here because name function signature needs
306 to be consistent with logic function signature for generated
307 test cases.
308
309 Returns:
310 A string representing the name of a generated EAP passpoint connect
311 test case.
312 """
313 name = self.gen_eap_test_name(config, ad)
314 name = name.replace("connect", "passpoint_connect")
315 return name
316
317 """Tests"""
Ang Li8e767182015-12-09 17:29:24 -0800318 @generated_test
Ang Li73697b32015-12-03 00:41:53 +0000319 def test_eap_connect(self):
320 """Test connecting to enterprise networks of different authentication
321 types.
322
323 The authentication types tested are:
324 EAP-TLS
325 EAP-PEAP with different phase2 types.
326 EAP-TTLS with different phase2 types.
327
328 Procedures:
329 For each enterprise wifi network
330 1. Connect to the network.
331 2. Send a GET request to a website and check response.
332
333 Expect:
334 Successful connection and Internet access through the enterprise
335 networks.
336 """
337 eap_configs = self.gen_eap_configs()
338 self.log.info("Testing %d different configs." % len(eap_configs))
Ang Li8e767182015-12-09 17:29:24 -0800339 random.shuffle(eap_configs)
Ang Li73697b32015-12-03 00:41:53 +0000340 failed = self.run_generated_testcases(
Ang Li8e767182015-12-09 17:29:24 -0800341 wutils.eap_connect,
Ang Li73697b32015-12-03 00:41:53 +0000342 eap_configs,
343 self.dut,
344 name_func=self.gen_eap_test_name)
345 msg = ("The following configs failed EAP connect test: %s" %
346 pprint.pformat(failed))
347 self.assert_true(len(failed) == 0, msg)
Ang Li73697b32015-12-03 00:41:53 +0000348
Ang Li8e767182015-12-09 17:29:24 -0800349 @generated_test
Ang Li73697b32015-12-03 00:41:53 +0000350 def test_eap_connect_negative(self):
351 """Test connecting to enterprise networks.
352
353 Procedures:
354 For each enterprise wifi network
355 1. Connect to the network with invalid credentials.
356
357 Expect:
358 Fail to establish connection.
359 """
360 neg_eap_configs = self.gen_negative_eap_configs()
361 self.log.info("Testing %d different configs." % len(neg_eap_configs))
Ang Li8e767182015-12-09 17:29:24 -0800362 random.shuffle(neg_eap_configs)
Ang Li73697b32015-12-03 00:41:53 +0000363 def name_gen(config, ad):
364 name = self.gen_eap_test_name(config, ad)
365 name += "-with_wrong-{}".format(config["invalid_field"])
366 return name
367 failed = self.run_generated_testcases(
368 self.eap_negative_connect_logic,
369 neg_eap_configs,
370 self.dut,
371 name_func=name_gen)
372 msg = ("The following configs failed negative EAP connect test: %s" %
373 pprint.pformat(failed))
374 self.assert_true(len(failed) == 0, msg)
Ang Li73697b32015-12-03 00:41:53 +0000375
Ang Li8e767182015-12-09 17:29:24 -0800376 @generated_test
Ang Li73697b32015-12-03 00:41:53 +0000377 def test_passpoint_connect(self):
378 """Test connecting to enterprise networks of different authentication
379 types with passpoint support.
380
381 The authentication types tested are:
382 EAP-TLS
383 EAP-TTLS with MSCHAPV2 as phase2.
384
385 Procedures:
386 For each enterprise wifi network
387 1. Connect to the network.
388 2. Send a GET request to a website and check response.
389
390 Expect:
391 Successful connection and Internet access through the enterprise
392 networks with passpoint support.
393 """
394 self.skip_if(not self.dut.droid.wifiIsPasspointSupported(),
395 "Passpoint is not supported on device %s" % self.dut.model)
396 passpoint_configs = self.gen_passpoint_configs()
397 self.log.info("Testing %d different configs." % len(passpoint_configs))
Ang Li8e767182015-12-09 17:29:24 -0800398 random.shuffle(passpoint_configs)
Ang Li73697b32015-12-03 00:41:53 +0000399 failed = self.run_generated_testcases(
Ang Li8e767182015-12-09 17:29:24 -0800400 wutils.eap_connect,
Ang Li73697b32015-12-03 00:41:53 +0000401 passpoint_configs,
402 self.dut,
403 name_func=self.gen_passpoint_test_name)
404 msg = ("The following configs failed passpoint connect test: %s" %
405 pprint.pformat(failed))
406 self.assert_true(len(failed) == 0, msg)
Ang Li73697b32015-12-03 00:41:53 +0000407
Ang Li8e767182015-12-09 17:29:24 -0800408 @generated_test
Ang Li73697b32015-12-03 00:41:53 +0000409 def test_passpoint_connect_negative(self):
410 """Test connecting to enterprise networks.
411
412 Procedures:
413 For each enterprise wifi network
414 1. Connect to the network with invalid credentials.
415
416 Expect:
417 Fail to establish connection.
418 """
419 self.skip_if(not self.dut.droid.wifiIsPasspointSupported(),
420 "Passpoint is not supported on device %s" % self.dut.model)
421 neg_passpoint_configs = self.gen_negative_passpoint_configs()
422 self.log.info("Testing %d different configs." % len(neg_passpoint_configs))
Ang Li8e767182015-12-09 17:29:24 -0800423 random.shuffle(neg_passpoint_configs)
Ang Li73697b32015-12-03 00:41:53 +0000424 def name_gen(config, ad):
425 name = self.gen_passpoint_test_name(config, ad)
426 name += "-with_wrong-{}".format(config["invalid_field"])
427 return name
428 failed = self.run_generated_testcases(
429 self.eap_negative_connect_logic,
430 neg_passpoint_configs,
431 self.dut,
432 name_func=name_gen)
433 msg = ("The following configs failed negative passpoint connect test: "
434 "%s") % pprint.pformat(failed)
435 self.assert_true(len(failed) == 0, msg)