2424from azure .eventhub import __version__
2525from azure .eventhub .sender import Sender
2626from azure .eventhub .receiver import Receiver
27- from azure .eventhub .common import EventHubError
27+ from azure .eventhub .common import EventHubError , parse_sas_token
28+
2829
2930log = logging .getLogger (__name__ )
3031
@@ -90,7 +91,9 @@ class EventHubClient(object):
9091 events to and receiving events from the Azure Event Hubs service.
9192 """
9293
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 ):
9497 """
9598 Constructs a new EventHubClient with the given address URL.
9699
@@ -113,8 +116,13 @@ def __init__(self, address, username=None, password=None, debug=False, http_prox
113116 :param auth_timeout: The time in seconds to wait for a token to be authorized by the service.
114117 The default value is 60 seconds. If set to 0, no timeout will be enforced from the client.
115118 :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
116123 """
117124 self .container_id = "eventhub.pysdk-" + str (uuid .uuid4 ())[:8 ]
125+ self .sas_token = sas_token
118126 self .address = urlparse (address )
119127 self .eh_name = self .address .path .lstrip ('/' )
120128 self .http_proxy = http_proxy
@@ -123,8 +131,8 @@ def __init__(self, address, username=None, password=None, debug=False, http_prox
123131 username = username or url_username
124132 url_password = unquote_plus (self .address .password ) if self .address .password else None
125133 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 " )
128136 self .auth_uri = "sb://{}{}" .format (self .address .hostname , self .address .path )
129137 self ._auth_config = {'username' : username , 'password' : password }
130138 self .get_auth = functools .partial (self ._create_auth )
@@ -136,9 +144,34 @@ def __init__(self, address, username=None, password=None, debug=False, http_prox
136144 log .info ("%r: Created the Event Hub client" , self .container_id )
137145
138146 @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
140168 """
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.
142175
143176 :param conn_str: The connection string.
144177 :type conn_str: str
@@ -196,13 +229,23 @@ def _create_auth(self, username=None, password=None):
196229 Create an ~uamqp.authentication.SASTokenAuth instance to authenticate
197230 the session.
198231
199- :param auth_uri: The URI to authenticate against.
200- :type auth_uri: str
201232 :param username: The name of the shared access policy.
202233 :type username: str
203234 :param password: The shared access key.
204235 :type password: str
205236 """
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+
206249 username = username or self ._auth_config ['username' ]
207250 password = password or self ._auth_config ['password' ]
208251 if "@sas.root" in username :
0 commit comments