Skip to content

Commit

Permalink
add server-side parameter handling for embeds
Browse files Browse the repository at this point in the history
  • Loading branch information
whummer committed May 3, 2016
1 parent d602127 commit e88ba01
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
41 changes: 39 additions & 2 deletions handlers/embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,35 @@

from redash import models, settings
from redash import serializers
from redash.utils import json_dumps
from redash.utils import json_dumps, collect_parameters_from_request
from redash.handlers import routes
from redash.handlers.base import org_scoped_rule, record_event
from redash.permissions import require_access, view_only
from authentication import current_org

#
# Run a parameterized query synchronously and return the result
# DISCLAIMER: Temporary solution to support parameters in queries. Should be
# removed once we refactor the query results API endpoints and handling
# on the client side. Please don't reuse in other API handlers.
#
def run_query_sync(data_source, parameter_values, query_text):
query_parameters = set(collect_query_parameters(query_text))
missing_params = set(query_parameters) - set(parameter_values.keys())
if missing_params:
raise Exception('Missing parameter value for: {}'.format(", ".join(missing_params)))

if query_parameters:
query_text = pystache.render(query_text, parameter_values)

try:
data, error = data_source.query_runner.run_query(query_text)
if error:
return None
return data
except Exception, e:
return None


@routes.route(org_scoped_rule('/embed/query/<query_id>/visualization/<visualization_id>'), methods=['GET'])
@login_required
Expand All @@ -22,10 +45,23 @@ def embed(query_id, visualization_id, org_slug=None):
vis = query.visualizations.where(models.Visualization.id == visualization_id).first()
qr = {}

parameter_values = collect_parameters_from_request(request.args)

if vis is not None:
vis = vis.to_dict()
qr = query.latest_query_data
if qr is None:
if settings.ALLOW_PARAMETERS_IN_EMBEDS == True and len(parameter_values) > 0:
# run parameterized query
#
# WARNING: Note that the external query parameters
# are a potential risk of SQL injections.
#
results = run_query_sync(query.data_source, parameter_values, query.query)
if results is None:
abort(400, message="Unable to get results for this query")
else:
qr = {"data": json.loads(results)}
elif qr is None:
abort(400, message="No Results for this query")
else:
qr = qr.to_dict()
Expand Down Expand Up @@ -54,6 +90,7 @@ def embed(query_id, visualization_id, org_slug=None):
query_result=json_dumps(qr))



@routes.route(org_scoped_rule('/public/dashboards/<token>'), methods=['GET'])
@login_required
def public_dashboard(token, org_slug=None):
Expand Down
4 changes: 4 additions & 0 deletions settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ def all_settings():
# Enhance schema fetching
SCHEMA_RUN_TABLE_SIZE_CALCULATIONS = parse_boolean(os.environ.get("REDASH_SCHEMA_RUN_TABLE_SIZE_CALCULATIONS", "false"))

# Allow Parameters in Embeds
# WARNING: With this option enabled, Redash reads query parameters from the request URL (risk of SQL injection!)
ALLOW_PARAMETERS_IN_EMBEDS = parse_boolean(os.environ.get("REDASH_ALLOW_PARAMETERS_IN_EMBEDS", "false"))

### Common Client config
COMMON_CLIENT_CONFIG = {
'allowScriptsInUserInput': ALLOW_SCRIPTS_IN_USER_INPUT,
Expand Down

0 comments on commit e88ba01

Please sign in to comment.