Search code examples
flaskcsrfapache-superset

cannot post a new DB to apache-superset, 400 Error with CSRF


I am unsure how I can set the CSRF token so apache superset is happy.. here is my code

Create a DB Connection for Apache Superset

import requests
import json

base_url = "http://SOMEIP:8088/"

login_url = base_url + "api/v1/security/login"
csrf_url = base_url + "api/v1/security/csrf_token"


def create_db_connection(session, db_ip, db_port, db_user, db_pass, db_name):

    url = base_url + "api/v1/database/"

    sqlalchemy_url = "postgresql://" + db_user + ":" + db_pass + "@" + db_ip + ":" + str(db_port)+"/" + db_name

    data_out = {
      "allow_csv_upload": True,
      "allow_ctas": True,
      "allow_cvas": True,
      "allow_dml": True,
      "allow_multi_schema_metadata_fetch": True,
      "allow_run_async": True,
      "cache_timeout": 0,
      "database_name": db_name,
      "expose_in_sqllab": True,
      "impersonate_user": True,
      "sqlalchemy_uri": sqlalchemy_url
    }

    response = session.post(url=url, headers=dict(Referrer=login_url), json=data_out)
    response.raise_for_status()

    return response


if __name__ == "__main__":

    username = "mysupersetuser"
    password = "mysupersetpass"

    db_user = "MYUSER"
    db_password = "MYDBPASS"
    db_host = "MYPOSTGRESIP"
    db_port = 5432
    db_name = "MYDBNAME"

    session = requests.session()

    login_url = base_url + "api/v1/security/login"

    login_data = {
      "password": password,
      "provider": "db",
      "refresh": False,
      "username": username
    }

    response = session.post(url=login_url, json=login_data)
    response.raise_for_status()

    head = {
        "Authorization": "Bearer " + json.loads(response.text)['access_token']
    }

    response = session.get(csrf_url, headers=head)
    response.raise_for_status()

    response = create_db_connection(session, db_ip=db_host, db_port=db_port, db_user=db_user, db_pass=db_password, db_name=db_name)

    print(str(response.text))

I see multiple ways people are stating to set the CSRF token.. but none have worked so far.

Always it's the same response 400

'{"errors": [{"message": "400 Bad Request: The CSRF token is missing.", "error_type": "GENERIC_BACKEND_ERROR", "level": "error", "extra": {"issue_codes": [{"code": 1011, "message": "Issue 1011 - Superset encountered an unexpected error."}]}}]}'

Solution

  • It looks like Apache-Superset uses Flask-AppBuilder which uses Flask_WTF. You should be able to set it in the request headers.

    def create_db_connection(session, db_ip, db_port, db_user, db_pass, db_name, token_from_your_crsf_url):
    
        headers = {
            'Referrer': login_url,
            'X-CSRFToken': token_from_your_crsf_url
        }
        ...
        response = session.post(url=url, headers=headers, json=data_out)
        ...