def test_validate_token(self, token, valid): """Validate that parseable token must have view scope and that an unparseable token is considered valid""" if valid: SynapseAuthTokenCredentials._validate_token(token) else: pytest.raises(SynapseAuthenticationError, SynapseAuthTokenCredentials._validate_token, token)
def _create_synapse_credential(self, syn, username, password, api_key, auth_token): if username is not None: if password is not None: retrieved_session_token = syn._getSessionToken( email=username, password=password) return SynapseApiKeyCredentials( syn._getAPIKey(retrieved_session_token), username) elif auth_token is None and api_key is not None: # auth token takes precedence over api key return SynapseApiKeyCredentials(api_key, username) if auth_token is not None: credentials = SynapseAuthTokenCredentials(auth_token) profile = syn.restGET('/userProfile', auth=credentials) profile_username = profile.get('userName') if username and username != profile_username: # if a username is not required when logging in with an auth token however if both are provided # raise an error if they do not correspond to avoid any ambiguity about what profile was logged in raise SynapseAuthenticationError( 'username and auth_token both provided but username does not match token profile' ) credentials.username = profile_username return credentials return None
def test_tokens_validated(self, mocker): """Validate that tokens are validated when a credentials object is created""" token = 'foo' mock_validate_token = mocker.patch.object(SynapseAuthTokenCredentials, '_validate_token') SynapseAuthTokenCredentials(token) mock_validate_token.assert_called_once_with(token)
def test_get_from_keyring(self, mock_keyring_get_password): mock_keyring_get_password.return_value = self.auth_token credentials = SynapseAuthTokenCredentials.get_from_keyring( self.username) mock_keyring_get_password.assert_called_once_with( self.KEYRING_NAME, self.username, ) assert credentials.username == self.username assert credentials.secret == self.auth_token
def _get_auth_info(self, syn, user_login_args): username = None password = None api_key = None auth_token = None if not user_login_args.skip_cache: username = user_login_args.username or cached_sessions.get_most_recent_user( ) if username: api_creds = SynapseApiKeyCredentials.get_from_keyring(username) auth_token_creds = SynapseAuthTokenCredentials.get_from_keyring( username) api_key = api_creds.secret if api_creds else None auth_token = auth_token_creds.secret if auth_token_creds else None return username, password, api_key, auth_token
def test_username_setter(self): credentials = SynapseAuthTokenCredentials(self.auth_token) assert credentials.username is None credentials.username = self.username assert credentials.username is self.username
def setup(self): self.username = "******" self.auth_token = 'opensesame' self.credentials = SynapseAuthTokenCredentials(self.auth_token, username=self.username) self.KEYRING_NAME = 'SYNAPSE.ORG_CLIENT_AUTH_TOKEN'
class TestSynapseAuthTokenCredentials: def setup(self): self.username = "******" self.auth_token = 'opensesame' self.credentials = SynapseAuthTokenCredentials(self.auth_token, username=self.username) self.KEYRING_NAME = 'SYNAPSE.ORG_CLIENT_AUTH_TOKEN' def test_username(self): assert self.username == self.credentials.username def test_username_setter(self): credentials = SynapseAuthTokenCredentials(self.auth_token) assert credentials.username is None credentials.username = self.username assert credentials.username is self.username def test_secret(self): assert self.credentials.secret == self.auth_token def test_call(self): """Test the __call__ method used by requests.auth""" initial_headers = {'existing': 'header'} auth_header = {'Authorization': f"Bearer {self.auth_token}"} request = MagicMock(spec=requests.Request) request.headers = initial_headers self.credentials(request) assert request.headers == {**initial_headers, **auth_header} def test_repr(self): assert ( f"SynapseAuthTokenCredentials(username='******', token='{self.auth_token}')" == repr(self.credentials)) @patch.object(keyring, 'get_password') def test_get_from_keyring(self, mock_keyring_get_password): mock_keyring_get_password.return_value = self.auth_token credentials = SynapseAuthTokenCredentials.get_from_keyring( self.username) mock_keyring_get_password.assert_called_once_with( self.KEYRING_NAME, self.username, ) assert credentials.username == self.username assert credentials.secret == self.auth_token @patch.object(keyring, 'delete_password') def test_delete_from_keyring(self, mock_keyring_delete_password): self.credentials.delete_from_keyring() mock_keyring_delete_password.assert_called_once_with( self.KEYRING_NAME, self.username, ) @patch.object(keyring, 'set_password') def test_store_to_keyring(self, mock_keyring_set_password): self.credentials.store_to_keyring() mock_keyring_set_password.assert_called_once_with( self.KEYRING_NAME, self.username, self.auth_token, ) def test_tokens_validated(self, mocker): """Validate that tokens are validated when a credentials object is created""" token = 'foo' mock_validate_token = mocker.patch.object(SynapseAuthTokenCredentials, '_validate_token') SynapseAuthTokenCredentials(token) mock_validate_token.assert_called_once_with(token) @pytest.mark.parametrize( "token,valid", [ # valid because not parseable at all. # we deem these valid to future-proof against a change to the token format that may not be parseable # in the same way (or at all) ('', True), ('thisisnotatoken', True), # invalid, parseable but do not contain view scope ('eyJ0eXAiOiJKV1QiLCJraWQiOiJXN05OOldMSlQ6SjVSSzpMN1RMOlQ3TDc6M1ZYNjpKRU9VOjY0NFI6VTNJWDo1S1oyOjdaQ0s6RlBUSCIsImFsZyI6IlJTMjU2In0.eyJhY2Nlc3MiOnsic2NvcGUiOlsibW9kaWZ5Il0sIm9pZGNfY2xhaW1zIjp7fX0sInRva2VuX3R5cGUiOiJQRVJTT05BTF9BQ0NFU1NfVE9LRU4iLCJpc3MiOiJodHRwczovL3JlcG8tcHJvZC0zNDQtMC5wcm9kLnNhZ2ViYXNlLm9yZy9hdXRoL3YxIiwiYXVkIjoiMCIsIm5iZiI6MTYxMzU4NTY5MywiaWF0IjoxNjEzNTg1NjkzLCJqdGkiOiI2MTMiLCJzdWIiOiIzNDA1MDk1In0.VFHau1pQJo1zCnK99R5QDY8zivwQg2S9K-aBKsYGpGwXlUuoQXAll9rjFo8ylz0Yy2qjVihCCxHZVqDOAnb_qjNYl2ZDO3C2QSACDDdITQM0lxVD1iuPoHtjM0Z6e1L4pTBOxpI2BqAlyXKV3se7E7Ix54E6JyVDTSACvOphwiM6Vkg5qmYHd8KWQXDXJRPG-ieQW4hXjbWElzaaQpUBGhesqVuZTgyAB1OIkWtJlirkLtxRXlXHsZ9jaNyrhtpscgu527kg2mIR_PePaEan3St-dMvRdggKrDGUmaxmLI68842eff__DRRJLiNdog4UJR5cbQP_9lFbv0l7ev5hEA', False), # noqa ('eyJ0eXAiOiJKV1QiLCJraWQiOiJXN05OOldMSlQ6SjVSSzpMN1RMOlQ3TDc6M1ZYNjpKRU9VOjY0NFI6VTNJWDo1S1oyOjdaQ0s6RlBUSCIsImFsZyI6IlJTMjU2In0.eyJhY2Nlc3MiOnsic2NvcGUiOlsibW9kaWZ5Il0sIm9pZGNfY2xhaW1zIjp7fX0sInRva2VuX3R5cGUiOiJQRVJTT05BTF9BQ0NFU1NfVE9LRU4iLCJpc3MiOiJodHRwczovL3JlcG8tcHJvZC0zNDQtMC5wcm9kLnNhZ2ViYXNlLm9yZy9hdXRoL3YxIiwiYXVkIjoiMCIsIm5iZiI6MTYxMzU4NTY5MywiaWF0IjoxNjEzNTg1NjkzLCJqdGkiOiI2MTMiLCJzdWIiOiIzNDA1MDk1In0.VFHau1pQJo1zCnK99R5QDY8zivwQg2S9K - aBKsYGpGwXlUuoQXAll9rjFo8ylz0Yy2qjVihCCxHZVqDOAnb_qjNYl2ZDO3C2QSACDDdITQM0lxVD1iuPoHtjM0Z6e1L4pTBOxpI2BqAlyXKV3se7E7Ix54E6JyVDTSACvOphwiM6Vkg5qmYHd8KWQXDXJRPG - ieQW4hXjbWElzaaQpUBGhesqVuZTgyAB1OIkWtJlirkLtxRXlXHsZ9jaNyrhtpscgu527kg2mIR_PePaEan3St - dMvRdggKrDGUmaxmLI68842eff__DRRJLiNdog4UJR5cbQP_9lFbv0l7ev5hEA', False), # noqa # valid, contain view scope ('eyJ0eXAiOiJKV1QiLCJraWQiOiJXN05OOldMSlQ6SjVSSzpMN1RMOlQ3TDc6M1ZYNjpKRU9VOjY0NFI6VTNJWDo1S1oyOjdaQ0s6RlBUSCIsImFsZyI6IlJTMjU2In0.eyJhY2Nlc3MiOnsic2NvcGUiOlsidmlldyJdLCJvaWRjX2NsYWltcyI6e319LCJ0b2tlbl90eXBlIjoiUEVSU09OQUxfQUNDRVNTX1RPS0VOIiwiaXNzIjoiaHR0cHM6Ly9yZXBvLXByb2QtMzQ0LTAucHJvZC5zYWdlYmFzZS5vcmcvYXV0aC92MSIsImF1ZCI6IjAiLCJuYmYiOjE2MTM1ODUxNjIsImlhdCI6MTYxMzU4NTE2MiwianRpIjoiNjEyIiwic3ViIjoiMzQwNTA5NSJ9.rNm-SlmWMP4039fcSpnoDNbu9hnkCfoQ0D4O4Cvd0PPlods6ww8eIaCrzfADZ4Uk5vb58R4pW0ZcZmx3mnwVA3rNnLFrgj8BwSwTFiazGoSJ4GWu5bqEviRxP1FD5fKsQHa3EOjd9Zj9u4AvygywWAH97YflNdALH--4aSgeNVcDBldVw5oR_r09j9vXAioeoSW3Ty4QUtIH05cFbWKJmzmZy8K14JIWxj5Dpw6NvfkQbcNuDDEZ2If8hTVr3AyNrDtAZwdp_fNX26caXkWeHWCYUQKv_KUxzj34CZHOu4eeuTSlM0ozfUmrq0LpK7W05WtUEaIoVq7WeNon9yFjLQ', True), # noqa ('eyJ0eXAiOiJKV1QiLCJraWQiOiJXN05OOldMSlQ6SjVSSzpMN1RMOlQ3TDc6M1ZYNjpKRU9VOjY0NFI6VTNJWDo1S1oyOjdaQ0s6RlBUSCIsImFsZyI6IlJTMjU2In0.eyJhY2Nlc3MiOnsic2NvcGUiOlsidmlldyIsImRvd25sb2FkIiwibW9kaWZ5Il0sIm9pZGNfY2xhaW1zIjp7fX0sInRva2VuX3R5cGUiOiJQRVJTT05BTF9BQ0NFU1NfVE9LRU4iLCJpc3MiOiJodHRwczovL3JlcG8tcHJvZC0zNDQtMC5wcm9kLnNhZ2ViYXNlLm9yZy9hdXRoL3YxIiwiYXVkIjoiMCIsIm5iZiI6MTYxMzU5Nzc0OSwiaWF0IjoxNjEzNTk3NzQ5LCJqdGkiOiI2MTQiLCJzdWIiOiIzNDA1MDk1In0.s_oB1PDOmZOQ43ALol6krcvs32QSR-sTbHd7wwFWgK9KActjpoqoSoypqYqMd4W5qIr0r633Pucc7KMZMK8jfZXSBAJsuBOXrJ5-4g2dwXib8TX_wWqXj6ten241_qOCVqWzEP9X3aIlAVTMExrIxaj3ReF_NKnVmgsk00L73UPezlG8OUBZBbG9_hvzgBObhqRhkYLA3-HwxuYtxOJfYz9iaJmDJ6xCG7VlEj2SZnBSt2tmScOo0FPCIZYFSvl9neNg9ITSD_B5AuigLHJDLQZD6goGCnB8StSa8rDGa8aCj_G9eM4bTIqdVKf3kctGtggbRQJ88JFVbsNCZNgvQ', True), # noqa ]) def test_validate_token(self, token, valid): """Validate that parseable token must have view scope and that an unparseable token is considered valid""" if valid: SynapseAuthTokenCredentials._validate_token(token) else: pytest.raises(SynapseAuthenticationError, SynapseAuthTokenCredentials._validate_token, token)