def test_body(conn_cfg): delete_temporary_credential( host=conn_cfg["host"], user=conn_cfg["user"], cred_type=MFA_TOKEN ) # first connection, no mfa token cache con = snowflake.connector.connect(**conn_cfg) assert con._rest.token == "TOKEN" assert con._rest.master_token == "MASTER_TOKEN" assert con._rest.mfa_token == "MFA_TOKEN" con.close() # second connection that uses the mfa token issued for first connection to login con = snowflake.connector.connect(**conn_cfg) assert con._rest.token == "NEW_TOKEN" assert con._rest.master_token == "NEW_MASTER_TOKEN" assert con._rest.mfa_token == "NEW_MFA_TOKEN" con.close() # third connection which is expected to login with new mfa token con = snowflake.connector.connect(**conn_cfg) assert con._rest.mfa_token is None con.close() with pytest.raises(DatabaseError): # A failed login will be forced by a mocked response for this connection # Under authentication failed exception, mfa cache is expected to be cleaned up con = snowflake.connector.connect(**conn_cfg) # no mfa cache token should be sent at this connection con = snowflake.connector.connect(**conn_cfg) con.close()
def test_body(): account = 'testaccount' user = '******' authenticator = 'externalbrowser' host = 'testaccount.snowflakecomputing.com' delete_temporary_credential(host=host, user=user, store_temporary_credential=True) # first connection con = snowflake.connector.connect( account=account, user=user, host=host, authenticator=authenticator, database='TESTDB', warehouse='TESTWH', client_store_temporary_credential=True, ) assert con._rest.token == 'TOKEN' assert con._rest.master_token == 'MASTER_TOKEN' assert con._rest.id_token == 'ID_TOKEN' # second connection that uses the id token to get the session token con = snowflake.connector.connect( account=account, user=user, host=host, authenticator=authenticator, database='TESTDB_NEW', # override the database warehouse='TESTWH_NEW', # override the warehouse client_store_temporary_credential=True, ) assert con._rest.token == 'NEW_TOKEN' assert con._rest.master_token == 'NEW_MASTER_TOKEN' assert con._rest.id_token is None assert con.database == 'TESTDB_NEW' assert con.warehouse == 'TESTWH_NEW'
def test_body(): account = "testaccount" user = "******" authenticator = "externalbrowser" host = "testaccount.snowflakecomputing.com" delete_temporary_credential(host=host, user=user, cred_type=ID_TOKEN) # first connection con = snowflake.connector.connect( account=account, user=user, host=host, authenticator=authenticator, database="TESTDB", warehouse="TESTWH", client_store_temporary_credential=True, ) assert con._rest.token == "TOKEN" assert con._rest.master_token == "MASTER_TOKEN" assert con._rest.id_token == "ID_TOKEN" # second connection that uses the id token to get the session token con = snowflake.connector.connect( account=account, user=user, host=host, authenticator=authenticator, database="TESTDB_NEW", # override the database warehouse="TESTWH_NEW", # override the warehouse client_store_temporary_credential=True, ) assert con._rest.token == "NEW_TOKEN" assert con._rest.master_token == "NEW_MASTER_TOKEN" assert con._rest.id_token is None assert con.database == "TESTDB_NEW" assert con.warehouse == "TESTWH_NEW"
def test_connect_externalbrowser(token_validity_test_values): """SSO Id Token Cache tests. This test should only be ran if keyring optional dependency is installed. In order to run this test, remove the above pytest.mark.skip annotation and run it. It will popup a windows once but the rest connections should not create popups. """ delete_temporary_credential( host=CONNECTION_PARAMETERS_SSO['host'], user=CONNECTION_PARAMETERS_SSO['user'], cred_type=ID_TOKEN) # delete existing temporary credential CONNECTION_PARAMETERS_SSO['client_store_temporary_credential'] = True # change database and schema to non-default one print( "[INFO] 1st connection gets id token and stores in the local cache (keychain/credential manager/cache file). " "This popup a browser to SSO login") cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) assert cnx.database == 'TESTDB' assert cnx.schema == 'PUBLIC' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' ret = cnx.cursor().execute( "select current_database(), current_schema(), " "current_role(), current_warehouse()").fetchall() assert ret[0][0] == 'TESTDB' assert ret[0][1] == 'PUBLIC' assert ret[0][2] == 'SYSADMIN' assert ret[0][3] == 'REGRESS' cnx.close() print("[INFO] 2nd connection reads the local cache and uses the id token. " "This should not popups a browser.") CONNECTION_PARAMETERS_SSO['database'] = 'testdb' CONNECTION_PARAMETERS_SSO['schema'] = 'testschema' cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) print("[INFO] Running a 10 seconds query. If the session expires in 10 " "seconds, the query should renew the token in the middle, " "and the current objects should be refreshed.") cnx.cursor().execute("select seq8() from table(generator(timelimit=>10))") assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' print("[INFO] Running a 1 second query. ") cnx.cursor().execute("select seq8() from table(generator(timelimit=>1))") assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' print("[INFO] Running a 90 seconds query. This pops up a browser in the " "middle of the query.") cnx.cursor().execute("select seq8() from table(generator(timelimit=>90))") assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' cnx.close() # change database and schema again to ensure they are overridden CONNECTION_PARAMETERS_SSO['database'] = 'testdb' CONNECTION_PARAMETERS_SSO['schema'] = 'testschema' cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' cnx.close() with snowflake.connector.connect( **CONNECTION_PARAMETERS_ADMIN) as cnx_admin: # cnx_admin.cursor().execute("alter account testaccount set ALLOW_UNPROTECTED_ID_TOKEN=false;") cnx_admin.cursor().execute( "alter account testaccount set ALLOW_ID_TOKEN=false;") cnx_admin.cursor().execute( "alter account testaccount set ID_TOKEN_FEATURE_ENABLED=false;") print( "[INFO] Login again with ALLOW_UNPROTECTED_ID_TOKEN unset. Please make sure this pops up the browser" ) cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) cnx.close()
def test_mfa_no_local_secure_storage(mockSnowflakeRestfulPostRequest): """Test whether username_password_mfa authenticator can work when no local secure storage is available.""" global mock_post_req_cnt mock_post_req_cnt = 0 # This test requires Mac/Win and no keyring lib is installed assert not installed_keyring def mock_post_request(url, headers, json_body, **kwargs): global mock_post_req_cnt ret = None body = json.loads(json_body) if mock_post_req_cnt == 0: # issue MFA token for a succeeded login assert (body["data"]["SESSION_PARAMETERS"].get( "CLIENT_REQUEST_MFA_TOKEN") is True) ret = { "success": True, "message": None, "data": { "token": "TOKEN", "masterToken": "MASTER_TOKEN", "mfaToken": "MFA_TOKEN", }, } elif mock_post_req_cnt == 2: # No local secure storage available, so no mfa cache token should be provided assert (body["data"]["SESSION_PARAMETERS"].get( "CLIENT_REQUEST_MFA_TOKEN") is True) assert "TOKEN" not in body["data"] ret = { "success": True, "message": None, "data": { "token": "NEW_TOKEN", "masterToken": "NEW_MASTER_TOKEN", }, } elif mock_post_req_cnt in [1, 3]: # connection.close() ret = {"success": True} mock_post_req_cnt += 1 return ret # POST requests mock mockSnowflakeRestfulPostRequest.side_effect = mock_post_request conn_cfg = { "account": "testaccount", "user": "******", "password": "******", "authenticator": "username_password_mfa", "host": "testaccount.snowflakecomputing.com", } delete_temporary_credential(host=conn_cfg["host"], user=conn_cfg["user"], cred_type=MFA_TOKEN) # first connection, no mfa token cache con = snowflake.connector.connect(**conn_cfg) assert con._rest.token == "TOKEN" assert con._rest.master_token == "MASTER_TOKEN" assert con._rest.mfa_token == "MFA_TOKEN" con.close() # second connection, no mfa token should be issued as well since no available local secure storage con = snowflake.connector.connect(**conn_cfg) assert con._rest.token == "NEW_TOKEN" assert con._rest.master_token == "NEW_MASTER_TOKEN" assert not con._rest.mfa_token con.close()
def test_mfa_no_local_secure_storage(mockSnowflakeRestfulPostRequest): """Test whether username_password_mfa authenticator can work when no local secure storage is available.""" global mock_post_req_cnt mock_post_req_cnt = 0 # This test requires Mac/Win and no keyring lib is installed assert not installed_keyring def mock_post_request(url, headers, json_body, **kwargs): global mock_post_req_cnt ret = None body = json.loads(json_body) if mock_post_req_cnt == 0: # issue MFA token for a succeeded login assert body['data']['SESSION_PARAMETERS'].get( 'CLIENT_REQUEST_MFA_TOKEN') is True ret = { 'success': True, 'message': None, 'data': { 'token': 'TOKEN', 'masterToken': 'MASTER_TOKEN', 'mfaToken': 'MFA_TOKEN', } } elif mock_post_req_cnt == 2: # No local secure storage available, so no mfa cache token should be provided assert body['data']['SESSION_PARAMETERS'].get( 'CLIENT_REQUEST_MFA_TOKEN') is True assert 'TOKEN' not in body['data'] ret = { 'success': True, 'message': None, 'data': { 'token': 'NEW_TOKEN', 'masterToken': 'NEW_MASTER_TOKEN', } } elif mock_post_req_cnt in [1, 3]: # connection.close() ret = {'success': True} mock_post_req_cnt += 1 return ret # POST requests mock mockSnowflakeRestfulPostRequest.side_effect = mock_post_request conn_cfg = { 'account': 'testaccount', 'user': '******', 'password': '******', 'authenticator': 'username_password_mfa', 'host': 'testaccount.snowflakecomputing.com', } delete_temporary_credential(host=conn_cfg['host'], user=conn_cfg['user'], cred_type=MFA_TOKEN) # first connection, no mfa token cache con = snowflake.connector.connect(**conn_cfg) assert con._rest.token == 'TOKEN' assert con._rest.master_token == 'MASTER_TOKEN' assert con._rest.mfa_token == 'MFA_TOKEN' con.close() # second connection, no mfa token should be issued as well since no available local secure storage con = snowflake.connector.connect(**conn_cfg) assert con._rest.token == 'NEW_TOKEN' assert con._rest.master_token == 'NEW_MASTER_TOKEN' assert not con._rest.mfa_token con.close()
def test_connect_externalbrowser(token_validity_test_values): """ SSO Id Token Cache tests. This is disabled by default. In order to run this test, remove the above pytest.mark.skip annotation and run it. It will popup a windows once but the rest connections should not create popups. """ delete_temporary_credential(host=CONNECTION_PARAMETERS_SSO['host'], user=CONNECTION_PARAMETERS_SSO['user'], store_temporary_credential=True ) # delete existing temporary credential CONNECTION_PARAMETERS_SSO['client_store_temporary_credential'] = True # change database and schema to non-default one print("[INFO] 1st connection gets id token and stores in the cache file. " "This popup a browser to SSO login") cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) assert cnx.database == 'TESTDB' assert cnx.schema == 'PUBLIC' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' ret = cnx.cursor().execute( "select current_database(), current_schema(), " "current_role(), current_warehouse()").fetchall() assert ret[0][0] == 'TESTDB' assert ret[0][1] == 'PUBLIC' assert ret[0][2] == 'SYSADMIN' assert ret[0][3] == 'REGRESS' cnx.close() print("[INFO] 2nd connection reads the cache file and uses the id token. " "This should not popups a browser.") CONNECTION_PARAMETERS_SSO['database'] = 'testdb' CONNECTION_PARAMETERS_SSO['schema'] = 'testschema' cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) print("[INFO] Running a 10 seconds query. If the session expires in 10 " "seconds, the query should renew the token in the middle, " "and the current objects should be refreshed.") cnx.cursor().execute("select seq8() from table(generator(timelimit=>10))") assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' print("[INFO] Running a 1 seconds query. ") cnx.cursor().execute("select seq8() from table(generator(timelimit=>1))") assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' print("[INFO] Running a 90 seconds query. This pops up a browser in the " "middle of the query.") cnx.cursor().execute("select seq8() from table(generator(timelimit=>90))") assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' # change database and schema again to ensure they are overridden CONNECTION_PARAMETERS_SSO['database'] = 'testdb' CONNECTION_PARAMETERS_SSO['schema'] = 'testschema' cnx = snowflake.connector.connect(**CONNECTION_PARAMETERS_SSO) assert cnx.database == 'TESTDB' assert cnx.schema == 'TESTSCHEMA' assert cnx.role == 'SYSADMIN' assert cnx.warehouse == 'REGRESS' cnx.close()