def test_set_iam_credentials_for_serverless_calls_get_credentials( mock_boto_client, mocker, serverless_iam_db_kwargs): rp: RedshiftProperty = RedshiftProperty() for k, v in serverless_iam_db_kwargs.items(): rp.put(k, v) mock_cred_provider = MagicMock() mock_cred_holder = MagicMock() mock_cred_provider.get_credentials.return_value = mock_cred_holder mock_cred_holder.has_associated_session = False spy = mocker.spy(rp, "put") IamHelper.set_cluster_credentials(mock_cred_provider, rp) # ensure describe_configuration is called mock_boto_client.assert_has_calls( [call().get_credentials(dbName=rp.db_name)]) # ensure host, port values were set assert spy.called # ensure RedshiftProperty.put method was called assert "user_name" in [c[0][0] for c in spy.call_args_list] assert "password" in [c[0][0] for c in spy.call_args_list]
def make_valid_saml_credentials_provider(): rp: RedshiftProperty = RedshiftProperty() rp.user_name = "AzureDiamond" rp.password = "******" scp: SamlCredentialsProvider = SamlCredentialsProvider() scp.add_parameter(rp) return scp, rp
def test_read_auth_profile_loads_json_payload(mocker): import json req_params: typing.Dict = { "auth_profile": "testProfile", "iam_access_key_id": "testAccessKey", "iam_secret_key": "someSecretKey", "iam_session_token": "someToken", "info": RedshiftProperty(), } req_params["info"].put("region", "us-east-1") mock_payload: typing.Dict[str, str] = { "region": "someTestRegion", "cluster_identifier": "someCluster" } mock_redshift_client: MagicMock = MagicMock() mock_redshift_client.describe_authentication_profiles.return_value = { "AuthenticationProfiles": [{ "AuthenticationProfileContent": json.dumps(mock_payload) }] } mocker.patch("boto3.client", return_value=mock_redshift_client) result = IamHelper.read_auth_profile(**req_params) assert result.region == mock_payload["region"] assert result.cluster_identifier == mock_payload["cluster_identifier"]
def test_read_auth_profile_invalid_json_payload_raises_exception(mocker): import json req_params: typing.Dict = { "auth_profile": "testProfile", "iam_access_key_id": "testAccessKey", "iam_secret_key": "someSecretKey", "iam_session_token": "someToken", "info": RedshiftProperty(), } req_params["info"].put("region", "us-east-1") mock_redshift_client: MagicMock = MagicMock() mock_redshift_client.describe_authentication_profiles.return_value = { "AuthenticationProfiles": [{ "AuthenticationProfileContent": "{{{{" }] } mocker.patch("boto3.client", return_value=mock_redshift_client) with pytest.raises( ProgrammingError, match= "Unable to decode the JSON content of the Redshift authentication profile" ): IamHelper.read_auth_profile(**req_params)
def make_valid_saml_credentials_provider( ) -> typing.Tuple[SamlCredentialsProvider, RedshiftProperty]: rp: RedshiftProperty = RedshiftProperty() rp.user_name = "AzureDiamond" rp.password = "******" scp: SamlCredentialsProvider = SamlCredentialsProvider() # type: ignore scp.add_parameter(rp) return scp, rp
def make_basic_redshift_property(**kwargs) -> RedshiftProperty: rp: RedshiftProperty = RedshiftProperty() for k, v in kwargs.items(): rp.put(k, v) rp.put("user_name", "awsuser") rp.put("host", "localhost") rp.put("db_name", "dev") return rp
def make_valid_adfs_credentials_provider(): rp: RedshiftProperty = RedshiftProperty() rp.user_name = "AzureDiamond" rp.password = "******" acp: AdfsCredentialsProvider = AdfsCredentialsProvider() rp.idp_host = "example.com" acp.add_parameter(rp) return acp, rp
def test_get_credentials_cache_key_no_db_groups(): rp: RedshiftProperty = RedshiftProperty() rp.db_user = "******" rp.db_name = "1" rp.cluster_identifier = "6" rp.auto_create = False res_cache_key: str = IamHelper.get_credentials_cache_key(rp, None) assert res_cache_key is not None assert res_cache_key == "2;1;6;False;900"
def make_valid_okta_credentials_provider(): rp: RedshiftProperty = RedshiftProperty() rp.user_name = "AzureDiamond" rp.password = "******" rp.idp_host = "test_idp_host" rp.app_id = "test_app_id" rp.app_name = "test_app_name" ocp: OktaCredentialsProvider = OktaCredentialsProvider() ocp.add_parameter(rp) return ocp, rp
def make_valid_azure_credentials_provider(): rp: RedshiftProperty = RedshiftProperty() rp.user_name = "AzureDiamond" rp.password = "******" acp: AzureCredentialsProvider = AzureCredentialsProvider() rp.idp_tenant = "example.com" rp.client_secret = "peanut butter" rp.client_id = "1234" acp.add_parameter(rp) return acp, rp
def test_get_credentials_cache_key(): rp: RedshiftProperty = RedshiftProperty() rp.db_user = "******" rp.db_name = "1" rp.db_groups = ["4", "3", "5"] rp.cluster_identifier = "6" rp.auto_create = False res_cache_key: str = IamHelper.get_credentials_cache_key(rp) assert res_cache_key is not None assert res_cache_key == "2;1;3,4,5;6;False"
def make_valid_browser_azure_credential_provider( ) -> BrowserAzureCredentialsProvider: properties: RedshiftProperty = RedshiftProperty() properties.user_name = "" properties.password = "" bacp: BrowserAzureCredentialsProvider = BrowserAzureCredentialsProvider() bacp.add_parameter(properties) # browser azure specific values bacp.idp_tenant = "abcdefghijklmnopqrstuvwxyz" bacp.client_secret = "happy" bacp.client_id = "123455678" return bacp
def test_set_iam_properties_use_redshift_auth_profile_calls_read_auth_profile( mocker): mocker.patch( "redshift_connector.idp_auth_helper.IdpAuthHelper.read_auth_profile", return_value=RedshiftProperty(kwargs={"": ""}), ) mocker.patch("redshift_connector.iam_helper.IamHelper.set_iam_credentials", return_value=None) spy = mocker.spy(IdpAuthHelper, "read_auth_profile") # anticipate read_auth_profile being called with the following parameters exp_call_arg: typing.Dict[str, str] = { "auth_profile": "someTestProfile", "access_key_id": "someAccessKeyIdValue", "session_token": "someSessionTokenValue", "secret_access_key": "someSecretAccessValue", "region": "someRegion", "endpoint_url": "someEndpointUrl", } rp: RedshiftProperty = make_basic_redshift_property( **{ **{ "iam": True, "ssl": True, "cluster_identifier": "someCluster" }, **exp_call_arg }) IamHelper.set_iam_properties(rp) assert spy.called is True assert spy.call_count == 1 assert "auth_profile" in spy.call_args[1] assert spy.call_args[1]["auth_profile"] == exp_call_arg["auth_profile"] assert "iam_access_key_id" in spy.call_args[1] assert spy.call_args[1]["iam_access_key_id"] == exp_call_arg[ "access_key_id"] assert "iam_session_token" in spy.call_args[1] assert spy.call_args[1]["iam_session_token"] == exp_call_arg[ "session_token"] assert "iam_secret_key" in spy.call_args[1] assert spy.call_args[1]["iam_secret_key"] == exp_call_arg[ "secret_access_key"] assert "info" in spy.call_args[1] assert spy.call_args[1]["info"].region == exp_call_arg["region"] assert spy.call_args[1]["info"].endpoint_url == exp_call_arg[ "endpoint_url"]
def get_set_iam_properties_args(**kwargs) -> typing.Dict[str, typing.Any]: return { "info": RedshiftProperty(), "user": "******", "host": "localhost", "database": "dev", "port": 5439, "password": "******", "source_address": None, "unix_sock": None, "ssl": False, "sslmode": "verify-ca", "timeout": None, "max_prepared_statements": 1, "tcp_keepalive": True, "application_name": None, "replication": None, "idp_host": None, "db_user": None, "iam": False, "app_id": None, "app_name": "testing", "preferred_role": None, "principal_arn": None, "credentials_provider": None, "region": None, "cluster_identifier": None, "client_id": None, "idp_tenant": None, "client_secret": None, "partner_sp_id": None, "idp_response_timeout": 1, "listen_port": 8000, "login_url": None, "auto_create": True, "db_groups": None, "force_lowercase": True, "allow_db_user_override": True, "client_protocol_version": ClientProtocolVersion.BASE_SERVER, "database_metadata_current_db_only": True, "access_key_id": None, "secret_access_key": None, "session_token": None, "profile": None, "ssl_insecure": None, "web_identity_token": None, "role_arn": None, "role_session_name": None, **kwargs, }
def make_redshift_property() -> RedshiftProperty: rp: RedshiftProperty = RedshiftProperty() rp.user_name = "*****@*****.**" rp.password = "******" rp.idp_host = "8000" rp.duration = 100 rp.preferred_role = "analyst" rp.sslInsecure = False rp.db_user = "******" rp.db_groups = ["employees"] rp.force_lowercase = True rp.auto_create = False rp.region = "us-west-1" rp.principal = "arn:aws:iam::123456789012:user/Development/product_1234/*" return rp
def test_set_iam_credentials_via_aws_credentials(mocker): redshift_property: RedshiftProperty = RedshiftProperty() redshift_property.profile = "profile_val" redshift_property.access_key_id = "access_val" redshift_property.secret_access_key = "secret_val" redshift_property.session_token = "session_val" mocker.patch( "redshift_connector.iam_helper.IamHelper.set_cluster_credentials", return_value=None) spy = mocker.spy(AWSCredentialsProvider, "add_parameter") IamHelper.set_iam_credentials(redshift_property) assert spy.called is True assert spy.call_count == 1 assert spy.call_args[0][1] == redshift_property
def make_redshift_property() -> RedshiftProperty: rp: RedshiftProperty = RedshiftProperty() rp.user_name = "*****@*****.**" rp.password = "******" rp.db_name = "dev" rp.cluster_identifier = "something" rp.idp_host = "8000" rp.duration = 100 rp.preferred_role = "analyst" rp.ssl_insecure = False rp.db_user = "******" rp.db_groups = ["employees"] rp.force_lowercase = True rp.auto_create = False rp.region = "us-west-1" rp.principal = "arn:aws:iam::123456789012:user/Development/product_1234/*" rp.client_protocol_version = ClientProtocolVersion.BASE_SERVER return rp
def test_set_iam_properties_redshift_auth_profile_does_override(mocker): mock_contents: typing.Dict[str, str] = { "password": "******", } mock_auth_profile_contents: RedshiftProperty = RedshiftProperty( **mock_contents) mocker.patch( "redshift_connector.idp_auth_helper.IdpAuthHelper.read_auth_profile", return_value=mock_auth_profile_contents) mocker.patch("redshift_connector.iam_helper.IamHelper.set_iam_credentials", return_value=None) redshift_auth_profile_spy = mocker.spy(IdpAuthHelper, "read_auth_profile") set_iam_crednetials_spy = mocker.spy(IamHelper, "set_iam_credentials") exp_call_arg: typing.Dict[str, str] = { "auth_profile": "someTestProfile", "access_key_id": "someAccessKeyIdValue", "session_token": "someSessionTokenValue", "secret_access_key": "someSecretAccessValue", "region": "someRegion", "endpoint_url": "someEndpointUrl", } rp: RedshiftProperty = make_basic_redshift_property( **{ **{ "iam": True, "ssl": True, "cluster_identifier": "someCluster" }, **exp_call_arg, }) res = IamHelper.set_iam_properties(rp) assert rp.password == mock_auth_profile_contents.password assert redshift_auth_profile_spy.called is True assert redshift_auth_profile_spy.call_count == 1 assert res.password == mock_auth_profile_contents.password assert set_iam_crednetials_spy.called is True assert set_iam_crednetials_spy.call_count == 1 assert set_iam_crednetials_spy.call_args[0][ 0].password == mock_auth_profile_contents.password
def test_set_iam_credentials_for_serverless_uses_redshift_serverless_client( mock_boto_client, serverless_iam_db_kwargs): rp: RedshiftProperty = RedshiftProperty() for k, v in serverless_iam_db_kwargs.items(): rp.put(k, v) mock_cred_provider = MagicMock() mock_cred_holder = MagicMock() mock_cred_provider.get_credentials.return_value = mock_cred_holder mock_cred_holder.has_associated_session = False IamHelper.set_cluster_credentials(mock_cred_provider, rp) # ensure client creation assert mock_boto_client.called is True assert mock_boto_client.call_count == 1 assert mock_boto_client.call_args[1][ "service_name"] == "redshift-serverless"
def get_set_iam_properties_args(**kwargs): return { "info": RedshiftProperty(), "user": "******", "host": "localhost", "database": "dev", "port": 5439, "password": "******", "source_address": None, "unix_sock": None, "ssl": False, "sslmode": "verify-ca", "timeout": None, "max_prepared_statements": 1, "tcp_keepalive": True, "application_name": None, "replication": None, "idp_host": None, "db_user": None, "iam": False, "app_id": None, "app_name": "testing", "preferred_role": None, "principal_arn": None, "credentials_provider": None, "region": None, "cluster_identifier": None, "client_id": None, "idp_tenant": None, "client_secret": None, "partner_sp_id": None, "idp_response_timeout": 1, "listen_port": 8000, "login_url": None, "auto_create": True, "db_groups": None, "force_lowercase": True, "allow_db_user_override": True, **kwargs, }
def test_read_auth_profile_raises_exception_if_profile_dne(mocker): from botocore import exceptions # type: ignore req_params: typing.Dict = { "auth_profile": "testProfile", "iam_access_key_id": "testAccessKey", "iam_secret_key": "someSecretKey", "iam_session_token": "someToken", "info": RedshiftProperty(), } req_params["info"].put("region", "us-east-1") mock_redshift_client: MagicMock = MagicMock() mock_redshift_client.describe_authentication_profiles.side_effect = exceptions.ClientError( operation_name="ErrorOp", error_response=MagicMock()) mocker.patch("boto3.client", return_value=mock_redshift_client) with pytest.raises( InterfaceError, match= "Unable to retrieve contents of Redshift authentication profile from server" ): IamHelper.read_auth_profile(**req_params)
def test_is_serverless_host(host, exp_is_serverless): info: RedshiftProperty = RedshiftProperty() info.host = host assert info.is_serverless_host == exp_is_serverless
def test_set_account_id_from_host(host, exp_account_id): info: RedshiftProperty = RedshiftProperty() info.host = host info.set_account_id_from_host() assert info.account_id == exp_account_id
def test_set_region_from_host(host, exp_region): info: RedshiftProperty = RedshiftProperty() info.host = host info.set_region_from_host() assert info.region == exp_region
def test_mask_secure_info_in_props_obscures_secret_value(rp_arg): rp: RedshiftProperty = RedshiftProperty() secret_value: str = "SECRET_VALUE" rp.put(rp_arg, secret_value) result = mask_secure_info_in_props(rp) assert result.__getattribute__(rp_arg) != secret_value