pyrad 2.5.2__tar.gz → 2.5.3__tar.gz

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 (60) hide show
  1. {pyrad-2.5.2 → pyrad-2.5.3}/CHANGES.rst +6 -0
  2. {pyrad-2.5.2 → pyrad-2.5.3}/LICENSE.txt +2 -2
  3. {pyrad-2.5.2/pyrad.egg-info → pyrad-2.5.3}/PKG-INFO +15 -18
  4. {pyrad-2.5.2 → pyrad-2.5.3}/README.rst +13 -8
  5. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/conf.py +3 -3
  6. {pyrad-2.5.2 → pyrad-2.5.3}/pyproject.toml +3 -5
  7. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/__init__.py +1 -1
  8. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/bidict.py +1 -1
  9. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/client.py +1 -2
  10. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/dictfile.py +2 -3
  11. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/dictionary.py +1 -1
  12. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/host.py +1 -1
  13. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/packet.py +25 -42
  14. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_packet.py +13 -13
  15. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tools.py +3 -0
  16. {pyrad-2.5.2 → pyrad-2.5.3/pyrad.egg-info}/PKG-INFO +15 -18
  17. pyrad-2.5.3/pyrad.egg-info/requires.txt +1 -0
  18. pyrad-2.5.2/pyrad.egg-info/requires.txt +0 -13
  19. {pyrad-2.5.2 → pyrad-2.5.3}/MANIFEST.in +0 -0
  20. {pyrad-2.5.2 → pyrad-2.5.3}/TODO.rst +0 -0
  21. {pyrad-2.5.2 → pyrad-2.5.3}/docs/Makefile +0 -0
  22. {pyrad-2.5.2 → pyrad-2.5.3}/docs/make.bat +0 -0
  23. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/_static/logo.png +0 -0
  24. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/api/client.rst +0 -0
  25. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/api/dictionary.rst +0 -0
  26. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/api/host.rst +0 -0
  27. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/api/packet.rst +0 -0
  28. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/api/proxy.rst +0 -0
  29. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/api/server.rst +0 -0
  30. {pyrad-2.5.2 → pyrad-2.5.3}/docs/source/index.rst +0 -0
  31. {pyrad-2.5.2 → pyrad-2.5.3}/example/acct.py +0 -0
  32. {pyrad-2.5.2 → pyrad-2.5.3}/example/auth.py +0 -0
  33. {pyrad-2.5.2 → pyrad-2.5.3}/example/auth_async.py +0 -0
  34. {pyrad-2.5.2 → pyrad-2.5.3}/example/client-coa.py +0 -0
  35. {pyrad-2.5.2 → pyrad-2.5.3}/example/coa.py +0 -0
  36. {pyrad-2.5.2 → pyrad-2.5.3}/example/dictionary +0 -0
  37. {pyrad-2.5.2 → pyrad-2.5.3}/example/dictionary.freeradius +0 -0
  38. {pyrad-2.5.2 → pyrad-2.5.3}/example/pyrad.log +0 -0
  39. {pyrad-2.5.2 → pyrad-2.5.3}/example/server.py +0 -0
  40. {pyrad-2.5.2 → pyrad-2.5.3}/example/server_async.py +0 -0
  41. {pyrad-2.5.2 → pyrad-2.5.3}/example/status.py +0 -0
  42. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/client_async.py +0 -0
  43. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/curved.py +0 -0
  44. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/proxy.py +0 -0
  45. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/server.py +0 -0
  46. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/server_async.py +0 -0
  47. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/__init__.py +0 -0
  48. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/mock.py +0 -0
  49. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_bidict.py +0 -0
  50. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_client.py +0 -0
  51. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_dictionary.py +0 -0
  52. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_host.py +0 -0
  53. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_proxy.py +0 -0
  54. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_server.py +0 -0
  55. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad/tests/test_tools.py +0 -0
  56. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad.egg-info/SOURCES.txt +0 -0
  57. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad.egg-info/dependency_links.txt +0 -0
  58. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad.egg-info/top_level.txt +0 -0
  59. {pyrad-2.5.2 → pyrad-2.5.3}/pyrad.egg-info/zip-safe +0 -0
  60. {pyrad-2.5.2 → pyrad-2.5.3}/setup.cfg +0 -0
@@ -1,6 +1,12 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 2.5.3 - Feb 5, 2026
5
+ -------------------
6
+
7
+ * remove python2 leftovers
8
+ * add support for Ascend-Data-Filter "delete" keyword
9
+
4
10
  2.5.2 - Jan 29, 2026
5
11
  --------------------
6
12
 
@@ -1,5 +1,5 @@
1
- Copyright 2020 Istvan Ruzman. All rights reserved.
2
- Copyright 2017-2026 Christian Giese. All rights reserved.
1
+ Copyright 2026 Christian Giese, Istvan Ruzman and Stefan Lieberth. All rights reserved.
2
+ Copyright 2002-2025 Christian Giese and Istvan Ruzman. All rights reserved.
3
3
  Copyright 2007-2008 Simplon. All rights reserved.
4
4
  Copyright 2002-2008 Wichert Akkerman. All rights reserved.
5
5
 
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrad
3
- Version: 2.5.2
3
+ Version: 2.5.3
4
4
  Summary: RADIUS tools
5
- Author-email: Istvan Ruzman <istvan@ruzman.eu>, Christian Giese <gic@gicnet.de>, Stefan Lieberth <stefan@lieberth.net>
5
+ Author-email: Christian Giese <gic@gicnet.de>, Istvan Ruzman <istvan@ruzman.eu>, Stefan Lieberth <stefan@lieberth.net>
6
6
  License: BSD-3-Clause
7
7
  Project-URL: Repository, https://github.com/pyradius/pyrad
8
8
  Project-URL: Documentation, https://pyradius-pyrad.readthedocs.io
@@ -23,14 +23,6 @@ Requires-Python: >=3.8
23
23
  Description-Content-Type: text/x-rst
24
24
  License-File: LICENSE.txt
25
25
  Requires-Dist: netaddr>=0.8.0
26
- Requires-Dist: six>=1.16.0
27
- Provides-Extra: test
28
- Requires-Dist: pytest>=8; extra == "test"
29
- Requires-Dist: mock; python_version < "3.10" and extra == "test"
30
- Provides-Extra: docs
31
- Requires-Dist: sphinx>=7.0; extra == "docs"
32
- Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
33
- Requires-Dist: sphinx-rtd-theme>=2.0; extra == "docs"
34
26
  Dynamic: license-file
35
27
 
36
28
 
@@ -59,18 +51,24 @@ pyrad is an implementation of a RADIUS client/server as described in RFC2865.
59
51
  It takes care of all the details like building RADIUS packets, sending
60
52
  them and decoding responses.
61
53
 
62
- Here is an example of doing a authentication request::
54
+ Here is an example of doing a authentication request:
55
+
56
+ .. code-block:: python
63
57
 
64
58
  from pyrad.client import Client
65
59
  from pyrad.dictionary import Dictionary
66
60
  import pyrad.packet
67
61
 
68
- srv = Client(server="localhost", secret=b"Kah3choteereethiejeimaeziecumi",
69
- dict=Dictionary("dictionary"))
62
+ srv = Client(
63
+ server="localhost",
64
+ secret=b"Kah3choteereethiejeimaeziecumi",
65
+ dict=Dictionary("dictionary"),
66
+ )
70
67
 
71
68
  # create request
72
- req = srv.CreateAuthPacket(code=pyrad.packet.AccessRequest,
73
- User_Name="wichert", NAS_Identifier="localhost")
69
+ req = srv.CreateAuthPacket(
70
+ code=pyrad.packet.AccessRequest, User_Name="wichert", NAS_Identifier="localhost"
71
+ )
74
72
  req["User-Password"] = req.PwCrypt("password")
75
73
 
76
74
  # send request
@@ -82,9 +80,8 @@ Here is an example of doing a authentication request::
82
80
  print("access denied")
83
81
 
84
82
  print("Attributes returned by server:")
85
- for i in reply.keys():
86
- print("%s: %s" % (i, reply[i]))
87
-
83
+ for key, val in reply.items():
84
+ print(f"{key}: {val}")
88
85
 
89
86
 
90
87
  Requirements & Installation
@@ -24,18 +24,24 @@ pyrad is an implementation of a RADIUS client/server as described in RFC2865.
24
24
  It takes care of all the details like building RADIUS packets, sending
25
25
  them and decoding responses.
26
26
 
27
- Here is an example of doing a authentication request::
27
+ Here is an example of doing a authentication request:
28
+
29
+ .. code-block:: python
28
30
 
29
31
  from pyrad.client import Client
30
32
  from pyrad.dictionary import Dictionary
31
33
  import pyrad.packet
32
34
 
33
- srv = Client(server="localhost", secret=b"Kah3choteereethiejeimaeziecumi",
34
- dict=Dictionary("dictionary"))
35
+ srv = Client(
36
+ server="localhost",
37
+ secret=b"Kah3choteereethiejeimaeziecumi",
38
+ dict=Dictionary("dictionary"),
39
+ )
35
40
 
36
41
  # create request
37
- req = srv.CreateAuthPacket(code=pyrad.packet.AccessRequest,
38
- User_Name="wichert", NAS_Identifier="localhost")
42
+ req = srv.CreateAuthPacket(
43
+ code=pyrad.packet.AccessRequest, User_Name="wichert", NAS_Identifier="localhost"
44
+ )
39
45
  req["User-Password"] = req.PwCrypt("password")
40
46
 
41
47
  # send request
@@ -47,9 +53,8 @@ Here is an example of doing a authentication request::
47
53
  print("access denied")
48
54
 
49
55
  print("Attributes returned by server:")
50
- for i in reply.keys():
51
- print("%s: %s" % (i, reply[i]))
52
-
56
+ for key, val in reply.items():
57
+ print(f"{key}: {val}")
53
58
 
54
59
 
55
60
  Requirements & Installation
@@ -57,9 +57,9 @@ author = u'Christian Giese <gic@gicnet.de>, Istvan Ruzman <istvan@ruzman.eu> and
57
57
  # built documents.
58
58
  #
59
59
  # The short X.Y version.
60
- version = u'2.5.2'
60
+ version = u'2.5.3'
61
61
  # The full version, including alpha/beta/rc tags.
62
- release = u'2.5.2'
62
+ release = u'2.5.3'
63
63
 
64
64
  # The language for content autogenerated by Sphinx. Refer to documentation
65
65
  # for a list of supported languages.
@@ -134,7 +134,7 @@ latex_elements = {
134
134
  # author, documentclass [howto, manual, or own class]).
135
135
  latex_documents = [
136
136
  (master_doc, 'pyrad.tex', u'pyrad Documentation',
137
- u'Christian Giese and Istvan Ruzman', 'manual'),
137
+ u'Christian Giese, Istvan Ruzman and Stefan Lieberth', 'manual'),
138
138
  ]
139
139
 
140
140
 
@@ -10,8 +10,8 @@ readme = "README.rst"
10
10
  license = { text = "BSD-3-Clause" }
11
11
  requires-python = ">=3.8"
12
12
  authors = [
13
- { name = "Istvan Ruzman", email = "istvan@ruzman.eu" },
14
13
  { name = "Christian Giese", email = "gic@gicnet.de" },
14
+ { name = "Istvan Ruzman", email = "istvan@ruzman.eu" },
15
15
  { name = "Stefan Lieberth", email = "stefan@lieberth.net" },
16
16
  ]
17
17
  keywords = ["radius", "authentication", "AAA", "accounting", "authorization", "RADIUS"]
@@ -32,13 +32,11 @@ classifiers = [
32
32
 
33
33
  dependencies = [
34
34
  "netaddr>=0.8.0",
35
- "six>=1.16.0",
36
35
  ]
37
36
 
38
- [project.optional-dependencies]
37
+ [dependency-groups]
39
38
  test = [
40
39
  "pytest>=8",
41
- "mock; python_version<'3.10'",
42
40
  ]
43
41
  docs = [
44
42
  "sphinx>=7.0",
@@ -56,7 +54,7 @@ include-package-data = true
56
54
  zip-safe = true
57
55
 
58
56
  [tool.pytest.ini_options]
59
- testpaths = ["tests"]
57
+ testpaths = ["pyrad/tests"]
60
58
  addopts = "-ra"
61
59
 
62
60
  [tool.setuptools.dynamic]
@@ -41,6 +41,6 @@ __docformat__ = 'epytext en'
41
41
  __author__ = 'Christian Giese <gic@gicnet.de>, Istvan Ruzman <istvan@ruzman.eu> and Stefan Lieberth <stefan@lieberth.net>'
42
42
  __url__ = 'http://pyrad.readthedocs.io/en/latest/?badge=latest'
43
43
  __copyright__ = 'Copyright 2002-2026 Wichert Akkerman, Christian Giese, Istvan Ruzman and Stefan Lieberth. All rights reserved.'
44
- __version__ = '2.5.2'
44
+ __version__ = '2.5.3'
45
45
 
46
46
  __all__ = ['client', 'dictionary', 'packet', 'server', 'tools', 'dictfile']
@@ -3,7 +3,7 @@
3
3
  # Bidirectional map
4
4
 
5
5
 
6
- class BiDict(object):
6
+ class BiDict:
7
7
  def __init__(self):
8
8
  self.forward = {}
9
9
  self.backward = {}
@@ -9,7 +9,6 @@ import select
9
9
  import socket
10
10
  import time
11
11
  import struct
12
- import six
13
12
  from pyrad import host
14
13
  from pyrad import packet
15
14
 
@@ -35,7 +34,7 @@ class Client(host.Host):
35
34
  :type timeout: float
36
35
  """
37
36
  def __init__(self, server, authport=1812, acctport=1813,
38
- coaport=3799, secret=six.b(''), dict=None, retries=3, timeout=5, enforce_ma=False):
37
+ coaport=3799, secret=b'', dict=None, retries=3, timeout=5, enforce_ma=False):
39
38
  """Constructor.
40
39
 
41
40
  :param server: hostname or IP address of RADIUS server
@@ -11,7 +11,7 @@ RADIUS $INCLUDE directives behind the scene.
11
11
  import os
12
12
 
13
13
 
14
- class _Node(object):
14
+ class _Node:
15
15
  """Dictionary file node
16
16
 
17
17
  A single dictionary file.
@@ -36,7 +36,7 @@ class _Node(object):
36
36
  return self.lines[self.current - 1]
37
37
 
38
38
 
39
- class DictFile(object):
39
+ class DictFile:
40
40
  """Dictionary file class
41
41
 
42
42
  An iterable file type that handles $INCLUDE
@@ -111,4 +111,3 @@ class DictFile(object):
111
111
  else:
112
112
  return line
113
113
  raise StopIteration
114
- next = __next__ # BBB for python <3
@@ -133,7 +133,7 @@ class Attribute(object):
133
133
  self.values.Add(key, value)
134
134
 
135
135
 
136
- class Dictionary(object):
136
+ class Dictionary:
137
137
  """RADIUS dictionary class.
138
138
  This class stores all information about vendors, attributes and their
139
139
  values as defined in RADIUS dictionary files.
@@ -4,7 +4,7 @@
4
4
  from pyrad import packet
5
5
 
6
6
 
7
- class Host(object):
7
+ class Host:
8
8
  """Generic RADIUS capable host.
9
9
 
10
10
  :ivar dict: RADIUS dictionary
@@ -6,9 +6,9 @@
6
6
 
7
7
  from collections import OrderedDict
8
8
  from pyrad import tools
9
+ import hashlib
9
10
  import hmac
10
11
  import struct
11
- import sys
12
12
 
13
13
  try:
14
14
  import secrets
@@ -18,24 +18,6 @@ except ImportError:
18
18
  random_generator = random.SystemRandom()
19
19
 
20
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
-
26
- if sys.version_info >= (3, 0):
27
- hmac_new = _hmac_md5
28
- else:
29
- hmac_new = hmac.new
30
-
31
- try:
32
- import hashlib
33
- md5_constructor = hashlib.md5
34
- except ImportError:
35
- # BBB for python 2.4
36
- import md5
37
- md5_constructor = md5.new
38
-
39
21
  # Packet codes
40
22
  AccessRequest = 1
41
23
  AccessAccept = 2
@@ -145,7 +127,7 @@ class Packet(OrderedDict):
145
127
  return self.message_authenticator
146
128
 
147
129
  def _refresh_message_authenticator(self):
148
- hmac_constructor = hmac_new(self.secret)
130
+ hmac_constructor = hmac.new(self.secret, digestmod='MD5')
149
131
 
150
132
  # Maintain a zero octets content for md5 and hmac calculation.
151
133
  self['Message-Authenticator'] = 16 * b'\00'
@@ -212,7 +194,7 @@ class Packet(OrderedDict):
212
194
  header = struct.pack('!BBH', self.code, self.id,
213
195
  (20 + len(attr)))
214
196
 
215
- hmac_constructor = hmac_new(key)
197
+ hmac_constructor = hmac.new(key, digestmod='MD5')
216
198
  hmac_constructor.update(header)
217
199
  if self.code in (AccountingRequest, DisconnectRequest,
218
200
  CoARequest, AccountingResponse):
@@ -419,8 +401,8 @@ class Packet(OrderedDict):
419
401
  attr = self._PktEncodeAttributes()
420
402
  header = struct.pack('!BBH', self.code, self.id, (20 + len(attr)))
421
403
 
422
- authenticator = md5_constructor(header[0:4] + self.authenticator
423
- + attr + self.secret).digest()
404
+ authenticator = hashlib.md5(header[0:4] + self.authenticator
405
+ + attr + self.secret).digest()
424
406
 
425
407
  return header + authenticator + attr
426
408
 
@@ -440,8 +422,8 @@ class Packet(OrderedDict):
440
422
  # response attributes if any, followed by the shared secret. The
441
423
  # resulting 16 octet MD5 hash value is stored in the Authenticator
442
424
  # field of the Accounting-Response packet.
443
- hash = md5_constructor(rawreply[0:4] + self.authenticator +
444
- rawreply[20:] + self.secret).digest()
425
+ hash = hashlib.md5(rawreply[0:4] + self.authenticator +
426
+ rawreply[20:] + self.secret).digest()
445
427
 
446
428
  if hash != rawreply[4:20]:
447
429
  return False
@@ -595,7 +577,7 @@ class Packet(OrderedDict):
595
577
  else:
596
578
  last = self.authenticator + salt
597
579
  while data:
598
- hash = md5_constructor(self.secret + last).digest()
580
+ hash = hashlib.md5(self.secret + last).digest()
599
581
  for i in range(16):
600
582
  result += bytes((hash[i] ^ data[i],))
601
583
 
@@ -707,11 +689,12 @@ class AuthPacket(Packet):
707
689
  header = struct.pack(
708
690
  '!BBH16s', self.code, self.id, (20 + 18 + len(attr)), self.authenticator
709
691
  )
710
- digest = hmac_new(
692
+ digest = hmac.new(
711
693
  self.secret,
712
694
  header
713
695
  + attr
714
696
  + struct.pack('!BB16s', 80, struct.calcsize('!BB16s'), b''),
697
+ digestmod='MD5'
715
698
  ).digest()
716
699
  return (
717
700
  header
@@ -743,7 +726,7 @@ class AuthPacket(Packet):
743
726
 
744
727
  last = self.authenticator
745
728
  while buf:
746
- hash = md5_constructor(self.secret + last).digest()
729
+ hash = hashlib.md5(self.secret + last).digest()
747
730
  for i in range(16):
748
731
  pw += bytes((hash[i] ^ buf[i],))
749
732
  (last, buf) = (buf[:16], buf[16:])
@@ -787,7 +770,7 @@ class AuthPacket(Packet):
787
770
 
788
771
  last = self.authenticator
789
772
  while buf:
790
- hash = md5_constructor(self.secret + last).digest()
773
+ hash = hashlib.md5(self.secret + last).digest()
791
774
  for i in range(16):
792
775
  result += bytes((hash[i] ^ buf[i],))
793
776
  last = result[-16:]
@@ -820,7 +803,7 @@ class AuthPacket(Packet):
820
803
  challenge = self.authenticator
821
804
  if 'CHAP-Challenge' in self:
822
805
  challenge = self['CHAP-Challenge'][0]
823
- return password == md5_constructor(chapid + userpwd + challenge).digest()
806
+ return password == hashlib.md5(chapid + userpwd + challenge).digest()
824
807
 
825
808
  def VerifyAuthRequest(self):
826
809
  """Verify request authenticator.
@@ -829,8 +812,8 @@ class AuthPacket(Packet):
829
812
  :rtype: boolean
830
813
  """
831
814
  assert (self.raw_packet)
832
- hash = md5_constructor(self.raw_packet[0:4] + 16 * b'\x00' +
833
- self.raw_packet[20:] + self.secret).digest()
815
+ hash = hashlib.md5(self.raw_packet[0:4] + 16 * b'\x00' +
816
+ self.raw_packet[20:] + self.secret).digest()
834
817
  return hash == self.authenticator
835
818
 
836
819
 
@@ -873,8 +856,8 @@ class AcctPacket(Packet):
873
856
  """
874
857
  assert (self.raw_packet)
875
858
 
876
- hash = md5_constructor(self.raw_packet[0:4] + 16 * b'\x00' +
877
- self.raw_packet[20:] + self.secret).digest()
859
+ hash = hashlib.md5(self.raw_packet[0:4] + 16 * b'\x00' +
860
+ self.raw_packet[20:] + self.secret).digest()
878
861
 
879
862
  return hash == self.authenticator
880
863
 
@@ -895,8 +878,8 @@ class AcctPacket(Packet):
895
878
 
896
879
  attr = self._PktEncodeAttributes()
897
880
  header = struct.pack('!BBH', self.code, self.id, (20 + len(attr)))
898
- self.authenticator = md5_constructor(header[0:4] + 16 * b'\x00' +
899
- attr + self.secret).digest()
881
+ self.authenticator = hashlib.md5(header[0:4] + 16 * b'\x00' +
882
+ attr + self.secret).digest()
900
883
 
901
884
  ans = header + self.authenticator + attr
902
885
 
@@ -941,8 +924,8 @@ class CoAPacket(Packet):
941
924
  :rtype: boolean
942
925
  """
943
926
  assert (self.raw_packet)
944
- hash = md5_constructor(self.raw_packet[0:4] + 16 * b'\x00' +
945
- self.raw_packet[20:] + self.secret).digest()
927
+ hash = hashlib.md5(self.raw_packet[0:4] + 16 * b'\x00' +
928
+ self.raw_packet[20:] + self.secret).digest()
946
929
  return hash == self.authenticator
947
930
 
948
931
  def RequestPacket(self):
@@ -960,14 +943,14 @@ class CoAPacket(Packet):
960
943
  self.id = self.CreateID()
961
944
 
962
945
  header = struct.pack('!BBH', self.code, self.id, (20 + len(attr)))
963
- self.authenticator = md5_constructor(header[0:4] + 16 * b'\x00' +
964
- attr + self.secret).digest()
946
+ self.authenticator = hashlib.md5(header[0:4] + 16 * b'\x00' +
947
+ attr + self.secret).digest()
965
948
 
966
949
  if self.message_authenticator:
967
950
  self._refresh_message_authenticator()
968
951
  attr = self._PktEncodeAttributes()
969
- self.authenticator = md5_constructor(header[0:4] + 16 * b'\x00' +
970
- attr + self.secret).digest()
952
+ self.authenticator = hashlib.md5(header[0:4] + 16 * b'\x00' +
953
+ attr + self.secret).digest()
971
954
 
972
955
  return header + self.authenticator + attr
973
956
 
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import hmac
2
3
  import os
3
4
  import struct
@@ -9,13 +10,6 @@ from collections import OrderedDict
9
10
  from pyrad import packet
10
11
  from pyrad.client import Client
11
12
  from pyrad.dictionary import Dictionary
12
- try:
13
- import hashlib
14
- md5_constructor = hashlib.md5
15
- except ImportError:
16
- # BBB for python 2.4
17
- import md5
18
- md5_constructor = md5.new
19
13
 
20
14
 
21
15
  class UtilityTests(unittest.TestCase):
@@ -106,17 +100,17 @@ class PacketTests(unittest.TestCase):
106
100
  request.id, (20 + len(attributes)))
107
101
 
108
102
  # Calculate the Message-Authenticator and update the attribute
109
- hmac_constructor = hmac.new(request.secret, None, md5_constructor)
103
+ hmac_constructor = hmac.new(request.secret, None, hashlib.md5)
110
104
  hmac_constructor.update(header + request.authenticator + attributes)
111
105
  updated_message_authenticator = hmac_constructor.digest()
112
106
  attributes = attributes.replace(b'\x00' * 16,
113
107
  updated_message_authenticator)
114
108
 
115
109
  # Calculate the response authenticator
116
- authenticator = md5_constructor(header
117
- + request.authenticator
118
- + attributes
119
- + request.secret).digest()
110
+ authenticator = hashlib.md5(header
111
+ + request.authenticator
112
+ + attributes
113
+ + request.secret).digest()
120
114
 
121
115
  reply_bytes = header + authenticator + attributes
122
116
  return packet.AuthPacket(packet=reply_bytes, dict=self.dict)
@@ -554,7 +548,7 @@ class AuthPacketChapTests(unittest.TestCase):
554
548
  def testVerifyChapPasswd(self):
555
549
  chap_id = b'9'
556
550
  chap_challenge = b'987654321'
557
- chap_password = chap_id + md5_constructor(
551
+ chap_password = chap_id + hashlib.md5(
558
552
  chap_id + b'test_password' + chap_challenge).digest()
559
553
  pkt = self.client.CreateAuthPacket(
560
554
  code=packet.AccessChallenge,
@@ -677,3 +671,9 @@ class AcctPacketTests(unittest.TestCase):
677
671
 
678
672
  # Vendor unknown preserved
679
673
  self.assertEqual(pkt[(594, 1)], [b'UNKNOWN_PRODUCT'])
674
+
675
+ raw_no_authenticator = raw[:4] + b"\x00" * 16 + raw[20:]
676
+ rebuilt = pkt.RequestPacket()
677
+ rebuilt_no_authenticator = rebuilt[:4] + b"\x00" * 16 + rebuilt[20:]
678
+
679
+ self.assertEqual(raw_no_authenticator, rebuilt_no_authenticator)
@@ -167,6 +167,9 @@ def EncodeAscendBinary(orig_str):
167
167
  "dportq": b"\x00",
168
168
  }
169
169
 
170
+ if orig_str.strip() == "delete":
171
+ return 8 * b"\x00"
172
+
170
173
  for t in orig_str.split(" "):
171
174
  key, value = t.split("=")
172
175
  if key == "family" and value == "ipv6":
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrad
3
- Version: 2.5.2
3
+ Version: 2.5.3
4
4
  Summary: RADIUS tools
5
- Author-email: Istvan Ruzman <istvan@ruzman.eu>, Christian Giese <gic@gicnet.de>, Stefan Lieberth <stefan@lieberth.net>
5
+ Author-email: Christian Giese <gic@gicnet.de>, Istvan Ruzman <istvan@ruzman.eu>, Stefan Lieberth <stefan@lieberth.net>
6
6
  License: BSD-3-Clause
7
7
  Project-URL: Repository, https://github.com/pyradius/pyrad
8
8
  Project-URL: Documentation, https://pyradius-pyrad.readthedocs.io
@@ -23,14 +23,6 @@ Requires-Python: >=3.8
23
23
  Description-Content-Type: text/x-rst
24
24
  License-File: LICENSE.txt
25
25
  Requires-Dist: netaddr>=0.8.0
26
- Requires-Dist: six>=1.16.0
27
- Provides-Extra: test
28
- Requires-Dist: pytest>=8; extra == "test"
29
- Requires-Dist: mock; python_version < "3.10" and extra == "test"
30
- Provides-Extra: docs
31
- Requires-Dist: sphinx>=7.0; extra == "docs"
32
- Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
33
- Requires-Dist: sphinx-rtd-theme>=2.0; extra == "docs"
34
26
  Dynamic: license-file
35
27
 
36
28
 
@@ -59,18 +51,24 @@ pyrad is an implementation of a RADIUS client/server as described in RFC2865.
59
51
  It takes care of all the details like building RADIUS packets, sending
60
52
  them and decoding responses.
61
53
 
62
- Here is an example of doing a authentication request::
54
+ Here is an example of doing a authentication request:
55
+
56
+ .. code-block:: python
63
57
 
64
58
  from pyrad.client import Client
65
59
  from pyrad.dictionary import Dictionary
66
60
  import pyrad.packet
67
61
 
68
- srv = Client(server="localhost", secret=b"Kah3choteereethiejeimaeziecumi",
69
- dict=Dictionary("dictionary"))
62
+ srv = Client(
63
+ server="localhost",
64
+ secret=b"Kah3choteereethiejeimaeziecumi",
65
+ dict=Dictionary("dictionary"),
66
+ )
70
67
 
71
68
  # create request
72
- req = srv.CreateAuthPacket(code=pyrad.packet.AccessRequest,
73
- User_Name="wichert", NAS_Identifier="localhost")
69
+ req = srv.CreateAuthPacket(
70
+ code=pyrad.packet.AccessRequest, User_Name="wichert", NAS_Identifier="localhost"
71
+ )
74
72
  req["User-Password"] = req.PwCrypt("password")
75
73
 
76
74
  # send request
@@ -82,9 +80,8 @@ Here is an example of doing a authentication request::
82
80
  print("access denied")
83
81
 
84
82
  print("Attributes returned by server:")
85
- for i in reply.keys():
86
- print("%s: %s" % (i, reply[i]))
87
-
83
+ for key, val in reply.items():
84
+ print(f"{key}: {val}")
88
85
 
89
86
 
90
87
  Requirements & Installation
@@ -0,0 +1 @@
1
+ netaddr>=0.8.0
@@ -1,13 +0,0 @@
1
- netaddr>=0.8.0
2
- six>=1.16.0
3
-
4
- [docs]
5
- sphinx>=7.0
6
- sphinx-autodoc-typehints
7
- sphinx-rtd-theme>=2.0
8
-
9
- [test]
10
- pytest>=8
11
-
12
- [test:python_version < "3.10"]
13
- mock
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes