pyrad 2.4__py3-none-any.whl → 2.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. docs/Makefile +20 -0
  2. docs/make.bat +36 -0
  3. docs/source/_static/logo.png +0 -0
  4. docs/source/api/client.rst +10 -0
  5. docs/source/api/dictionary.rst +10 -0
  6. docs/source/api/host.rst +7 -0
  7. docs/source/api/packet.rst +48 -0
  8. docs/source/api/proxy.rst +7 -0
  9. docs/source/api/server.rst +13 -0
  10. docs/source/conf.py +158 -0
  11. docs/source/index.rst +75 -0
  12. example/acct.py +41 -0
  13. example/auth.py +37 -0
  14. example/auth_async.py +164 -0
  15. example/client-coa.py +61 -0
  16. example/coa.py +40 -0
  17. example/dictionary +405 -0
  18. example/dictionary.freeradius +91 -0
  19. example/pyrad.log +0 -0
  20. example/server.py +68 -0
  21. example/server_async.py +117 -0
  22. example/status.py +26 -0
  23. pyrad/__init__.py +3 -3
  24. pyrad/client.py +14 -6
  25. pyrad/client_async.py +16 -13
  26. pyrad/dictfile.py +2 -5
  27. pyrad/dictionary.py +6 -7
  28. pyrad/host.py +1 -1
  29. pyrad/packet.py +145 -114
  30. pyrad/proxy.py +2 -2
  31. pyrad/server.py +3 -7
  32. pyrad/server_async.py +3 -4
  33. pyrad/tests/__init__.py +5 -0
  34. pyrad/tests/mock.py +145 -0
  35. pyrad/tests/test_bidict.py +56 -0
  36. pyrad/tests/test_client.py +183 -0
  37. pyrad/tests/test_dictionary.py +357 -0
  38. pyrad/tests/test_host.py +87 -0
  39. pyrad/tests/test_packet.py +679 -0
  40. pyrad/tests/test_proxy.py +96 -0
  41. pyrad/tests/test_server.py +323 -0
  42. pyrad/tests/test_tools.py +126 -0
  43. pyrad/tools.py +254 -158
  44. {pyrad-2.4.dist-info → pyrad-2.5.1.dist-info}/METADATA +45 -22
  45. pyrad-2.5.1.dist-info/RECORD +51 -0
  46. {pyrad-2.4.dist-info → pyrad-2.5.1.dist-info}/WHEEL +1 -1
  47. {pyrad-2.4.dist-info → pyrad-2.5.1.dist-info/licenses}/LICENSE.txt +1 -1
  48. pyrad-2.5.1.dist-info/top_level.txt +3 -0
  49. pyrad-2.4.dist-info/RECORD +0 -19
  50. pyrad-2.4.dist-info/top_level.txt +0 -1
  51. {pyrad-2.4.dist-info → pyrad-2.5.1.dist-info}/zip-safe +0 -0
pyrad/packet.py CHANGED
@@ -5,18 +5,26 @@
5
5
  # A RADIUS packet as defined in RFC 2138
6
6
 
7
7
  from collections import OrderedDict
8
+ from pyrad import tools
9
+ import hmac
8
10
  import struct
11
+ import sys
12
+
9
13
  try:
10
14
  import secrets
11
15
  random_generator = secrets.SystemRandom()
12
16
  except ImportError:
13
17
  import random
14
18
  random_generator = random.SystemRandom()
15
- import hmac
16
19
 
17
- import sys
20
+
21
+ def _hmac_md5(*args, **kwargs):
22
+ """Py3 hmac.new() wrapper with explicit MD5 digestmod."""
23
+ return hmac.new(*args, digestmod='MD5', **kwargs)
24
+
25
+
18
26
  if sys.version_info >= (3, 0):
19
- hmac_new = lambda *x, **y: hmac.new(*x, digestmod='MD5', **y)
27
+ hmac_new = _hmac_md5
20
28
  else:
21
29
  hmac_new = hmac.new
22
30
 
@@ -27,8 +35,6 @@ except ImportError:
27
35
  # BBB for python 2.4
28
36
  import md5
29
37
  md5_constructor = md5.new
30
- import six
31
- from pyrad import tools
32
38
 
33
39
  # Packet codes
34
40
  AccessRequest = 1
@@ -60,7 +66,7 @@ class Packet(OrderedDict):
60
66
  attributes the value will always be a sequence. pyrad makes sure
61
67
  to preserve the ordering when encoding and decoding packets.
62
68
 
63
- There are two ways to use the map intereface: if attribute
69
+ There are two ways to use the map interface: if attribute
64
70
  names are used pyrad take care of en-/decoding data. If
65
71
  the attribute type number (or a vendor ID/attribute type
66
72
  tuple for vendor attributes) is used you work with the
@@ -70,7 +76,7 @@ class Packet(OrderedDict):
70
76
  :obj:`AuthPacket` or :obj:`AcctPacket` classes.
71
77
  """
72
78
 
73
- def __init__(self, code=0, id=None, secret=six.b(''), authenticator=None,
79
+ def __init__(self, code=0, id=None, secret=b'', authenticator=None,
74
80
  **attributes):
75
81
  """Constructor
76
82
 
@@ -91,13 +97,14 @@ class Packet(OrderedDict):
91
97
  self.id = id
92
98
  else:
93
99
  self.id = CreateID()
94
- if not isinstance(secret, six.binary_type):
100
+ if not isinstance(secret, bytes):
95
101
  raise TypeError('secret must be a binary string')
96
102
  self.secret = secret
97
103
  if authenticator is not None and \
98
- not isinstance(authenticator, six.binary_type):
104
+ not isinstance(authenticator, bytes):
99
105
  raise TypeError('authenticator must be a binary string')
100
106
  self.authenticator = authenticator
107
+ self.request_authenticator = None # used for storing request authenticator in reply packets
101
108
  self.message_authenticator = None
102
109
  self.raw_packet = None
103
110
 
@@ -124,7 +131,7 @@ class Packet(OrderedDict):
124
131
 
125
132
  self.message_authenticator = True
126
133
  # Maintain a zero octets content for md5 and hmac calculation.
127
- self['Message-Authenticator'] = 16 * six.b('\00')
134
+ self['Message-Authenticator'] = 16 * b'\00'
128
135
 
129
136
  if self.id is None:
130
137
  self.id = self.CreateID()
@@ -141,7 +148,7 @@ class Packet(OrderedDict):
141
148
  hmac_constructor = hmac_new(self.secret)
142
149
 
143
150
  # Maintain a zero octets content for md5 and hmac calculation.
144
- self['Message-Authenticator'] = 16 * six.b('\00')
151
+ self['Message-Authenticator'] = 16 * b'\00'
145
152
  attr = self._PktEncodeAttributes()
146
153
 
147
154
  header = struct.pack('!BBH', self.code, self.id,
@@ -150,7 +157,7 @@ class Packet(OrderedDict):
150
157
  hmac_constructor.update(header[0:4])
151
158
  if self.code in (AccountingRequest, DisconnectRequest,
152
159
  CoARequest, AccountingResponse):
153
- hmac_constructor.update(16 * six.b('\00'))
160
+ hmac_constructor.update(16 * b'\00')
154
161
  else:
155
162
  # NOTE: self.authenticator on reply packet is initialized
156
163
  # with request authenticator by design.
@@ -197,9 +204,9 @@ class Packet(OrderedDict):
197
204
  # attributes exactly as sent.
198
205
  if self.raw_packet:
199
206
  attr = self.raw_packet[20:]
200
- attr = attr.replace(prev_ma[0], 16 * six.b('\00'))
207
+ attr = attr.replace(prev_ma[0], 16 * b'\00')
201
208
  else:
202
- self['Message-Authenticator'] = 16 * six.b('\00')
209
+ self['Message-Authenticator'] = 16 * b'\00'
203
210
  attr = self._PktEncodeAttributes()
204
211
 
205
212
  header = struct.pack('!BBH', self.code, self.id,
@@ -211,7 +218,7 @@ class Packet(OrderedDict):
211
218
  CoARequest, AccountingResponse):
212
219
  if original_code is None or original_code != StatusServer:
213
220
  # TODO: Handle Status-Server response correctly.
214
- hmac_constructor.update(16 * six.b('\00'))
221
+ hmac_constructor.update(16 * b'\00')
215
222
  elif self.code in (AccessAccept, AccessChallenge,
216
223
  AccessReject):
217
224
  if original_authenticator is None:
@@ -241,6 +248,10 @@ class Packet(OrderedDict):
241
248
  **attributes)
242
249
 
243
250
  def _DecodeValue(self, attr, value):
251
+ if attr.encrypt == 2:
252
+ # salt decrypt attribute
253
+ value = self.SaltDecrypt(value)
254
+
244
255
  if attr.values.HasBackward(value):
245
256
  return attr.values.GetBackward(value)
246
257
  else:
@@ -283,7 +294,7 @@ class Packet(OrderedDict):
283
294
  return key
284
295
 
285
296
  attr = self.dict.attributes[key]
286
- if attr.vendor and not attr.is_sub_attribute: #sub attribute keys don't need vendor
297
+ if attr.vendor and not attr.is_sub_attribute: # sub attribute keys don't need vendor
287
298
  return (self.dict.vendors.GetForward(attr.vendor), attr.code)
288
299
  else:
289
300
  return attr.code
@@ -324,7 +335,7 @@ class Packet(OrderedDict):
324
335
  return res
325
336
 
326
337
  def __getitem__(self, key):
327
- if not isinstance(key, six.string_types):
338
+ if not isinstance(key, str):
328
339
  return OrderedDict.__getitem__(self, key)
329
340
 
330
341
  values = OrderedDict.__getitem__(self, self._EncodeKey(key))
@@ -355,7 +366,7 @@ class Packet(OrderedDict):
355
366
  OrderedDict.__delitem__(self, self._EncodeKey(key))
356
367
 
357
368
  def __setitem__(self, key, item):
358
- if isinstance(key, six.string_types):
369
+ if isinstance(key, str):
359
370
  (key, item) = self._EncodeKeyValues(key, item)
360
371
  OrderedDict.__setitem__(self, key, item)
361
372
  else:
@@ -374,14 +385,10 @@ class Packet(OrderedDict):
374
385
  :return: valid packet authenticator
375
386
  :rtype: binary string
376
387
  """
377
-
378
- data = []
379
- for _ in range(16):
380
- data.append(random_generator.randrange(0, 256))
381
- if six.PY3:
382
- return bytes(data)
383
- else:
384
- return ''.join(chr(b) for b in data)
388
+ return bytes(
389
+ random_generator.randrange(0, 256)
390
+ for _ in range(16)
391
+ )
385
392
 
386
393
  def CreateID(self):
387
394
  """Create a packet ID. All RADIUS requests have a ID which is used to
@@ -403,8 +410,8 @@ class Packet(OrderedDict):
403
410
  :return: raw packet
404
411
  :rtype: string
405
412
  """
406
- assert(self.authenticator)
407
- assert(self.secret is not None)
413
+ assert (self.authenticator)
414
+ assert (self.secret is not None)
408
415
 
409
416
  if self.message_authenticator:
410
417
  self._refresh_message_authenticator()
@@ -417,14 +424,14 @@ class Packet(OrderedDict):
417
424
 
418
425
  return header + authenticator + attr
419
426
 
420
- def VerifyReply(self, reply, rawreply=None):
427
+ def VerifyReply(self, reply, rawreply=None, enforce_ma=False):
421
428
  if reply.id != self.id:
422
429
  return False
423
430
 
424
431
  if rawreply is None:
425
432
  rawreply = reply.ReplyPacket()
426
433
 
427
- attr = reply._PktEncodeAttributes()
434
+ _ = reply._PktEncodeAttributes()
428
435
  # The Authenticator field in an Accounting-Response packet is called
429
436
  # the Response Authenticator, and contains a one-way MD5 hash
430
437
  # calculated over a stream of octets consisting of the Accounting
@@ -438,6 +445,13 @@ class Packet(OrderedDict):
438
445
 
439
446
  if hash != rawreply[4:20]:
440
447
  return False
448
+
449
+ if enforce_ma:
450
+ if self.message_authenticator is None:
451
+ return False
452
+ if not self.verify_message_authenticator():
453
+ return False
454
+
441
455
  return True
442
456
 
443
457
  def _PktEncodeAttribute(self, key, value):
@@ -450,11 +464,11 @@ class Packet(OrderedDict):
450
464
 
451
465
  def _PktEncodeTlv(self, tlv_key, tlv_value):
452
466
  tlv_attr = self.dict.attributes[self._DecodeKey(tlv_key)]
453
- curr_avp = six.b('')
467
+ curr_avp = b''
454
468
  avps = []
455
469
  max_sub_attribute_len = max(map(lambda item: len(item[1]), tlv_value.items()))
456
470
  for i in range(max_sub_attribute_len):
457
- sub_attr_encoding = six.b('')
471
+ sub_attr_encoding = b''
458
472
  for (code, datalst) in tlv_value.items():
459
473
  if i < len(datalst):
460
474
  sub_attr_encoding += self._PktEncodeAttribute(code, datalst[i])
@@ -470,7 +484,7 @@ class Packet(OrderedDict):
470
484
  value = struct.pack('!BB', tlv_attr.code, (len(avp) + 2)) + avp
471
485
  tlv_avps.append(value)
472
486
  if tlv_attr.vendor:
473
- vendor_avps = six.b('')
487
+ vendor_avps = b''
474
488
  for avp in tlv_avps:
475
489
  vendor_avps += struct.pack(
476
490
  '!BBL', 26, (len(avp) + 6),
@@ -481,10 +495,9 @@ class Packet(OrderedDict):
481
495
  return b''.join(tlv_avps)
482
496
 
483
497
  def _PktEncodeAttributes(self):
484
- result = six.b('')
498
+ result = b''
485
499
  for (code, datalst) in self.items():
486
- attribute = self.dict.attributes.get(self._DecodeKey(code))
487
- if attribute and attribute.type == 'tlv':
500
+ if self._PktIsTlvAttribute(code):
488
501
  result += self._PktEncodeTlv(code, datalst)
489
502
  else:
490
503
  for data in datalst:
@@ -498,21 +511,20 @@ class Packet(OrderedDict):
498
511
  return [(26, data)]
499
512
 
500
513
  (vendor, atype, length) = struct.unpack('!LBB', data[:6])[0:3]
501
- attribute = self.dict.attributes.get(self._DecodeKey((vendor, atype)))
502
514
  try:
503
- if attribute and attribute.type == 'tlv':
515
+ if self._PktIsTlvAttribute((vendor, atype)):
504
516
  self._PktDecodeTlvAttribute((vendor, atype), data[6:length + 4])
505
517
  tlvs = [] # tlv is added to the packet inside _PktDecodeTlvAttribute
506
518
  else:
507
519
  tlvs = [((vendor, atype), data[6:length + 4])]
508
- except:
520
+ except Exception:
509
521
  return [(26, data)]
510
522
 
511
523
  sumlength = 4 + length
512
524
  while len(data) > sumlength:
513
525
  try:
514
526
  atype, length = struct.unpack('!BB', data[sumlength:sumlength+2])[0:2]
515
- except:
527
+ except Exception:
516
528
  return [(26, data)]
517
529
  tlvs.append(((vendor, atype), data[sumlength+2:sumlength+length]))
518
530
  sumlength += length
@@ -527,6 +539,10 @@ class Packet(OrderedDict):
527
539
  sub_attributes.setdefault(atype, []).append(data[loc+2:loc+length])
528
540
  loc += length
529
541
 
542
+ def _PktIsTlvAttribute(self, code):
543
+ attr = self.dict.attributes.get(self._DecodeKey(code))
544
+ return (attr is not None and attr.type == 'tlv')
545
+
530
546
  def DecodePacket(self, packet):
531
547
  """Initialize the object from raw packet data. Decode a packet as
532
548
  received from the network and decode it.
@@ -555,11 +571,9 @@ class Packet(OrderedDict):
555
571
  raise PacketError('Attribute header is corrupt')
556
572
 
557
573
  if attrlen < 2:
558
- raise PacketError(
559
- 'Attribute length is too small (%d)' % attrlen)
574
+ raise PacketError('Attribute length is too small (%d)' % attrlen)
560
575
 
561
576
  value = packet[2:attrlen]
562
- attribute = self.dict.attributes.get(self._DecodeKey(key))
563
577
  if key == 26:
564
578
  for (key, value) in self._PktDecodeVendorAttribute(value):
565
579
  self.setdefault(key, []).append(value)
@@ -567,63 +581,82 @@ class Packet(OrderedDict):
567
581
  # POST: Message Authenticator AVP is present.
568
582
  self.message_authenticator = True
569
583
  self.setdefault(key, []).append(value)
570
- elif attribute and attribute.type == 'tlv':
571
- self._PktDecodeTlvAttribute(key,value)
584
+ elif self._PktIsTlvAttribute(key):
585
+ self._PktDecodeTlvAttribute(key, value)
572
586
  else:
573
587
  self.setdefault(key, []).append(value)
574
588
 
575
589
  packet = packet[attrlen:]
576
590
 
591
+ def _salt_en_decrypt(self, data, salt):
592
+ result = b''
593
+ if self.request_authenticator is not None:
594
+ last = self.request_authenticator + salt
595
+ else:
596
+ last = self.authenticator + salt
597
+ while data:
598
+ hash = md5_constructor(self.secret + last).digest()
599
+ for i in range(16):
600
+ result += bytes((hash[i] ^ data[i],))
601
+
602
+ last = result[-16:]
603
+ data = data[16:]
604
+ return result
605
+
577
606
  def SaltCrypt(self, value):
578
- """Salt Encryption
607
+ """SaltEncrypt
579
608
 
580
609
  :param value: plaintext value
581
- :type password: unicode string
610
+ :type: unicode string
582
611
  :return: obfuscated version of the value
583
612
  :rtype: binary string
584
613
  """
585
614
 
586
- if isinstance(value, six.text_type):
615
+ if isinstance(value, str):
587
616
  value = value.encode('utf-8')
588
617
 
589
618
  if self.authenticator is None:
590
619
  # self.authenticator = self.CreateAuthenticator()
591
- self.authenticator = 16 * six.b('\x00')
620
+ self.authenticator = 16 * b'\x00'
592
621
 
622
+ # create salt
593
623
  random_value = 32768 + random_generator.randrange(0, 32767)
594
- if six.PY3:
595
- salt_raw = struct.pack('!H', random_value )
596
- salt = chr(salt_raw[0]) + chr(salt_raw[1])
597
- else:
598
- salt = struct.pack('!H', random_value )
599
- salt = chr(ord(salt[0]) | 1 << 7)+salt[1]
600
-
601
- result = six.b(salt)
624
+ salt_raw = struct.pack('!H', random_value)
602
625
 
626
+ # length prefixing
603
627
  length = struct.pack("B", len(value))
604
- buf = length + value
605
- if len(buf) % 16 != 0:
606
- buf += six.b('\x00') * (16 - (len(buf) % 16))
628
+ value = length + value
607
629
 
608
- last = self.authenticator + six.b(salt)
609
- while buf:
610
- hash = md5_constructor(self.secret + last).digest()
611
- if six.PY3:
612
- for i in range(16):
613
- result += bytes((hash[i] ^ buf[i],))
614
- else:
615
- for i in range(16):
616
- result += chr(ord(hash[i]) ^ ord(buf[i]))
630
+ # zero padding
631
+ if len(value) % 16 != 0:
632
+ value += b'\x00' * (16 - (len(value) % 16))
617
633
 
618
- last = result[-16:]
619
- buf = buf[16:]
634
+ return salt_raw + self._salt_en_decrypt(value, salt_raw)
620
635
 
621
- return result
636
+ def SaltDecrypt(self, value):
637
+ """ SaltDecrypt
638
+
639
+ :param value: encrypted value including salt
640
+ :type: binary string
641
+ :return: decrypted plaintext string
642
+ :rtype: unicode string
643
+ """
644
+ # extract salt
645
+ salt = value[:2]
646
+
647
+ # decrypt
648
+ value = self._salt_en_decrypt(value[2:], salt)
649
+
650
+ # remove padding
651
+ length = value[0]
652
+ value = value[1:length+1]
653
+
654
+ return value
622
655
 
623
656
 
624
657
  class AuthPacket(Packet):
625
- def __init__(self, code=AccessRequest, id=None, secret=six.b(''),
626
- authenticator=None, auth_type='pap', **attributes):
658
+ def __init__(self, code=AccessRequest, id=None, secret=b'',
659
+ authenticator=None, auth_type='pap', **attributes):
627
660
  """Constructor
628
661
 
629
662
  :param code: packet type code
@@ -692,34 +725,39 @@ class AuthPacket(Packet):
692
725
  return header + attr
693
726
 
694
727
  def PwDecrypt(self, password):
695
- """Obfuscate a RADIUS password. RADIUS hides passwords in packets by
728
+ """De-Obfuscate a RADIUS password. RADIUS hides passwords in packets by
696
729
  using an algorithm based on the MD5 hash of the packet authenticator
697
730
  and RADIUS secret. This function reverses the obfuscation process.
698
731
 
732
+ Although RFC2865 does not explicitly state UTF-8 for the password field,
733
+ the rest of RFC2865 defines UTF-8 as the encoding expected for the decrypted password.
734
+
735
+
699
736
  :param password: obfuscated form of password
700
737
  :type password: binary string
701
738
  :return: plaintext password
702
739
  :rtype: unicode string
703
740
  """
704
741
  buf = password
705
- pw = six.b('')
742
+ pw = b''
706
743
 
707
744
  last = self.authenticator
708
745
  while buf:
709
746
  hash = md5_constructor(self.secret + last).digest()
710
- if six.PY3:
711
- for i in range(16):
712
- pw += bytes((hash[i] ^ buf[i],))
713
- else:
714
- for i in range(16):
715
- pw += chr(ord(hash[i]) ^ ord(buf[i]))
716
-
747
+ for i in range(16):
748
+ pw += bytes((hash[i] ^ buf[i],))
717
749
  (last, buf) = (buf[:16], buf[16:])
718
750
 
719
- while pw.endswith(six.b('\x00')):
751
+ # This is safe even with UTF-8 encoding since no valid encoding of UTF-8
752
+ # (other than encoding U+0000 NULL) will produce a bytestream containing 0x00 byte.
753
+ while pw.endswith(b'\x00'):
720
754
  pw = pw[:-1]
721
755
 
722
- return pw.decode('utf-8')
756
+ # If the shared secret with the client is not the same, then de-obfuscating the password
757
+ # field may yield illegal UTF-8 bytes. Therefore, in order not to provoke an Exception here
758
+ # (which would be not consistently generated since this will depend on the random data
759
+ # chosen by the client) we simply ignore un-parsable UTF-8 sequences.
760
+ return pw.decode('utf-8', errors="ignore")
723
761
 
724
762
  def PwCrypt(self, password):
725
763
  """Obfuscate password.
@@ -738,25 +776,20 @@ class AuthPacket(Packet):
738
776
  if self.authenticator is None:
739
777
  self.authenticator = self.CreateAuthenticator()
740
778
 
741
- if isinstance(password, six.text_type):
779
+ if isinstance(password, str):
742
780
  password = password.encode('utf-8')
743
781
 
744
782
  buf = password
745
783
  if len(password) % 16 != 0:
746
- buf += six.b('\x00') * (16 - (len(password) % 16))
784
+ buf += b'\x00' * (16 - (len(password) % 16))
747
785
 
748
- result = six.b('')
786
+ result = b''
749
787
 
750
788
  last = self.authenticator
751
789
  while buf:
752
790
  hash = md5_constructor(self.secret + last).digest()
753
- if six.PY3:
754
- for i in range(16):
755
- result += bytes((hash[i] ^ buf[i],))
756
- else:
757
- for i in range(16):
758
- result += chr(ord(hash[i]) ^ ord(buf[i]))
759
-
791
+ for i in range(16):
792
+ result += bytes((hash[i] ^ buf[i],))
760
793
  last = result[-16:]
761
794
  buf = buf[16:]
762
795
 
@@ -774,16 +807,14 @@ class AuthPacket(Packet):
774
807
  if not self.authenticator:
775
808
  self.authenticator = self.CreateAuthenticator()
776
809
 
777
- if isinstance(userpwd, six.text_type):
810
+ if isinstance(userpwd, str):
778
811
  userpwd = userpwd.strip().encode('utf-8')
779
812
 
780
813
  chap_password = tools.DecodeOctets(self.get(3)[0])
781
814
  if len(chap_password) != 17:
782
815
  return False
783
816
 
784
- chapid = chap_password[0]
785
- if six.PY3:
786
- chapid = chr(chapid).encode('utf-8')
817
+ chapid = chap_password[:1]
787
818
  password = chap_password[1:]
788
819
 
789
820
  challenge = self.authenticator
@@ -794,11 +825,11 @@ class AuthPacket(Packet):
794
825
  def VerifyAuthRequest(self):
795
826
  """Verify request authenticator.
796
827
 
797
- :return: True if verification failed else False
828
+ :return: True if verification passed else False
798
829
  :rtype: boolean
799
830
  """
800
- assert(self.raw_packet)
801
- hash = md5_constructor(self.raw_packet[0:4] + 16 * six.b('\x00') +
831
+ assert (self.raw_packet)
832
+ hash = md5_constructor(self.raw_packet[0:4] + 16 * b'\x00' +
802
833
  self.raw_packet[20:] + self.secret).digest()
803
834
  return hash == self.authenticator
804
835
 
@@ -808,7 +839,7 @@ class AcctPacket(Packet):
808
839
  of the generic :obj:`Packet` class for accounting packets.
809
840
  """
810
841
 
811
- def __init__(self, code=AccountingRequest, id=None, secret=six.b(''),
842
+ def __init__(self, code=AccountingRequest, id=None, secret=b'',
812
843
  authenticator=None, **attributes):
813
844
  """Constructor
814
845
 
@@ -837,12 +868,12 @@ class AcctPacket(Packet):
837
868
  def VerifyAcctRequest(self):
838
869
  """Verify request authenticator.
839
870
 
840
- :return: False if verification failed else True
871
+ :return: True if verification passed else False
841
872
  :rtype: boolean
842
873
  """
843
- assert(self.raw_packet)
874
+ assert (self.raw_packet)
844
875
 
845
- hash = md5_constructor(self.raw_packet[0:4] + 16 * six.b('\x00') +
876
+ hash = md5_constructor(self.raw_packet[0:4] + 16 * b'\x00' +
846
877
  self.raw_packet[20:] + self.secret).digest()
847
878
 
848
879
  return hash == self.authenticator
@@ -864,7 +895,7 @@ class AcctPacket(Packet):
864
895
 
865
896
  attr = self._PktEncodeAttributes()
866
897
  header = struct.pack('!BBH', self.code, self.id, (20 + len(attr)))
867
- self.authenticator = md5_constructor(header[0:4] + 16 * six.b('\x00') +
898
+ self.authenticator = md5_constructor(header[0:4] + 16 * b'\x00' +
868
899
  attr + self.secret).digest()
869
900
 
870
901
  ans = header + self.authenticator + attr
@@ -877,8 +908,8 @@ class CoAPacket(Packet):
877
908
  of the generic :obj:`Packet` class for CoA packets.
878
909
  """
879
910
 
880
- def __init__(self, code=CoARequest, id=None, secret=six.b(''),
881
- authenticator=None, **attributes):
911
+ def __init__(self, code=CoARequest, id=None, secret=b'',
912
+ authenticator=None, **attributes):
882
913
  """Constructor
883
914
 
884
915
  :param dict: RADIUS dictionary
@@ -906,11 +937,11 @@ class CoAPacket(Packet):
906
937
  def VerifyCoARequest(self):
907
938
  """Verify request authenticator.
908
939
 
909
- :return: False if verification failed else True
940
+ :return: True if verification passed else False
910
941
  :rtype: boolean
911
942
  """
912
- assert(self.raw_packet)
913
- hash = md5_constructor(self.raw_packet[0:4] + 16 * six.b('\x00') +
943
+ assert (self.raw_packet)
944
+ hash = md5_constructor(self.raw_packet[0:4] + 16 * b'\x00' +
914
945
  self.raw_packet[20:] + self.secret).digest()
915
946
  return hash == self.authenticator
916
947
 
@@ -929,13 +960,13 @@ class CoAPacket(Packet):
929
960
  self.id = self.CreateID()
930
961
 
931
962
  header = struct.pack('!BBH', self.code, self.id, (20 + len(attr)))
932
- self.authenticator = md5_constructor(header[0:4] + 16 * six.b('\x00') +
963
+ self.authenticator = md5_constructor(header[0:4] + 16 * b'\x00' +
933
964
  attr + self.secret).digest()
934
965
 
935
966
  if self.message_authenticator:
936
967
  self._refresh_message_authenticator()
937
968
  attr = self._PktEncodeAttributes()
938
- self.authenticator = md5_constructor(header[0:4] + 16 * six.b('\x00') +
969
+ self.authenticator = md5_constructor(header[0:4] + 16 * b'\x00' +
939
970
  attr + self.secret).digest()
940
971
 
941
972
  return header + self.authenticator + attr
pyrad/proxy.py CHANGED
@@ -25,7 +25,7 @@ class Proxy(Server):
25
25
  self._proxyfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
26
26
  self._fdmap[self._proxyfd.fileno()] = self._proxyfd
27
27
  self._poll.register(self._proxyfd.fileno(),
28
- (select.POLLIN | select.POLLPRI | select.POLLERR))
28
+ (select.POLLIN | select.POLLPRI | select.POLLERR))
29
29
 
30
30
  def _HandleProxyPacket(self, pkt):
31
31
  """Process a packet received on the reply socket.
@@ -41,7 +41,7 @@ class Proxy(Server):
41
41
  pkt.secret = self.hosts[pkt.source[0]].secret
42
42
 
43
43
  if pkt.code not in [packet.AccessAccept, packet.AccessReject,
44
- packet.AccountingResponse]:
44
+ packet.AccountingResponse]:
45
45
  raise ServerPacketError('Received non-response on proxy socket')
46
46
 
47
47
  def _ProcessInput(self, fd):
pyrad/server.py CHANGED
@@ -114,7 +114,7 @@ class Server(host.Host):
114
114
  """
115
115
  results = set()
116
116
  try:
117
- tmp = socket.getaddrinfo(addr, 'www')
117
+ tmp = socket.getaddrinfo(addr, 80)
118
118
  except socket.gaierror:
119
119
  return []
120
120
 
@@ -123,10 +123,9 @@ class Server(host.Host):
123
123
 
124
124
  return results
125
125
 
126
-
127
126
  def BindToAddress(self, addr):
128
- """Add an address to listen to.
129
- An empty string indicated you want to listen on all addresses.
127
+ """Add an address to listen on a specific interface.
128
+ String "0.0.0.0" indicates you want to listen on all interfaces.
130
129
 
131
130
  :param addr: IP address to listen on
132
131
  :type addr: string
@@ -151,7 +150,6 @@ class Server(host.Host):
151
150
  coafd.bind((address, self.coaport))
152
151
  self.coafds.append(coafd)
153
152
 
154
-
155
153
  def HandleAuthPacket(self, pkt):
156
154
  """Authentication packet handler.
157
155
  This is an empty function that is called when a valid
@@ -247,7 +245,6 @@ class Server(host.Host):
247
245
  :type pkt: Packet class instance
248
246
  """
249
247
  self._AddSecret(pkt)
250
- pkt.secret = self.hosts[pkt.source[0]].secret
251
248
  if pkt.code == packet.CoARequest:
252
249
  self.HandleCoaPacket(pkt)
253
250
  elif pkt.code == packet.DisconnectRequest:
@@ -255,7 +252,6 @@ class Server(host.Host):
255
252
  else:
256
253
  raise ServerPacketError('Received non-coa packet on coa port')
257
254
 
258
-
259
255
  def _GrabPacket(self, pktgen, fd):
260
256
  """Read a packet from a network connection.
261
257
  This method assumes there is data waiting for to be read.