redash/tests/handlers/test_embed.py
Omer Lachish dd477d49ec
Sharing embeds with safe parameters (#3495)
* change has_access and require_access signatures to work with the objects that require access, instead of their groups

* change has_access and require_access signatures to work with the objects that require access, instead of their groups

* use the textless endpoint (/api/queries/:id/results) for pristine
queriest

* Revert "use the textless endpoint (/api/queries/:id/results) for pristine"

This reverts commit cd2cee77385ecf79efd2f1aa21fab0dd43943264.

* go to textless /api/queries/:id/results by default

* change `run_query`'s signature to accept a ParameterizedQuery instead of
constructing it inside

* raise HTTP 400 when receiving invalid parameter values. Fixes #3394

* support querystring params

* extract coercing of numbers to function, along with a friendlier
implementation

* wire embeds to textless endpoint

* allow users with view_only permissions to execute queries on the
textless endpoint, as it only allows safe queries to run

* enqueue jobs for ApiUsers

* add parameters component for embeds

* include existing parameters in embed code

* fetch correct values for json requests

* remove previous embed parameter code

* rename `id` to `user_id`

* support executing queries using Query api_keys by instantiating an ApiUser that would be able to execute the specific query

* bring back ALLOW_PARAMETERS_IN_EMBEDS (with link on deprecation coming up)

* show deprecation messages for ALLOW_PARAMETERS_IN_EMBEDS. Also, move
other message (email not verified) to use the same mechanism

* add link to forum message on setting deprecation

* rephrase deprecation message

* add link to forum message regarding embed deprecation

* change API to /api/queries/:id/dropdowns/:dropdown_id

* split to 2 different dropdown endpoints and implement the second

* add test cases for /api/queries/:id/dropdowns/:id

* use new /dropdowns endpoint in frontend

* first e2e test for sharing embeds

* Pleasing the CodeClimate overlords

* All glory to CodeClimate

* change has_access and require_access signatures to work with the objects that require access, instead of their groups

* split has_access between normal users and ApiKey users

* remove residues from bad rebase

* allow access to safe queries via api keys

* rename `object` to `obj`

* support both objects and group dicts in `has_access` and `require_access`

* simplify permission tests once `has_access` accepts groups

* change has_access and require_access signatures to work with the objects that require access, instead of their groups

* rename `object` to `obj`

* support both objects and group dicts in `has_access` and `require_access`

* simplify permission tests once `has_access` accepts groups

* fix bad rebase

* send embed parameters through POST data

* no need to log `is_api_key`

* move query fetching by api_key to within the Query model

* fetch user by adding a get_by_id function on the User model

* pass parameters as POST data (fixes test failure introduced by switching
from query string parameters to POST data)

* test the right thing - queries with safe parameters should be embeddable

* introduce cy.clickThrough

* add another Cypress test to make sure unsafe queries cannot be embedded

* serialize Parameters into query string

* set is_api_key as the last parameter to (hopefully) avoid
backward-dependency problems

* Update redash/models/parameterized_query.py

Co-Authored-By: rauchy <omer@rauchy.net>

* attempt to fix empty percy snapshots

* snap percies after DOM is fully loaded
2019-04-02 11:45:38 +03:00

91 lines
4.0 KiB
Python

from tests import BaseTestCase
from redash.models import db
class TestUnembedables(BaseTestCase):
def test_not_embedable(self):
query = self.factory.create_query()
res = self.make_request('get', '/api/queries/{0}'.format(query.id))
self.assertEquals(res.status_code, 200)
self.assertIn("frame-ancestors 'none'", res.headers['Content-Security-Policy'])
self.assertEqual(res.headers['X-Frame-Options'], 'deny')
class TestEmbedVisualization(BaseTestCase):
def test_sucesss(self):
vis = self.factory.create_visualization()
vis.query_rel.latest_query_data = self.factory.create_query_result()
db.session.add(vis.query_rel)
res = self.make_request("get", "/embed/query/{}/visualization/{}".format(vis.query_rel.id, vis.id), is_json=False)
self.assertEqual(res.status_code, 200)
self.assertIn('frame-ancestors *', res.headers['Content-Security-Policy'])
self.assertNotIn("X-Frame-Options", res.headers)
# TODO: this should be applied to the new API endpoint
class TestPublicDashboard(BaseTestCase):
def test_success(self):
dashboard = self.factory.create_dashboard()
api_key = self.factory.create_api_key(object=dashboard)
res = self.make_request('get', '/public/dashboards/{}'.format(api_key.api_key), user=False, is_json=False)
self.assertEqual(res.status_code, 200)
self.assertIn('frame-ancestors *', res.headers['Content-Security-Policy'])
self.assertNotIn("X-Frame-Options", res.headers)
def test_works_for_logged_in_user(self):
dashboard = self.factory.create_dashboard()
api_key = self.factory.create_api_key(object=dashboard)
res = self.make_request('get', '/public/dashboards/{}'.format(api_key.api_key), is_json=False)
self.assertEqual(res.status_code, 200)
def test_bad_token(self):
res = self.make_request('get', '/public/dashboards/bad-token', user=False, is_json=False)
self.assertEqual(res.status_code, 302)
def test_inactive_token(self):
dashboard = self.factory.create_dashboard()
api_key = self.factory.create_api_key(object=dashboard, active=False)
res = self.make_request('get', '/public/dashboards/{}'.format(api_key.api_key), user=False, is_json=False)
self.assertEqual(res.status_code, 302)
# Not relevant for now, as tokens in api_keys table are only created for dashboards. Once this changes, we should
# add this test.
# def test_token_doesnt_belong_to_dashboard(self):
# pass
class TestAPIPublicDashboard(BaseTestCase):
def test_success(self):
dashboard = self.factory.create_dashboard()
api_key = self.factory.create_api_key(object=dashboard)
res = self.make_request('get', '/api/dashboards/public/{}'.format(api_key.api_key), user=False, is_json=False)
self.assertEqual(res.status_code, 200)
self.assertIn('frame-ancestors *', res.headers['Content-Security-Policy'])
self.assertNotIn("X-Frame-Options", res.headers)
def test_works_for_logged_in_user(self):
dashboard = self.factory.create_dashboard()
api_key = self.factory.create_api_key(object=dashboard)
res = self.make_request('get', '/api/dashboards/public/{}'.format(api_key.api_key), is_json=False)
self.assertEqual(res.status_code, 200)
def test_bad_token(self):
res = self.make_request('get', '/api/dashboards/public/bad-token', user=False, is_json=False)
self.assertEqual(res.status_code, 404)
def test_inactive_token(self):
dashboard = self.factory.create_dashboard()
api_key = self.factory.create_api_key(object=dashboard, active=False)
res = self.make_request('get', '/api/dashboards/public/{}'.format(api_key.api_key), user=False, is_json=False)
self.assertEqual(res.status_code, 404)
# Not relevant for now, as tokens in api_keys table are only created for dashboards. Once this changes, we should
# add this test.
# def test_token_doesnt_belong_to_dashboard(self):
# pass