Skip to content

Commit 50290c7

Browse files
committed
auth: Add support for multiple ZAP authenticators in same process
Enable running multiple ZAP authenticators concurrently within a single process by allowing custom socket addresses in the start() method. This exposes functionality available in libzmq's C API that was previously inaccessible from Python. Previously, all authenticators were hardcoded to bind to the single address "inproc://zeromq.zap.01", preventing multiple authenticators from coexisting. This limitation made it impossible to apply different authentication policies to different socket groups in the same process. I've been using this patch privately for years, because my code needs it. Time to send it upstream. Changes: - Add optional socket_addr parameter to Authenticator.start() - Add optional socket_addr parameter to AsyncioAuthenticator.start() - Add optional socket_addr parameter to ThreadAuthenticator.start() - All parameters default to "inproc://zeromq.zap.01" for backward compatibility - Add documentation with usage examples This change is fully backward compatible - existing code continues to work without modification.
1 parent b184fed commit 50290c7

File tree

3 files changed

+65
-10
lines changed

3 files changed

+65
-10
lines changed

zmq/auth/asyncio.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717

1818

1919
class AsyncioAuthenticator(Authenticator):
20-
"""ZAP authentication for use in the asyncio IO loop"""
20+
"""ZAP authentication for use in the asyncio IO loop
21+
22+
.. versionadded:: 27.2
23+
Multiple authenticators can now run in the same process
24+
by specifying different socket addresses in ``start()``.
25+
See :class:`zmq.auth.Authenticator` for details and examples.
26+
"""
2127

2228
__poller: Optional[Poller]
2329
__task: Any
@@ -46,9 +52,20 @@ async def __handle_zap(self) -> None:
4652
msg = self.zap_socket.recv_multipart()
4753
await self.handle_zap_message(msg)
4854

49-
def start(self) -> None:
50-
"""Start ZAP authentication"""
51-
super().start()
55+
def start(self, socket_addr="inproc://zeromq.zap.01") -> None:
56+
"""Start ZAP authentication
57+
58+
Parameters
59+
----------
60+
socket_addr : str, optional
61+
The address to bind the ZAP socket to.
62+
Default is "inproc://zeromq.zap.01"
63+
64+
.. versionadded:: 27.2
65+
Support for custom socket addresses, enabling multiple
66+
authenticators in the same process.
67+
"""
68+
super().start(socket_addr)
5269
self.__poller = Poller()
5370
self.__poller.register(self.zap_socket, zmq.POLLIN)
5471
self.__task = asyncio.ensure_future(self.__handle_zap())

zmq/auth/base.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ class Authenticator:
3535
main thread, other authentication classes (such as :mod:`zmq.auth.thread`)
3636
are provided.
3737
38+
Multiple Authenticators
39+
-----------------------
40+
41+
.. versionadded:: 27.2
42+
43+
Multiple authenticators can run in the same process by binding to different
44+
ZAP socket addresses. This allows different authentication policies for
45+
different sets of sockets within the same application::
46+
47+
# Create two authenticators with different policies
48+
frontend_auth = zmq.auth.asyncio.AsyncioAuthenticator()
49+
frontend_auth.start(socket_addr="inproc://zap-frontend")
50+
51+
backend_auth = zmq.auth.asyncio.AsyncioAuthenticator()
52+
backend_auth.start(socket_addr="inproc://zap-backend")
53+
3854
Note:
3955
4056
- libzmq provides four levels of security: default NULL (which the Authenticator does
@@ -77,11 +93,22 @@ def __init__(
7793
self.certs = {}
7894
self.log = log or logging.getLogger('zmq.auth')
7995

80-
def start(self) -> None:
81-
"""Create and bind the ZAP socket"""
96+
def start(self, socket_addr="inproc://zeromq.zap.01") -> None:
97+
"""Create and bind the ZAP socket
98+
99+
Parameters
100+
----------
101+
socket_addr : str, optional
102+
The address to bind the ZAP socket to.
103+
Default is "inproc://zeromq.zap.01"
104+
105+
.. versionadded:: 27.2
106+
Support for custom socket addresses, enabling multiple
107+
authenticators in the same process.
108+
"""
82109
self.zap_socket = self.context.socket(zmq.REP, socket_class=zmq.Socket)
83110
self.zap_socket.linger = 1
84-
self.zap_socket.bind("inproc://zeromq.zap.01")
111+
self.zap_socket.bind(socket_addr)
85112
self.log.debug("Starting")
86113

87114
def stop(self) -> None:

zmq/auth/thread.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,21 @@ def __init__(
100100
self.pipe_endpoint = f"inproc://{id(self)}.inproc"
101101
self.thread = None # type: ignore
102102

103-
def start(self) -> None:
104-
"""Start the authentication thread"""
103+
def start(self, socket_addr="inproc://zeromq.zap.01") -> None:
104+
"""Start the authentication thread
105+
106+
Parameters
107+
----------
108+
socket_addr : str, optional
109+
The address to bind the ZAP socket to.
110+
Default is "inproc://zeromq.zap.01"
111+
112+
.. versionadded:: 27.2
113+
Support for custom socket addresses, enabling multiple
114+
authenticators in the same process.
115+
"""
105116
# start the Authenticator
106-
super().start()
117+
super().start(socket_addr)
107118

108119
# create a socket pair to communicate with auth thread.
109120
self.pipe = self.context.socket(zmq.PAIR, socket_class=zmq.Socket)

0 commit comments

Comments
 (0)