def test_load_tokens_with_invalid_refresh_token( mem_storage, expired_tokens_with_refresh, refresh_authorizer_raises_invalid_grant): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = expired_tokens_with_refresh with pytest.raises(TokensExpired): cli.load_tokens()
def test_globus_sdk_query_params(mock_sdk_oauth2_get_authorize_url, mock_input, mock_token_response): cli = NativeClient(client_id=str(uuid4()), token_storage=None) cli.login(additional_params={'foo': 'bar'}) assert mock_sdk_oauth2_get_authorize_url.called mock_sdk_oauth2_get_authorize_url.assert_called_with( query_params={'foo': 'bar'})
def test_client_load_auto_refresh(expired_tokens_with_refresh, mem_storage, mock_refresh_token_authorizer): mem_storage.tokens = expired_tokens_with_refresh cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) tokens = cli.load_tokens() for tset in tokens.values(): assert tset['access_token'] == '<Refreshed Access Token>'
def test_additional_params_raises_warning(monkeypatch, mock_input, mock_token_response): log = Mock() monkeypatch.setattr(fair_research_login.client, 'log', log) cli = NativeClient(client_id=str(uuid4()), token_storage=None) cli.login(additional_params={'foo': 'bar'}) assert log.warning.called
def test_custom_local_server_handler(mock_input, mock_webbrowser, mock_token_response, mem_storage): # Shows handlers are fungible and ANY code handler can be used cli = NativeClient(client_id=str(uuid4()), local_server_code_handler=InputCodeHandler(), token_storage=mem_storage) cli.login()
def test_login_with_no_storage(mock_input, mock_webbrowser, mock_token_response): cli = NativeClient(client_id=str(uuid4()), local_server_code_handler=InputCodeHandler(), token_storage=None) tokens = cli.login() assert tokens == mock_token_response.by_resource_server
def test_save_new_tokens(mem_storage, mock_tokens): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = {} ts1 = {'auth.globus.org': mock_tokens['auth.globus.org']} ts2 = {'transfer.api.globus.org': mock_tokens['transfer.api.globus.org']} cli.save_tokens(ts1) cli.save_tokens(ts2) expected = {'auth.globus.org', 'transfer.api.globus.org'} assert set(mem_storage.tokens.keys()) == expected
def test_load_tokens_by_scope(mem_storage, mock_tokens): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = mock_tokens tokens = cli.load_tokens_by_scope() assert len(tokens) == 5 assert set(tokens.keys()) == { 'openid', 'profile', 'email', 'custom_scope', 'urn:globus:auth:scope:transfer.api.globus.org:all' }
def test_login_no_local_server(monkeypatch, mock_input, mock_webbrowser, mock_token_response, mem_storage): monkeypatch.setattr(LocalServerCodeHandler, 'authenticate', Mock()) monkeypatch.setattr(InputCodeHandler, 'authenticate', Mock()) cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) cli.login(no_local_server=True) assert not LocalServerCodeHandler.authenticate.called assert InputCodeHandler.authenticate.called
def test_login_revokes_old_live_token(mock_revoke, mock_tokens, mem_storage): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = {'auth.globus.org': mock_tokens['auth.globus.org']} new_tokens = {'auth.globus.org': mock_tokens['auth.globus.org'].copy()} # Mock new login 10 seconds after the first one new_tokens['auth.globus.org']['access_token'] = 'new_ac' new_tokens['auth.globus.org']['expires_at_seconds'] += 10 cli.save_tokens(new_tokens) assert mock_revoke.call_count == 1
def test_code_handler_auth_fail(monkeypatch, mock_input, mock_webbrowser, mock_token_response, mem_storage): monkeypatch.setattr(LocalServerCodeHandler, 'authenticate', Mock(return_value=None)) monkeypatch.setattr(InputCodeHandler, 'authenticate', Mock(return_value=None)) cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) with pytest.raises(AuthFailure): cli.login()
def test_load_accepts_string_or_iterable_requested_scopes( mem_storage, mock_tokens): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = mock_tokens scopes = ('openid profile email custom_scope ' 'urn:globus:auth:scope:transfer.api.globus.org:all') tokens = cli.load_tokens(scopes) assert len(tokens) == 3 authorizers = cli.get_authorizers(scopes) assert len(authorizers) == 3
def globus_login(self): """ Perform a Globus login to acquire auth tokens for FuncX analyses. Must be done before experiment.add_config() """ fx_scope = "https://auth.globus.org/scopes/facd7ccc-c5f4-42aa-916b-a0e270e2c2a9/all" search_scope = "urn:globus:auth:scope:search.api.globus.org:all" scopes = [fx_scope, search_scope, "openid"] cli = NativeClient(client_id=CLIENT_ID) self.tokens = cli.login(refresh_tokens=True, no_local_server=True, no_browser=True, requested_scopes=scopes)
def test_client_get_authorizers(mock_tokens, mock_refresh_token_authorizer, mem_storage): mock_tokens['resource.server.org']['refresh_token'] = '<Refresh Token>' mem_storage.tokens = mock_tokens cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) for rs, authorizer in cli.get_authorizers().items(): if rs == 'resource.server.org': assert isinstance(authorizer, globus_sdk.RefreshTokenAuthorizer) else: assert isinstance(authorizer, globus_sdk.AccessTokenAuthorizer)
def test_code_handler_keyboard_interrupt_skip(monkeypatch, mock_input, mock_webbrowser, mem_storage, mock_token_response): monkeypatch.setattr(LocalServerCodeHandler, 'authenticate', Mock(side_effect=KeyboardInterrupt())) monkeypatch.setattr(InputCodeHandler, 'authenticate', Mock()) cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) cli.login() assert InputCodeHandler.authenticate.called
def __init__(self): # initialize a transfer_client if it has not been done already if Globus.transfer_client == None: native_client = NativeClient( client_id=settings.globus.get("client_id"), app_name="Globus Endpoint Performance Dashboard", default_scopes=settings.globus.get("scopes")) native_client.login(no_local_server=True, refresh_tokens=True) transfer_authorizer = native_client.get_authorizers().get( "transfer.api.globus.org") Globus.transfer_client = TransferClient(transfer_authorizer)
def test_authorizer_refresh_hook(mock_tokens, mock_refresh_token_authorizer, mem_storage): mock_tokens['resource.server.org']['refresh_token'] = '<Refresh Token>' mem_storage.tokens = mock_tokens cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) rs_auth = cli.get_authorizers()['resource.server.org'] rs_auth.expires_at = 0 rs_auth.check_expiration_time() tokens = cli.load_tokens() assert 'example.on.refresh.success' in tokens.keys()
def test_client_token_refresh_with_requested_scope_subset( mem_storage, expired_tokens_with_refresh, mock_refresh_token_authorizer): mem_storage.tokens = expired_tokens_with_refresh cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) tokens = cli.load_tokens(requested_scopes=['profile']) assert tokens for tset in mem_storage.tokens.values(): if tset['resource_server'] == 'auth.globus.org': assert tset['access_token'] == '<Refreshed Access Token>' else: assert tset['access_token'] != '<Refreshed Access Token>'
def test_remote_server_fallback(monkeypatch, mock_input, mock_webbrowser, mock_token_response, mem_storage, mock_is_remote_session): mock_is_remote_session.return_value = True monkeypatch.setattr(LocalServerCodeHandler, 'authenticate', Mock()) monkeypatch.setattr(InputCodeHandler, 'authenticate', Mock()) cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) cli.login() assert mock_is_remote_session.called assert not LocalServerCodeHandler.authenticate.called assert InputCodeHandler.authenticate.called
def test_save_overwrite_tokens(mem_storage, mock_tokens, mock_revoke): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = {} ts1 = {'auth.globus.org': mock_tokens['auth.globus.org']} ts2 = {'auth.globus.org': ts1['auth.globus.org'].copy()} ts2['auth.globus.org']['access_token'] = 'new_acc' ts2['auth.globus.org']['refresh_token'] = 'new_ref' ts2['auth.globus.org']['expires_at_seconds'] = ( ts2['auth.globus.org']['expires_at_seconds'] + 10) cli.save_tokens(ts1) cli.save_tokens(ts2) assert mem_storage.tokens['auth.globus.org']['access_token'] == 'new_acc' assert mem_storage.tokens['auth.globus.org']['refresh_token'] == 'new_ref'
def test_client_get_authorizers_by_scope(mock_tokens, mock_refresh_token_authorizer, mem_storage): mock_tokens['resource.server.org']['refresh_token'] = '<Refresh Token>' mem_storage.tokens = mock_tokens cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) by_scope = cli.get_authorizers_by_scope() assert len(by_scope) == 5 for scope, authorizer in by_scope.items(): if scope == 'custom_scope': assert isinstance(authorizer, globus_sdk.RefreshTokenAuthorizer) else: assert isinstance(authorizer, globus_sdk.AccessTokenAuthorizer)
def test_client_load_errors_silenced_on_login(monkeypatch, mem_storage, mock_input, mock_webbrowser, mock_token_response): def raise_load_error(*args, **kwargs): raise LoadError() monkeypatch.setattr(mem_storage, 'read_tokens', raise_load_error) monkeypatch.setattr(mem_storage, 'write_tokens', raise_load_error) cli = NativeClient(client_id=str(uuid4()), local_server_code_handler=InputCodeHandler(), token_storage=None) tokens = cli.login() assert tokens == mock_token_response.by_resource_server
def test_keyboard_interrupt_disables_browser_open(monkeypatch, mock_input, mock_webbrowser): InputCodeHandler.set_browser_enabled(True) is_remote = Mock(return_value=False) user_interrupt = Mock(side_effect=KeyboardInterrupt()) monkeypatch.setattr(InputCodeHandler, 'is_remote_session', is_remote) monkeypatch.setattr(InputCodeHandler, 'get_code', user_interrupt) cli = NativeClient(client_id=str(uuid4()), code_handlers=[InputCodeHandler(), InputCodeHandler()]) # Login should open the browser the first time, but not the second. with pytest.raises(AuthFailure): cli.login() assert mock_webbrowser.call_count == 1
def preactivate_globus(self): """ Read the local globus endpoint UUID from ~/.zstash.ini. If the ini file does not exist, create an ini file with empty values, and try to find the local endpoint UUID based on the FQDN """ local_endpoint = None ini_path = os.path.expanduser("~/.zstash.ini") ini = configparser.ConfigParser() if ini.read(ini_path): if "local" in ini.sections(): local_endpoint = ini["local"].get("globus_endpoint_uuid") else: ini["local"] = {"globus_endpoint_uuid": ""} try: with open(ini_path, "w") as f: ini.write(f) except Exception as e: self.fail(e) if not local_endpoint: fqdn = socket.getfqdn() for pattern in regex_endpoint_map.keys(): if re.fullmatch(pattern, fqdn): local_endpoint = regex_endpoint_map.get(pattern) break if not local_endpoint: # self.fail("{} does not have the local Globus endpoint set".format(ini_path)) self.skipTest( "{} does not have the local Globus endpoint set".format( ini_path)) native_client = NativeClient( client_id="6c1629cf-446c-49e7-af95-323c6412397f", app_name="Zstash", default_scopes= "openid urn:globus:auth:scope:transfer.api.globus.org:all", ) native_client.login(no_local_server=True, refresh_tokens=True) transfer_authorizer = native_client.get_authorizers().get( "transfer.api.globus.org") self.transfer_client = TransferClient(transfer_authorizer) for ep_id in [hpss_globus_endpoint, local_endpoint]: r = self.transfer_client.endpoint_autoactivate(ep_id, if_expires_in=600) if r.get("code") == "AutoActivationFailed": self.fail( "The {} endpoint is not activated or the current activation expires soon. Please go to https://app.globus.org/file-manager/collections/{} and (re)-activate the endpoint." .format(ep_id, ep_id))
def test_client_token_calls_with_no_storage_raise_error(mock_tokens): cli = NativeClient(client_id=str(uuid4()), token_storage=None) with pytest.raises(LoadError): cli.load_tokens() with pytest.raises(LoadError): cli.save_tokens(mock_tokens) with pytest.raises(LoadError): cli.logout()
def test_save_overwrite_scope(mem_storage, mock_tokens, mock_revoke): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) mem_storage.tokens = {} ts1 = {'auth.globus.org': mock_tokens['auth.globus.org']} ts2 = {'auth.globus.org': ts1['auth.globus.org'].copy()} ts2['auth.globus.org']['scope'] = 'openid profile' # A new scope will come with new access tokens, so ensure those change too ts2['auth.globus.org']['access_token'] = 'new_acc' ts2['auth.globus.org']['refresh_token'] = 'new_ref' ts2['auth.globus.org']['expires_at_seconds'] = ( ts2['auth.globus.org']['expires_at_seconds'] + 10) cli.save_tokens(ts1) cli.save_tokens(ts2) assert mem_storage.tokens['auth.globus.org']['scope'] == 'openid profile' assert mem_storage.tokens['auth.globus.org']['access_token'] == 'new_acc' assert mem_storage.tokens['auth.globus.org']['refresh_token'] == 'new_ref'
def test_client_defaults(): cli = NativeClient(client_id=str(uuid4())) assert isinstance(cli.token_storage, MultiClientTokenStorage) assert isinstance(cli.code_handlers, tuple) local_server_handler, input_handler = cli.code_handlers assert isinstance(local_server_handler, LocalServerCodeHandler) assert isinstance(input_handler, InputCodeHandler)
def test_custom_token_storage(): class GoodStorage: def write_tokens(self, tokens): pass def read_tokens(self): pass def clear_tokens(self): pass NativeClient(client_id=str(uuid4()), token_storage=GoodStorage())
def test_non_requested_token_does_not_cancel_load(mem_storage, mock_tokens, mock_expired_tokens): cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) good = [ 'openid', 'profile', 'urn:globus:auth:scope:transfer.api.globus.org:all' ] exp = 'custom_scope' exprs = 'resource.server.org' mem_storage.tokens = mock_tokens mem_storage.tokens[exprs] = mock_expired_tokens[exprs] # should not raise cli.load_tokens(requested_scopes=good) cli.load_tokens() with pytest.raises(TokensExpired): cli.load_tokens(requested_scopes=exp)
def test_client_when_cannot_refresh(mock_expired_tokens, mem_storage, mock_refresh_token_authorizer): mem_storage.tokens = mock_expired_tokens cli = NativeClient(client_id=str(uuid4()), token_storage=mem_storage) with pytest.raises(TokensExpired): cli.load_tokens()