def _build_engine(self, credentials: dict, **kwargs) -> "sa.engine.Engine": """ Using a set of given credentials, constructs an Execution Engine , connecting to a database using a URL or a private key path. """ # Update credentials with anything passed during connection time drivername = credentials.pop("drivername") schema_name = credentials.pop("schema_name", None) if schema_name is not None: logger.warning( "schema_name specified creating a URL with schema is not supported. Set a default " "schema on the user connecting to your database." ) create_engine_kwargs = kwargs connect_args = credentials.pop("connect_args", None) if connect_args: create_engine_kwargs["connect_args"] = connect_args if "private_key_path" in credentials: options, create_engine_kwargs = self._get_sqlalchemy_key_pair_auth_url( drivername, credentials ) else: options = get_sqlalchemy_url(drivername, **credentials) self.drivername = drivername engine = sa.create_engine(options, **create_engine_kwargs) return engine
def _get_sqlalchemy_connection_options(self, **kwargs): drivername = None if "credentials" in self._datasource_config: credentials = self._datasource_config["credentials"] else: credentials = {} create_engine_kwargs = {} connect_args = credentials.pop("connect_args", None) if connect_args: create_engine_kwargs["connect_args"] = connect_args # if a connection string or url was provided in the profile, use that if "connection_string" in credentials: options = credentials["connection_string"] elif "url" in credentials: options = credentials["url"] else: # Update credentials with anything passed during connection time drivername = credentials.pop("drivername") schema_name = credentials.pop("schema_name", None) if schema_name is not None: logger.warning( "schema_name specified creating a URL with schema is not supported. Set a default " "schema on the user connecting to your database.") if "private_key_path" in credentials: options, create_engine_kwargs = self._get_sqlalchemy_key_pair_auth_url( drivername, credentials) else: options = get_sqlalchemy_url(drivername, **credentials) return options, create_engine_kwargs, drivername
def _get_sqlalchemy_key_pair_auth_url( drivername: str, credentials: dict, ) -> Tuple["sa.engine.url.URL", Dict]: """ Utilizing a private key path and a passphrase in a given credentials dictionary, attempts to encode the provided values into a private key. If passphrase is incorrect, this will fail and an exception is raised. Args: drivername(str) - The name of the driver class credentials(dict) - A dictionary of database credentials used to access the database Returns: a tuple consisting of a url with the serialized key-pair authentication, and a dictionary of engine kwargs. """ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization private_key_path = credentials.pop("private_key_path") private_key_passphrase = credentials.pop("private_key_passphrase") with Path(private_key_path).expanduser().resolve().open( mode="rb") as key: try: p_key = serialization.load_pem_private_key( key.read(), password=private_key_passphrase.encode() if private_key_passphrase else None, backend=default_backend(), ) except ValueError as e: if "incorrect password" in str(e).lower(): raise DatasourceKeyPairAuthBadPassphraseError( datasource_name="SqlAlchemyDatasource", message= "Decryption of key failed, was the passphrase incorrect?", ) from e else: raise e pkb = p_key.private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) credentials_driver_name = credentials.pop("drivername", None) create_engine_kwargs = {"connect_args": {"private_key": pkb}} return ( get_sqlalchemy_url(drivername or credentials_driver_name, **credentials), create_engine_kwargs, )
def _get_sqlalchemy_key_pair_auth_url(self, drivername, credentials): from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization private_key_path = credentials.pop("private_key_path") private_key_passphrase = credentials.pop("private_key_passphrase") with Path(private_key_path).expanduser().resolve().open( mode="rb") as key: try: p_key = serialization.load_pem_private_key( key.read(), password=private_key_passphrase.encode() if private_key_passphrase else None, backend=default_backend(), ) except ValueError as e: if "incorrect password" in str(e).lower(): raise DatasourceKeyPairAuthBadPassphraseError( datasource_name="SqlAlchemyDatasource", message= "Decryption of key failed, was the passphrase incorrect?", ) from e else: raise e pkb = p_key.private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) credentials_driver_name = credentials.pop("drivername", None) create_engine_kwargs = {"connect_args": {"private_key": pkb}} return ( get_sqlalchemy_url(drivername or credentials_driver_name, **credentials), create_engine_kwargs, )
def _build_engine(self, credentials, **kwargs) -> "sa.engine.Engine": """ Using a set of given credentials, constructs an Execution Engine , connecting to a database using a URL or a private key path. """ # Update credentials with anything passed during connection time drivername = credentials.pop("drivername") create_engine_kwargs = kwargs self._schema_name = credentials.pop("schema", None) connect_args = credentials.pop("connect_args", None) if connect_args: create_engine_kwargs["connect_args"] = connect_args if "private_key_path" in credentials: options, create_engine_kwargs = self._get_sqlalchemy_key_pair_auth_url( drivername, credentials) else: options = get_sqlalchemy_url(drivername, **credentials) self.drivername = drivername engine = sa.create_engine(options, **create_engine_kwargs) return engine