def test_parse_token_response(self): client = MobileApplicationClient(self.client_id) # Parse code and state response = client.parse_request_uri_response(self.response_uri, scope=self.scope) self.assertEqual(response, self.token) self.assertEqual(client.access_token, response.get("access_token")) self.assertEqual(client.refresh_token, response.get("refresh_token")) self.assertEqual(client.token_type, response.get("token_type")) # Mismatching scope self.assertRaises(Warning, client.parse_request_uri_response, self.response_uri, scope="invalid") os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '4' token = client.parse_request_uri_response(self.response_uri, scope='invalid') self.assertTrue(token.scope_changed) scope_changes_recorded = [] def record_scope_change(sender, message, old, new): scope_changes_recorded.append((message, old, new)) signals.scope_changed.connect(record_scope_change) try: client.parse_request_uri_response(self.response_uri, scope="invalid") self.assertEqual(len(scope_changes_recorded), 1) message, old, new = scope_changes_recorded[0] self.assertEqual(message, 'Scope has changed from "invalid" to "/profile".') self.assertEqual(old, ['invalid']) self.assertEqual(new, ['/profile']) finally: signals.scope_changed.disconnect(record_scope_change) del os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE']
def test_parse_token_response(self): client = MobileApplicationClient(self.client_id) # Parse code and state response = client.parse_request_uri_response(self.response_uri, scope=self.scope) self.assertEqual(response, self.token) self.assertEqual(client.access_token, response.get("access_token")) self.assertEqual(client.refresh_token, response.get("refresh_token")) self.assertEqual(client.token_type, response.get("token_type")) # Mismatching scope self.assertRaises(Warning, client.parse_request_uri_response, self.response_uri, scope="invalid") os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '4' token = client.parse_request_uri_response(self.response_uri, scope='invalid') self.assertTrue(token.scope_changed) scope_changes_recorded = [] def record_scope_change(sender, message, old, new): scope_changes_recorded.append((message, old, new)) signals.scope_changed.connect(record_scope_change) try: client.parse_request_uri_response(self.response_uri, scope="invalid") self.assertEqual(len(scope_changes_recorded), 1) message, old, new = scope_changes_recorded[0] self.assertEqual(message, 'Scope has changed from "invalid" to "/profile".') self.assertEqual(old, ['invalid']) self.assertEqual(new, ['/profile']) finally: signals.scope_changed.disconnect(record_scope_change) del os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE']
def test_populate_attributes(self): client = MobileApplicationClient(self.client_id) response_uri = (self.response_uri + "&code=EVIL-CODE") client.parse_request_uri_response(response_uri, scope=self.scope) # We must not accidentally pick up any further security # credentials at this point. self.assertIsNone(client.code)
def test_populate_attributes(self): client = MobileApplicationClient(self.client_id) response_uri = (self.response_uri + "&code=EVIL-CODE") client.parse_request_uri_response(response_uri, scope=self.scope) # We must not accidentally pick up any further security # credentials at this point. self.assertIsNone(client.code)
def test_parse_token_response(self): client = MobileApplicationClient(self.client_id) # Parse code and state response = client.parse_request_uri_response(self.response_uri, scope=self.scope) self.assertEqual(response, self.token) self.assertEqual(client.access_token, response.get("access_token")) self.assertEqual(client.refresh_token, response.get("refresh_token")) self.assertEqual(client.token_type, response.get("token_type")) # Mismatching scope self.assertRaises(Warning, client.parse_request_uri_response, self.response_uri, scope="invalid")
def test_parse_token_response(self): client = MobileApplicationClient(self.client_id) # Parse code and state response = client.parse_request_uri_response(self.response_uri, scope=self.scope) self.assertEqual(response, self.token) self.assertEqual(client.access_token, response.get("access_token")) self.assertEqual(client.refresh_token, response.get("refresh_token")) self.assertEqual(client.token_type, response.get("token_type")) # Mismatching scope self.assertRaises(Warning, client.parse_request_uri_response, self.response_uri, scope="invalid")
class Client(object): def __init__(self, username, password, client_id=None, api_key=None): if client_id is None: client_id = uuid.uuid4() self.client_id = client_id self._api_key = api_key self.username = username self.password = password self.endpoint = MobileApplicationClient(self.client_id) @property def api_key(self): if self._api_key is None: self._api_key = self.register() return self._api_key def url_for_workflow(self, workflow): return 'https://%s/view/%s' % (RESOURCE_URL, workflow) def url_for_register(self): return 'https://%s/register' % AUTH_URL def register(self): params = { 'username': self.username, 'password': self.password } response = requests.get(self.url_for_register(), params=params, verify=False) if response.status_code == 201: if 'X-API-Key' in response.headers: return response.headers['X-API-Key'] else: raise RuntimeError('No X-API-Key header in response (%s)' % response.text) elif response.status_code == 401: raise RuntimeError('Not authorized (%s)' % response.text) else: raise RuntimeError('Unexpected response %d from authorization server (%s)' % (response.status_code, response.text)) def view_without_access_token(self, workflow_name): response = requests.get(self.url_for_workflow(workflow_name), verify=False) if response.status_code == 401: return response elif response.status_code == 404: raise RuntimeError('Not found (%s)' % response.text) else: raise RuntimeError('Unexpected response %d from resource server (%s)' % (response.status_code, response.text)) def extract_auth_headers(self, response): try: oauth_url = response.headers['X-OAuth-URL'] # Must be Unicode for oauthlib, le sigh: required_scope = unicode(response.headers['X-Required-Scope']) except KeyError: raise RuntimeError('Did not find expected headers in response from ' 'resource server') return oauth_url, required_scope def authorize(self, oauth_url, redirect_uri, required_scope): headers = { 'X-API-Key': self.api_key, } request_url = self.endpoint.prepare_request_uri(oauth_url, redirect_uri=redirect_uri, scope=required_scope) response = requests.get(request_url, headers=headers, allow_redirects=False, verify=False) if response.status_code == 302: return response elif response.status_code == 401: raise RuntimeError('Not authorized (%s)' % response.text) elif response.status_code == 403: raise RuntimeError('Forbidden (%s)' % response.text) else: raise RuntimeError('Unexpected response %d from authorization server (%s)' % (response.status_code, response.text)) def create_access_token(self, location): return AccessToken(**self.endpoint.parse_request_uri_response(location)) def view_with_access_token(self, workflow_name, access_token): response = requests.get(self.url_for_workflow(workflow_name), params=access_token.as_query_params, verify=False) if response.status_code == 200: return response elif response.status_code == 403: raise RuntimeError('Forbidden (%s)' % response.text) elif response.status_code == 404: raise RuntimeError('Not found (%s)' % response.text) else: raise RuntimeError('Unexpected response %d from resource server (%s)' % (response.status_code, response.text)) def get_access_token_for_view_workflow(self, workflow_name): initial_view_response = self.view_without_access_token(workflow_name) oauth_url, required_scope = self.extract_auth_headers(initial_view_response) authorize_response = self.authorize(oauth_url=oauth_url, redirect_uri=self.url_for_workflow(workflow_name), required_scope=required_scope) return self.create_access_token(authorize_response.headers['Location']) def view_workflow(self, workflow_name, access_token=None): if access_token is None: access_token = self.get_access_token_for_view_workflow(workflow_name) view_response = self.view_with_access_token(workflow_name, access_token) return view_response.text