security_tests.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. # Licensed to the Apache Software Foundation (ASF) under one
  2. # or more contributor license agreements. See the NOTICE file
  3. # distributed with this work for additional information
  4. # regarding copyright ownership. The ASF licenses this file
  5. # to you under the Apache License, Version 2.0 (the
  6. # "License"); you may not use this file except in compliance
  7. # with the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing,
  12. # software distributed under the License is distributed on an
  13. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. # KIND, either express or implied. See the License for the
  15. # specific language governing permissions and limitations
  16. # under the License.
  17. # isort:skip_file
  18. import inspect
  19. import unittest
  20. from unittest.mock import Mock, patch
  21. import prison
  22. import tests.test_app
  23. from superset import app, appbuilder, db, security_manager, viz
  24. from superset.connectors.druid.models import DruidCluster, DruidDatasource
  25. from superset.connectors.sqla.models import SqlaTable
  26. from superset.exceptions import SupersetSecurityException
  27. from superset.models.core import Database
  28. from superset.models.slice import Slice
  29. from superset.utils.core import get_example_database
  30. from .base_tests import SupersetTestCase
  31. def get_perm_tuples(role_name):
  32. perm_set = set()
  33. for perm in security_manager.find_role(role_name).permissions:
  34. perm_set.add((perm.permission.name, perm.view_menu.name))
  35. return perm_set
  36. SCHEMA_ACCESS_ROLE = "schema_access_role"
  37. def create_schema_perm(view_menu_name: str) -> None:
  38. permission = "schema_access"
  39. security_manager.add_permission_view_menu(permission, view_menu_name)
  40. perm_view = security_manager.find_permission_view_menu(permission, view_menu_name)
  41. security_manager.add_permission_role(
  42. security_manager.find_role(SCHEMA_ACCESS_ROLE), perm_view
  43. )
  44. return None
  45. def delete_schema_perm(view_menu_name: str) -> None:
  46. pv = security_manager.find_permission_view_menu("schema_access", "[examples].[2]")
  47. security_manager.del_permission_role(
  48. security_manager.find_role(SCHEMA_ACCESS_ROLE), pv
  49. )
  50. security_manager.del_permission_view_menu("schema_access", "[examples].[2]")
  51. return None
  52. class RolePermissionTests(SupersetTestCase):
  53. """Testing export role permissions."""
  54. def setUp(self):
  55. session = db.session
  56. security_manager.add_role(SCHEMA_ACCESS_ROLE)
  57. session.commit()
  58. ds = (
  59. db.session.query(SqlaTable)
  60. .filter_by(table_name="wb_health_population")
  61. .first()
  62. )
  63. ds.schema = "temp_schema"
  64. ds.schema_perm = ds.get_schema_perm()
  65. ds_slices = (
  66. session.query(Slice)
  67. .filter_by(datasource_type="table")
  68. .filter_by(datasource_id=ds.id)
  69. .all()
  70. )
  71. for s in ds_slices:
  72. s.schema_perm = ds.schema_perm
  73. create_schema_perm("[examples].[temp_schema]")
  74. gamma_user = security_manager.find_user(username="gamma")
  75. gamma_user.roles.append(security_manager.find_role(SCHEMA_ACCESS_ROLE))
  76. session.commit()
  77. def tearDown(self):
  78. session = db.session
  79. ds = (
  80. session.query(SqlaTable)
  81. .filter_by(table_name="wb_health_population")
  82. .first()
  83. )
  84. schema_perm = ds.schema_perm
  85. ds.schema = None
  86. ds.schema_perm = None
  87. ds_slices = (
  88. session.query(Slice)
  89. .filter_by(datasource_type="table")
  90. .filter_by(datasource_id=ds.id)
  91. .all()
  92. )
  93. for s in ds_slices:
  94. s.schema_perm = None
  95. delete_schema_perm(schema_perm)
  96. session.delete(security_manager.find_role(SCHEMA_ACCESS_ROLE))
  97. session.commit()
  98. def test_set_perm_sqla_table(self):
  99. session = db.session
  100. table = SqlaTable(
  101. schema="tmp_schema",
  102. table_name="tmp_perm_table",
  103. database=get_example_database(),
  104. )
  105. session.add(table)
  106. session.commit()
  107. stored_table = (
  108. session.query(SqlaTable).filter_by(table_name="tmp_perm_table").one()
  109. )
  110. self.assertEquals(
  111. stored_table.perm, f"[examples].[tmp_perm_table](id:{stored_table.id})"
  112. )
  113. self.assertIsNotNone(
  114. security_manager.find_permission_view_menu(
  115. "datasource_access", stored_table.perm
  116. )
  117. )
  118. self.assertEquals(stored_table.schema_perm, "[examples].[tmp_schema]")
  119. self.assertIsNotNone(
  120. security_manager.find_permission_view_menu(
  121. "schema_access", stored_table.schema_perm
  122. )
  123. )
  124. # table name change
  125. stored_table.table_name = "tmp_perm_table_v2"
  126. session.commit()
  127. stored_table = (
  128. session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
  129. )
  130. self.assertEquals(
  131. stored_table.perm, f"[examples].[tmp_perm_table_v2](id:{stored_table.id})"
  132. )
  133. self.assertIsNotNone(
  134. security_manager.find_permission_view_menu(
  135. "datasource_access", stored_table.perm
  136. )
  137. )
  138. # no changes in schema
  139. self.assertEquals(stored_table.schema_perm, "[examples].[tmp_schema]")
  140. self.assertIsNotNone(
  141. security_manager.find_permission_view_menu(
  142. "schema_access", stored_table.schema_perm
  143. )
  144. )
  145. # schema name change
  146. stored_table.schema = "tmp_schema_v2"
  147. session.commit()
  148. stored_table = (
  149. session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
  150. )
  151. self.assertEquals(
  152. stored_table.perm, f"[examples].[tmp_perm_table_v2](id:{stored_table.id})"
  153. )
  154. self.assertIsNotNone(
  155. security_manager.find_permission_view_menu(
  156. "datasource_access", stored_table.perm
  157. )
  158. )
  159. # no changes in schema
  160. self.assertEquals(stored_table.schema_perm, "[examples].[tmp_schema_v2]")
  161. self.assertIsNotNone(
  162. security_manager.find_permission_view_menu(
  163. "schema_access", stored_table.schema_perm
  164. )
  165. )
  166. # database change
  167. new_db = Database(sqlalchemy_uri="some_uri", database_name="tmp_db")
  168. session.add(new_db)
  169. stored_table.database = (
  170. session.query(Database).filter_by(database_name="tmp_db").one()
  171. )
  172. session.commit()
  173. stored_table = (
  174. session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
  175. )
  176. self.assertEquals(
  177. stored_table.perm, f"[tmp_db].[tmp_perm_table_v2](id:{stored_table.id})"
  178. )
  179. self.assertIsNotNone(
  180. security_manager.find_permission_view_menu(
  181. "datasource_access", stored_table.perm
  182. )
  183. )
  184. # no changes in schema
  185. self.assertEquals(stored_table.schema_perm, "[tmp_db].[tmp_schema_v2]")
  186. self.assertIsNotNone(
  187. security_manager.find_permission_view_menu(
  188. "schema_access", stored_table.schema_perm
  189. )
  190. )
  191. # no schema
  192. stored_table.schema = None
  193. session.commit()
  194. stored_table = (
  195. session.query(SqlaTable).filter_by(table_name="tmp_perm_table_v2").one()
  196. )
  197. self.assertEquals(
  198. stored_table.perm, f"[tmp_db].[tmp_perm_table_v2](id:{stored_table.id})"
  199. )
  200. self.assertIsNotNone(
  201. security_manager.find_permission_view_menu(
  202. "datasource_access", stored_table.perm
  203. )
  204. )
  205. self.assertIsNone(stored_table.schema_perm)
  206. session.delete(new_db)
  207. session.delete(stored_table)
  208. session.commit()
  209. def test_set_perm_druid_datasource(self):
  210. session = db.session
  211. druid_cluster = (
  212. session.query(DruidCluster).filter_by(cluster_name="druid_test").one()
  213. )
  214. datasource = DruidDatasource(
  215. datasource_name="tmp_datasource",
  216. cluster=druid_cluster,
  217. cluster_id=druid_cluster.id,
  218. )
  219. session.add(datasource)
  220. session.commit()
  221. # store without a schema
  222. stored_datasource = (
  223. session.query(DruidDatasource)
  224. .filter_by(datasource_name="tmp_datasource")
  225. .one()
  226. )
  227. self.assertEquals(
  228. stored_datasource.perm,
  229. f"[druid_test].[tmp_datasource](id:{stored_datasource.id})",
  230. )
  231. self.assertIsNotNone(
  232. security_manager.find_permission_view_menu(
  233. "datasource_access", stored_datasource.perm
  234. )
  235. )
  236. self.assertIsNone(stored_datasource.schema_perm)
  237. # store with a schema
  238. stored_datasource.datasource_name = "tmp_schema.tmp_datasource"
  239. session.commit()
  240. self.assertEquals(
  241. stored_datasource.perm,
  242. f"[druid_test].[tmp_schema.tmp_datasource](id:{stored_datasource.id})",
  243. )
  244. self.assertIsNotNone(
  245. security_manager.find_permission_view_menu(
  246. "datasource_access", stored_datasource.perm
  247. )
  248. )
  249. self.assertIsNotNone(stored_datasource.schema_perm, "[druid_test].[tmp_schema]")
  250. self.assertIsNotNone(
  251. security_manager.find_permission_view_menu(
  252. "schema_access", stored_datasource.schema_perm
  253. )
  254. )
  255. session.delete(stored_datasource)
  256. session.commit()
  257. def test_set_perm_druid_cluster(self):
  258. session = db.session
  259. cluster = DruidCluster(cluster_name="tmp_druid_cluster")
  260. session.add(cluster)
  261. stored_cluster = (
  262. session.query(DruidCluster)
  263. .filter_by(cluster_name="tmp_druid_cluster")
  264. .one()
  265. )
  266. self.assertEquals(
  267. stored_cluster.perm, f"[tmp_druid_cluster].(id:{stored_cluster.id})"
  268. )
  269. self.assertIsNotNone(
  270. security_manager.find_permission_view_menu(
  271. "database_access", stored_cluster.perm
  272. )
  273. )
  274. stored_cluster.cluster_name = "tmp_druid_cluster2"
  275. session.commit()
  276. self.assertEquals(
  277. stored_cluster.perm, f"[tmp_druid_cluster2].(id:{stored_cluster.id})"
  278. )
  279. self.assertIsNotNone(
  280. security_manager.find_permission_view_menu(
  281. "database_access", stored_cluster.perm
  282. )
  283. )
  284. session.delete(stored_cluster)
  285. session.commit()
  286. def test_set_perm_database(self):
  287. session = db.session
  288. database = Database(
  289. database_name="tmp_database", sqlalchemy_uri="sqlite://test"
  290. )
  291. session.add(database)
  292. stored_db = (
  293. session.query(Database).filter_by(database_name="tmp_database").one()
  294. )
  295. self.assertEquals(stored_db.perm, f"[tmp_database].(id:{stored_db.id})")
  296. self.assertIsNotNone(
  297. security_manager.find_permission_view_menu(
  298. "database_access", stored_db.perm
  299. )
  300. )
  301. stored_db.database_name = "tmp_database2"
  302. session.commit()
  303. stored_db = (
  304. session.query(Database).filter_by(database_name="tmp_database2").one()
  305. )
  306. self.assertEquals(stored_db.perm, f"[tmp_database2].(id:{stored_db.id})")
  307. self.assertIsNotNone(
  308. security_manager.find_permission_view_menu(
  309. "database_access", stored_db.perm
  310. )
  311. )
  312. session.delete(stored_db)
  313. session.commit()
  314. def test_set_perm_slice(self):
  315. session = db.session
  316. database = Database(
  317. database_name="tmp_database", sqlalchemy_uri="sqlite://test"
  318. )
  319. table = SqlaTable(table_name="tmp_perm_table", database=database)
  320. session.add(database)
  321. session.add(table)
  322. session.commit()
  323. # no schema permission
  324. slice = Slice(
  325. datasource_id=table.id,
  326. datasource_type="table",
  327. datasource_name="tmp_perm_table",
  328. slice_name="slice_name",
  329. )
  330. session.add(slice)
  331. session.commit()
  332. slice = session.query(Slice).filter_by(slice_name="slice_name").one()
  333. self.assertEquals(slice.perm, table.perm)
  334. self.assertEquals(slice.perm, f"[tmp_database].[tmp_perm_table](id:{table.id})")
  335. self.assertEquals(slice.schema_perm, table.schema_perm)
  336. self.assertIsNone(slice.schema_perm)
  337. table.schema = "tmp_perm_schema"
  338. table.table_name = "tmp_perm_table_v2"
  339. session.commit()
  340. # TODO(bogdan): modify slice permissions on the table update.
  341. self.assertNotEquals(slice.perm, table.perm)
  342. self.assertEquals(slice.perm, f"[tmp_database].[tmp_perm_table](id:{table.id})")
  343. self.assertEquals(
  344. table.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})"
  345. )
  346. # TODO(bogdan): modify slice schema permissions on the table update.
  347. self.assertNotEquals(slice.schema_perm, table.schema_perm)
  348. self.assertIsNone(slice.schema_perm)
  349. # updating slice refreshes the permissions
  350. slice.slice_name = "slice_name_v2"
  351. session.commit()
  352. self.assertEquals(slice.perm, table.perm)
  353. self.assertEquals(
  354. slice.perm, f"[tmp_database].[tmp_perm_table_v2](id:{table.id})"
  355. )
  356. self.assertEquals(slice.schema_perm, table.schema_perm)
  357. self.assertEquals(slice.schema_perm, "[tmp_database].[tmp_perm_schema]")
  358. session.delete(slice)
  359. session.delete(table)
  360. session.delete(database)
  361. session.commit()
  362. # TODO test slice permission
  363. @patch("superset.security.manager.g")
  364. def test_schemas_accessible_by_user_admin(self, mock_g):
  365. mock_g.user = security_manager.find_user("admin")
  366. with self.client.application.test_request_context():
  367. database = get_example_database()
  368. schemas = security_manager.schemas_accessible_by_user(
  369. database, ["1", "2", "3"]
  370. )
  371. self.assertEquals(schemas, ["1", "2", "3"]) # no changes
  372. @patch("superset.security.manager.g")
  373. def test_schemas_accessible_by_user_schema_access(self, mock_g):
  374. # User has schema access to the schema 1
  375. create_schema_perm("[examples].[1]")
  376. mock_g.user = security_manager.find_user("gamma")
  377. with self.client.application.test_request_context():
  378. database = get_example_database()
  379. schemas = security_manager.schemas_accessible_by_user(
  380. database, ["1", "2", "3"]
  381. )
  382. # temp_schema is not passed in the params
  383. self.assertEquals(schemas, ["1"])
  384. delete_schema_perm("[examples].[1]")
  385. @patch("superset.security.manager.g")
  386. def test_schemas_accessible_by_user_datasource_access(self, mock_g):
  387. # User has schema access to the datasource temp_schema.wb_health_population in examples DB.
  388. mock_g.user = security_manager.find_user("gamma")
  389. with self.client.application.test_request_context():
  390. database = get_example_database()
  391. schemas = security_manager.schemas_accessible_by_user(
  392. database, ["temp_schema", "2", "3"]
  393. )
  394. self.assertEquals(schemas, ["temp_schema"])
  395. @patch("superset.security.manager.g")
  396. def test_schemas_accessible_by_user_datasource_and_schema_access(self, mock_g):
  397. # User has schema access to the datasource temp_schema.wb_health_population in examples DB.
  398. create_schema_perm("[examples].[2]")
  399. mock_g.user = security_manager.find_user("gamma")
  400. with self.client.application.test_request_context():
  401. database = get_example_database()
  402. schemas = security_manager.schemas_accessible_by_user(
  403. database, ["temp_schema", "2", "3"]
  404. )
  405. self.assertEquals(schemas, ["temp_schema", "2"])
  406. vm = security_manager.find_permission_view_menu(
  407. "schema_access", "[examples].[2]"
  408. )
  409. self.assertIsNotNone(vm)
  410. delete_schema_perm("[examples].[2]")
  411. def test_gamma_user_schema_access_to_dashboards(self):
  412. self.login(username="gamma")
  413. data = str(self.client.get("api/v1/dashboard/").data)
  414. self.assertIn("/superset/dashboard/world_health/", data)
  415. self.assertNotIn("/superset/dashboard/births/", data)
  416. def test_gamma_user_schema_access_to_tables(self):
  417. self.login(username="gamma")
  418. data = str(self.client.get("tablemodelview/list/").data)
  419. self.assertIn("wb_health_population", data)
  420. self.assertNotIn("birth_names", data)
  421. def test_gamma_user_schema_access_to_charts(self):
  422. self.login(username="gamma")
  423. data = str(self.client.get("api/v1/chart/").data)
  424. self.assertIn(
  425. "Life Expectancy VS Rural %", data
  426. ) # wb_health_population slice, has access
  427. self.assertIn(
  428. "Parallel Coordinates", data
  429. ) # wb_health_population slice, has access
  430. self.assertNotIn("Girl Name Cloud", data) # birth_names slice, no access
  431. def test_sqllab_gamma_user_schema_access_to_sqllab(self):
  432. session = db.session
  433. example_db = session.query(Database).filter_by(database_name="examples").one()
  434. example_db.expose_in_sqllab = True
  435. session.commit()
  436. arguments = {
  437. "keys": ["none"],
  438. "filters": [{"col": "expose_in_sqllab", "opr": "eq", "value": True}],
  439. "order_columns": "database_name",
  440. "order_direction": "asc",
  441. "page": 0,
  442. "page_size": -1,
  443. }
  444. NEW_FLASK_GET_SQL_DBS_REQUEST = f"/api/v1/database/?q={prison.dumps(arguments)}"
  445. self.login(username="gamma")
  446. databases_json = self.client.get(NEW_FLASK_GET_SQL_DBS_REQUEST).json
  447. self.assertEquals(databases_json["count"], 1)
  448. self.logout()
  449. def assert_can_read(self, view_menu, permissions_set):
  450. self.assertIn(("can_list", view_menu), permissions_set)
  451. def assert_can_write(self, view_menu, permissions_set):
  452. self.assertIn(("can_add", view_menu), permissions_set)
  453. self.assertIn(("can_delete", view_menu), permissions_set)
  454. self.assertIn(("can_edit", view_menu), permissions_set)
  455. def assert_cannot_write(self, view_menu, permissions_set):
  456. self.assertNotIn(("can_add", view_menu), permissions_set)
  457. self.assertNotIn(("can_delete", view_menu), permissions_set)
  458. self.assertNotIn(("can_edit", view_menu), permissions_set)
  459. self.assertNotIn(("can_save", view_menu), permissions_set)
  460. def assert_can_all(self, view_menu, permissions_set):
  461. self.assert_can_read(view_menu, permissions_set)
  462. self.assert_can_write(view_menu, permissions_set)
  463. def assert_can_gamma(self, perm_set):
  464. self.assert_can_read("TableModelView", perm_set)
  465. # make sure that user can create slices and dashboards
  466. self.assert_can_all("SliceModelView", perm_set)
  467. self.assert_can_all("DashboardModelView", perm_set)
  468. self.assertIn(("can_add_slices", "Superset"), perm_set)
  469. self.assertIn(("can_copy_dash", "Superset"), perm_set)
  470. self.assertIn(("can_created_dashboards", "Superset"), perm_set)
  471. self.assertIn(("can_created_slices", "Superset"), perm_set)
  472. self.assertIn(("can_csv", "Superset"), perm_set)
  473. self.assertIn(("can_dashboard", "Superset"), perm_set)
  474. self.assertIn(("can_explore", "Superset"), perm_set)
  475. self.assertIn(("can_explore_json", "Superset"), perm_set)
  476. self.assertIn(("can_fave_dashboards", "Superset"), perm_set)
  477. self.assertIn(("can_fave_slices", "Superset"), perm_set)
  478. self.assertIn(("can_save_dash", "Superset"), perm_set)
  479. self.assertIn(("can_slice", "Superset"), perm_set)
  480. self.assertIn(("can_explore", "Superset"), perm_set)
  481. self.assertIn(("can_explore_json", "Superset"), perm_set)
  482. self.assertIn(("can_userinfo", "UserDBModelView"), perm_set)
  483. def assert_can_alpha(self, perm_set):
  484. self.assert_can_all("TableModelView", perm_set)
  485. self.assertIn(("all_datasource_access", "all_datasource_access"), perm_set)
  486. def assert_cannot_alpha(self, perm_set):
  487. if app.config["ENABLE_ACCESS_REQUEST"]:
  488. self.assert_cannot_write("AccessRequestsModelView", perm_set)
  489. self.assert_can_all("AccessRequestsModelView", perm_set)
  490. self.assert_cannot_write("Queries", perm_set)
  491. self.assert_cannot_write("RoleModelView", perm_set)
  492. self.assert_cannot_write("UserDBModelView", perm_set)
  493. def assert_can_admin(self, perm_set):
  494. self.assert_can_all("DatabaseView", perm_set)
  495. self.assert_can_all("RoleModelView", perm_set)
  496. self.assert_can_all("UserDBModelView", perm_set)
  497. self.assertIn(("all_database_access", "all_database_access"), perm_set)
  498. self.assertIn(("can_override_role_permissions", "Superset"), perm_set)
  499. self.assertIn(("can_sync_druid_source", "Superset"), perm_set)
  500. self.assertIn(("can_override_role_permissions", "Superset"), perm_set)
  501. self.assertIn(("can_approve", "Superset"), perm_set)
  502. def test_is_admin_only(self):
  503. self.assertFalse(
  504. security_manager._is_admin_only(
  505. security_manager.find_permission_view_menu("can_list", "TableModelView")
  506. )
  507. )
  508. self.assertFalse(
  509. security_manager._is_admin_only(
  510. security_manager.find_permission_view_menu(
  511. "all_datasource_access", "all_datasource_access"
  512. )
  513. )
  514. )
  515. log_permissions = ["can_list", "can_show"]
  516. for log_permission in log_permissions:
  517. self.assertTrue(
  518. security_manager._is_admin_only(
  519. security_manager.find_permission_view_menu(
  520. log_permission, "LogModelView"
  521. )
  522. )
  523. )
  524. if app.config["ENABLE_ACCESS_REQUEST"]:
  525. self.assertTrue(
  526. security_manager._is_admin_only(
  527. security_manager.find_permission_view_menu(
  528. "can_list", "AccessRequestsModelView"
  529. )
  530. )
  531. )
  532. self.assertTrue(
  533. security_manager._is_admin_only(
  534. security_manager.find_permission_view_menu(
  535. "can_edit", "UserDBModelView"
  536. )
  537. )
  538. )
  539. self.assertTrue(
  540. security_manager._is_admin_only(
  541. security_manager.find_permission_view_menu("can_approve", "Superset")
  542. )
  543. )
  544. @unittest.skipUnless(
  545. SupersetTestCase.is_module_installed("pydruid"), "pydruid not installed"
  546. )
  547. def test_is_alpha_only(self):
  548. self.assertFalse(
  549. security_manager._is_alpha_only(
  550. security_manager.find_permission_view_menu("can_list", "TableModelView")
  551. )
  552. )
  553. self.assertTrue(
  554. security_manager._is_alpha_only(
  555. security_manager.find_permission_view_menu(
  556. "muldelete", "TableModelView"
  557. )
  558. )
  559. )
  560. self.assertTrue(
  561. security_manager._is_alpha_only(
  562. security_manager.find_permission_view_menu(
  563. "all_datasource_access", "all_datasource_access"
  564. )
  565. )
  566. )
  567. self.assertTrue(
  568. security_manager._is_alpha_only(
  569. security_manager.find_permission_view_menu(
  570. "all_database_access", "all_database_access"
  571. )
  572. )
  573. )
  574. def test_is_gamma_pvm(self):
  575. self.assertTrue(
  576. security_manager._is_gamma_pvm(
  577. security_manager.find_permission_view_menu("can_list", "TableModelView")
  578. )
  579. )
  580. def test_gamma_permissions_basic(self):
  581. self.assert_can_gamma(get_perm_tuples("Gamma"))
  582. self.assert_cannot_alpha(get_perm_tuples("Alpha"))
  583. @unittest.skipUnless(
  584. SupersetTestCase.is_module_installed("pydruid"), "pydruid not installed"
  585. )
  586. def test_alpha_permissions(self):
  587. alpha_perm_tuples = get_perm_tuples("Alpha")
  588. self.assert_can_gamma(alpha_perm_tuples)
  589. self.assert_can_alpha(alpha_perm_tuples)
  590. self.assert_cannot_alpha(alpha_perm_tuples)
  591. @unittest.skipUnless(
  592. SupersetTestCase.is_module_installed("pydruid"), "pydruid not installed"
  593. )
  594. def test_admin_permissions(self):
  595. self.assert_can_gamma(get_perm_tuples("Admin"))
  596. self.assert_can_alpha(get_perm_tuples("Admin"))
  597. self.assert_can_admin(get_perm_tuples("Admin"))
  598. def test_sql_lab_permissions(self):
  599. sql_lab_set = get_perm_tuples("sql_lab")
  600. self.assertIn(("can_sql_json", "Superset"), sql_lab_set)
  601. self.assertIn(("can_csv", "Superset"), sql_lab_set)
  602. self.assertIn(("can_search_queries", "Superset"), sql_lab_set)
  603. self.assert_cannot_alpha(sql_lab_set)
  604. def test_granter_permissions(self):
  605. granter_set = get_perm_tuples("granter")
  606. self.assertIn(("can_override_role_permissions", "Superset"), granter_set)
  607. self.assertIn(("can_approve", "Superset"), granter_set)
  608. self.assert_cannot_alpha(granter_set)
  609. def test_gamma_permissions(self):
  610. def assert_can_read(view_menu):
  611. self.assertIn(("can_list", view_menu), gamma_perm_set)
  612. def assert_can_write(view_menu):
  613. self.assertIn(("can_add", view_menu), gamma_perm_set)
  614. self.assertIn(("can_delete", view_menu), gamma_perm_set)
  615. self.assertIn(("can_edit", view_menu), gamma_perm_set)
  616. def assert_cannot_write(view_menu):
  617. self.assertNotIn(("can_add", view_menu), gamma_perm_set)
  618. self.assertNotIn(("can_delete", view_menu), gamma_perm_set)
  619. self.assertNotIn(("can_edit", view_menu), gamma_perm_set)
  620. self.assertNotIn(("can_save", view_menu), gamma_perm_set)
  621. def assert_can_all(view_menu):
  622. assert_can_read(view_menu)
  623. assert_can_write(view_menu)
  624. gamma_perm_set = set()
  625. for perm in security_manager.find_role("Gamma").permissions:
  626. gamma_perm_set.add((perm.permission.name, perm.view_menu.name))
  627. # check read only perms
  628. assert_can_read("TableModelView")
  629. # make sure that user can create slices and dashboards
  630. assert_can_all("SliceModelView")
  631. assert_can_all("DashboardModelView")
  632. self.assertIn(("can_add_slices", "Superset"), gamma_perm_set)
  633. self.assertIn(("can_copy_dash", "Superset"), gamma_perm_set)
  634. self.assertIn(("can_created_dashboards", "Superset"), gamma_perm_set)
  635. self.assertIn(("can_created_slices", "Superset"), gamma_perm_set)
  636. self.assertIn(("can_csv", "Superset"), gamma_perm_set)
  637. self.assertIn(("can_dashboard", "Superset"), gamma_perm_set)
  638. self.assertIn(("can_explore", "Superset"), gamma_perm_set)
  639. self.assertIn(("can_explore_json", "Superset"), gamma_perm_set)
  640. self.assertIn(("can_fave_dashboards", "Superset"), gamma_perm_set)
  641. self.assertIn(("can_fave_slices", "Superset"), gamma_perm_set)
  642. self.assertIn(("can_save_dash", "Superset"), gamma_perm_set)
  643. self.assertIn(("can_slice", "Superset"), gamma_perm_set)
  644. self.assertIn(("can_userinfo", "UserDBModelView"), gamma_perm_set)
  645. def test_views_are_secured(self):
  646. """Preventing the addition of unsecured views without has_access decorator"""
  647. # These FAB views are secured in their body as opposed to by decorators
  648. method_whitelist = ("action", "action_post")
  649. # List of redirect & other benign views
  650. views_whitelist = [
  651. ["MyIndexView", "index"],
  652. ["UtilView", "back"],
  653. ["LocaleView", "index"],
  654. ["AuthDBView", "login"],
  655. ["AuthDBView", "logout"],
  656. ["R", "index"],
  657. ["Superset", "log"],
  658. ["Superset", "theme"],
  659. ["Superset", "welcome"],
  660. ["SecurityApi", "login"],
  661. ["SecurityApi", "refresh"],
  662. ["SupersetIndexView", "index"],
  663. ]
  664. unsecured_views = []
  665. for view_class in appbuilder.baseviews:
  666. class_name = view_class.__class__.__name__
  667. for name, value in inspect.getmembers(
  668. view_class, predicate=inspect.ismethod
  669. ):
  670. if (
  671. name not in method_whitelist
  672. and [class_name, name] not in views_whitelist
  673. and hasattr(value, "_urls")
  674. and not hasattr(value, "_permission_name")
  675. ):
  676. unsecured_views.append((class_name, name))
  677. if unsecured_views:
  678. view_str = "\n".join([str(v) for v in unsecured_views])
  679. raise Exception(f"Some views are not secured:\n{view_str}")
  680. class SecurityManagerTests(SupersetTestCase):
  681. """
  682. Testing the Security Manager.
  683. """
  684. @patch("superset.security.SupersetSecurityManager.datasource_access")
  685. def test_assert_datasource_permission(self, mock_datasource_access):
  686. datasource = self.get_datasource_mock()
  687. # Datasource with the "datasource_access" permission.
  688. mock_datasource_access.return_value = True
  689. security_manager.assert_datasource_permission(datasource)
  690. # Datasource without the "datasource_access" permission.
  691. mock_datasource_access.return_value = False
  692. with self.assertRaises(SupersetSecurityException):
  693. security_manager.assert_datasource_permission(datasource)
  694. @patch("superset.security.SupersetSecurityManager.datasource_access")
  695. def test_assert_query_context_permission(self, mock_datasource_access):
  696. query_context = Mock()
  697. query_context.datasource = self.get_datasource_mock()
  698. # Query context with the "datasource_access" permission.
  699. mock_datasource_access.return_value = True
  700. security_manager.assert_query_context_permission(query_context)
  701. # Query context without the "datasource_access" permission.
  702. mock_datasource_access.return_value = False
  703. with self.assertRaises(SupersetSecurityException):
  704. security_manager.assert_query_context_permission(query_context)
  705. @patch("superset.security.SupersetSecurityManager.datasource_access")
  706. def test_assert_viz_permission(self, mock_datasource_access):
  707. test_viz = viz.TableViz(self.get_datasource_mock(), form_data={})
  708. # Visualization with the "datasource_access" permission.
  709. mock_datasource_access.return_value = True
  710. security_manager.assert_viz_permission(test_viz)
  711. # Visualization without the "datasource_access" permission.
  712. mock_datasource_access.return_value = False
  713. with self.assertRaises(SupersetSecurityException):
  714. security_manager.assert_viz_permission(test_viz)