Query Result API response shouldn't include query information for non authenticated users (#3985)

* avoid catching errors on text widgets' load(), as they don't have a visualization and therefore do not return any promise

* throw error when failing to load widgets on public dashboards - in case something needs to be done with it at a later time, and it's the right thing to do anyway

* use Promise.resolve instead of checking for undefined

* call serialize_query_result instead of directly calling to_dict

* filter unneeded query result fields for unauthenticated users

* test for serialization filtering

* lint

* use project instead of list comprehension
This commit is contained in:
Omer Lachish
2019-07-18 12:12:49 +03:00
committed by Arik Fraimovich
parent 4989bfae60
commit d1edd3d068
4 changed files with 26 additions and 5 deletions

View File

@@ -12,7 +12,7 @@ from redash.tasks import QueryTask
from redash.tasks.queries import enqueue_query
from redash.utils import (collect_parameters_from_request, gen_query_hash, json_dumps, utcnow, to_filename)
from redash.models.parameterized_query import ParameterizedQuery, InvalidParameterError, dropdown_values
from redash.serializers import serialize_query_result_to_csv, serialize_query_result_to_xlsx
from redash.serializers import serialize_query_result, serialize_query_result_to_csv, serialize_query_result_to_xlsx
def error_response(message):
@@ -42,7 +42,7 @@ def run_query(query, parameters, data_source, query_id, max_age=0):
query_result = models.QueryResult.get_latest(data_source, query.text, max_age)
if query_result:
return {'query_result': query_result.to_dict()}
return {'query_result': serialize_query_result(query_result, current_user.is_api_user())}
else:
job = enqueue_query(query.text, data_source, current_user.id, current_user.is_api_user(), metadata={
"Username": repr(current_user) if current_user.is_api_user() else current_user.email,

View File

@@ -12,7 +12,7 @@ from redash.permissions import has_access, view_only
from redash.utils import json_loads
from redash.models.parameterized_query import ParameterizedQuery
from .query_result import serialize_query_result_to_csv, serialize_query_result_to_xlsx
from .query_result import serialize_query_result, serialize_query_result_to_csv, serialize_query_result_to_xlsx
def public_widget(widget):

View File

@@ -1,7 +1,7 @@
import cStringIO
import csv
import xlsxwriter
from funcy import rpartial
from funcy import rpartial, project
from dateutil.parser import isoparse as parse_date
from redash.utils import json_loads, UnicodeWriter
from redash.query_runner import (TYPE_BOOLEAN, TYPE_DATE, TYPE_DATETIME)
@@ -57,6 +57,14 @@ def _get_column_lists(columns):
return fieldnames, special_columns
def serialize_query_result(query_result, is_api_user):
if is_api_user:
publicly_needed_keys = ['data', 'retrieved_at']
return project(query_result.to_dict(), publicly_needed_keys)
else:
return query_result.to_dict()
def serialize_query_result_to_csv(query_result):
s = cStringIO.StringIO()

View File

@@ -6,7 +6,7 @@ from tests import BaseTestCase
from redash import models
from redash.utils import utcnow, json_dumps
from redash.serializers import serialize_query_result_to_csv
from redash.serializers import serialize_query_result, serialize_query_result_to_csv
data = {
@@ -24,6 +24,19 @@ data = {
]
}
class QueryResultSerializationTest(BaseTestCase):
def test_serializes_all_keys_for_authenticated_users(self):
query_result = self.factory.create_query_result(data=json_dumps({}))
serialized = serialize_query_result(query_result, False)
self.assertSetEqual(set(query_result.to_dict().keys()),
set(serialized.keys()))
def test_doesnt_serialize_sensitive_keys_for_unauthenticated_users(self):
query_result = self.factory.create_query_result(data=json_dumps({}))
serialized = serialize_query_result(query_result, True)
self.assertSetEqual(set(['data', 'retrieved_at']),
set(serialized.keys()))
class CsvSerializationTest(BaseTestCase):
def get_csv_content(self):
query_result = self.factory.create_query_result(data=json_dumps(data))