def create_authenticator(self, connection, debug=False, **kwargs): """Create the AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.connection.Connection :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :rtype: uamqp.c_uamqp.CBSTokenAuth """ self._connection = connection self._session = Session(connection, **kwargs) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout, self._connection.container_id) self._cbs_auth.set_trace(debug) except ValueError: self._session.destroy() raise errors.AMQPConnectionError( "Unable to open authentication session on connection {}.\n" "Please confirm target hostname exists: {}".format( connection.container_id, connection.hostname)) return self._cbs_auth
def create_authenticator(self, connection, debug=False): """Create the AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.Connection :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :returns: ~uamqp.c_uamqp.CBSTokenAuth """ self._lock = threading.Lock() self._session = Session( connection, incoming_window=constants.MAX_FRAME_SIZE_BYTES, outgoing_window=constants.MAX_FRAME_SIZE_BYTES) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout) self._cbs_auth.set_trace(debug) except ValueError: raise errors.AMQPConnectionError( "Unable to open authentication session. " "Please confirm target URI exists.") return self._cbs_auth
class CBSAuthMixin(object): """Mixin to handle sending and refreshing CBS auth tokens.""" def update_token(self): """Update a token that is about to expire. This is specific to a particular token type, and therefore must be implemented in a child class. """ raise errors.TokenExpired( "Unable to refresh token - no refresh logic implemented.") def create_authenticator(self, connection, debug=False, **kwargs): """Create the AMQP session and the CBS channel with which to negotiate the token. :param connection: The underlying AMQP connection on which to create the session. :type connection: ~uamqp.connection.Connection :param debug: Whether to emit network trace logging events for the CBS session. Default is `False`. Logging events are set at INFO level. :type debug: bool :rtype: uamqp.c_uamqp.CBSTokenAuth """ self._connection = connection self._session = Session(connection, **kwargs) try: self._cbs_auth = c_uamqp.CBSTokenAuth( self.audience, self.token_type, self.token, int(self.expires_at), self._session._session, # pylint: disable=protected-access self.timeout, self._connection.container_id) self._cbs_auth.set_trace(debug) except ValueError: self._session.destroy() raise errors.AMQPConnectionError( "Unable to open authentication session on connection {}.\n" "Please confirm target hostname exists: {}".format( connection.container_id, connection.hostname)) return self._cbs_auth def close_authenticator(self): """Close the CBS auth channel and session.""" _logger.info("Shutting down CBS session on connection: %r.", self._connection.container_id) try: _logger.debug("Unlocked CBS to close on connection: %r.", self._connection.container_id) self._cbs_auth.destroy() _logger.info("Auth closed, destroying session on connection: %r.", self._connection.container_id) self._session.destroy() finally: _logger.info( "Finished shutting down CBS session on connection: %r.", self._connection.container_id) def handle_token(self): """This function is called periodically to check the status of the current token if there is one, and request a new one if needed. If the token request fails, it will be retried according to the retry policy. A token refresh will be attempted if the token will expire soon. This function will return a tuple of two booleans. The first represents whether the token authentication has not completed within it's given timeout window. The second indicates whether the token negotiation is still in progress. :raises: ~uamqp.errors.AuthenticationException if the token authentication fails. :raises: ~uamqp.errors.TokenExpired if the token has expired and cannot be refreshed. :rtype: tuple[bool, bool] """ # pylint: disable=protected-access timeout = False in_progress = False try: self._connection.lock() if self._connection._closing or self._connection._error: return timeout, in_progress auth_status = self._cbs_auth.get_status() auth_status = constants.CBSAuthStatus(auth_status) if auth_status == constants.CBSAuthStatus.Error: if self.retries >= self._retry_policy.retries: # pylint: disable=no-member _logger.warning( "Authentication Put-Token failed. Retries exhausted.") raise errors.TokenAuthFailure( *self._cbs_auth.get_failure_info()) else: error_code, error_description = self._cbs_auth.get_failure_info( ) _logger.info("Authentication status: %r, description: %r", error_code, error_description) _logger.info("Authentication Put-Token failed. Retrying.") self.retries += 1 # pylint: disable=no-member time.sleep(self._retry_policy.backoff) self._cbs_auth.authenticate() in_progress = True elif auth_status == constants.CBSAuthStatus.Failure: errors.AuthenticationException( "Failed to open CBS authentication link.") elif auth_status == constants.CBSAuthStatus.Expired: raise errors.TokenExpired("CBS Authentication Expired.") elif auth_status == constants.CBSAuthStatus.Timeout: timeout = True elif auth_status == constants.CBSAuthStatus.InProgress: in_progress = True elif auth_status == constants.CBSAuthStatus.RefreshRequired: _logger.info( "Token on connection %r will expire soon - attempting to refresh.", self._connection.container_id) self.update_token() self._cbs_auth.refresh(self.token, int(self.expires_at)) elif auth_status == constants.CBSAuthStatus.Idle: self._cbs_auth.authenticate() in_progress = True elif auth_status != constants.CBSAuthStatus.Ok: raise errors.AuthenticationException("Invalid auth state.") except compat.TimeoutException: _logger.debug( "CBS auth timed out while waiting for lock acquisition.") return None, None except ValueError as e: raise errors.AuthenticationException( "Token authentication failed: {}".format(e)) finally: self._connection.release() return timeout, in_progress