Skip to content

Commit

Permalink
Check datasource level perms for downloading csv and fetching results
Browse files Browse the repository at this point in the history
  • Loading branch information
Bogdan Kyryliuk committed Jan 24, 2017
1 parent 2f27353 commit 6e5eed8
Showing 1 changed file with 37 additions and 32 deletions.
69 changes: 37 additions & 32 deletions superset/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,24 @@ def datasource_access_by_name(
return True
return False

def datasource_access_by_fullname(
self, database, full_table_name, schema):
table_name_pieces = full_table_name.split(".")
if len(table_name_pieces) == 2:
table_schema = table_name_pieces[0]
table_name = table_name_pieces[1]
else:
table_schema = schema
table_name = table_name_pieces[0]
return self.datasource_access_by_name(
database, table_name, schema=table_schema)

def rejected_datasources(self, sql, database, schema):
superset_query = sql_parse.SupersetQuery(sql)
return [
t for t in superset_query.tables if not
self.datasource_access_by_fullname(database, t, schema)]


class ListWidgetWithCheckboxes(ListWidget):
"""An alternative to list view that renders Boolean fields as checkboxes
Expand Down Expand Up @@ -2405,18 +2423,19 @@ def results(self, key):

blob = results_backend.get(key)
if blob:
json_payload = zlib.decompress(blob)
obj = json.loads(json_payload)
db_id = obj['query']['dbId']
session = db.session()
mydb = session.query(models.Database).filter_by(id=db_id).one()

if not self.database_access(mydb):
return json_error_response(
get_database_access_error_msg(mydb.database_name))
query = (
db.session.query(models.Query)
.filter_by(results_key=key)
.one()
)
rejected_tables = self.rejected_datasources(
query.sql, query.database, query.schema)
if rejected_tables:
return json_error_response(get_datasource_access_error_msg(
'{}'.format(rejected_tables)))

return Response(
json_payload,
zlib.decompress(blob),
status=200,
mimetype="application/json")
else:
Expand All @@ -2435,20 +2454,10 @@ def results(self, key):
@log_this
def sql_json(self):
"""Runs arbitrary sql and returns and json"""
def table_accessible(database, full_table_name, schema_name=None):
table_name_pieces = full_table_name.split(".")
if len(table_name_pieces) == 2:
table_schema = table_name_pieces[0]
table_name = table_name_pieces[1]
else:
table_schema = schema_name
table_name = table_name_pieces[0]
return self.datasource_access_by_name(
database, table_name, schema=table_schema)

async = request.form.get('runAsync') == 'true'
sql = request.form.get('sql')
database_id = request.form.get('database_id')
schema = request.form.get('schema') or None

session = db.session()
mydb = session.query(models.Database).filter_by(id=database_id).one()
Expand All @@ -2457,16 +2466,10 @@ def table_accessible(database, full_table_name, schema_name=None):
json_error_response(
'Database with id {} is missing.'.format(database_id))

superset_query = sql_parse.SupersetQuery(sql)
schema = request.form.get('schema')
schema = schema if schema else None

rejected_tables = [
t for t in superset_query.tables if not
table_accessible(mydb, t, schema_name=schema)]
rejected_tables = self.rejected_datasources(sql, mydb, schema)
if rejected_tables:
return json_error_response(
get_datasource_access_error_msg('{}'.format(rejected_tables)))
return json_error_response(get_datasource_access_error_msg(
'{}'.format(rejected_tables)))
session.commit()

select_as_cta = request.form.get('select_as_cta') == 'true'
Expand Down Expand Up @@ -2541,8 +2544,10 @@ def csv(self, client_id):
.one()
)

if not self.database_access(query.database):
flash(get_database_access_error_msg(query.database.database_name))
rejected_tables = self.rejected_datasources(
query.sql, query.database, query.schema)
if rejected_tables:
flash(get_datasource_access_error_msg('{}'.format(rejected_tables)))
return redirect('/')

sql = query.select_sql or query.sql
Expand Down

0 comments on commit 6e5eed8

Please sign in to comment.