]> git.ipfire.org Git - thirdparty/hostap.git/blob - tests/hwsim/test_radius.py
tests: Pass full apdev to add_ap() function (1)
[thirdparty/hostap.git] / tests / hwsim / test_radius.py
1 # RADIUS tests
2 # Copyright (c) 2013-2015, Jouni Malinen <j@w1.fi>
3 #
4 # This software may be distributed under the terms of the BSD license.
5 # See README for more details.
6
7 import binascii
8 import hashlib
9 import hmac
10 import logging
11 logger = logging.getLogger()
12 import os
13 import select
14 import struct
15 import subprocess
16 import threading
17 import time
18
19 import hostapd
20 from utils import HwsimSkip, require_under_vm, skip_with_fips
21 from test_ap_hs20 import build_dhcp_ack
22 from test_ap_ft import ft_params1
23
24 def connect(dev, ssid, wait_connect=True):
25 dev.connect(ssid, key_mgmt="WPA-EAP", scan_freq="2412",
26 eap="PSK", identity="psk.user@example.com",
27 password_hex="0123456789abcdef0123456789abcdef",
28 wait_connect=wait_connect)
29
30 def test_radius_auth_unreachable(dev, apdev):
31 """RADIUS Authentication server unreachable"""
32 params = hostapd.wpa2_eap_params(ssid="radius-auth")
33 params['auth_server_port'] = "18139"
34 hostapd.add_ap(apdev[0], params)
35 hapd = hostapd.Hostapd(apdev[0]['ifname'])
36 connect(dev[0], "radius-auth", wait_connect=False)
37 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
38 if ev is None:
39 raise Exception("Timeout on EAP start")
40 logger.info("Checking for RADIUS retries")
41 time.sleep(4)
42 mib = hapd.get_mib()
43 if "radiusAuthClientAccessRequests" not in mib:
44 raise Exception("Missing MIB fields")
45 if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
46 raise Exception("Missing RADIUS Authentication retransmission")
47 if int(mib["radiusAuthClientPendingRequests"]) < 1:
48 raise Exception("Missing pending RADIUS Authentication request")
49
50 def test_radius_auth_unreachable2(dev, apdev):
51 """RADIUS Authentication server unreachable (2)"""
52 subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
53 params = hostapd.wpa2_eap_params(ssid="radius-auth")
54 params['auth_server_addr'] = "192.168.213.17"
55 params['auth_server_port'] = "18139"
56 hostapd.add_ap(apdev[0], params)
57 hapd = hostapd.Hostapd(apdev[0]['ifname'])
58 subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
59 connect(dev[0], "radius-auth", wait_connect=False)
60 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
61 if ev is None:
62 raise Exception("Timeout on EAP start")
63 logger.info("Checking for RADIUS retries")
64 time.sleep(4)
65 mib = hapd.get_mib()
66 if "radiusAuthClientAccessRequests" not in mib:
67 raise Exception("Missing MIB fields")
68 if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
69 raise Exception("Missing RADIUS Authentication retransmission")
70
71 def test_radius_auth_unreachable3(dev, apdev):
72 """RADIUS Authentication server initially unreachable, but then available"""
73 subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
74 params = hostapd.wpa2_eap_params(ssid="radius-auth")
75 params['auth_server_addr'] = "192.168.213.18"
76 hostapd.add_ap(apdev[0], params)
77 hapd = hostapd.Hostapd(apdev[0]['ifname'])
78 connect(dev[0], "radius-auth", wait_connect=False)
79 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
80 if ev is None:
81 raise Exception("Timeout on EAP start")
82 subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
83 time.sleep(0.1)
84 dev[0].request("DISCONNECT")
85 hapd.set('auth_server_addr_replace', '127.0.0.1')
86 dev[0].request("RECONNECT")
87
88 dev[0].wait_connected()
89
90 def test_radius_acct_unreachable(dev, apdev):
91 """RADIUS Accounting server unreachable"""
92 params = hostapd.wpa2_eap_params(ssid="radius-acct")
93 params['acct_server_addr'] = "127.0.0.1"
94 params['acct_server_port'] = "18139"
95 params['acct_server_shared_secret'] = "radius"
96 hostapd.add_ap(apdev[0], params)
97 hapd = hostapd.Hostapd(apdev[0]['ifname'])
98 connect(dev[0], "radius-acct")
99 logger.info("Checking for RADIUS retries")
100 time.sleep(4)
101 mib = hapd.get_mib()
102 if "radiusAccClientRetransmissions" not in mib:
103 raise Exception("Missing MIB fields")
104 if int(mib["radiusAccClientRetransmissions"]) < 2:
105 raise Exception("Missing RADIUS Accounting retransmissions")
106 if int(mib["radiusAccClientPendingRequests"]) < 2:
107 raise Exception("Missing pending RADIUS Accounting requests")
108
109 def test_radius_acct_unreachable2(dev, apdev):
110 """RADIUS Accounting server unreachable(2)"""
111 subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
112 params = hostapd.wpa2_eap_params(ssid="radius-acct")
113 params['acct_server_addr'] = "192.168.213.17"
114 params['acct_server_port'] = "18139"
115 params['acct_server_shared_secret'] = "radius"
116 hostapd.add_ap(apdev[0], params)
117 hapd = hostapd.Hostapd(apdev[0]['ifname'])
118 subprocess.call(['ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
119 connect(dev[0], "radius-acct")
120 logger.info("Checking for RADIUS retries")
121 time.sleep(4)
122 mib = hapd.get_mib()
123 if "radiusAccClientRetransmissions" not in mib:
124 raise Exception("Missing MIB fields")
125 if int(mib["radiusAccClientRetransmissions"]) < 1 and int(mib["radiusAccClientPendingRequests"]) < 1:
126 raise Exception("Missing pending or retransmitted RADIUS Accounting requests")
127
128 def test_radius_acct_unreachable3(dev, apdev):
129 """RADIUS Accounting server initially unreachable, but then available"""
130 require_under_vm()
131 subprocess.call(['ip', 'ro', 'replace', 'blackhole', '192.168.213.18'])
132 as_hapd = hostapd.Hostapd("as")
133 as_mib_start = as_hapd.get_mib(param="radius_server")
134 params = hostapd.wpa2_eap_params(ssid="radius-acct")
135 params['acct_server_addr'] = "192.168.213.18"
136 params['acct_server_port'] = "1813"
137 params['acct_server_shared_secret'] = "radius"
138 hostapd.add_ap(apdev[0], params)
139 hapd = hostapd.Hostapd(apdev[0]['ifname'])
140 connect(dev[0], "radius-acct")
141 subprocess.call(['ip', 'ro', 'del', 'blackhole', '192.168.213.18'])
142 time.sleep(0.1)
143 dev[0].request("DISCONNECT")
144 hapd.set('acct_server_addr_replace', '127.0.0.1')
145 dev[0].request("RECONNECT")
146 dev[0].wait_connected()
147 time.sleep(1)
148 as_mib_end = as_hapd.get_mib(param="radius_server")
149 req_s = int(as_mib_start['radiusAccServTotalResponses'])
150 req_e = int(as_mib_end['radiusAccServTotalResponses'])
151 if req_e <= req_s:
152 raise Exception("Unexpected RADIUS server acct MIB value")
153
154 def test_radius_acct_unreachable4(dev, apdev):
155 """RADIUS Accounting server unreachable and multiple STAs"""
156 params = hostapd.wpa2_eap_params(ssid="radius-acct")
157 params['acct_server_addr'] = "127.0.0.1"
158 params['acct_server_port'] = "18139"
159 params['acct_server_shared_secret'] = "radius"
160 hostapd.add_ap(apdev[0], params)
161 hapd = hostapd.Hostapd(apdev[0]['ifname'])
162 for i in range(20):
163 connect(dev[0], "radius-acct")
164 dev[0].request("REMOVE_NETWORK all")
165 dev[0].wait_disconnected()
166
167 def test_radius_acct(dev, apdev):
168 """RADIUS Accounting"""
169 as_hapd = hostapd.Hostapd("as")
170 as_mib_start = as_hapd.get_mib(param="radius_server")
171 params = hostapd.wpa2_eap_params(ssid="radius-acct")
172 params['acct_server_addr'] = "127.0.0.1"
173 params['acct_server_port'] = "1813"
174 params['acct_server_shared_secret'] = "radius"
175 params['radius_auth_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
176 params['radius_acct_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
177 hostapd.add_ap(apdev[0], params)
178 hapd = hostapd.Hostapd(apdev[0]['ifname'])
179 connect(dev[0], "radius-acct")
180 dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
181 eap="PAX", identity="test-class",
182 password_hex="0123456789abcdef0123456789abcdef")
183 dev[2].connect("radius-acct", key_mgmt="WPA-EAP",
184 eap="GPSK", identity="gpsk-cui",
185 password="abcdefghijklmnop0123456789abcdef",
186 scan_freq="2412")
187 logger.info("Checking for RADIUS counters")
188 count = 0
189 while True:
190 mib = hapd.get_mib()
191 if int(mib['radiusAccClientResponses']) >= 3:
192 break
193 time.sleep(0.1)
194 count += 1
195 if count > 10:
196 raise Exception("Did not receive Accounting-Response packets")
197
198 if int(mib['radiusAccClientRetransmissions']) > 0:
199 raise Exception("Unexpected Accounting-Request retransmission")
200
201 as_mib_end = as_hapd.get_mib(param="radius_server")
202
203 req_s = int(as_mib_start['radiusAccServTotalRequests'])
204 req_e = int(as_mib_end['radiusAccServTotalRequests'])
205 if req_e < req_s + 2:
206 raise Exception("Unexpected RADIUS server acct MIB value")
207
208 acc_s = int(as_mib_start['radiusAuthServAccessAccepts'])
209 acc_e = int(as_mib_end['radiusAuthServAccessAccepts'])
210 if acc_e < acc_s + 1:
211 raise Exception("Unexpected RADIUS server auth MIB value")
212
213 def test_radius_acct_non_ascii_ssid(dev, apdev):
214 """RADIUS Accounting and non-ASCII SSID"""
215 params = hostapd.wpa2_eap_params()
216 params['acct_server_addr'] = "127.0.0.1"
217 params['acct_server_port'] = "1813"
218 params['acct_server_shared_secret'] = "radius"
219 ssid2 = "740665007374"
220 params['ssid2'] = ssid2
221 hostapd.add_ap(apdev[0], params)
222 dev[0].connect(ssid2=ssid2, key_mgmt="WPA-EAP", scan_freq="2412",
223 eap="PSK", identity="psk.user@example.com",
224 password_hex="0123456789abcdef0123456789abcdef")
225
226 def test_radius_acct_pmksa_caching(dev, apdev):
227 """RADIUS Accounting with PMKSA caching"""
228 as_hapd = hostapd.Hostapd("as")
229 as_mib_start = as_hapd.get_mib(param="radius_server")
230 params = hostapd.wpa2_eap_params(ssid="radius-acct")
231 params['acct_server_addr'] = "127.0.0.1"
232 params['acct_server_port'] = "1813"
233 params['acct_server_shared_secret'] = "radius"
234 hapd = hostapd.add_ap(apdev[0], params)
235 connect(dev[0], "radius-acct")
236 dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
237 eap="PAX", identity="test-class",
238 password_hex="0123456789abcdef0123456789abcdef")
239 for d in [ dev[0], dev[1] ]:
240 d.request("REASSOCIATE")
241 d.wait_connected(timeout=15, error="Reassociation timed out")
242
243 count = 0
244 while True:
245 mib = hapd.get_mib()
246 if int(mib['radiusAccClientResponses']) >= 4:
247 break
248 time.sleep(0.1)
249 count += 1
250 if count > 10:
251 raise Exception("Did not receive Accounting-Response packets")
252
253 if int(mib['radiusAccClientRetransmissions']) > 0:
254 raise Exception("Unexpected Accounting-Request retransmission")
255
256 as_mib_end = as_hapd.get_mib(param="radius_server")
257
258 req_s = int(as_mib_start['radiusAccServTotalRequests'])
259 req_e = int(as_mib_end['radiusAccServTotalRequests'])
260 if req_e < req_s + 2:
261 raise Exception("Unexpected RADIUS server acct MIB value")
262
263 acc_s = int(as_mib_start['radiusAuthServAccessAccepts'])
264 acc_e = int(as_mib_end['radiusAuthServAccessAccepts'])
265 if acc_e < acc_s + 1:
266 raise Exception("Unexpected RADIUS server auth MIB value")
267
268 def test_radius_acct_interim(dev, apdev):
269 """RADIUS Accounting interim update"""
270 as_hapd = hostapd.Hostapd("as")
271 params = hostapd.wpa2_eap_params(ssid="radius-acct")
272 params['acct_server_addr'] = "127.0.0.1"
273 params['acct_server_port'] = "1813"
274 params['acct_server_shared_secret'] = "radius"
275 params['radius_acct_interim_interval'] = "1"
276 hostapd.add_ap(apdev[0], params)
277 hapd = hostapd.Hostapd(apdev[0]['ifname'])
278 connect(dev[0], "radius-acct")
279 logger.info("Checking for RADIUS counters")
280 as_mib_start = as_hapd.get_mib(param="radius_server")
281 time.sleep(3.1)
282 as_mib_end = as_hapd.get_mib(param="radius_server")
283 req_s = int(as_mib_start['radiusAccServTotalRequests'])
284 req_e = int(as_mib_end['radiusAccServTotalRequests'])
285 if req_e < req_s + 3:
286 raise Exception("Unexpected RADIUS server acct MIB value")
287
288 def test_radius_acct_interim_unreachable(dev, apdev):
289 """RADIUS Accounting interim update with unreachable server"""
290 params = hostapd.wpa2_eap_params(ssid="radius-acct")
291 params['acct_server_addr'] = "127.0.0.1"
292 params['acct_server_port'] = "18139"
293 params['acct_server_shared_secret'] = "radius"
294 params['radius_acct_interim_interval'] = "1"
295 hapd = hostapd.add_ap(apdev[0], params)
296 start = hapd.get_mib()
297 connect(dev[0], "radius-acct")
298 logger.info("Waiting for interium accounting updates")
299 time.sleep(3.1)
300 end = hapd.get_mib()
301 req_s = int(start['radiusAccClientTimeouts'])
302 req_e = int(end['radiusAccClientTimeouts'])
303 if req_e < req_s + 2:
304 raise Exception("Unexpected RADIUS server acct MIB value")
305
306 def test_radius_acct_interim_unreachable2(dev, apdev):
307 """RADIUS Accounting interim update with unreachable server (retry)"""
308 params = hostapd.wpa2_eap_params(ssid="radius-acct")
309 params['acct_server_addr'] = "127.0.0.1"
310 params['acct_server_port'] = "18139"
311 params['acct_server_shared_secret'] = "radius"
312 # Use long enough interim update interval to allow RADIUS retransmission
313 # case (3 seconds) to trigger first.
314 params['radius_acct_interim_interval'] = "4"
315 hapd = hostapd.add_ap(apdev[0], params)
316 start = hapd.get_mib()
317 connect(dev[0], "radius-acct")
318 logger.info("Waiting for interium accounting updates")
319 time.sleep(7.5)
320 end = hapd.get_mib()
321 req_s = int(start['radiusAccClientTimeouts'])
322 req_e = int(end['radiusAccClientTimeouts'])
323 if req_e < req_s + 2:
324 raise Exception("Unexpected RADIUS server acct MIB value")
325
326 def test_radius_acct_ipaddr(dev, apdev):
327 """RADIUS Accounting and Framed-IP-Address"""
328 try:
329 _test_radius_acct_ipaddr(dev, apdev)
330 finally:
331 subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'down'],
332 stderr=open('/dev/null', 'w'))
333 subprocess.call(['brctl', 'delbr', 'ap-br0'],
334 stderr=open('/dev/null', 'w'))
335
336 def _test_radius_acct_ipaddr(dev, apdev):
337 params = { "ssid": "radius-acct-open",
338 'acct_server_addr': "127.0.0.1",
339 'acct_server_port': "1813",
340 'acct_server_shared_secret': "radius",
341 'proxy_arp': '1',
342 'ap_isolate': '1',
343 'bridge': 'ap-br0' }
344 hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
345 try:
346 hapd.enable()
347 except:
348 # For now, do not report failures due to missing kernel support
349 raise HwsimSkip("Could not start hostapd - assume proxyarp not supported in kernel version")
350 bssid = apdev[0]['bssid']
351
352 subprocess.call(['brctl', 'setfd', 'ap-br0', '0'])
353 subprocess.call(['ip', 'link', 'set', 'dev', 'ap-br0', 'up'])
354
355 dev[0].connect("radius-acct-open", key_mgmt="NONE", scan_freq="2412")
356 addr0 = dev[0].own_addr()
357
358 pkt = build_dhcp_ack(dst_ll="ff:ff:ff:ff:ff:ff", src_ll=bssid,
359 ip_src="192.168.1.1", ip_dst="255.255.255.255",
360 yiaddr="192.168.1.123", chaddr=addr0)
361 if "OK" not in hapd.request("DATA_TEST_FRAME ifname=ap-br0 " + binascii.hexlify(pkt)):
362 raise Exception("DATA_TEST_FRAME failed")
363
364 dev[0].request("DISCONNECT")
365 dev[0].wait_disconnected()
366 hapd.disable()
367
368 def send_and_check_reply(srv, req, code, error_cause=0):
369 reply = srv.SendPacket(req)
370 logger.debug("RADIUS response from hostapd")
371 for i in reply.keys():
372 logger.debug("%s: %s" % (i, reply[i]))
373 if reply.code != code:
374 raise Exception("Unexpected response code")
375 if error_cause:
376 if 'Error-Cause' not in reply:
377 raise Exception("Missing Error-Cause")
378 if reply['Error-Cause'][0] != error_cause:
379 raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
380
381 def test_radius_acct_psk(dev, apdev):
382 """RADIUS Accounting - PSK"""
383 as_hapd = hostapd.Hostapd("as")
384 params = hostapd.wpa2_params(ssid="radius-acct", passphrase="12345678")
385 params['acct_server_addr'] = "127.0.0.1"
386 params['acct_server_port'] = "1813"
387 params['acct_server_shared_secret'] = "radius"
388 hapd = hostapd.add_ap(apdev[0], params)
389 dev[0].connect("radius-acct", psk="12345678", scan_freq="2412")
390
391 def test_radius_acct_psk_sha256(dev, apdev):
392 """RADIUS Accounting - PSK SHA256"""
393 as_hapd = hostapd.Hostapd("as")
394 params = hostapd.wpa2_params(ssid="radius-acct", passphrase="12345678")
395 params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
396 params['acct_server_addr'] = "127.0.0.1"
397 params['acct_server_port'] = "1813"
398 params['acct_server_shared_secret'] = "radius"
399 hapd = hostapd.add_ap(apdev[0], params)
400 dev[0].connect("radius-acct", key_mgmt="WPA-PSK-SHA256",
401 psk="12345678", scan_freq="2412")
402
403 def test_radius_acct_ft_psk(dev, apdev):
404 """RADIUS Accounting - FT-PSK"""
405 as_hapd = hostapd.Hostapd("as")
406 params = ft_params1(ssid="radius-acct", passphrase="12345678")
407 params['acct_server_addr'] = "127.0.0.1"
408 params['acct_server_port'] = "1813"
409 params['acct_server_shared_secret'] = "radius"
410 hapd = hostapd.add_ap(apdev[0], params)
411 dev[0].connect("radius-acct", key_mgmt="FT-PSK",
412 psk="12345678", scan_freq="2412")
413
414 def test_radius_acct_ieee8021x(dev, apdev):
415 """RADIUS Accounting - IEEE 802.1X"""
416 skip_with_fips(dev[0])
417 as_hapd = hostapd.Hostapd("as")
418 params = hostapd.radius_params()
419 params["ssid"] = "radius-acct-1x"
420 params["ieee8021x"] = "1"
421 params["wep_key_len_broadcast"] = "13"
422 params["wep_key_len_unicast"] = "13"
423 params['acct_server_addr'] = "127.0.0.1"
424 params['acct_server_port'] = "1813"
425 params['acct_server_shared_secret'] = "radius"
426 hapd = hostapd.add_ap(apdev[0], params)
427 dev[0].connect("radius-acct-1x", key_mgmt="IEEE8021X", eap="PSK",
428 identity="psk.user@example.com",
429 password_hex="0123456789abcdef0123456789abcdef",
430 scan_freq="2412")
431
432 def test_radius_das_disconnect(dev, apdev):
433 """RADIUS Dynamic Authorization Extensions - Disconnect"""
434 try:
435 import pyrad.client
436 import pyrad.packet
437 import pyrad.dictionary
438 import radius_das
439 except ImportError:
440 raise HwsimSkip("No pyrad modules available")
441
442 params = hostapd.wpa2_eap_params(ssid="radius-das")
443 params['radius_das_port'] = "3799"
444 params['radius_das_client'] = "127.0.0.1 secret"
445 params['radius_das_require_event_timestamp'] = "1"
446 params['own_ip_addr'] = "127.0.0.1"
447 params['nas_identifier'] = "nas.example.com"
448 hapd = hostapd.add_ap(apdev[0], params)
449 connect(dev[0], "radius-das")
450 addr = dev[0].p2p_interface_addr()
451 sta = hapd.get_sta(addr)
452 id = sta['dot1xAuthSessionId']
453
454 dict = pyrad.dictionary.Dictionary("dictionary.radius")
455
456 srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
457 secret="secret", dict=dict)
458 srv.retries = 1
459 srv.timeout = 1
460
461 logger.info("Disconnect-Request with incorrect secret")
462 req = radius_das.DisconnectPacket(dict=dict, secret="incorrect",
463 User_Name="foo",
464 NAS_Identifier="localhost",
465 Event_Timestamp=int(time.time()))
466 logger.debug(req)
467 try:
468 reply = srv.SendPacket(req)
469 raise Exception("Unexpected response to Disconnect-Request")
470 except pyrad.client.Timeout:
471 logger.info("Disconnect-Request with incorrect secret properly ignored")
472
473 logger.info("Disconnect-Request without Event-Timestamp")
474 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
475 User_Name="psk.user@example.com")
476 logger.debug(req)
477 try:
478 reply = srv.SendPacket(req)
479 raise Exception("Unexpected response to Disconnect-Request")
480 except pyrad.client.Timeout:
481 logger.info("Disconnect-Request without Event-Timestamp properly ignored")
482
483 logger.info("Disconnect-Request with non-matching Event-Timestamp")
484 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
485 User_Name="psk.user@example.com",
486 Event_Timestamp=123456789)
487 logger.debug(req)
488 try:
489 reply = srv.SendPacket(req)
490 raise Exception("Unexpected response to Disconnect-Request")
491 except pyrad.client.Timeout:
492 logger.info("Disconnect-Request with non-matching Event-Timestamp properly ignored")
493
494 logger.info("Disconnect-Request with unsupported attribute")
495 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
496 User_Name="foo",
497 User_Password="foo",
498 Event_Timestamp=int(time.time()))
499 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 401)
500
501 logger.info("Disconnect-Request with invalid Calling-Station-Id")
502 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
503 User_Name="foo",
504 Calling_Station_Id="foo",
505 Event_Timestamp=int(time.time()))
506 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 407)
507
508 logger.info("Disconnect-Request with mismatching User-Name")
509 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
510 User_Name="foo",
511 Event_Timestamp=int(time.time()))
512 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
513
514 logger.info("Disconnect-Request with mismatching Calling-Station-Id")
515 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
516 Calling_Station_Id="12:34:56:78:90:aa",
517 Event_Timestamp=int(time.time()))
518 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
519
520 logger.info("Disconnect-Request with mismatching Acct-Session-Id")
521 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
522 Acct_Session_Id="12345678-87654321",
523 Event_Timestamp=int(time.time()))
524 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
525
526 logger.info("Disconnect-Request with mismatching Acct-Session-Id (len)")
527 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
528 Acct_Session_Id="12345678",
529 Event_Timestamp=int(time.time()))
530 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
531
532 logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id")
533 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
534 Acct_Multi_Session_Id="12345678+87654321",
535 Event_Timestamp=int(time.time()))
536 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
537
538 logger.info("Disconnect-Request with mismatching Acct-Multi-Session-Id (len)")
539 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
540 Acct_Multi_Session_Id="12345678",
541 Event_Timestamp=int(time.time()))
542 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
543
544 logger.info("Disconnect-Request with no session identification attributes")
545 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
546 Event_Timestamp=int(time.time()))
547 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 503)
548
549 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
550 if ev is not None:
551 raise Exception("Unexpected disconnection")
552
553 logger.info("Disconnect-Request with mismatching NAS-IP-Address")
554 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
555 NAS_IP_Address="192.168.3.4",
556 Acct_Session_Id=id,
557 Event_Timestamp=int(time.time()))
558 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403)
559
560 logger.info("Disconnect-Request with mismatching NAS-Identifier")
561 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
562 NAS_Identifier="unknown.example.com",
563 Acct_Session_Id=id,
564 Event_Timestamp=int(time.time()))
565 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, 403)
566
567 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
568 if ev is not None:
569 raise Exception("Unexpected disconnection")
570
571 logger.info("Disconnect-Request with matching Acct-Session-Id")
572 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
573 NAS_IP_Address="127.0.0.1",
574 NAS_Identifier="nas.example.com",
575 Acct_Session_Id=id,
576 Event_Timestamp=int(time.time()))
577 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
578
579 dev[0].wait_disconnected(timeout=10)
580 dev[0].wait_connected(timeout=10, error="Re-connection timed out")
581
582 logger.info("Disconnect-Request with matching Acct-Multi-Session-Id")
583 sta = hapd.get_sta(addr)
584 multi_sess_id = sta['authMultiSessionId']
585 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
586 NAS_IP_Address="127.0.0.1",
587 NAS_Identifier="nas.example.com",
588 Acct_Multi_Session_Id=multi_sess_id,
589 Event_Timestamp=int(time.time()))
590 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
591
592 dev[0].wait_disconnected(timeout=10)
593 dev[0].wait_connected(timeout=10, error="Re-connection timed out")
594
595 logger.info("Disconnect-Request with matching User-Name")
596 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
597 NAS_Identifier="nas.example.com",
598 User_Name="psk.user@example.com",
599 Event_Timestamp=int(time.time()))
600 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
601
602 dev[0].wait_disconnected(timeout=10)
603 dev[0].wait_connected(timeout=10, error="Re-connection timed out")
604
605 logger.info("Disconnect-Request with matching Calling-Station-Id")
606 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
607 NAS_IP_Address="127.0.0.1",
608 Calling_Station_Id=addr,
609 Event_Timestamp=int(time.time()))
610 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
611
612 dev[0].wait_disconnected(timeout=10)
613 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", "CTRL-EVENT-CONNECTED"])
614 if ev is None:
615 raise Exception("Timeout while waiting for re-connection")
616 if "CTRL-EVENT-EAP-STARTED" not in ev:
617 raise Exception("Unexpected skipping of EAP authentication in reconnection")
618 dev[0].wait_connected(timeout=10, error="Re-connection timed out")
619
620 logger.info("Disconnect-Request with matching Calling-Station-Id and non-matching CUI")
621 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
622 Calling_Station_Id=addr,
623 Chargeable_User_Identity="foo@example.com",
624 Event_Timestamp=int(time.time()))
625 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503)
626
627 logger.info("Disconnect-Request with matching CUI")
628 dev[1].connect("radius-das", key_mgmt="WPA-EAP",
629 eap="GPSK", identity="gpsk-cui",
630 password="abcdefghijklmnop0123456789abcdef",
631 scan_freq="2412")
632 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
633 Chargeable_User_Identity="gpsk-chargeable-user-identity",
634 Event_Timestamp=int(time.time()))
635 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
636
637 dev[1].wait_disconnected(timeout=10)
638 dev[1].wait_connected(timeout=10, error="Re-connection timed out")
639
640 ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
641 if ev is not None:
642 raise Exception("Unexpected disconnection")
643
644 connect(dev[2], "radius-das")
645
646 logger.info("Disconnect-Request with matching User-Name - multiple sessions matching")
647 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
648 NAS_Identifier="nas.example.com",
649 User_Name="psk.user@example.com",
650 Event_Timestamp=int(time.time()))
651 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=508)
652
653 logger.info("Disconnect-Request with User-Name matching multiple sessions, Calling-Station-Id only one")
654 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
655 NAS_Identifier="nas.example.com",
656 Calling_Station_Id=addr,
657 User_Name="psk.user@example.com",
658 Event_Timestamp=int(time.time()))
659 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
660
661 dev[0].wait_disconnected(timeout=10)
662 dev[0].wait_connected(timeout=10, error="Re-connection timed out")
663
664 ev = dev[2].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
665 if ev is not None:
666 raise Exception("Unexpected disconnection")
667
668 logger.info("Disconnect-Request with matching Acct-Multi-Session-Id after disassociation")
669 sta = hapd.get_sta(addr)
670 multi_sess_id = sta['authMultiSessionId']
671 dev[0].request("DISCONNECT")
672 dev[0].wait_disconnected(timeout=10)
673 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
674 NAS_IP_Address="127.0.0.1",
675 NAS_Identifier="nas.example.com",
676 Acct_Multi_Session_Id=multi_sess_id,
677 Event_Timestamp=int(time.time()))
678 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
679
680 dev[0].request("RECONNECT")
681 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
682 if ev is None:
683 raise Exception("Timeout on EAP start")
684 dev[0].wait_connected(timeout=15)
685
686 logger.info("Disconnect-Request with matching User-Name after disassociation")
687 dev[0].request("DISCONNECT")
688 dev[0].wait_disconnected(timeout=10)
689 dev[2].request("DISCONNECT")
690 dev[2].wait_disconnected(timeout=10)
691 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
692 NAS_IP_Address="127.0.0.1",
693 NAS_Identifier="nas.example.com",
694 User_Name="psk.user@example.com",
695 Event_Timestamp=int(time.time()))
696 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
697
698 logger.info("Disconnect-Request with matching CUI after disassociation")
699 dev[1].request("DISCONNECT")
700 dev[1].wait_disconnected(timeout=10)
701 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
702 NAS_IP_Address="127.0.0.1",
703 NAS_Identifier="nas.example.com",
704 Chargeable_User_Identity="gpsk-chargeable-user-identity",
705 Event_Timestamp=int(time.time()))
706 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
707
708 logger.info("Disconnect-Request with matching Calling-Station-Id after disassociation")
709 dev[0].request("RECONNECT")
710 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
711 if ev is None:
712 raise Exception("Timeout on EAP start")
713 dev[0].wait_connected(timeout=15)
714 dev[0].request("DISCONNECT")
715 dev[0].wait_disconnected(timeout=10)
716 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
717 NAS_IP_Address="127.0.0.1",
718 NAS_Identifier="nas.example.com",
719 Calling_Station_Id=addr,
720 Event_Timestamp=int(time.time()))
721 send_and_check_reply(srv, req, pyrad.packet.DisconnectACK)
722
723 logger.info("Disconnect-Request with mismatching Calling-Station-Id after disassociation")
724 req = radius_das.DisconnectPacket(dict=dict, secret="secret",
725 NAS_IP_Address="127.0.0.1",
726 NAS_Identifier="nas.example.com",
727 Calling_Station_Id=addr,
728 Event_Timestamp=int(time.time()))
729 send_and_check_reply(srv, req, pyrad.packet.DisconnectNAK, error_cause=503)
730
731 def test_radius_das_coa(dev, apdev):
732 """RADIUS Dynamic Authorization Extensions - CoA"""
733 try:
734 import pyrad.client
735 import pyrad.packet
736 import pyrad.dictionary
737 import radius_das
738 except ImportError:
739 raise HwsimSkip("No pyrad modules available")
740
741 params = hostapd.wpa2_eap_params(ssid="radius-das")
742 params['radius_das_port'] = "3799"
743 params['radius_das_client'] = "127.0.0.1 secret"
744 params['radius_das_require_event_timestamp'] = "1"
745 hapd = hostapd.add_ap(apdev[0], params)
746 connect(dev[0], "radius-das")
747 addr = dev[0].p2p_interface_addr()
748 sta = hapd.get_sta(addr)
749 id = sta['dot1xAuthSessionId']
750
751 dict = pyrad.dictionary.Dictionary("dictionary.radius")
752
753 srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
754 secret="secret", dict=dict)
755 srv.retries = 1
756 srv.timeout = 1
757
758 # hostapd does not currently support CoA-Request, so NAK is expected
759 logger.info("CoA-Request with matching Acct-Session-Id")
760 req = radius_das.CoAPacket(dict=dict, secret="secret",
761 Acct_Session_Id=id,
762 Event_Timestamp=int(time.time()))
763 send_and_check_reply(srv, req, pyrad.packet.CoANAK, error_cause=405)
764
765 def test_radius_ipv6(dev, apdev):
766 """RADIUS connection over IPv6"""
767 params = {}
768 params['ssid'] = 'as'
769 params['beacon_int'] = '2000'
770 params['radius_server_clients'] = 'auth_serv/radius_clients_ipv6.conf'
771 params['radius_server_ipv6'] = '1'
772 params['radius_server_auth_port'] = '18129'
773 params['radius_server_acct_port'] = '18139'
774 params['eap_server'] = '1'
775 params['eap_user_file'] = 'auth_serv/eap_user.conf'
776 params['ca_cert'] = 'auth_serv/ca.pem'
777 params['server_cert'] = 'auth_serv/server.pem'
778 params['private_key'] = 'auth_serv/server.key'
779 hostapd.add_ap(apdev[1], params)
780
781 params = hostapd.wpa2_eap_params(ssid="radius-ipv6")
782 params['auth_server_addr'] = "::0"
783 params['auth_server_port'] = "18129"
784 params['acct_server_addr'] = "::0"
785 params['acct_server_port'] = "18139"
786 params['acct_server_shared_secret'] = "radius"
787 params['own_ip_addr'] = "::0"
788 hostapd.add_ap(apdev[0], params)
789 connect(dev[0], "radius-ipv6")
790
791 def test_radius_macacl(dev, apdev):
792 """RADIUS MAC ACL"""
793 params = hostapd.radius_params()
794 params["ssid"] = "radius"
795 params["macaddr_acl"] = "2"
796 hostapd.add_ap(apdev[0], params)
797 dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
798
799 def test_radius_macacl_acct(dev, apdev):
800 """RADIUS MAC ACL and accounting enabled"""
801 params = hostapd.radius_params()
802 params["ssid"] = "radius"
803 params["macaddr_acl"] = "2"
804 params['acct_server_addr'] = "127.0.0.1"
805 params['acct_server_port'] = "1813"
806 params['acct_server_shared_secret'] = "radius"
807 hostapd.add_ap(apdev[0], params)
808 dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
809 dev[1].connect("radius", key_mgmt="NONE", scan_freq="2412")
810 dev[1].request("DISCONNECT")
811 dev[1].wait_disconnected()
812 dev[1].request("RECONNECT")
813
814 def test_radius_failover(dev, apdev):
815 """RADIUS Authentication and Accounting server failover"""
816 subprocess.call(['ip', 'ro', 'replace', '192.168.213.17', 'dev', 'lo'])
817 as_hapd = hostapd.Hostapd("as")
818 as_mib_start = as_hapd.get_mib(param="radius_server")
819 params = hostapd.wpa2_eap_params(ssid="radius-failover")
820 params["auth_server_addr"] = "192.168.213.17"
821 params["auth_server_port"] = "1812"
822 params["auth_server_shared_secret"] = "testing"
823 params['acct_server_addr'] = "192.168.213.17"
824 params['acct_server_port'] = "1813"
825 params['acct_server_shared_secret'] = "testing"
826 params['radius_retry_primary_interval'] = "20"
827 hapd = hostapd.add_ap(apdev[0], params, no_enable=True)
828 hapd.set("auth_server_addr", "127.0.0.1")
829 hapd.set("auth_server_port", "1812")
830 hapd.set("auth_server_shared_secret", "radius")
831 hapd.set('acct_server_addr', "127.0.0.1")
832 hapd.set('acct_server_port', "1813")
833 hapd.set('acct_server_shared_secret', "radius")
834 hapd.enable()
835 ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=30)
836 if ev is None:
837 raise Exception("AP startup timed out")
838 if "AP-ENABLED" not in ev:
839 raise Exception("AP startup failed")
840 start = os.times()[4]
841
842 try:
843 subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17'])
844 dev[0].request("SET EAPOL::authPeriod 5")
845 connect(dev[0], "radius-failover", wait_connect=False)
846 dev[0].wait_connected(timeout=20)
847 finally:
848 dev[0].request("SET EAPOL::authPeriod 30")
849 subprocess.call(['ip', 'ro', 'del', '192.168.213.17'])
850
851 as_mib_end = as_hapd.get_mib(param="radius_server")
852 req_s = int(as_mib_start['radiusAccServTotalRequests'])
853 req_e = int(as_mib_end['radiusAccServTotalRequests'])
854 if req_e <= req_s:
855 raise Exception("Unexpected RADIUS server acct MIB value")
856
857 end = os.times()[4]
858 try:
859 subprocess.call(['ip', 'ro', 'replace', 'prohibit', '192.168.213.17'])
860 dev[1].request("SET EAPOL::authPeriod 5")
861 if end - start < 21:
862 time.sleep(21 - (end - start))
863 connect(dev[1], "radius-failover", wait_connect=False)
864 dev[1].wait_connected(timeout=20)
865 finally:
866 dev[1].request("SET EAPOL::authPeriod 30")
867 subprocess.call(['ip', 'ro', 'del', '192.168.213.17'])
868
869 def run_pyrad_server(srv, t_events):
870 srv.RunWithStop(t_events)
871
872 def test_radius_protocol(dev, apdev):
873 """RADIUS Authentication protocol tests with a fake server"""
874 try:
875 import pyrad.server
876 import pyrad.packet
877 import pyrad.dictionary
878 except ImportError:
879 raise HwsimSkip("No pyrad modules available")
880
881 class TestServer(pyrad.server.Server):
882 def _HandleAuthPacket(self, pkt):
883 pyrad.server.Server._HandleAuthPacket(self, pkt)
884 logger.info("Received authentication request")
885 reply = self.CreateReplyPacket(pkt)
886 reply.code = pyrad.packet.AccessAccept
887 if self.t_events['msg_auth'].is_set():
888 logger.info("Add Message-Authenticator")
889 if self.t_events['wrong_secret'].is_set():
890 logger.info("Use incorrect RADIUS shared secret")
891 pw = "incorrect"
892 else:
893 pw = reply.secret
894 hmac_obj = hmac.new(pw)
895 hmac_obj.update(struct.pack("B", reply.code))
896 hmac_obj.update(struct.pack("B", reply.id))
897
898 # reply attributes
899 reply.AddAttribute("Message-Authenticator",
900 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
901 attrs = reply._PktEncodeAttributes()
902
903 # Length
904 flen = 4 + 16 + len(attrs)
905 hmac_obj.update(struct.pack(">H", flen))
906 hmac_obj.update(pkt.authenticator)
907 hmac_obj.update(attrs)
908 if self.t_events['double_msg_auth'].is_set():
909 logger.info("Include two Message-Authenticator attributes")
910 else:
911 del reply[80]
912 reply.AddAttribute("Message-Authenticator", hmac_obj.digest())
913 self.SendReplyPacket(pkt.fd, reply)
914
915 def RunWithStop(self, t_events):
916 self._poll = select.poll()
917 self._fdmap = {}
918 self._PrepareSockets()
919 self.t_events = t_events
920
921 while not t_events['stop'].is_set():
922 for (fd, event) in self._poll.poll(1000):
923 if event == select.POLLIN:
924 try:
925 fdo = self._fdmap[fd]
926 self._ProcessInput(fdo)
927 except ServerPacketError as err:
928 logger.info("pyrad server dropping packet: " + str(err))
929 except pyrad.packet.PacketError as err:
930 logger.info("pyrad server received invalid packet: " + str(err))
931 else:
932 logger.error("Unexpected event in pyrad server main loop")
933
934 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
935 authport=18138, acctport=18139)
936 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
937 "radius",
938 "localhost")
939 srv.BindToAddress("")
940 t_events = {}
941 t_events['stop'] = threading.Event()
942 t_events['msg_auth'] = threading.Event()
943 t_events['wrong_secret'] = threading.Event()
944 t_events['double_msg_auth'] = threading.Event()
945 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events))
946 t.start()
947
948 try:
949 params = hostapd.wpa2_eap_params(ssid="radius-test")
950 params['auth_server_port'] = "18138"
951 hapd = hostapd.add_ap(apdev[0], params)
952 connect(dev[0], "radius-test", wait_connect=False)
953 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"], timeout=15)
954 if ev is None:
955 raise Exception("Timeout on EAP start")
956 time.sleep(1)
957 dev[0].request("REMOVE_NETWORK all")
958 time.sleep(0.1)
959 dev[0].dump_monitor()
960 t_events['msg_auth'].set()
961 t_events['wrong_secret'].set()
962 connect(dev[0], "radius-test", wait_connect=False)
963 time.sleep(1)
964 dev[0].request("REMOVE_NETWORK all")
965 time.sleep(0.1)
966 dev[0].dump_monitor()
967 t_events['wrong_secret'].clear()
968 connect(dev[0], "radius-test", wait_connect=False)
969 time.sleep(1)
970 dev[0].request("REMOVE_NETWORK all")
971 time.sleep(0.1)
972 dev[0].dump_monitor()
973 t_events['double_msg_auth'].set()
974 connect(dev[0], "radius-test", wait_connect=False)
975 time.sleep(1)
976 finally:
977 t_events['stop'].set()
978 t.join()
979
980 def test_radius_psk(dev, apdev):
981 """WPA2 with PSK from RADIUS"""
982 try:
983 import pyrad.server
984 import pyrad.packet
985 import pyrad.dictionary
986 except ImportError:
987 raise HwsimSkip("No pyrad modules available")
988
989 class TestServer(pyrad.server.Server):
990 def _HandleAuthPacket(self, pkt):
991 pyrad.server.Server._HandleAuthPacket(self, pkt)
992 logger.info("Received authentication request")
993 reply = self.CreateReplyPacket(pkt)
994 reply.code = pyrad.packet.AccessAccept
995 a = "\xab\xcd"
996 secret = reply.secret
997 if self.t_events['long'].is_set():
998 p = b'\x10' + "0123456789abcdef" + 15 * b'\x00'
999 b = hashlib.md5(secret + pkt.authenticator + a).digest()
1000 pp = bytearray(p[0:16])
1001 bb = bytearray(b)
1002 cc = bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
1003
1004 b = hashlib.md5(reply.secret + bytes(cc)).digest()
1005 pp = bytearray(p[16:32])
1006 bb = bytearray(b)
1007 cc += bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
1008
1009 data = '\x00' + a + bytes(cc)
1010 else:
1011 p = b'\x08' + "12345678" + 7 * b'\x00'
1012 b = hashlib.md5(secret + pkt.authenticator + a).digest()
1013 pp = bytearray(p)
1014 bb = bytearray(b)
1015 cc = bytearray(pp[i] ^ bb[i] for i in range(len(bb)))
1016 data = '\x00' + a + bytes(cc)
1017 reply.AddAttribute("Tunnel-Password", data)
1018 self.SendReplyPacket(pkt.fd, reply)
1019
1020 def RunWithStop(self, t_events):
1021 self._poll = select.poll()
1022 self._fdmap = {}
1023 self._PrepareSockets()
1024 self.t_events = t_events
1025
1026 while not t_events['stop'].is_set():
1027 for (fd, event) in self._poll.poll(1000):
1028 if event == select.POLLIN:
1029 try:
1030 fdo = self._fdmap[fd]
1031 self._ProcessInput(fdo)
1032 except ServerPacketError as err:
1033 logger.info("pyrad server dropping packet: " + str(err))
1034 except pyrad.packet.PacketError as err:
1035 logger.info("pyrad server received invalid packet: " + str(err))
1036 else:
1037 logger.error("Unexpected event in pyrad server main loop")
1038
1039 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
1040 authport=18138, acctport=18139)
1041 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
1042 "radius",
1043 "localhost")
1044 srv.BindToAddress("")
1045 t_events = {}
1046 t_events['stop'] = threading.Event()
1047 t_events['long'] = threading.Event()
1048 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events))
1049 t.start()
1050
1051 try:
1052 ssid = "test-wpa2-psk"
1053 params = hostapd.radius_params()
1054 params['ssid'] = ssid
1055 params["wpa"] = "2"
1056 params["wpa_key_mgmt"] = "WPA-PSK"
1057 params["rsn_pairwise"] = "CCMP"
1058 params['macaddr_acl'] = '2'
1059 params['wpa_psk_radius'] = '2'
1060 params['auth_server_port'] = "18138"
1061 hapd = hostapd.add_ap(apdev[0], params)
1062 dev[0].connect(ssid, psk="12345678", scan_freq="2412")
1063 t_events['long'].set()
1064 dev[1].connect(ssid, psk="0123456789abcdef", scan_freq="2412")
1065 finally:
1066 t_events['stop'].set()
1067 t.join()
1068
1069 def test_radius_auth_force_client_addr(dev, apdev):
1070 """RADIUS client address specified"""
1071 params = hostapd.wpa2_eap_params(ssid="radius-auth")
1072 params['radius_client_addr'] = "127.0.0.1"
1073 hapd = hostapd.add_ap(apdev[0], params)
1074 connect(dev[0], "radius-auth")
1075
1076 def test_radius_auth_force_invalid_client_addr(dev, apdev):
1077 """RADIUS client address specified and invalid address"""
1078 params = hostapd.wpa2_eap_params(ssid="radius-auth")
1079 #params['radius_client_addr'] = "10.11.12.14"
1080 params['radius_client_addr'] = "1::2"
1081 hapd = hostapd.add_ap(apdev[0], params)
1082 connect(dev[0], "radius-auth", wait_connect=False)
1083 ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
1084 if ev is None:
1085 raise Exception("Timeout on EAP start")
1086 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=1)
1087 if ev is not None:
1088 raise Exception("Unexpected connection")
1089
1090 def add_message_auth(req):
1091 req.authenticator = req.CreateAuthenticator()
1092 hmac_obj = hmac.new(req.secret)
1093 hmac_obj.update(struct.pack("B", req.code))
1094 hmac_obj.update(struct.pack("B", req.id))
1095
1096 # request attributes
1097 req.AddAttribute("Message-Authenticator",
1098 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
1099 attrs = req._PktEncodeAttributes()
1100
1101 # Length
1102 flen = 4 + 16 + len(attrs)
1103 hmac_obj.update(struct.pack(">H", flen))
1104 hmac_obj.update(req.authenticator)
1105 hmac_obj.update(attrs)
1106 del req[80]
1107 req.AddAttribute("Message-Authenticator", hmac_obj.digest())
1108
1109 def test_radius_server_failures(dev, apdev):
1110 """RADIUS server failure cases"""
1111 try:
1112 import pyrad.client
1113 import pyrad.packet
1114 import pyrad.dictionary
1115 except ImportError:
1116 raise HwsimSkip("No pyrad modules available")
1117
1118 dict = pyrad.dictionary.Dictionary("dictionary.radius")
1119 client = pyrad.client.Client(server="127.0.0.1", authport=1812,
1120 secret="radius", dict=dict)
1121 client.retries = 1
1122 client.timeout = 1
1123
1124 # unexpected State
1125 req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest,
1126 User_Name="foo")
1127 req['State'] = 'foo-state'
1128 add_message_auth(req)
1129 reply = client.SendPacket(req)
1130 if reply.code != pyrad.packet.AccessReject:
1131 raise Exception("Unexpected RADIUS response code " + str(reply.code))
1132
1133 # no EAP-Message
1134 req = client.CreateAuthPacket(code=pyrad.packet.AccessRequest,
1135 User_Name="foo")
1136 add_message_auth(req)
1137 try:
1138 reply = client.SendPacket(req)
1139 raise Exception("Unexpected response")
1140 except pyrad.client.Timeout:
1141 pass
1142
1143 def test_ap_vlan_wpa2_psk_radius_required(dev, apdev):
1144 """AP VLAN with WPA2-PSK and RADIUS attributes required"""
1145 try:
1146 import pyrad.server
1147 import pyrad.packet
1148 import pyrad.dictionary
1149 except ImportError:
1150 raise HwsimSkip("No pyrad modules available")
1151
1152 class TestServer(pyrad.server.Server):
1153 def _HandleAuthPacket(self, pkt):
1154 pyrad.server.Server._HandleAuthPacket(self, pkt)
1155 logger.info("Received authentication request")
1156 reply = self.CreateReplyPacket(pkt)
1157 reply.code = pyrad.packet.AccessAccept
1158 secret = reply.secret
1159 if self.t_events['extra'].is_set():
1160 reply.AddAttribute("Chargeable-User-Identity", "test-cui")
1161 reply.AddAttribute("User-Name", "test-user")
1162 if self.t_events['long'].is_set():
1163 reply.AddAttribute("Tunnel-Type", 13)
1164 reply.AddAttribute("Tunnel-Medium-Type", 6)
1165 reply.AddAttribute("Tunnel-Private-Group-ID", "1")
1166 self.SendReplyPacket(pkt.fd, reply)
1167
1168 def RunWithStop(self, t_events):
1169 self._poll = select.poll()
1170 self._fdmap = {}
1171 self._PrepareSockets()
1172 self.t_events = t_events
1173
1174 while not t_events['stop'].is_set():
1175 for (fd, event) in self._poll.poll(1000):
1176 if event == select.POLLIN:
1177 try:
1178 fdo = self._fdmap[fd]
1179 self._ProcessInput(fdo)
1180 except ServerPacketError as err:
1181 logger.info("pyrad server dropping packet: " + str(err))
1182 except pyrad.packet.PacketError as err:
1183 logger.info("pyrad server received invalid packet: " + str(err))
1184 else:
1185 logger.error("Unexpected event in pyrad server main loop")
1186
1187 srv = TestServer(dict=pyrad.dictionary.Dictionary("dictionary.radius"),
1188 authport=18138, acctport=18139)
1189 srv.hosts["127.0.0.1"] = pyrad.server.RemoteHost("127.0.0.1",
1190 "radius",
1191 "localhost")
1192 srv.BindToAddress("")
1193 t_events = {}
1194 t_events['stop'] = threading.Event()
1195 t_events['long'] = threading.Event()
1196 t_events['extra'] = threading.Event()
1197 t = threading.Thread(target=run_pyrad_server, args=(srv, t_events))
1198 t.start()
1199
1200 try:
1201 ssid = "test-wpa2-psk"
1202 params = hostapd.radius_params()
1203 params['ssid'] = ssid
1204 params["wpa"] = "2"
1205 params["wpa_key_mgmt"] = "WPA-PSK"
1206 params["rsn_pairwise"] = "CCMP"
1207 params['macaddr_acl'] = '2'
1208 params['dynamic_vlan'] = "2"
1209 params['wpa_passphrase'] = '0123456789abcdefghi'
1210 params['auth_server_port'] = "18138"
1211 hapd = hostapd.add_ap(apdev[0], params)
1212
1213 logger.info("connecting without VLAN")
1214 dev[0].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412",
1215 wait_connect=False)
1216 ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED",
1217 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20)
1218 if ev is None:
1219 raise Exception("Timeout on connection attempt")
1220 if "CTRL-EVENT-CONNECTED" in ev:
1221 raise Exception("Unexpected success without vlan parameters")
1222 logger.info("connecting without VLAN failed as expected")
1223
1224 logger.info("connecting without VLAN (CUI/User-Name)")
1225 t_events['extra'].set()
1226 dev[1].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412",
1227 wait_connect=False)
1228 ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED",
1229 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20)
1230 if ev is None:
1231 raise Exception("Timeout on connection attempt")
1232 if "CTRL-EVENT-CONNECTED" in ev:
1233 raise Exception("Unexpected success without vlan parameters(2)")
1234 logger.info("connecting without VLAN failed as expected(2)")
1235 t_events['extra'].clear()
1236
1237 t_events['long'].set()
1238 logger.info("connecting with VLAN")
1239 dev[2].connect(ssid, psk="0123456789abcdefghi", scan_freq="2412",
1240 wait_connect=False)
1241 ev = dev[2].wait_event(["CTRL-EVENT-CONNECTED",
1242 "CTRL-EVENT-SSID-TEMP-DISABLED"], timeout=20)
1243 if ev is None:
1244 raise Exception("Timeout on connection attempt")
1245 if "CTRL-EVENT-SSID-TEMP-DISABLED" in ev:
1246 raise Exception("Unexpected failure with vlan parameters")
1247 logger.info("connecting with VLAN succeeded as expected")
1248 finally:
1249 t_events['stop'].set()
1250 t.join()