lziosi commented on issue #16398: URL: https://github.com/apache/superset/issues/16398#issuecomment-1184678574
In case this helps anyone else, the problem with the above code is that the CSRF token must be obtained in the same session as where it is used, because there is a session cookie added by the call that creates the CSRF token. This became evident after reading: https://github.com/wtforms/flask-wtf/blob/4b90067908f0ab42bf25f4bc580a4367e09e27dd/src/flask_wtf/csrf.py#L66 However, after fixing that, I got the new error: `400 Bad Request: The referrer header is missing.` The fix for this second error must take into account the fact that Referrer header should be misspelled as Referer: https://flask.palletsprojects.com/en/2.1.x/api/#flask.Request.referrer In the end this code worked fine: ``` import requests import json import os BASE_URL = os.getenv("BASE_URL") USERNAME = os.getenv("USERNAME") PASSWORD = os.getenv('PASSWORD') SUPERSET_DB_NAME = os.getenv('SUPERSET_DB_NAME') DB_NAME = os.getenv('DB_NAME') DB_PORT = os.getenv('DB_PORT') DB_HOST = os.getenv('DB_HOST') DB_USER = os.getenv('DB_USER') DB_PASSWORD = os.getenv('DB_PASSWORD') # https://levelup.gitconnected.com/solve-the-dreadful-certificate-issues-in-python-requests-module-2020d922c72f # The CA_BUNDLE variable contains the absolute path of a file that has the root-ca, intermediate-ca and site-cert # The 3 certs can be exported by Google Chrome as individual Base 64 encoded CER files # Then manually chained into a single file # When working in a test environment, you can set CA_BUNDLE to False CA_BUNDLE=False def login(base_url, username, password): url = base_url + 'api/v1/security/login' payload = {'password': password, 'provider': 'ldap', 'refresh': 'true', 'username': username} payload_json = json.dumps(payload) headers = {'Content-Type': 'application/json'} try: res = requests.post(url, data=payload_json, verify=CA_BUNDLE, headers=headers) res.raise_for_status() access_token = res.json()['access_token'] refresh_token = res.json()['refresh_token'] return access_token, refresh_token except requests.exceptions.RequestException as err: print("Request Exception:", err) except requests.exceptions.HTTPError as errh: print("Http Error:", errh) except requests.exceptions.ConnectionError as errc: print("Error Connecting:", errc) except requests.exceptions.Timeout as errt: print("Timeout Error:", errt) def create_database(base_url, access_token, superset_database_name, database_name, database_port, database_host, database_user, database_password): csrf_url = base_url + 'api/v1/security/csrf_token' # Construct the Authorization header of the form Bearer access_token headers = {'Authorization': 'Bearer ' + access_token} url = base_url + 'api/v1/database' payload = { "database_name": superset_database_name, "engine": "postgresql", "configuration_method": "sqlalchemy_form", "sqlalchemy_uri": "postgresql+psycopg2://{}:{}@{}:{}/{}".\ format(database_user, database_password, database_host, database_port, database_name) } payload_json = json.dumps(payload) try: session = requests.Session() session.headers['Authorization'] = 'Bearer ' + access_token session.headers['Content-Type'] = 'application/json' # Note: it is mandatory that the csrf token be obtained in the same session where it will be used csrf_res = session.get(csrf_url, verify=CA_BUNDLE) # Note that Referrer must be misspelled as Referer, see: # https://flask.palletsprojects.com/en/2.1.x/api/#flask.Request.referrer # The Referer[sic] request - header field allows the client to specify, # for the server’s benefit, the address (URI) of the resource from which the Request-URI was obtained # (the “referrer”, although the header field is misspelled). session.headers['Referer']= csrf_url session.headers['X-CSRFToken'] = csrf_res.json()['result'] res = session.post(url, data=payload_json, verify=CA_BUNDLE) res.raise_for_status() except requests.exceptions.RequestException as err: print("Request Exception:", err) except requests.exceptions.HTTPError as errh: print("Http Error:", errh) except requests.exceptions.ConnectionError as errc: print("Error Connecting:", errc) except requests.exceptions.Timeout as errt: print("Timeout Error:", errt) if __name__ == '__main__': access_token, refresh_token = login(BASE_URL, USERNAME, PASSWORD) create_database(BASE_URL, access_token, SUPERSET_DB_NAME, DB_NAME, DB_PORT, DB_HOST, DB_USER, DB_PASSWORD) ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
