pyrad.client_async – asyncio client

asyncio RADIUS client.

class pyrad.client_async.ClientAsync(server, auth_port=1812, acct_port=1813, coa_port=3799, secret=b'', dict=None, loop=None, retries=3, timeout=30, logger_name='pyrad', enforce_ma=False)[source]

Basic asyncio RADIUS client.

Sends requests to one RADIUS server, retransmits them if no reply is received and verifies the replies. Await initialize_transports() before creating and sending packets, and deinitialize_transports() when done. There is one transport (socket) each for authentication, accounting and CoA packets.

Variables:
  • server – hostname or IP address of the RADIUS server

  • secret – RADIUS secret shared with the server

  • retries – number of times a request is retransmitted, it is sent at most retries + 1 times

  • timeout – number of seconds to wait for a reply after each send

  • enforce_ma – require a Message-Authenticator in replies to Access-Request and Status-Server packets

Parameters:
  • server (str) – hostname or IP address of the RADIUS server

  • auth_port (int) – server port for authentication packets

  • acct_port (int) – server port for accounting packets

  • coa_port (int) – server port for CoA and Disconnect packets

  • secret (bytes) – RADIUS secret

  • dict (pyrad.dictionary.Dictionary) – RADIUS dictionary

  • loop (asyncio.AbstractEventLoop) – event loop, defaults to the running loop

  • retries (int) – number of times a request is retransmitted, it is sent at most retries + 1 times

  • timeout (float) – number of seconds to wait for a reply after each send

  • logger_name (str) – name of the logger

  • enforce_ma (bool) – require a Message-Authenticator in replies to Access-Request and Status-Server packets (a Message-Authenticator in a reply is always verified)

CreateAcctPacket(**args)[source]

Create an accounting packet for the server of this client.

The packet has the dictionary and secret of the client and an id that is not used by a pending request of the accounting transport. The keyword arguments are passed to pyrad.packet.AcctPacket: packet arguments (code, authenticator, message_authenticator, packet) and attributes to add, with - in the attribute names replaced by _. The default code is Accounting-Request; code=pyrad.packet.StatusServer creates a Status-Server packet to the accounting port.

Returns:

a new packet

Return type:

pyrad.packet.AcctPacket

Raises:

Exception – the accounting transport is not initialized, or 256 requests are pending

CreateAuthPacket(**args)[source]

Create an authentication packet for the server of this client.

The packet has the dictionary and secret of the client and an id that is not used by a pending request of the authentication transport. The keyword arguments are passed to pyrad.packet.AuthPacket: packet arguments (code, authenticator, message_authenticator, packet) and attributes to add, with - in the attribute names replaced by _. The default code is Access-Request, use code=pyrad.packet.StatusServer for a Status-Server packet to the authentication port.

A Message-Authenticator is added when the packet is encoded, as countermeasure against the BlastRADIUS attack (CVE-2024-3596); disable it with message_authenticator=False.

For PAP the password must be encrypted: pkt['User-Password'] = pkt.PwCrypt(password).

With auth_type='eap-md5', SendPacket() authenticates with EAP-MD5 instead; User-Password then holds the cleartext password.

Returns:

a new packet

Return type:

pyrad.packet.AuthPacket

Raises:

Exception – the authentication transport is not initialized, or 256 requests are pending

CreateCoAPacket(**args)[source]

Create a CoA-Request or Disconnect-Request for this client’s server.

The packet has the dictionary and secret of the client and an id that is not used by a pending request of the CoA transport. The keyword arguments are passed to pyrad.packet.CoAPacket: packet arguments (code, authenticator, message_authenticator, packet) and attributes to add, with - in the attribute names replaced by _. The default code is CoA-Request, pass code=pyrad.packet.DisconnectRequest for a Disconnect-Request.

Returns:

a new packet

Return type:

pyrad.packet.CoAPacket

Raises:

Exception – the CoA transport is not initialized, or 256 requests are pending

CreatePacket(id, **args)[source]

Create a generic packet with the dictionary and secret of the client.

A generic pyrad.packet.Packet cannot be sent with SendPacket(), use CreateAuthPacket(), CreateAcctPacket() or CreateCoAPacket() instead.

Parameters:
  • id (int) – packet identifier

  • args – further arguments of pyrad.packet.Packet and attributes to add

Returns:

a new packet

Return type:

pyrad.packet.Packet

Raises:

Exception – id is None

SendPacket(pkt)[source]

Send a request to the RADIUS server.

This is not a coroutine: the request is sent right away and a future is returned, await it for the reply. An AuthPacket is sent with the authentication transport, an AcctPacket with the accounting transport and a CoAPacket with the CoA transport.

If no valid reply is received within timeout seconds, the request is retransmitted (the same bytes as the first attempt), at most retries times. Invalid replies are ignored. Without a valid reply the future fails with the builtin TimeoutError after (retries + 1) * timeout seconds (on Python 3.10 this is not asyncio.TimeoutError). It fails with ConnectionAbortedError if deinitialize_transports() closes the transport first.

With auth_type='eap-md5' the client authenticates with EAP-MD5 (RFC 3748, RFC 3579), like pyrad.client.Client.SendPacket(): the EAP-Response/Identity carries the User-Name, and User-Password holds the cleartext password, which is used for the MD5 response but not sent. The Access-Challenge of the server is answered automatically and the future has the final reply.

Parameters:

pkt (pyrad.packet.Packet) – the request to send

Returns:

future with the reply packet; check reply.code

Return type:

asyncio.Future

Raises:
  • Exception – the transport is not initialized, the packet class is not supported, or a request with the same id is pending

  • ValueError – an attribute value cannot be encoded, or auth_type='eap-md5' without User-Name or User-Password

async deinitialize_transports(deinit_coa=True, deinit_auth=True, deinit_acct=True)[source]

Close the sockets to the server.

Requests still waiting for a reply on a closed transport fail with ConnectionAbortedError.

Parameters:
  • deinit_coa (bool) – close the CoA transport

  • deinit_auth (bool) – close the authentication transport

  • deinit_acct (bool) – close the accounting transport

async initialize_transports(enable_acct=False, enable_auth=False, enable_coa=False, local_addr=None, local_auth_port=None, local_acct_port=None, local_coa_port=None)[source]

Open the sockets to the server.

At least one transport has to be enabled. Packets can only be created and sent for enabled transports. Transports which are already open are left as they are.

Parameters:
  • enable_acct (bool) – open the accounting transport

  • enable_auth (bool) – open the authentication transport

  • enable_coa (bool) – open the CoA transport

  • local_addr (str) – local address to bind to, with the local port of a transport or any free port

  • local_auth_port (int) – local port of the authentication transport, only used with local_addr

  • local_acct_port (int) – local port of the accounting transport, only used with local_addr

  • local_coa_port (int) – local port of the CoA transport, only used with local_addr

Raises:
  • Exception – no transport is enabled

  • OSError – a socket cannot be opened

property loop

The event loop, the running one if none was passed.