24
24
from azure .eventhub import __version__
25
25
from azure .eventhub .sender import Sender
26
26
from azure .eventhub .receiver import Receiver
27
- from azure .eventhub .common import EventHubError
27
+ from azure .eventhub .common import EventHubError , parse_sas_token
28
+
28
29
29
30
log = logging .getLogger (__name__ )
30
31
@@ -90,7 +91,9 @@ class EventHubClient(object):
90
91
events to and receiving events from the Azure Event Hubs service.
91
92
"""
92
93
93
- def __init__ (self , address , username = None , password = None , debug = False , http_proxy = None , auth_timeout = 60 ):
94
+ def __init__ (
95
+ self , address , username = None , password = None , debug = False ,
96
+ http_proxy = None , auth_timeout = 60 , sas_token = None ):
94
97
"""
95
98
Constructs a new EventHubClient with the given address URL.
96
99
@@ -113,8 +116,13 @@ def __init__(self, address, username=None, password=None, debug=False, http_prox
113
116
:param auth_timeout: The time in seconds to wait for a token to be authorized by the service.
114
117
The default value is 60 seconds. If set to 0, no timeout will be enforced from the client.
115
118
:type auth_timeout: int
119
+ :param sas_token: A SAS token or function that returns a SAS token. If a function is supplied,
120
+ it will be used to retrieve subsequent tokens in the case of token expiry. The function should
121
+ take no arguments.
122
+ :type sas_token: str or callable
116
123
"""
117
124
self .container_id = "eventhub.pysdk-" + str (uuid .uuid4 ())[:8 ]
125
+ self .sas_token = sas_token
118
126
self .address = urlparse (address )
119
127
self .eh_name = self .address .path .lstrip ('/' )
120
128
self .http_proxy = http_proxy
@@ -123,8 +131,8 @@ def __init__(self, address, username=None, password=None, debug=False, http_prox
123
131
username = username or url_username
124
132
url_password = unquote_plus (self .address .password ) if self .address .password else None
125
133
password = password or url_password
126
- if not username or not password :
127
- raise ValueError ("Missing username and/or password. " )
134
+ if ( not username or not password ) and not sas_token :
135
+ raise ValueError ("Please supply either username and password, or a SAS token " )
128
136
self .auth_uri = "sb://{}{}" .format (self .address .hostname , self .address .path )
129
137
self ._auth_config = {'username' : username , 'password' : password }
130
138
self .get_auth = functools .partial (self ._create_auth )
@@ -136,9 +144,34 @@ def __init__(self, address, username=None, password=None, debug=False, http_prox
136
144
log .info ("%r: Created the Event Hub client" , self .container_id )
137
145
138
146
@classmethod
139
- def from_connection_string (cls , conn_str , eventhub = None , ** kwargs ):
147
+ def from_sas_token (cls , address , sas_token , eventhub = None , ** kwargs ):
148
+ """Create an EventHubClient from an existing auth token or token generator.
149
+
150
+ :param address: The Event Hub address URL
151
+ :type address: str
152
+ :param sas_token: A SAS token or function that returns a SAS token. If a function is supplied,
153
+ it will be used to retrieve subsequent tokens in the case of token expiry. The function should
154
+ take no arguments.
155
+ :type sas_token: str or callable
156
+ :param eventhub: The name of the EventHub, if not already included in the address URL.
157
+ :type eventhub: str
158
+ :param debug: Whether to output network trace logs to the logger. Default
159
+ is `False`.
160
+ :type debug: bool
161
+ :param http_proxy: HTTP proxy settings. This must be a dictionary with the following
162
+ keys: 'proxy_hostname' (str value) and 'proxy_port' (int value).
163
+ Additionally the following keys may also be present: 'username', 'password'.
164
+ :type http_proxy: dict[str, Any]
165
+ :param auth_timeout: The time in seconds to wait for a token to be authorized by the service.
166
+ The default value is 60 seconds. If set to 0, no timeout will be enforced from the client.
167
+ :type auth_timeout: int
140
168
"""
141
- Create an EventHubClient from a connection string.
169
+ address = _build_uri (address , eventhub )
170
+ return cls (address , sas_token = sas_token , ** kwargs )
171
+
172
+ @classmethod
173
+ def from_connection_string (cls , conn_str , eventhub = None , ** kwargs ):
174
+ """Create an EventHubClient from a connection string.
142
175
143
176
:param conn_str: The connection string.
144
177
:type conn_str: str
@@ -196,13 +229,23 @@ def _create_auth(self, username=None, password=None):
196
229
Create an ~uamqp.authentication.SASTokenAuth instance to authenticate
197
230
the session.
198
231
199
- :param auth_uri: The URI to authenticate against.
200
- :type auth_uri: str
201
232
:param username: The name of the shared access policy.
202
233
:type username: str
203
234
:param password: The shared access key.
204
235
:type password: str
205
236
"""
237
+ if self .sas_token :
238
+ token = self .sas_token () if callable (self .sas_token ) else self .sas_token
239
+ try :
240
+ expiry = int (parse_sas_token (token )['se' ])
241
+ except (KeyError , TypeError , IndexError ):
242
+ raise ValueError ("Supplied SAS token has no valid expiry value." )
243
+ return authentication .SASTokenAuth (
244
+ self .auth_uri , self .auth_uri , token ,
245
+ expires_at = expiry ,
246
+ timeout = self .auth_timeout ,
247
+ http_proxy = self .http_proxy )
248
+
206
249
username = username or self ._auth_config ['username' ]
207
250
password = password or self ._auth_config ['password' ]
208
251
if "@sas.root" in username :
0 commit comments