mirror of
https://github.com/valitydev/redash.git
synced 2024-11-07 01:25:16 +00:00
Return unsafe sharing error from backend (#3990)
* return message explaining unsafe sharing * use backend-generated message for public dashboards * use backend-generated message for embeds * Update redash/handlers/query_results.py Co-Authored-By: Arik Fraimovich <arik@arikfr.com> * refactor simple (non-interpolated) query result handler error messages to a single location * use error_messages to test out unsafe error messages (along with a couple of others) * Update redash/handlers/query_results.py Co-Authored-By: Ran Byron <ranbena@gmail.com> * Update redash/handlers/query_results.py Co-Authored-By: Arik Fraimovich <arik@arikfr.com>
This commit is contained in:
parent
9bdb3412a5
commit
ea0e411053
@ -39,11 +39,7 @@ const VisualizationEmbed = {
|
||||
|
||||
document.querySelector('body').classList.add('headless');
|
||||
|
||||
if (this.query.is_safe) {
|
||||
this.refreshQueryResults();
|
||||
} else {
|
||||
this.error = "Can't embed queries with text parameters.";
|
||||
}
|
||||
this.refreshQueryResults();
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -38,16 +38,7 @@ const PublicDashboardPage = {
|
||||
loadDashboard($http, $route).then((data) => {
|
||||
this.dashboard = new Dashboard(data);
|
||||
this.dashboard.widgets = Dashboard.prepareDashboardWidgets(this.dashboard.widgets);
|
||||
this.dashboard.widgets.forEach((widget) => {
|
||||
widget.load(!!refreshRate).catch((error) => {
|
||||
const isSafe = widget.getQuery() ? widget.getQuery().is_safe : true;
|
||||
if (!isSafe) {
|
||||
error.errorMessage = 'This query contains potentially unsafe parameters and cannot be executed on a publicly shared dashboard.';
|
||||
}
|
||||
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
this.dashboard.widgets.forEach(widget => widget.load(!!refreshRate));
|
||||
this.filters = []; // TODO: implement (@/services/dashboard.js:collectDashboardFilters)
|
||||
this.filtersOnChange = (allFilters) => {
|
||||
this.filters = allFilters;
|
||||
|
@ -15,8 +15,16 @@ from redash.models.parameterized_query import ParameterizedQuery, InvalidParamet
|
||||
from redash.serializers import serialize_query_result, serialize_query_result_to_csv, serialize_query_result_to_xlsx
|
||||
|
||||
|
||||
def error_response(message):
|
||||
return {'job': {'status': 4, 'error': message}}, 400
|
||||
def error_response(message, http_status=400):
|
||||
return {'job': {'status': 4, 'error': message}}, http_status
|
||||
|
||||
|
||||
error_messages = {
|
||||
'unsafe_when_shared': error_response('This query contains potentially unsafe parameters and cannot be executed on a shared dashboard or an embedded visualization.', 403),
|
||||
'unsafe_on_view_only': error_response('This query contains potentially unsafe parameters and cannot be executed with read-only access to this data source.', 403),
|
||||
'no_permission': error_response('You do not have permission to run queries with this data source.', 403),
|
||||
'select_data_source': error_response('Please select data source to run this query.', 401)
|
||||
}
|
||||
|
||||
|
||||
def run_query(query, parameters, data_source, query_id, max_age=0):
|
||||
@ -92,10 +100,10 @@ class QueryResultListResource(BaseResource):
|
||||
if data_source_id:
|
||||
data_source = models.DataSource.get_by_id_and_org(params.get('data_source_id'), self.current_org)
|
||||
else:
|
||||
return {'job': {'status': 4, 'error': 'Please select data source to run this query.'}}, 401
|
||||
return error_messages['select_data_source']
|
||||
|
||||
if not has_access(data_source, self.current_user, not_view_only):
|
||||
return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403
|
||||
return error_messages['no_permission']
|
||||
|
||||
self.record_event({
|
||||
'action': 'execute_query',
|
||||
@ -182,7 +190,13 @@ class QueryResultResource(BaseResource):
|
||||
if has_access(query, self.current_user, allow_executing_with_view_only_permissions):
|
||||
return run_query(query.parameterized, parameter_values, query.data_source, query_id, max_age)
|
||||
else:
|
||||
return {'job': {'status': 4, 'error': 'You do not have permission to run queries with this data source.'}}, 403
|
||||
if not query.parameterized.is_safe:
|
||||
if current_user.is_api_user():
|
||||
return error_messages['unsafe_when_shared']
|
||||
else:
|
||||
return error_messages['unsafe_on_view_only']
|
||||
else:
|
||||
return error_messages['no_permission']
|
||||
|
||||
@require_permission('view_query')
|
||||
def get(self, query_id=None, query_result_id=None, filetype='json'):
|
||||
|
@ -2,6 +2,7 @@ from tests import BaseTestCase
|
||||
|
||||
from redash.models import db
|
||||
from redash.utils import json_dumps
|
||||
from redash.handlers.query_results import error_messages
|
||||
|
||||
|
||||
class TestQueryResultsCacheHeaders(BaseTestCase):
|
||||
@ -111,8 +112,7 @@ class TestQueryResultListAPI(BaseTestCase):
|
||||
'max_age': 0})
|
||||
|
||||
self.assertEquals(rv.status_code, 401)
|
||||
self.assertNotIn('query_result', rv.json)
|
||||
self.assertIn('job', rv.json)
|
||||
self.assertDictEqual(rv.json, error_messages['select_data_source'][0])
|
||||
|
||||
|
||||
class TestQueryResultAPI(BaseTestCase):
|
||||
@ -145,6 +145,14 @@ class TestQueryResultAPI(BaseTestCase):
|
||||
self.assertEquals(rv.status_code, 200)
|
||||
self.assertIn('job', rv.json)
|
||||
|
||||
def test_execute_but_has_no_access_to_data_source(self):
|
||||
ds = self.factory.create_data_source(group=self.factory.create_group())
|
||||
query = self.factory.create_query(data_source=ds)
|
||||
|
||||
rv = self.make_request('post', '/api/queries/{}/results'.format(query.id))
|
||||
self.assertEquals(rv.status_code, 403)
|
||||
self.assertDictEqual(rv.json, error_messages['no_permission'][0])
|
||||
|
||||
def test_execute_with_no_parameter_values(self):
|
||||
query = self.factory.create_query()
|
||||
|
||||
@ -159,6 +167,7 @@ class TestQueryResultAPI(BaseTestCase):
|
||||
|
||||
rv = self.make_request('post', '/api/queries/{}/results'.format(query.id), data={"parameters": {}})
|
||||
self.assertEquals(rv.status_code, 403)
|
||||
self.assertDictEqual(rv.json, error_messages['unsafe_on_view_only'][0])
|
||||
|
||||
def test_allows_execution_of_safe_queries_on_view_only_data_sources(self):
|
||||
ds = self.factory.create_data_source(group=self.factory.org.default_group, view_only=True)
|
||||
@ -174,6 +183,7 @@ class TestQueryResultAPI(BaseTestCase):
|
||||
data = {'parameters': {'foo': 'bar'}}
|
||||
rv = self.make_request('post', '/api/queries/{}/results?api_key={}'.format(query.id, query.api_key), data=data)
|
||||
self.assertEquals(rv.status_code, 403)
|
||||
self.assertDictEqual(rv.json, error_messages['unsafe_when_shared'][0])
|
||||
|
||||
def test_access_with_query_api_key(self):
|
||||
ds = self.factory.create_data_source(group=self.factory.org.default_group, view_only=False)
|
||||
|
Loading…
Reference in New Issue
Block a user