def do_fetch(): # client_secret is not really a secret in that case. So an attacker can # impersonate service's identity in OAuth2 flow. But that's generally # fine as long as a list of allowed redirect_uri's associated with client_id # is limited to 'localhost' or 'urn:ietf:wg:oauth:2.0:oob'. In that case # attacker needs some process running on user's machine to successfully # complete the flow and grab access_token. When you have malicious code # running on your machine you're screwed anyway. response = requests.get( '%s/auth/api/v1/server/oauth_config' % urlhost.rstrip('/'), verify=tools.get_cacerts_bundle()) if response.status_code == 200: try: config = response.json() if not isinstance(config, dict): raise ValueError() return _ServiceConfig( config['client_id'], config['client_not_so_secret'], config.get('primary_url')) except (KeyError, ValueError) as err: logging.error('Invalid response from the service: %s', err) else: logging.warning( 'Error when fetching oauth_config, HTTP status code %d', response.status_code) return None
def test_http_level_errors(self): def token_gen(_account_id, _scopes): self.fail('must not be called') with local_auth_server(token_gen, 'acc_1'): # Wrong URL. ctx = luci_context.read('local_auth') r = requests.post( url= 'http://127.0.0.1:%d/blah/LuciLocalAuthService.GetOAuthToken' % ctx['rpc_port'], data=json.dumps({ 'account_id': 'acc_1', 'scopes': ['A', 'B', 'C'], 'secret': ctx['secret'], }), headers={'Content-Type': 'application/json'}) self.assertEqual(404, r.status_code) # Wrong HTTP method. r = requests.get( url='http://127.0.0.1:%d/rpc/LuciLocalAuthService.GetOAuthToken' % ctx['rpc_port'], data=json.dumps({ 'account_id': 'acc_1', 'scopes': ['A', 'B', 'C'], 'secret': ctx['secret'], }), headers={'Content-Type': 'application/json'}) self.assertEqual(501, r.status_code) # Wrong content type. r = requests.post( url='http://127.0.0.1:%d/rpc/LuciLocalAuthService.GetOAuthToken' % ctx['rpc_port'], data=json.dumps({ 'account_id': 'acc_1', 'scopes': ['A', 'B', 'C'], 'secret': ctx['secret'], }), headers={'Content-Type': 'application/xml'}) self.assertEqual(400, r.status_code) # Bad JSON. r = requests.post( url='http://127.0.0.1:%d/rpc/LuciLocalAuthService.GetOAuthToken' % ctx['rpc_port'], data='not a json', headers={'Content-Type': 'application/json'}) self.assertEqual(400, r.status_code)
def _fetch_oauth_client_id(urlhost): """Ask service to for client_id and client_secret to use.""" # client_secret is not really a secret in that case. So an attacker can # impersonate service's identity in OAuth2 flow. But that's generally # fine as long as a list of allowed redirect_uri's associated with client_id # is limited to 'localhost' or 'urn:ietf:wg:oauth:2.0:oob'. In that case # attacker needs some process running on user's machine to successfully # complete the flow and grab access_token. When you have malicious code # running on your machine your screwed anyway. response = requests.get("%s/auth/api/v1/server/oauth_config" % urlhost.rstrip("/")) if response.status_code == 200: try: config = response.json() if not isinstance(config, dict): raise ValueError() return config["client_id"], config["client_not_so_secret"] except (KeyError, ValueError) as err: logging.error("Invalid response from the service: %s", err) else: logging.error("Error when fetching oauth_config, HTTP status code %d", response.status_code) return None, None