mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added support of Row Security Policies. Fixes #5516
This commit is contained in:
parent
bfa0b87791
commit
18277543b6
@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
|
|||||||
New features
|
New features
|
||||||
************
|
************
|
||||||
|
|
||||||
|
| `Issue #5516 <https://redmine.postgresql.org/issues/5516>`_ - Added support of Row Security Policies.
|
||||||
| `Issue #5576 <https://redmine.postgresql.org/issues/5576>`_ - Improve error messaging if the storage and log directories cannot be created.
|
| `Issue #5576 <https://redmine.postgresql.org/issues/5576>`_ - Improve error messaging if the storage and log directories cannot be created.
|
||||||
|
|
||||||
Housekeeping
|
Housekeeping
|
||||||
|
@ -665,6 +665,17 @@ class TableView(BaseTableView, DataTypeReader, VacuumSettings,
|
|||||||
table_row_count_threshold = table_row_count_pref.get()
|
table_row_count_threshold = table_row_count_pref.get()
|
||||||
estimated_row_count = int(res['rows'][0].get('reltuples', 0))
|
estimated_row_count = int(res['rows'][0].get('reltuples', 0))
|
||||||
|
|
||||||
|
# Check whether 'rlspolicy' in response as it supported for
|
||||||
|
# version 9.5 and above
|
||||||
|
if 'rlspolicy' in res['rows'][0]:
|
||||||
|
# Set the value of rls policy
|
||||||
|
if res['rows'][0]['rlspolicy'] == "true":
|
||||||
|
res['rows'][0]['rlspolicy'] = True
|
||||||
|
|
||||||
|
# Set the value of force rls policy for table owner
|
||||||
|
if res['rows'][0]['forcerlspolicy'] == "true":
|
||||||
|
res['rows'][0]['forcerlspolicy'] = True
|
||||||
|
|
||||||
# If estimated rows are greater than threshold then
|
# If estimated rows are greater than threshold then
|
||||||
if estimated_row_count and \
|
if estimated_row_count and \
|
||||||
estimated_row_count > table_row_count_threshold:
|
estimated_row_count > table_row_count_threshold:
|
||||||
|
@ -0,0 +1,589 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
"""Implements policy Node"""
|
||||||
|
|
||||||
|
import simplejson as json
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
import pgadmin.browser.server_groups.servers.databases as databases
|
||||||
|
from flask import render_template, request, jsonify
|
||||||
|
from flask_babelex import gettext
|
||||||
|
from pgadmin.browser.collection import CollectionNodeModule
|
||||||
|
from pgadmin.browser.utils import PGChildNodeView
|
||||||
|
from pgadmin.utils.ajax import make_json_response, internal_server_error, \
|
||||||
|
make_response as ajax_response, gone
|
||||||
|
from pgadmin.utils.driver import get_driver
|
||||||
|
from config import PG_DEFAULT_DRIVER
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables. \
|
||||||
|
row_security_policies import utils as row_security_policies_utils
|
||||||
|
from pgadmin.utils.compile_template_name import compile_template_path
|
||||||
|
|
||||||
|
|
||||||
|
class RowSecurityModule(CollectionNodeModule):
|
||||||
|
"""
|
||||||
|
class RowSecurityModule(CollectionNodeModule)
|
||||||
|
|
||||||
|
A module class for policy node derived from CollectionNodeModule.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
-------
|
||||||
|
* __init__(*args, **kwargs)
|
||||||
|
- Method is used to initialize the RowSecurityModule
|
||||||
|
and it's base module.
|
||||||
|
|
||||||
|
* get_nodes(gid, sid, did)
|
||||||
|
- Method is used to generate the browser collection node.
|
||||||
|
|
||||||
|
* node_inode()
|
||||||
|
- Method is overplidden from its base class to
|
||||||
|
make the node as leaf node.
|
||||||
|
|
||||||
|
* script_load()
|
||||||
|
- Load the module script for policy, when any of the database node is
|
||||||
|
initialized.
|
||||||
|
"""
|
||||||
|
|
||||||
|
NODE_TYPE = 'row_security_policy'
|
||||||
|
COLLECTION_LABEL = gettext('RLS Policies')
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(RowSecurityModule, self).__init__(*args, **kwargs)
|
||||||
|
self.min_gpdbver = 1000000000
|
||||||
|
self.min_ver = 90500
|
||||||
|
self.max_ver = None
|
||||||
|
|
||||||
|
def get_nodes(self, gid, sid, did, scid, **kwargs):
|
||||||
|
"""
|
||||||
|
Generate the collection node
|
||||||
|
:param gid: group id
|
||||||
|
:param sid: server id
|
||||||
|
:param did: database id
|
||||||
|
:param scid: Schema ID
|
||||||
|
"""
|
||||||
|
yield self.generate_browser_collection_node(did)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_inode(self):
|
||||||
|
"""
|
||||||
|
Overplide the property to make the node as leaf node
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def script_load(self):
|
||||||
|
"""
|
||||||
|
Load the module script for policy, when any of the database node is
|
||||||
|
initialized.
|
||||||
|
"""
|
||||||
|
return databases.DatabaseModule.NODE_TYPE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def module_use_template_javascript(self):
|
||||||
|
"""
|
||||||
|
Returns whether Jinja2 template is used for generating the javascript
|
||||||
|
module.
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
blueprint = RowSecurityModule(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class RowSecurityView(PGChildNodeView):
|
||||||
|
"""
|
||||||
|
class RowSecurityView(PGChildNodeView)
|
||||||
|
|
||||||
|
A view class for policy node derived from PGChildNodeView.
|
||||||
|
This class is
|
||||||
|
responsible for all the stuff related to view like
|
||||||
|
create/update/delete policy, showing properties of policy node,
|
||||||
|
showing sql in sql pane.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
-------
|
||||||
|
* __init__(**kwargs)
|
||||||
|
- Method is used to initialize the RowSecurityView and it's base view.
|
||||||
|
|
||||||
|
* check_precondition()
|
||||||
|
- This function will behave as a decorator which will checks
|
||||||
|
database connection before running view, it will also attaches
|
||||||
|
manager,conn & template_path properties to self
|
||||||
|
|
||||||
|
* list()
|
||||||
|
- This function is used to list all the policy nodes within that
|
||||||
|
collection.
|
||||||
|
|
||||||
|
* nodes()
|
||||||
|
- This function will used to create all the child node within that
|
||||||
|
collection. Here it will create all the policy nodes.
|
||||||
|
|
||||||
|
* properties(gid, sid, did, rg_id)
|
||||||
|
- This function will show the properties of the selected policy node
|
||||||
|
|
||||||
|
* create(gid, sid, did, rg_id)
|
||||||
|
- This function will create the new policy object
|
||||||
|
|
||||||
|
* update(gid, sid, did, rg_id)
|
||||||
|
- This function will update the data for the selected policy node
|
||||||
|
|
||||||
|
* delete(self, gid, sid, rg_id):
|
||||||
|
- This function will drop the policy object
|
||||||
|
|
||||||
|
* msql(gid, sid, did, rg_id)
|
||||||
|
- This function is used to return modified sql for the selected
|
||||||
|
policy node
|
||||||
|
|
||||||
|
* get_sql(data, rg_id)
|
||||||
|
- This function will generate sql from model data
|
||||||
|
|
||||||
|
* sql(gid, sid, did, rg_id):
|
||||||
|
- This function will generate sql to show in sql pane for the selected
|
||||||
|
policy node.
|
||||||
|
"""
|
||||||
|
|
||||||
|
node_type = blueprint.node_type
|
||||||
|
|
||||||
|
parent_ids = [
|
||||||
|
{'type': 'int', 'id': 'gid'},
|
||||||
|
{'type': 'int', 'id': 'sid'},
|
||||||
|
{'type': 'int', 'id': 'did'},
|
||||||
|
{'type': 'int', 'id': 'scid'},
|
||||||
|
{'type': 'int', 'id': 'tid'}
|
||||||
|
]
|
||||||
|
ids = [
|
||||||
|
{'type': 'int', 'id': 'plid'}
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = dict({
|
||||||
|
'obj': [
|
||||||
|
{'get': 'properties', 'delete': 'delete', 'put': 'update'},
|
||||||
|
{'get': 'list', 'post': 'create', 'delete': 'delete'}
|
||||||
|
],
|
||||||
|
'delete': [{'delete': 'delete'}, {'delete': 'delete'}],
|
||||||
|
'nodes': [{'get': 'node'}, {'get': 'nodes'}],
|
||||||
|
'sql': [{'get': 'sql'}],
|
||||||
|
'msql': [{'get': 'msql'}, {'get': 'msql'}],
|
||||||
|
'stats': [{'get': 'statistics'}],
|
||||||
|
'dependency': [{'get': 'dependencies'}],
|
||||||
|
'dependent': [{'get': 'dependents'}]
|
||||||
|
})
|
||||||
|
|
||||||
|
def _init_(self, **kwargs):
|
||||||
|
self.conn = None
|
||||||
|
self.template_path = None
|
||||||
|
self.manager = None
|
||||||
|
super(RowSecurityView, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
def check_precondition(f):
|
||||||
|
"""
|
||||||
|
This function will behave as a decorator which will check the
|
||||||
|
database connection before running view. It will also attach
|
||||||
|
manager, conn & template_path properties to self
|
||||||
|
"""
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def wrap(*args, **kwargs):
|
||||||
|
# Here args[0] will hold self & kwargs will hold gid,sid,did
|
||||||
|
self = args[0]
|
||||||
|
self.manager = get_driver(
|
||||||
|
PG_DEFAULT_DRIVER
|
||||||
|
).connection_manager(kwargs['sid'])
|
||||||
|
self.conn = self.manager.connection(did=kwargs['did'])
|
||||||
|
schema, table = row_security_policies_utils.get_parent(self.conn,
|
||||||
|
kwargs[
|
||||||
|
'tid'])
|
||||||
|
self.datlastsysoid = self.manager.db_info[
|
||||||
|
kwargs['did']
|
||||||
|
]['datlastsysoid'] if self.manager.db_info is not None and \
|
||||||
|
kwargs['did'] in self.manager.db_info else 0
|
||||||
|
self.schema = schema
|
||||||
|
self.table = table
|
||||||
|
# Set template path for the sql scripts
|
||||||
|
self.table_template_path = compile_template_path(
|
||||||
|
'tables/sql',
|
||||||
|
self.manager.server_type,
|
||||||
|
self.manager.version
|
||||||
|
)
|
||||||
|
self.template_path = 'row_security_policies/sql/#{0}#'.format(
|
||||||
|
self.manager.version)
|
||||||
|
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def list(self, gid, sid, did, scid, tid):
|
||||||
|
"""
|
||||||
|
Fetch all policy properties and render into properties tab
|
||||||
|
"""
|
||||||
|
|
||||||
|
# fetch schema name by schema id
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.template_path, 'properties.sql']), tid=tid)
|
||||||
|
status, res = self.conn.execute_dict(sql)
|
||||||
|
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
return ajax_response(
|
||||||
|
response=res['rows'],
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def node(self, gid, sid, did, scid, tid, plid):
|
||||||
|
"""
|
||||||
|
return single node
|
||||||
|
"""
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.template_path, 'nodes.sql']), plid=plid)
|
||||||
|
|
||||||
|
status, rset = self.conn.execute_2darray(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset)
|
||||||
|
|
||||||
|
if len(rset['rows']) == 0:
|
||||||
|
return gone(gettext("""Could not find the policy in the table."""))
|
||||||
|
|
||||||
|
res = self.blueprint.generate_browser_node(
|
||||||
|
rset['rows'][0]['oid'],
|
||||||
|
tid,
|
||||||
|
rset['rows'][0]['name'],
|
||||||
|
icon="icon-row_security_policy"
|
||||||
|
)
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
data=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def nodes(self, gid, sid, did, scid, tid):
|
||||||
|
"""
|
||||||
|
List all the policies under the policies Collection node
|
||||||
|
"""
|
||||||
|
res = []
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.template_path, 'nodes.sql']), tid=tid)
|
||||||
|
|
||||||
|
status, rset = self.conn.execute_2darray(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset)
|
||||||
|
|
||||||
|
for row in rset['rows']:
|
||||||
|
res.append(
|
||||||
|
self.blueprint.generate_browser_node(
|
||||||
|
row['oid'],
|
||||||
|
tid,
|
||||||
|
row['name'],
|
||||||
|
icon="icon-row_security_policy"
|
||||||
|
))
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
data=res,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def properties(self, gid, sid, did, scid, tid, plid):
|
||||||
|
"""
|
||||||
|
Fetch the properties of an individual policy and render in
|
||||||
|
properties tab
|
||||||
|
|
||||||
|
"""
|
||||||
|
status, data = self._fetch_properties(plid)
|
||||||
|
if not status:
|
||||||
|
return data
|
||||||
|
|
||||||
|
return ajax_response(
|
||||||
|
response=data,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
def _fetch_properties(self, plid):
|
||||||
|
"""
|
||||||
|
This function is used to fetch the properties of the specified object
|
||||||
|
:param plid:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.template_path, 'properties.sql']
|
||||||
|
), plid=plid, datlastsysoid=self.datlastsysoid)
|
||||||
|
status, res = self.conn.execute_dict(sql)
|
||||||
|
|
||||||
|
if not status:
|
||||||
|
return False, internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
if len(res['rows']) == 0:
|
||||||
|
return False, gone(
|
||||||
|
gettext("""Could not find the policy in the table."""))
|
||||||
|
|
||||||
|
data = dict(res['rows'][0])
|
||||||
|
|
||||||
|
res = data
|
||||||
|
|
||||||
|
return True, res
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def create(self, gid, sid, did, scid, tid):
|
||||||
|
"""
|
||||||
|
This function will creates new the policy object
|
||||||
|
:param did: database id
|
||||||
|
:param sid: server id
|
||||||
|
:param gid: group id
|
||||||
|
:param tid: table id
|
||||||
|
:param scid: Schema ID
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
required_args = [
|
||||||
|
'name',
|
||||||
|
]
|
||||||
|
|
||||||
|
data = request.form if request.form else json.loads(
|
||||||
|
request.data, encoding='utf-8'
|
||||||
|
)
|
||||||
|
data['schema'] = self.schema
|
||||||
|
data['table'] = self.table
|
||||||
|
for arg in required_args:
|
||||||
|
if arg not in data:
|
||||||
|
return make_json_response(
|
||||||
|
status=410,
|
||||||
|
success=0,
|
||||||
|
errormsg=gettext(
|
||||||
|
"Could not find the required parameter ({})."
|
||||||
|
).format(arg)
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
sql = render_template("/".join([self.template_path, 'create.sql']),
|
||||||
|
data=data,
|
||||||
|
conn=self.conn,
|
||||||
|
)
|
||||||
|
status, res = self.conn.execute_scalar(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
# we need oid to to add object in tree at browser
|
||||||
|
sql = render_template(
|
||||||
|
"/".join([self.template_path, 'get_position.sql']),
|
||||||
|
tid=tid, data=data
|
||||||
|
)
|
||||||
|
status, plid = self.conn.execute_scalar(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=tid)
|
||||||
|
return jsonify(
|
||||||
|
node=self.blueprint.generate_browser_node(
|
||||||
|
plid,
|
||||||
|
tid,
|
||||||
|
data['name'],
|
||||||
|
icon="icon-row_security_policy"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def update(self, gid, sid, scid, did, tid, plid=None):
|
||||||
|
"""
|
||||||
|
This function will update policy object
|
||||||
|
:param plid: policy id
|
||||||
|
:param did: database id
|
||||||
|
:param sid: server id
|
||||||
|
:param gid: group id
|
||||||
|
:param tid: table id
|
||||||
|
:param scid: Schema ID
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
data = request.form if request.form else json.loads(
|
||||||
|
request.data, encoding='utf-8'
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
sql, name = row_security_policies_utils.get_sql(self.conn, data,
|
||||||
|
did,
|
||||||
|
tid, plid,
|
||||||
|
self.datlastsysoid,
|
||||||
|
self.schema,
|
||||||
|
self.table)
|
||||||
|
# Most probably this is due to error
|
||||||
|
if not isinstance(sql, str):
|
||||||
|
return sql
|
||||||
|
status, res = self.conn.execute_scalar(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
node=self.blueprint.generate_browser_node(
|
||||||
|
plid,
|
||||||
|
tid,
|
||||||
|
name,
|
||||||
|
icon="icon-row_security_policy"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def delete(self, gid, sid, did, scid, tid, plid=None):
|
||||||
|
"""
|
||||||
|
This function will drop the policy object
|
||||||
|
:param plid: policy id
|
||||||
|
:param did: database id
|
||||||
|
:param sid: server id
|
||||||
|
:param gid: group id
|
||||||
|
:param tid: table id
|
||||||
|
:param scid: Schema ID
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Below will deplide if it's simple drop or drop with cascade call
|
||||||
|
if self.cmd == 'delete':
|
||||||
|
# This is a cascade operation
|
||||||
|
cascade = True
|
||||||
|
else:
|
||||||
|
cascade = False
|
||||||
|
|
||||||
|
if plid is None:
|
||||||
|
data = request.form if request.form else json.loads(
|
||||||
|
request.data, encoding='utf-8'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
data = {'ids': [plid]}
|
||||||
|
|
||||||
|
for plid in data['ids']:
|
||||||
|
try:
|
||||||
|
# Get name for policy from plid
|
||||||
|
sql = render_template("/".join([self.template_path,
|
||||||
|
'get_policy_name.sql']),
|
||||||
|
plid=plid)
|
||||||
|
status, res = self.conn.execute_dict(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
if not res['rows']:
|
||||||
|
return make_json_response(
|
||||||
|
status=410,
|
||||||
|
success=0,
|
||||||
|
errormsg=gettext(
|
||||||
|
'Error: Object not found.'
|
||||||
|
),
|
||||||
|
info=gettext(
|
||||||
|
'The specified policy object could not be found.\n'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# drop policy
|
||||||
|
result = res['rows'][0]
|
||||||
|
result['schema'] = self.schema
|
||||||
|
result['table'] = self.table
|
||||||
|
sql = render_template("/".join([self.template_path,
|
||||||
|
'delete.sql']),
|
||||||
|
policy_name=result['name'],
|
||||||
|
cascade=cascade,
|
||||||
|
result=result
|
||||||
|
)
|
||||||
|
status, res = self.conn.execute_scalar(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return internal_server_error(errormsg=str(e))
|
||||||
|
|
||||||
|
return make_json_response(
|
||||||
|
success=1,
|
||||||
|
info=gettext("policy dropped")
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def msql(self, gid, sid, did, scid, tid, plid=None):
|
||||||
|
"""
|
||||||
|
This function returns modified sql
|
||||||
|
"""
|
||||||
|
data = dict(request.args)
|
||||||
|
|
||||||
|
sql, name = row_security_policies_utils.get_sql(self.conn, data, did,
|
||||||
|
tid, plid,
|
||||||
|
self.datlastsysoid,
|
||||||
|
self.schema,
|
||||||
|
self.table)
|
||||||
|
if not isinstance(sql, str):
|
||||||
|
return sql
|
||||||
|
sql = sql.strip('\n').strip(' ')
|
||||||
|
|
||||||
|
if sql == '':
|
||||||
|
sql = "--modified sql"
|
||||||
|
return make_json_response(
|
||||||
|
data=sql,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def sql(self, gid, sid, did, scid, tid, plid):
|
||||||
|
"""
|
||||||
|
This function will generate sql to render into the sql panel
|
||||||
|
"""
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.template_path, 'properties.sql']), plid=plid)
|
||||||
|
status, res = self.conn.execute_dict(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
if len(res['rows']) == 0:
|
||||||
|
return gone(gettext("""Could not find the policy in the table."""))
|
||||||
|
res = dict(res['rows'][0])
|
||||||
|
res_data = res
|
||||||
|
res_data['schema'] = self.schema
|
||||||
|
res_data['table'] = self.table
|
||||||
|
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[self.template_path, 'create.sql']),
|
||||||
|
data=res_data, display_comments=True)
|
||||||
|
|
||||||
|
return ajax_response(response=sql)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def dependents(self, gid, sid, did, scid, tid, plid):
|
||||||
|
"""
|
||||||
|
This function gets the dependents and returns an ajax response
|
||||||
|
for the policy node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
plid: policy ID
|
||||||
|
tid: table id
|
||||||
|
scid: Schema ID
|
||||||
|
"""
|
||||||
|
dependents_result = self.get_dependents(self.conn, plid)
|
||||||
|
return ajax_response(
|
||||||
|
response=dependents_result,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_precondition
|
||||||
|
def dependencies(self, gid, sid, did, scid, tid, plid):
|
||||||
|
"""
|
||||||
|
This function gets the dependencies and returns an ajax response
|
||||||
|
for the policy node.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
gid: Server Group ID
|
||||||
|
sid: Server ID
|
||||||
|
did: Database ID
|
||||||
|
plid: policy ID
|
||||||
|
tid: table id
|
||||||
|
scid: Schema ID
|
||||||
|
"""
|
||||||
|
dependencies_result = self.get_dependencies(self.conn, plid)
|
||||||
|
return ajax_response(
|
||||||
|
response=dependencies_result,
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
RowSecurityView.register_node_view(blueprint)
|
@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#DDF99D;stroke:#1A6016;stroke-width:1.131;stroke-miterlimit:10;}
|
||||||
|
.st1{fill:#1A6016;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M6.3,9V7.2c0-2.5,1.8-4.6,4.1-4.6l0,0c2.3,0,4.1,2,4.1,4.8v1.8"/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M16.1,20.4H4.8c-0.9,0-1.6-0.7-1.6-1.6v-8.1c0-0.9,0.7-1.6,1.6-1.6h11.3c0.9,0,1.6,0.7,1.6,1.6V19
|
||||||
|
C17.8,19.9,17,20.4,16.1,20.4z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M10.4,16.9L10.4,16.9c-1.2,0-2.1-0.9-2.1-2.1l0,0c0-1.2,0.9-2.1,2.1-2.1l0,0c1.2,0,2.1,0.9,2.1,2.1l0,0
|
||||||
|
C12.6,16,11.6,16.9,10.4,16.9z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M9.4,10V8.2c0-2.5,1.8-4.6,4.1-4.6l0,0c2.3,0,4.1,2,4.1,4.8v1.8"/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M19.1,21.4H7.8c-0.9,0-1.6-0.7-1.6-1.6v-8.1c0-0.9,0.7-1.6,1.6-1.6h11.3c0.9,0,1.6,0.7,1.6,1.6V20
|
||||||
|
C20.8,20.9,20,21.4,19.1,21.4z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M13.4,17.9L13.4,17.9c-1.2,0-2.1-0.9-2.1-2.1l0,0c0-1.2,0.9-2.1,2.1-2.1l0,0c1.2,0,2.1,0.9,2.1,2.1l0,0
|
||||||
|
C15.6,17,14.6,17.9,13.4,17.9z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 24.1.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#DDF99D;stroke:#1A6016;stroke-width:0.6165;stroke-miterlimit:10;}
|
||||||
|
.st1{fill:#1A6016;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M5.2,6.4V5.2C5.2,3.5,6.4,2,8,2l0,0c1.6,0,2.8,1.4,2.8,3.2v1.2"/>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M11.9,14H4.1C3.4,14,3,13.5,3,13V7.4c0-0.6,0.5-1,1.1-1h7.9c0.6,0,1.1,0.5,1.1,1v5.5
|
||||||
|
C13.1,13.5,12.5,14,11.9,14z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M8,11.4L8,11.4c-0.7,0-1.2-0.5-1.2-1.2l0,0C6.8,9.5,7.3,9,8,9l0,0c0.7,0,1.2,0.5,1.2,1.2l0,0
|
||||||
|
C9.2,10.9,8.7,11.4,8,11.4z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 904 B |
@ -0,0 +1,184 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
define('pgadmin.node.row_security_policy', [
|
||||||
|
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||||
|
'sources/pgadmin', 'pgadmin.browser',
|
||||||
|
'pgadmin.backform', 'pgadmin.alertifyjs',
|
||||||
|
'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||||
|
'pgadmin.browser.collection',
|
||||||
|
], function(
|
||||||
|
gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, alertify,
|
||||||
|
SchemaChildTreeNode
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (!pgBrowser.Nodes['coll-row_security_policy']) {
|
||||||
|
pgAdmin.Browser.Nodes['coll-row_security_policy'] =
|
||||||
|
pgAdmin.Browser.Collection.extend({
|
||||||
|
node: 'row_security_policy',
|
||||||
|
label: gettext('RLS Policies'),
|
||||||
|
type: 'coll-row_security_policy',
|
||||||
|
columns: ['name', 'description'],
|
||||||
|
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||||
|
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pgBrowser.Nodes['row_security_policy']) {
|
||||||
|
pgAdmin.Browser.Nodes['row_security_policy'] = pgBrowser.Node.extend({
|
||||||
|
parent_type: ['table', 'view', 'partition'],
|
||||||
|
collection_type: ['coll-table', 'coll-view'],
|
||||||
|
type: 'row_security_policy',
|
||||||
|
label: gettext('RLS Policy'),
|
||||||
|
hasSQL: true,
|
||||||
|
hasDepends: true,
|
||||||
|
width: pgBrowser.stdW.sm + 'px',
|
||||||
|
sqlAlterHelp: 'sql-alterpolicy.html',
|
||||||
|
sqlCreateHelp: 'sql-createpolicy.html',
|
||||||
|
dialogHelp: url_for('help.static', {'filename': 'row_security_policy_dialog.html'}),
|
||||||
|
url_jump_after_node: 'schema',
|
||||||
|
Init: function() {
|
||||||
|
/* Avoid mulitple registration of menus */
|
||||||
|
if (this.initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
|
||||||
|
pgBrowser.add_menus([{
|
||||||
|
name: 'create_row_security_policy_on_coll', node: 'coll-row_security_policy', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
|
category: 'create', priority: 1, label: gettext('RLS Policy...'),
|
||||||
|
icon: 'wcTabIcon icon-row_security_policy', data: {action: 'create', check: true},
|
||||||
|
enable: 'canCreate',
|
||||||
|
},{
|
||||||
|
name: 'create_row_security_policy', node: 'row_security_policy', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
|
category: 'create', priority: 1, label: gettext('RLS Policy...'),
|
||||||
|
icon: 'wcTabIcon icon-row_security_policy', data: {action: 'create', check: true},
|
||||||
|
enable: 'canCreate',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'create_row_security_policy_on_coll', node: 'table', module: this,
|
||||||
|
applies: ['object', 'context'], callback: 'show_obj_properties',
|
||||||
|
category: 'create', priority: 6, label: gettext('RLS Policy...'),
|
||||||
|
icon: 'wcTabIcon icon-row_security_policy', data: {action: 'create', check: true},
|
||||||
|
enable: 'canCreate',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||||
|
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||||
|
model: pgAdmin.Browser.Node.Model.extend({
|
||||||
|
idAttribute: 'oid',
|
||||||
|
defaults: {
|
||||||
|
name: undefined,
|
||||||
|
policyowner: 'public',
|
||||||
|
},
|
||||||
|
schema: [{
|
||||||
|
id: 'name', label: gettext('Name'), cell: 'string',
|
||||||
|
editable: true, type: 'text', readonly: false, cellHeaderClasses: 'width_percent_50',
|
||||||
|
},{
|
||||||
|
id: 'oid', label: gettext('OID'), cell: 'string',
|
||||||
|
editable: false, type: 'text', mode: ['properties'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'event', label: gettext('Event'), control: 'select2', deps:['event'],
|
||||||
|
group: gettext('Commands'), type: 'text',readonly: function(m) {
|
||||||
|
return !m.isNew();},
|
||||||
|
select2: {
|
||||||
|
width: '100%',
|
||||||
|
allowClear: true,
|
||||||
|
},
|
||||||
|
options:[
|
||||||
|
{label: 'SELECT', value: 'SELECT'},
|
||||||
|
{label: 'INSERT', value: 'INSERT'},
|
||||||
|
{label: 'UPDATE', value: 'UPDATE'},
|
||||||
|
{label: 'DELETE', value: 'DELETE'},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'using', label: gettext('Using'), deps: ['using', 'event'],
|
||||||
|
type: 'text', disabled: 'disableUsing',
|
||||||
|
mode: ['create', 'edit', 'properties'],
|
||||||
|
control: 'sql-field', visible: true, group: gettext('Commands'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'withcheck', label: gettext('With Check'), deps: ['withcheck', 'event'],
|
||||||
|
type: 'text', mode: ['create', 'edit', 'properties'],
|
||||||
|
control: 'sql-field', visible: true, group: gettext('Commands'),
|
||||||
|
disabled: 'disableWithCheck',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'policyowner', label: gettext('Role'), cell: 'string',
|
||||||
|
control: 'node-list-by-name',
|
||||||
|
node: 'role', select2: { allowClear: false },
|
||||||
|
mode: ['properties', 'edit','create'],
|
||||||
|
transform: function() {
|
||||||
|
var res =
|
||||||
|
Backform.NodeListByNameControl.prototype.defaults.transform.apply(
|
||||||
|
this, arguments
|
||||||
|
);
|
||||||
|
res.unshift({
|
||||||
|
label: 'public', value: 'public',
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
validate: function(keys) {
|
||||||
|
var msg;
|
||||||
|
this.errorModel.clear();
|
||||||
|
|
||||||
|
// If nothing to validate
|
||||||
|
if (keys && keys.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_.isUndefined(this.get('name'))
|
||||||
|
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||||
|
msg = gettext('Name cannot be empty.');
|
||||||
|
this.errorModel.set('name', msg);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
disableWithCheck: function(m){
|
||||||
|
var event = m.get('event');
|
||||||
|
if ((event == 'SELECT') || (event == 'DELETE')){
|
||||||
|
m.set('withcheck', '');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
disableUsing: function(m){
|
||||||
|
var event = m.get('event');
|
||||||
|
|
||||||
|
if (event == 'INSERT'){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
}),
|
||||||
|
canCreate: function(itemData, item) {
|
||||||
|
|
||||||
|
var treeData = this.getTreeNodeHierarchy(item),
|
||||||
|
server = treeData['server'];
|
||||||
|
|
||||||
|
if (server && server.version < 90500)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// by default we want to allow create menu
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pgBrowser.Nodes['row_security_policy'];
|
||||||
|
});
|
@ -0,0 +1,16 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class RulesTestGenerator(BaseTestGenerator):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
return []
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
-- POLICY: policy_1 ON public.test_emp_rule
|
||||||
|
|
||||||
|
-- DROP POLICY policy_1 ON public.test_emp_rule;
|
||||||
|
|
||||||
|
CREATE POLICY policy_1
|
||||||
|
ON public.test_emp_rule
|
||||||
|
FOR ALL
|
||||||
|
TO public
|
||||||
|
;
|
||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
ALTER POLICY test ON public.test_emp_rule
|
||||||
|
RENAME TO policy_1;
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
-- POLICY: insert_policy ON public.test_emp_rule
|
||||||
|
|
||||||
|
-- DROP POLICY insert_policy ON public.test_emp_rule;
|
||||||
|
|
||||||
|
CREATE POLICY insert_policy
|
||||||
|
ON public.test_emp_rule
|
||||||
|
FOR INSERT
|
||||||
|
TO public
|
||||||
|
;
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
-- POLICY: test ON public.test_emp_rule
|
||||||
|
|
||||||
|
-- DROP POLICY test ON public.test_emp_rule;
|
||||||
|
|
||||||
|
CREATE POLICY test
|
||||||
|
ON public.test_emp_rule
|
||||||
|
FOR ALL
|
||||||
|
TO public
|
||||||
|
;
|
||||||
|
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
-- POLICY: select_policy ON public.test_emp_rule
|
||||||
|
|
||||||
|
-- DROP POLICY select_policy ON public.test_emp_rule;
|
||||||
|
|
||||||
|
CREATE POLICY select_policy
|
||||||
|
ON public.test_emp_rule
|
||||||
|
FOR SELECT
|
||||||
|
TO public
|
||||||
|
;
|
||||||
|
|
@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"scenarios": [
|
||||||
|
{
|
||||||
|
"type": "create",
|
||||||
|
"name": "Create Table For RLS policy",
|
||||||
|
"endpoint": "NODE-table.obj",
|
||||||
|
"sql_endpoint": "NODE-table.sql_id",
|
||||||
|
"data": {
|
||||||
|
"name": "test_emp_rule",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "emp_id",
|
||||||
|
"cltype": "integer",
|
||||||
|
"is_primary_key": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"cltype": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "salary",
|
||||||
|
"cltype": "bigint"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"is_partitioned": false,
|
||||||
|
"schema": "public",
|
||||||
|
"spcname": "pg_default"
|
||||||
|
},
|
||||||
|
"store_object_id": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "create",
|
||||||
|
"name": "Create select RLS policy",
|
||||||
|
"endpoint": "NODE-row_security_policy.obj",
|
||||||
|
"sql_endpoint": "NODE-row_security_policy.sql_id",
|
||||||
|
"data": {
|
||||||
|
"name": "select_policy",
|
||||||
|
"event": "SELECT",
|
||||||
|
"policyowner": "public"
|
||||||
|
},
|
||||||
|
"expected_sql_file": "create_select_policy.sql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "create",
|
||||||
|
"name": "Create INSERT RLS policy",
|
||||||
|
"endpoint": "NODE-row_security_policy.obj",
|
||||||
|
"sql_endpoint": "NODE-row_security_policy.sql_id",
|
||||||
|
"data": {
|
||||||
|
"name": "insert_policy",
|
||||||
|
"event": "INSERT",
|
||||||
|
"policyowner": "public"
|
||||||
|
},
|
||||||
|
"expected_sql_file": "create_insert_policy.sql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "create",
|
||||||
|
"name": "Create RLS policy",
|
||||||
|
"endpoint": "NODE-row_security_policy.obj",
|
||||||
|
"sql_endpoint": "NODE-row_security_policy.sql_id",
|
||||||
|
"data": {
|
||||||
|
"name": "test"
|
||||||
|
},
|
||||||
|
"expected_sql_file": "create_public_policy.sql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "alter",
|
||||||
|
"name": "Alter policy name",
|
||||||
|
"endpoint": "NODE-row_security_policy.obj_id",
|
||||||
|
"sql_endpoint": "NODE-row_security_policy.sql_id",
|
||||||
|
"msql_endpoint": "NODE-row_security_policy.msql_id",
|
||||||
|
"data": {
|
||||||
|
"name": "policy_1"
|
||||||
|
},
|
||||||
|
"expected_sql_file": "alter_policy.sql",
|
||||||
|
"expected_msql_file": "alter_policy_msql.sql"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "delete",
|
||||||
|
"name": "Drop policy",
|
||||||
|
"endpoint": "NODE-row_security_policy.delete_id",
|
||||||
|
"data": {
|
||||||
|
"name": "test_delete_policy_$%{}[]()&*^!@\"'`\\/#"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,493 @@
|
|||||||
|
{
|
||||||
|
"add_policy": [
|
||||||
|
{
|
||||||
|
"name": "Add policy Node",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"event": "INSERT"
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Add owner specific policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"owner_policy": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"policyowner": "PLACE_HOLDER",
|
||||||
|
"event": "SELECT"
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while adding a policy using wrong table",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"wrong_table_id": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"event": "Update"
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 410
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while adding a policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"error_creating_policy": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error ')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while while fetching the policy id using policy name",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"internal_server_error": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",
|
||||||
|
"return_value": "(True, True),(False, 'Mocked Internal Server Error ')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Exception while adding a policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error ')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get_policy": [
|
||||||
|
{
|
||||||
|
"name": "Get a policy URL",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policy URL using wrong policy id",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"incorrect_policy_id": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 410
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policy properties",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policies properties under table nodes",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"table_nodes": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policies properties under table nodes",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"table_nodes": true,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policy Node",
|
||||||
|
"url": "/browser/row_security_policy/nodes/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policy Node using wrong policy id",
|
||||||
|
"url": "/browser/row_security_policy/nodes/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"incorrect_policy_id": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 410
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policy Node dependants",
|
||||||
|
"url": "/browser/row_security_policy/dependent/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policy Node dependency",
|
||||||
|
"url": "/browser/row_security_policy/dependency/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching the policies under the table nodes using wrong table id",
|
||||||
|
"url": "/browser/row_security_policy/nodes/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_2darray",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get all the policies under the table nodes",
|
||||||
|
"url": "/browser/row_security_policy/nodes/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"table_nodes": true,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get all the policies under the table nodes using wrong table id",
|
||||||
|
"url": "/browser/row_security_policy/nodes/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"incorrect_table_id": true,
|
||||||
|
"table_nodes": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching all the policies under the table nodes using wrong table id",
|
||||||
|
"url": "/browser/row_security_policy/nodes/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"table_nodes": true,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_2darray",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policy SQL",
|
||||||
|
"url": "/browser/row_security_policy/sql/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Get a policy SQL using wrong policy id",
|
||||||
|
"url": "/browser/row_security_policy/sql/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"incorrect_policy_id": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 410
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fetch msql of policy using wrong policy id",
|
||||||
|
"url": "/browser/row_security_policy/msql/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.browser.server_groups.servers.databases.schemas.tables.row_security_policies.utils.get_sql",
|
||||||
|
"return_value": "('', 'Mocked response')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"delete_policy": [
|
||||||
|
{
|
||||||
|
"name": "Delete a policy URL",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policy to delete",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while deleting the policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policy to delete",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||||
|
"return_value": "(True, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "policy not found while deleting a policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"invalid_policy_id": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 410
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"update_policy": [
|
||||||
|
{
|
||||||
|
"name": "update a policy name",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "update a policy owner",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"owner_policy": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER",
|
||||||
|
"policyowner": "PLACEHOLDER"
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "update a policy using clause",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER",
|
||||||
|
"using": true
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "update a policy with check clause",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER",
|
||||||
|
"withcheck": true
|
||||||
|
},
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policy to update",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while updating the policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",
|
||||||
|
"return_value": "(False, 'Mocked Internal Server Error')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while fetching a policy to update using wrong policy id",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"wrong_policy_id": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error while updating the policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": false,
|
||||||
|
"mocking_required": true,
|
||||||
|
"test_data": {
|
||||||
|
"name": "PLACE_HOLDER",
|
||||||
|
"id": "PLACE_HOLDER"
|
||||||
|
},
|
||||||
|
"mock_data": {
|
||||||
|
"function_name": "pgadmin.browser.server_groups.servers.databases.schemas.tables.row_security_policies.utils.get_sql",
|
||||||
|
"return_value": "('')"
|
||||||
|
},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"delete_multiple_policy": [
|
||||||
|
{
|
||||||
|
"name": "Delete multiple policy",
|
||||||
|
"url": "/browser/row_security_policy/obj/",
|
||||||
|
"is_positive_test": true,
|
||||||
|
"mocking_required": false,
|
||||||
|
"mock_data": {},
|
||||||
|
"expected_data": {
|
||||||
|
"status_code": 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||||
|
import utils as tables_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||||
|
utils as schema_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||||
|
database_utils
|
||||||
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
|
from regression import parent_node_dict
|
||||||
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
from . import utils as policy_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.roles.tests import \
|
||||||
|
utils as roles_utils
|
||||||
|
|
||||||
|
if sys.version_info < (3, 3):
|
||||||
|
from mock import patch
|
||||||
|
else:
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
class RulesAddTestCase(BaseTestGenerator):
|
||||||
|
"""This class will add new Policy under table node."""
|
||||||
|
scenarios = utils.generate_scenarios('add_policy',
|
||||||
|
policy_utils.test_cases)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||||
|
schema_info = parent_node_dict["schema"][-1]
|
||||||
|
self.server_id = schema_info["server_id"]
|
||||||
|
self.db_id = schema_info["db_id"]
|
||||||
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id)
|
||||||
|
if not db_con['data']["connected"]:
|
||||||
|
raise Exception("Could not connect to database to add a Policy.")
|
||||||
|
self.schema_id = schema_info["schema_id"]
|
||||||
|
self.schema_name = schema_info["schema_name"]
|
||||||
|
|
||||||
|
schema_response = schema_utils.verify_schemas(self.server,
|
||||||
|
self.db_name,
|
||||||
|
self.schema_name)
|
||||||
|
if not schema_response:
|
||||||
|
raise Exception("Could not find the schema to add a Policy.")
|
||||||
|
self.table_name = "table_for_policy_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
if hasattr(self, "owner_policy"):
|
||||||
|
self.role_name = "role_for_policy_%s" % str(uuid.uuid4())[1:8]
|
||||||
|
self.role_id = roles_utils.create_role(self.server, self.role_name)
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
"""This function will Policy under table node."""
|
||||||
|
self.test_data['name'] = \
|
||||||
|
"test_policy_add_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
|
||||||
|
if hasattr(self, "owner_policy"):
|
||||||
|
self.test_data['policyowner'] = self.role_name
|
||||||
|
|
||||||
|
data = self.test_data
|
||||||
|
if self.is_positive_test:
|
||||||
|
response = self.create_policy(data)
|
||||||
|
else:
|
||||||
|
if hasattr(self, 'wrong_table_id'):
|
||||||
|
del data["name"]
|
||||||
|
response = self.create_policy(data)
|
||||||
|
elif hasattr(self, 'internal_server_error'):
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
side_effect=eval(self.mock_data["return_value"])):
|
||||||
|
response = self.create_policy(data)
|
||||||
|
elif hasattr(self, 'error_creating_policy'):
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
return_value=eval(self.mock_data["return_value"])):
|
||||||
|
response = self.create_policy(data)
|
||||||
|
else:
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
side_effect=eval(self.mock_data["return_value"])):
|
||||||
|
response = self.create_policy(data)
|
||||||
|
self.assertEquals(response.status_code,
|
||||||
|
self.expected_data["status_code"])
|
||||||
|
|
||||||
|
def create_policy(self, data):
|
||||||
|
return self.tester.post(
|
||||||
|
"{0}{1}/{2}/{3}/{4}/{5}/".format(self.url, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id,
|
||||||
|
self.schema_id, self.table_id),
|
||||||
|
data=json.dumps(data),
|
||||||
|
content_type='html/json'
|
||||||
|
)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
connection = utils.get_db_connection(self.server['db'],
|
||||||
|
self.server['username'],
|
||||||
|
self.server['db_password'],
|
||||||
|
self.server['host'],
|
||||||
|
self.server['port'],
|
||||||
|
self.server['sslmode'])
|
||||||
|
if hasattr(self, "owner_policy"):
|
||||||
|
policy_utils.delete_policy(self.server, self.db_name,
|
||||||
|
self.test_data['name'],
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
roles_utils.delete_role(connection, self.role_name)
|
||||||
|
|
||||||
|
# Disconnect the database
|
||||||
|
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,91 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||||
|
import utils as tables_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||||
|
utils as schema_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||||
|
database_utils
|
||||||
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
|
from regression import parent_node_dict
|
||||||
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
from . import utils as policy_utils
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info < (3, 3):
|
||||||
|
from mock import patch
|
||||||
|
else:
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyDeleteTestCase(BaseTestGenerator):
|
||||||
|
"""This class will delete policy under table node."""
|
||||||
|
scenarios = utils.generate_scenarios('delete_policy',
|
||||||
|
policy_utils.test_cases)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||||
|
schema_info = parent_node_dict["schema"][-1]
|
||||||
|
self.server_id = schema_info["server_id"]
|
||||||
|
self.db_id = schema_info["db_id"]
|
||||||
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id)
|
||||||
|
if not db_con['data']["connected"]:
|
||||||
|
raise Exception("Could not connect to database to delete policy.")
|
||||||
|
self.schema_id = schema_info["schema_id"]
|
||||||
|
self.schema_name = schema_info["schema_name"]
|
||||||
|
schema_response = schema_utils.verify_schemas(self.server,
|
||||||
|
self.db_name,
|
||||||
|
self.schema_name)
|
||||||
|
if not schema_response:
|
||||||
|
raise Exception("Could not find the schema to delete policy.")
|
||||||
|
self.table_name = "table_column_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
self.policy_name = "test_policy_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.policy_id = policy_utils.create_policy(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name,
|
||||||
|
self.policy_name)
|
||||||
|
|
||||||
|
def delete_policy(self):
|
||||||
|
return self.tester.delete(
|
||||||
|
"{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id,
|
||||||
|
self.schema_id, self.table_id,
|
||||||
|
self.policy_id),
|
||||||
|
follow_redirects=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
"""This function will delete policy under table node."""
|
||||||
|
policy_response = policy_utils.verify_policy(self.server, self.db_name,
|
||||||
|
self.policy_name)
|
||||||
|
if not policy_response:
|
||||||
|
raise Exception("Could not find the policy to delete.")
|
||||||
|
|
||||||
|
if self.is_positive_test:
|
||||||
|
if hasattr(self, "invalid_policy_id"):
|
||||||
|
self.policy_id = 9999
|
||||||
|
response = self.delete_policy()
|
||||||
|
else:
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
return_value=eval(self.mock_data["return_value"])):
|
||||||
|
response = self.delete_policy()
|
||||||
|
|
||||||
|
self.assertEquals(response.status_code,
|
||||||
|
self.expected_data["status_code"])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Disconnect the database
|
||||||
|
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,94 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
import json
|
||||||
|
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||||
|
import utils as tables_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||||
|
utils as schema_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||||
|
database_utils
|
||||||
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
|
from regression import parent_node_dict
|
||||||
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
from . import utils as policy_utils
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyDeleteTestCases(BaseTestGenerator):
|
||||||
|
"""This class will delete policy under table node."""
|
||||||
|
|
||||||
|
scenarios = utils.generate_scenarios('delete_multiple_policy',
|
||||||
|
policy_utils.test_cases)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||||
|
schema_info = parent_node_dict["schema"][-1]
|
||||||
|
self.server_id = schema_info["server_id"]
|
||||||
|
self.db_id = schema_info["db_id"]
|
||||||
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id)
|
||||||
|
if not db_con['data']["connected"]:
|
||||||
|
raise Exception("Could not connect to database to delete policy.")
|
||||||
|
self.schema_id = schema_info["schema_id"]
|
||||||
|
self.schema_name = schema_info["schema_name"]
|
||||||
|
schema_response = schema_utils.verify_schemas(self.server,
|
||||||
|
self.db_name,
|
||||||
|
self.schema_name)
|
||||||
|
if not schema_response:
|
||||||
|
raise Exception("Could not find the schema to delete policy.")
|
||||||
|
self.table_name = "table_column_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
self.policy_name = "test_policy_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.policy_name_1 = "test_policy_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.rule_ids = [policy_utils.create_policy(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name,
|
||||||
|
self.policy_name),
|
||||||
|
policy_utils.create_policy(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name,
|
||||||
|
self.policy_name_1),
|
||||||
|
]
|
||||||
|
|
||||||
|
def delete_multiple_policy(self, data):
|
||||||
|
return self.tester.delete(
|
||||||
|
"{0}{1}/{2}/{3}/{4}/{5}/".format(self.url, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id,
|
||||||
|
self.schema_id, self.table_id
|
||||||
|
),
|
||||||
|
follow_redirects=True,
|
||||||
|
data=json.dumps(data),
|
||||||
|
content_type='html/json'
|
||||||
|
)
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
"""This function will delete policy under table node."""
|
||||||
|
rule_response = policy_utils.verify_policy(self.server, self.db_name,
|
||||||
|
self.policy_name)
|
||||||
|
if not rule_response:
|
||||||
|
raise Exception("Could not find the policy to delete.")
|
||||||
|
|
||||||
|
rule_response = policy_utils.verify_policy(self.server, self.db_name,
|
||||||
|
self.policy_name_1)
|
||||||
|
if not rule_response:
|
||||||
|
raise Exception("Could not find the policy to delete.")
|
||||||
|
|
||||||
|
data = {'ids': self.rule_ids}
|
||||||
|
if self.is_positive_test:
|
||||||
|
response = self.delete_multiple_policy(data)
|
||||||
|
self.assertEquals(response.status_code,
|
||||||
|
self.expected_data["status_code"])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Disconnect the database
|
||||||
|
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,98 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||||
|
import utils as tables_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||||
|
utils as schema_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||||
|
database_utils
|
||||||
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
|
from regression import parent_node_dict
|
||||||
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
from . import utils as policy_utils
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info < (3, 3):
|
||||||
|
from mock import patch
|
||||||
|
else:
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyGetTestCase(BaseTestGenerator):
|
||||||
|
"""This class will fetch the Policy under table node."""
|
||||||
|
scenarios = utils.generate_scenarios('get_policy',
|
||||||
|
policy_utils.test_cases)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||||
|
schema_info = parent_node_dict["schema"][-1]
|
||||||
|
self.server_id = schema_info["server_id"]
|
||||||
|
self.db_id = schema_info["db_id"]
|
||||||
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id)
|
||||||
|
if not db_con['data']["connected"]:
|
||||||
|
raise Exception("Could not connect to database to delete Policy.")
|
||||||
|
self.schema_id = schema_info["schema_id"]
|
||||||
|
self.schema_name = schema_info["schema_name"]
|
||||||
|
schema_response = schema_utils.verify_schemas(self.server,
|
||||||
|
self.db_name,
|
||||||
|
self.schema_name)
|
||||||
|
if not schema_response:
|
||||||
|
raise Exception("Could not find the schema to delete Policy.")
|
||||||
|
self.table_name = "table_column_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
self.policy_name = "test_policy_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.policy_id = policy_utils.create_policy(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name,
|
||||||
|
self.policy_name)
|
||||||
|
|
||||||
|
def get_policy(self):
|
||||||
|
return self.tester.get(
|
||||||
|
"{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id,
|
||||||
|
self.schema_id, self.table_id,
|
||||||
|
self.policy_id),
|
||||||
|
follow_redirects=True
|
||||||
|
)
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
"""This function will fetch the Policy under table node."""
|
||||||
|
|
||||||
|
if self.is_positive_test:
|
||||||
|
if hasattr(self, "incorrect_policy_id"):
|
||||||
|
self.policy_id = 9999
|
||||||
|
if hasattr(self, "table_nodes"):
|
||||||
|
self.policy_id = ''
|
||||||
|
response = self.get_policy()
|
||||||
|
else:
|
||||||
|
response = self.get_policy()
|
||||||
|
else:
|
||||||
|
if hasattr(self, "table_nodes"):
|
||||||
|
self.policy_id = ''
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
return_value=eval(self.mock_data["return_value"])):
|
||||||
|
response = self.get_policy()
|
||||||
|
else:
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
return_value=eval(self.mock_data["return_value"])):
|
||||||
|
response = self.get_policy()
|
||||||
|
|
||||||
|
self.assertEquals(response.status_code,
|
||||||
|
self.expected_data["status_code"])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
# Disconnect the database
|
||||||
|
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,122 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
|
||||||
|
import utils as tables_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
|
||||||
|
utils as schema_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
|
||||||
|
database_utils
|
||||||
|
from pgadmin.utils.route import BaseTestGenerator
|
||||||
|
from regression import parent_node_dict
|
||||||
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
from . import utils as policy_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.roles.tests import \
|
||||||
|
utils as roles_utils
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info < (3, 3):
|
||||||
|
from mock import patch
|
||||||
|
else:
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
|
class PolicyUpdateTestCase(BaseTestGenerator):
|
||||||
|
"""This class will update the policy under table node."""
|
||||||
|
scenarios = utils.generate_scenarios('update_policy',
|
||||||
|
policy_utils.test_cases)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.db_name = parent_node_dict["database"][-1]["db_name"]
|
||||||
|
schema_info = parent_node_dict["schema"][-1]
|
||||||
|
self.server_id = schema_info["server_id"]
|
||||||
|
self.db_id = schema_info["db_id"]
|
||||||
|
db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id)
|
||||||
|
if not db_con['data']["connected"]:
|
||||||
|
raise Exception("Could not connect to database to delete policy.")
|
||||||
|
self.schema_id = schema_info["schema_id"]
|
||||||
|
self.schema_name = schema_info["schema_name"]
|
||||||
|
schema_response = schema_utils.verify_schemas(self.server,
|
||||||
|
self.db_name,
|
||||||
|
self.schema_name)
|
||||||
|
if not schema_response:
|
||||||
|
raise Exception("Could not find the schema to delete policy.")
|
||||||
|
self.table_name = "table_column_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.table_id = tables_utils.create_table(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
self.policy_name = "test_policy_delete_%s" % (str(uuid.uuid4())[1:8])
|
||||||
|
self.policy_id = policy_utils.create_policy(self.server, self.db_name,
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name,
|
||||||
|
self.policy_name)
|
||||||
|
if hasattr(self, "owner_policy"):
|
||||||
|
self.role_name = "role_for_policy_%s" % \
|
||||||
|
str(uuid.uuid4())[1:8]
|
||||||
|
self.role_id = roles_utils.create_role(self.server, self.role_name)
|
||||||
|
|
||||||
|
def update_policy(self, data):
|
||||||
|
return self.tester.put(
|
||||||
|
"{0}{1}/{2}/{3}/{4}/{5}/{6}".format(self.url, utils.SERVER_GROUP,
|
||||||
|
self.server_id, self.db_id,
|
||||||
|
self.schema_id, self.table_id,
|
||||||
|
self.policy_id),
|
||||||
|
data=json.dumps(data),
|
||||||
|
follow_redirects=True)
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
"""This function will update the policy under table node."""
|
||||||
|
policy_name = policy_utils.verify_policy(self.server, self.db_name,
|
||||||
|
self.policy_name)
|
||||||
|
self.test_data['name'] = "test_policy_update_%s" % (
|
||||||
|
str(uuid.uuid4())[1:8])
|
||||||
|
self.test_data['id'] = self.policy_id
|
||||||
|
|
||||||
|
if hasattr(self, 'owner_policy'):
|
||||||
|
self.test_data['policyowner'] = self.role_name
|
||||||
|
|
||||||
|
if not policy_name:
|
||||||
|
raise Exception("Could not find the policy to update.")
|
||||||
|
|
||||||
|
if self.is_positive_test:
|
||||||
|
if hasattr(self, "wrong_policy_id"):
|
||||||
|
self.policy_id = 9999
|
||||||
|
if hasattr(self, "plid_none"):
|
||||||
|
self.policy_id = ''
|
||||||
|
response = self.update_policy(self.test_data)
|
||||||
|
else:
|
||||||
|
with patch(self.mock_data["function_name"],
|
||||||
|
return_value=eval(self.mock_data["return_value"])):
|
||||||
|
if hasattr(self, "wrong_policy_id"):
|
||||||
|
self.policy_id = 9999
|
||||||
|
response = self.update_policy(self.test_data)
|
||||||
|
|
||||||
|
self.assertEquals(response.status_code,
|
||||||
|
self.expected_data["status_code"])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
connection = utils.get_db_connection(self.server['db'],
|
||||||
|
self.server['username'],
|
||||||
|
self.server['db_password'],
|
||||||
|
self.server['host'],
|
||||||
|
self.server['port'],
|
||||||
|
self.server['sslmode'])
|
||||||
|
|
||||||
|
if hasattr(self, "owner_policy"):
|
||||||
|
policy_utils.delete_policy(self.server, self.db_name,
|
||||||
|
self.test_data['name'],
|
||||||
|
self.schema_name,
|
||||||
|
self.table_name)
|
||||||
|
roles_utils.delete_role(connection, self.role_name)
|
||||||
|
# Disconnect the database
|
||||||
|
database_utils.disconnect_database(self, self.server_id, self.db_id)
|
@ -0,0 +1,140 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from regression.python_test_utils import test_utils as utils
|
||||||
|
|
||||||
|
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(CURRENT_PATH + "/rls_test_data.json") as data_file:
|
||||||
|
test_cases = json.load(data_file)
|
||||||
|
|
||||||
|
|
||||||
|
def create_policy(server, db_name, schema_name, table_name, policy_name):
|
||||||
|
"""
|
||||||
|
This function creates a policy under provided table.
|
||||||
|
:param server: server details
|
||||||
|
:type server: dict
|
||||||
|
:param db_name: database name
|
||||||
|
:type db_name: str
|
||||||
|
:param schema_name: schema name
|
||||||
|
:type schema_name: str
|
||||||
|
:param table_name: table name
|
||||||
|
:type table_name: str
|
||||||
|
:param policy_name: policy name
|
||||||
|
:type policy_name: str
|
||||||
|
:return policy_id: policy id
|
||||||
|
:rtype: int
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
connection = utils.get_db_connection(db_name,
|
||||||
|
server['username'],
|
||||||
|
server['db_password'],
|
||||||
|
server['host'],
|
||||||
|
server['port'],
|
||||||
|
server['sslmode'])
|
||||||
|
old_isolation_level = connection.isolation_level
|
||||||
|
connection.set_isolation_level(0)
|
||||||
|
pg_cursor = connection.cursor()
|
||||||
|
query = "CREATE policy %s on %s.%s To public" % \
|
||||||
|
(policy_name, schema_name, table_name)
|
||||||
|
pg_cursor.execute(query)
|
||||||
|
connection.set_isolation_level(old_isolation_level)
|
||||||
|
connection.commit()
|
||||||
|
# Get role oid of newly added policy
|
||||||
|
pg_cursor.execute("select oid from pg_policy where polname='%s'" %
|
||||||
|
policy_name)
|
||||||
|
policy = pg_cursor.fetchone()
|
||||||
|
policy_id = ''
|
||||||
|
if policy:
|
||||||
|
policy_id = policy[0]
|
||||||
|
connection.close()
|
||||||
|
return policy_id
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def verify_policy(server, db_name, policy_name):
|
||||||
|
"""
|
||||||
|
This function verifies policy exist in database or not.
|
||||||
|
:param server: server details
|
||||||
|
:type server: dict
|
||||||
|
:param db_name: database name
|
||||||
|
:type db_name: str
|
||||||
|
:param policy_name: policy name
|
||||||
|
:type policy_name: str
|
||||||
|
:return policy: policy record from database
|
||||||
|
:rtype: tuple
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
connection = utils.get_db_connection(db_name,
|
||||||
|
server['username'],
|
||||||
|
server['db_password'],
|
||||||
|
server['host'],
|
||||||
|
server['port'],
|
||||||
|
server['sslmode'])
|
||||||
|
pg_cursor = connection.cursor()
|
||||||
|
pg_cursor.execute("select * from pg_policy where polname='%s'" %
|
||||||
|
policy_name)
|
||||||
|
policy = pg_cursor.fetchone()
|
||||||
|
connection.close()
|
||||||
|
return policy
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def delete_policy(server, db_name, policy_name, schema_name, table_name):
|
||||||
|
"""
|
||||||
|
This function use to delete the existing roles in the servers
|
||||||
|
|
||||||
|
:param db_name: db_name
|
||||||
|
:type db_name: db_name object
|
||||||
|
:param server: server
|
||||||
|
:type server: server object
|
||||||
|
:param policy_name: policy name
|
||||||
|
:type policy_name: str
|
||||||
|
:param schema_name: schema name
|
||||||
|
:type schema_name: str
|
||||||
|
:param table_name: table name
|
||||||
|
:type table_name: str
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
connection = utils.get_db_connection(db_name,
|
||||||
|
server['username'],
|
||||||
|
server['db_password'],
|
||||||
|
server['host'],
|
||||||
|
server['port'],
|
||||||
|
server['sslmode'])
|
||||||
|
pg_cursor = connection.cursor()
|
||||||
|
|
||||||
|
pg_cursor.execute("select * from pg_policy where polname='%s'" %
|
||||||
|
policy_name)
|
||||||
|
policy_count = pg_cursor.fetchone()
|
||||||
|
if policy_count:
|
||||||
|
old_isolation_level = connection.isolation_level
|
||||||
|
connection.set_isolation_level(0)
|
||||||
|
pg_cursor = connection.cursor()
|
||||||
|
query = "DROP policy %s on %s.%s" % \
|
||||||
|
(policy_name, schema_name, table_name)
|
||||||
|
pg_cursor.execute(query)
|
||||||
|
connection.set_isolation_level(old_isolation_level)
|
||||||
|
connection.commit()
|
||||||
|
connection.close()
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc(file=sys.stderr)
|
||||||
|
raise
|
@ -0,0 +1,145 @@
|
|||||||
|
##########################################################################
|
||||||
|
#
|
||||||
|
# pgAdmin 4 - PostgreSQL Tools
|
||||||
|
#
|
||||||
|
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||||
|
# This software is released under the PostgreSQL Licence
|
||||||
|
#
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
""" Implements Utility class for row level security. """
|
||||||
|
|
||||||
|
from flask import render_template
|
||||||
|
from flask_babelex import gettext as _
|
||||||
|
from pgadmin.utils.ajax import internal_server_error
|
||||||
|
from pgadmin.utils.exception import ObjectGone
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
def get_template_path(f):
|
||||||
|
"""
|
||||||
|
This function will behave as a decorator which will prepare
|
||||||
|
the template path based on database server version.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def wrap(*args, **kwargs):
|
||||||
|
# Here args[0] will hold the connection object
|
||||||
|
conn_obj = args[0]
|
||||||
|
if 'template_path' not in kwargs or kwargs['template_path'] is None:
|
||||||
|
kwargs['template_path'] = 'row_security_policies/sql/#{0}#'.format(
|
||||||
|
conn_obj.manager.version)
|
||||||
|
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
|
||||||
|
@get_template_path
|
||||||
|
def get_parent(conn, tid, template_path=None):
|
||||||
|
"""
|
||||||
|
This function will return the parent of the given table.
|
||||||
|
:param conn: Connection Object
|
||||||
|
:param tid: Table oid
|
||||||
|
:param template_path: Optional template path
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
SQL = render_template("/".join([template_path,
|
||||||
|
'get_parent.sql']), tid=tid)
|
||||||
|
status, rset = conn.execute_2darray(SQL)
|
||||||
|
if not status:
|
||||||
|
raise Exception(rset)
|
||||||
|
|
||||||
|
schema = ''
|
||||||
|
table = ''
|
||||||
|
if 'rows' in rset and len(rset['rows']) > 0:
|
||||||
|
schema = rset['rows'][0]['schema']
|
||||||
|
table = rset['rows'][0]['table']
|
||||||
|
|
||||||
|
return schema, table
|
||||||
|
|
||||||
|
|
||||||
|
@get_template_path
|
||||||
|
def get_sql(conn, data, did, tid, plid, datlastsysoid, schema, table,
|
||||||
|
mode=None, template_path=None):
|
||||||
|
"""
|
||||||
|
This function will generate sql from model data
|
||||||
|
"""
|
||||||
|
|
||||||
|
if plid is not None:
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[template_path, 'properties.sql']), plid=plid)
|
||||||
|
status, res = conn.execute_dict(sql)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=res)
|
||||||
|
if len(res['rows']) == 0:
|
||||||
|
raise ObjectGone(_('Could not find the index in the table.'))
|
||||||
|
res_data = dict(res['rows'][0])
|
||||||
|
|
||||||
|
res = res_data
|
||||||
|
|
||||||
|
old_data = res
|
||||||
|
old_data['schema'] = schema
|
||||||
|
old_data['table'] = table
|
||||||
|
sql = render_template(
|
||||||
|
"/".join([template_path, 'update.sql']),
|
||||||
|
data=data, o_data=old_data
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
data['schema'] = schema
|
||||||
|
data['table'] = table
|
||||||
|
sql = render_template("/".join(
|
||||||
|
[template_path, 'create.sql']), data=data)
|
||||||
|
return sql, data['name'] if 'name' in data else old_data['name']
|
||||||
|
|
||||||
|
|
||||||
|
@get_template_path
|
||||||
|
def get_reverse_engineered_sql(conn, schema, table, did, tid, plid,
|
||||||
|
datlastsysoid,
|
||||||
|
template_path=None, with_header=True):
|
||||||
|
"""
|
||||||
|
This function will return reverse engineered sql for specified trigger.
|
||||||
|
|
||||||
|
:param conn: Connection Object
|
||||||
|
:param schema: Schema
|
||||||
|
:param table: Table
|
||||||
|
:param did: DB ID
|
||||||
|
:param tid: Table ID
|
||||||
|
:param plid: Policy ID
|
||||||
|
:param datlastsysoid:
|
||||||
|
:param template_path: Optional template path
|
||||||
|
:param with_header: Optional parameter to decide whether the SQL will be
|
||||||
|
returned with header or not
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
SQL = render_template("/".join(
|
||||||
|
[template_path, 'properties.sql']), plid=plid)
|
||||||
|
|
||||||
|
status, res = conn.execute_dict(SQL)
|
||||||
|
if not status:
|
||||||
|
raise Exception(res)
|
||||||
|
|
||||||
|
if len(res['rows']) == 0:
|
||||||
|
raise ObjectGone(_('Could not find the index in the table.'))
|
||||||
|
|
||||||
|
data = dict(res['rows'][0])
|
||||||
|
# Adding parent into data dict, will be using it while creating sql
|
||||||
|
data['schema'] = schema
|
||||||
|
data['table'] = table
|
||||||
|
|
||||||
|
SQL, name = get_sql(conn, data, did, tid, None, datlastsysoid, schema,
|
||||||
|
table)
|
||||||
|
|
||||||
|
if with_header:
|
||||||
|
sql_header = u"-- POLICY: {0}\n\n-- ".format(data['name'])
|
||||||
|
|
||||||
|
sql_header += render_template("/".join([template_path,
|
||||||
|
'delete.sql']),
|
||||||
|
policy_name=data['name'],
|
||||||
|
result=data
|
||||||
|
)
|
||||||
|
|
||||||
|
SQL = sql_header + '\n\n' + SQL
|
||||||
|
|
||||||
|
return SQL
|
@ -468,7 +468,52 @@ define('pgadmin.node.table', [
|
|||||||
return tbl_oid;
|
return tbl_oid;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
|
id: 'rlspolicy', label: gettext('RLS Policy?'), cell: 'switch',
|
||||||
|
type: 'switch', mode: ['properties','edit', 'create'],
|
||||||
|
group: gettext('advanced'),
|
||||||
|
visible: function(m) {
|
||||||
|
if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
|
||||||
|
&& !_.isUndefined(m.node_info.server.version) &&
|
||||||
|
m.node_info.server.version >= 90500)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
disabled: function(m) {
|
||||||
|
if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
|
||||||
|
&& !_.isUndefined(m.node_info.server.version) &&
|
||||||
|
m.node_info.server.version < 90500)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return m.inSchema();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'forcerlspolicy', label: gettext('Force RLS Policy?'), cell: 'switch',
|
||||||
|
type: 'switch', mode: ['properties','edit', 'create'], deps: ['rlspolicy'],
|
||||||
|
group: gettext('advanced'),
|
||||||
|
visible: function(m) {
|
||||||
|
if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
|
||||||
|
&& !_.isUndefined(m.node_info.server.version) &&
|
||||||
|
m.node_info.server.version >= 90500)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
disabled: function(m) {
|
||||||
|
if (m.get('rlspolicy')){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setTimeout(function() {
|
||||||
|
m.set('forcerlspolicy', false);
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
id: 'advanced', label: gettext('Advanced'), type: 'group',
|
id: 'advanced', label: gettext('Advanced'), type: 'group',
|
||||||
visible: ShowAdvancedTab.show_advanced_tab,
|
visible: ShowAdvancedTab.show_advanced_tab,
|
||||||
}, {
|
}, {
|
||||||
@ -1202,6 +1247,20 @@ define('pgadmin.node.table', [
|
|||||||
this.errorModel.set('partition_keys', msg);
|
this.errorModel.set('partition_keys', msg);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
if (this.get('rlspolicy') && this.isNew()){
|
||||||
|
Alertify.confirm(
|
||||||
|
gettext('Check Policy?'),
|
||||||
|
gettext('Check if any policy exist. If no policy exists for the table, a default-deny policy is used, meaning that no rows are visible or can be modified'),
|
||||||
|
function() {
|
||||||
|
self.close();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
// Do nothing.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
this.errorModel.unset('partition_keys');
|
this.errorModel.unset('partition_keys');
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
{# CREATE POLICY Statement #}
|
||||||
|
|
||||||
|
-- POLICY: {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }}
|
||||||
|
|
||||||
|
-- DROP POLICY {{ conn|qtIdent(data.name) }} ON {{ conn|qtIdent(data.schema, data.table) }};
|
||||||
|
|
||||||
|
CREATE POLICY {{ data.name }}
|
||||||
|
ON {{conn|qtIdent(data.schema, data.table)}}
|
||||||
|
{% if data.event %}
|
||||||
|
FOR {{ data.event|upper }}
|
||||||
|
{% endif %}
|
||||||
|
{% if data.policyowner %}
|
||||||
|
TO {{ conn|qtTypeIdent(data.policyowner) }}
|
||||||
|
{% else %}
|
||||||
|
TO public
|
||||||
|
{% endif %}
|
||||||
|
{% if data.using %}
|
||||||
|
USING ({{ data.using }})
|
||||||
|
{% endif %}
|
||||||
|
{% if data.withcheck %}
|
||||||
|
WITH CHECK ({{ data.withcheck }})
|
||||||
|
{% endif %};
|
@ -0,0 +1 @@
|
|||||||
|
DROP POLICY {{ conn|qtIdent(policy_name) }} ON {{conn|qtIdent(result.schema, result.table)}};
|
@ -0,0 +1,5 @@
|
|||||||
|
SELECT nsp.nspname AS schema ,rel.relname AS table
|
||||||
|
FROM pg_class rel
|
||||||
|
JOIN pg_namespace nsp
|
||||||
|
ON rel.relnamespace = nsp.oid::oid
|
||||||
|
WHERE rel.oid = {{tid}}::oid
|
@ -0,0 +1,9 @@
|
|||||||
|
{% if plid %}
|
||||||
|
SELECT
|
||||||
|
pl.oid AS oid,
|
||||||
|
pl.polname AS name
|
||||||
|
FROM
|
||||||
|
pg_policy pl
|
||||||
|
WHERE
|
||||||
|
pl.oid = {{ plid }}
|
||||||
|
{% endif %}
|
@ -0,0 +1,2 @@
|
|||||||
|
SELECT pl.oid FROM pg_policy pl
|
||||||
|
WHERE pl.polrelid = {{tid}}::oid AND pl.polname = {{data.name|qtLiteral}};
|
@ -0,0 +1,13 @@
|
|||||||
|
SELECT
|
||||||
|
pl.oid AS oid,
|
||||||
|
pl.polname AS name
|
||||||
|
FROM
|
||||||
|
pg_policy pl
|
||||||
|
WHERE
|
||||||
|
{% if tid %}
|
||||||
|
pl.polrelid = {{ tid }}
|
||||||
|
{% elif plid %}
|
||||||
|
pl.oid = {{ plid }}
|
||||||
|
{% endif %}
|
||||||
|
ORDER BY
|
||||||
|
pl.polname;
|
@ -0,0 +1,19 @@
|
|||||||
|
SELECT
|
||||||
|
pl.oid AS oid,
|
||||||
|
pl.polname AS name,
|
||||||
|
rw.cmd AS event,
|
||||||
|
rw.qual AS using,
|
||||||
|
rw.with_check AS withcheck,
|
||||||
|
array_to_string(rw.roles::name[], ', ') AS policyowner
|
||||||
|
FROM
|
||||||
|
pg_policy pl
|
||||||
|
JOIN pg_policies rw ON pl.polname=rw.policyname
|
||||||
|
WHERE
|
||||||
|
{% if plid %}
|
||||||
|
pl.oid = {{ plid }}
|
||||||
|
{% endif %}
|
||||||
|
{% if tid %}
|
||||||
|
pl.polrelid = {{ tid }}
|
||||||
|
{% endif %};
|
||||||
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
|||||||
|
{#####################################################}
|
||||||
|
{## Change policy owner ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.policyowner and o_data.policyowner != data.policyowner %}
|
||||||
|
ALTER POLICY {{ o_data.name }} ON {{conn|qtIdent(o_data.schema, o_data.table)}}
|
||||||
|
TO {{ conn|qtTypeIdent(data.policyowner) }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Change policy using condition ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.using and o_data.withcheck != data.using %}
|
||||||
|
ALTER POLICY {{ o_data.name }} ON {{conn|qtIdent(o_data.schema, o_data.table)}}
|
||||||
|
USING ({{ data.using }});
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Change policy with check condition ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.withcheck and o_data.withcheck != data.withcheck %}
|
||||||
|
ALTER POLICY {{ o_data.name }} ON {{conn|qtIdent(o_data.schema, o_data.table)}}
|
||||||
|
WITH CHECK ({{ data.withcheck }});
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Change policy name ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.name and o_data.name != data.name %}
|
||||||
|
ALTER POLICY {{ o_data.name }} ON {{conn|qtIdent(o_data.schema, o_data.table)}}
|
||||||
|
RENAME TO {{ conn|qtIdent(data.name) }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
@ -104,6 +104,23 @@ TABLESPACE {{ conn|qtIdent(data.spcname) }};
|
|||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
OWNER to {{conn|qtIdent(data.relowner)}};
|
OWNER to {{conn|qtIdent(data.relowner)}};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{### Security Labels on Table ###}
|
{### Security Labels on Table ###}
|
||||||
{% if data.seclabels and data.seclabels|length > 0 %}
|
{% if data.seclabels and data.seclabels|length > 0 %}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r
|
|||||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
||||||
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
||||||
typ.typrelid AS typoid,
|
typ.typrelid AS typoid, rel.relrowsecurity as rlspolicy, rel.relforcerowsecurity as forcerlspolicy,
|
||||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||||
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
||||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
||||||
|
@ -105,6 +105,23 @@ TABLESPACE {{ conn|qtIdent(data.spcname) }};
|
|||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
OWNER to {{conn|qtIdent(data.relowner)}};
|
OWNER to {{conn|qtIdent(data.relowner)}};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{### Security Labels on Table ###}
|
{### Security Labels on Table ###}
|
||||||
{% if data.seclabels and data.seclabels|length > 0 %}
|
{% if data.seclabels and data.seclabels|length > 0 %}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r
|
|||||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
||||||
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
||||||
typ.typrelid AS typoid,
|
typ.typrelid AS typoid, rel.relrowsecurity as rlspolicy, rel.relforcerowsecurity as forcerlspolicy,
|
||||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||||
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
||||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
||||||
|
@ -212,6 +212,30 @@ COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}}
|
|||||||
IS {{data.description|qtLiteral}};
|
IS {{data.description|qtLiteral}};
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.rlspolicy is defined and data.rlspolicy != o_data.rlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
DISABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.forcerlspolicy is defined and data.forcerlspolicy != o_data.forcerlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
NO FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{#####################################################}
|
{#####################################################}
|
||||||
{## Update table Privileges ##}
|
{## Update table Privileges ##}
|
||||||
{#####################################################}
|
{#####################################################}
|
||||||
|
@ -123,6 +123,23 @@ TABLESPACE {{ conn|qtIdent(data.spcname) }};
|
|||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
OWNER to {{conn|qtIdent(data.relowner)}};
|
OWNER to {{conn|qtIdent(data.relowner)}};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{### Security Labels on Table ###}
|
{### Security Labels on Table ###}
|
||||||
{% if data.seclabels and data.seclabels|length > 0 %}
|
{% if data.seclabels and data.seclabels|length > 0 %}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r
|
|||||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
||||||
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
||||||
typ.typrelid AS typoid,
|
typ.typrelid AS typoid, rel.relrowsecurity as rlspolicy, rel.relforcerowsecurity as forcerlspolicy,
|
||||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||||
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
||||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
||||||
|
@ -50,6 +50,31 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
|||||||
SET TABLESPACE {{conn|qtIdent(data.spcname)}};
|
SET TABLESPACE {{conn|qtIdent(data.spcname)}};
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.rlspolicy is defined and data.rlspolicy != o_data.rlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
DISABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.forcerlspolicy is defined and data.forcerlspolicy != o_data.forcerlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
NO FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{#####################################################}
|
{#####################################################}
|
||||||
{## change fillfactor settings ##}
|
{## change fillfactor settings ##}
|
||||||
{#####################################################}
|
{#####################################################}
|
||||||
|
@ -92,6 +92,24 @@ TABLESPACE {{ conn|qtIdent(data.spcname) }};
|
|||||||
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
OWNER to {{conn|qtIdent(data.relowner)}};
|
OWNER to {{conn|qtIdent(data.relowner)}};
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{### Security Labels on Table ###}
|
{### Security Labels on Table ###}
|
||||||
{% if data.seclabels and data.seclabels|length > 0 %}
|
{% if data.seclabels and data.seclabels|length > 0 %}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS r
|
|||||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, rel.reloftype,
|
||||||
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
CASE WHEN typ.typname IS NOT NULL THEN (select quote_ident(nspname) FROM pg_namespace WHERE oid = {{scid}}::oid )||'.'||quote_ident(typ.typname) ELSE typ.typname END AS typname,
|
||||||
typ.typrelid AS typoid,
|
typ.typrelid AS typoid,rel.relrowsecurity as rlspolicy, rel.relforcerowsecurity as forcerlspolicy,
|
||||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||||
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
|
||||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
||||||
|
@ -42,6 +42,31 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
|||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.rlspolicy is defined and data.rlspolicy != o_data.rlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
DISABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.forcerlspolicy is defined and data.forcerlspolicy != o_data.forcerlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
NO FORCE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{#####################################################}
|
{#####################################################}
|
||||||
{## Change hasOID attribute of table ##}
|
{## Change hasOID attribute of table ##}
|
||||||
{#####################################################}
|
{#####################################################}
|
||||||
|
@ -171,3 +171,18 @@ EXTERNAL{% elif c.attstorage == 'x'%}EXTENDED{% endif %};
|
|||||||
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.foreign_key)}}
|
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.foreign_key)}}
|
||||||
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.check_constraint)}}
|
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.check_constraint)}}
|
||||||
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.exclude_constraint)}}
|
{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.exclude_constraint)}}
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
@ -50,7 +50,7 @@ FROM (
|
|||||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
|
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age,
|
||||||
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age,
|
||||||
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, NULL AS reloftype, NULL AS typname,
|
rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, NULL AS reloftype, NULL AS typname,
|
||||||
typ.typrelid AS typoid,
|
typ.typrelid AS typoid, rel.relrowsecurity as rlspolicy, rel.relforcerowsecurity as forcerlspolicy,
|
||||||
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
(CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable,
|
||||||
ARRAY[]::varchar[] AS seclabels,
|
ARRAY[]::varchar[] AS seclabels,
|
||||||
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
|
||||||
|
@ -125,6 +125,30 @@ ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} RESET (
|
|||||||
);
|
);
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.rlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
ENABLE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.rlspolicy is defined and data.rlspolicy != o_data.rlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
DISABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{#####################################################}
|
||||||
|
{## Force Enable Row Level Security Policy on table ##}
|
||||||
|
{#####################################################}
|
||||||
|
{% if data.forcerlspolicy %}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
FORCE ROW LEVEL SECURITY;
|
||||||
|
{% elif data.forcerlspolicy is defined and data.forcerlspolicy != o_data.forcerlspolicy%}
|
||||||
|
ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
|
||||||
|
NO FORCE ROW LEVEL SECURITY;
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{#####################################}
|
{#####################################}
|
||||||
{## Toast table AutoVacuum settings ##}
|
{## Toast table AutoVacuum settings ##}
|
||||||
{#####################################}
|
{#####################################}
|
||||||
|
@ -42,6 +42,9 @@ from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
|||||||
triggers import utils as trigger_utils
|
triggers import utils as trigger_utils
|
||||||
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
from pgadmin.browser.server_groups.servers.databases.schemas.tables.\
|
||||||
compound_triggers import utils as compound_trigger_utils
|
compound_triggers import utils as compound_trigger_utils
|
||||||
|
from pgadmin.browser.server_groups.servers.databases.schemas. \
|
||||||
|
tables.row_security_policies import \
|
||||||
|
utils as row_security_policies_utils
|
||||||
|
|
||||||
|
|
||||||
class BaseTableView(PGChildNodeView, BasePartitionTable):
|
class BaseTableView(PGChildNodeView, BasePartitionTable):
|
||||||
@ -121,6 +124,10 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
|||||||
self.index_template_path = compile_template_path(
|
self.index_template_path = compile_template_path(
|
||||||
'indexes/sql', server_type, ver)
|
'indexes/sql', server_type, ver)
|
||||||
|
|
||||||
|
# Template for index node
|
||||||
|
self.row_security_policies_template_path = \
|
||||||
|
'row_security_policies/sql/#{0}#'.format(ver)
|
||||||
|
|
||||||
# Template for trigger node
|
# Template for trigger node
|
||||||
self.trigger_template_path = \
|
self.trigger_template_path = \
|
||||||
'triggers/sql/{0}/#{1}#'.format(server_type, ver)
|
'triggers/sql/{0}/#{1}#'.format(server_type, ver)
|
||||||
@ -511,6 +518,33 @@ class BaseTableView(PGChildNodeView, BasePartitionTable):
|
|||||||
|
|
||||||
main_sql.append(index_sql.strip('\n'))
|
main_sql.append(index_sql.strip('\n'))
|
||||||
|
|
||||||
|
"""
|
||||||
|
########################################################
|
||||||
|
# 2) Reverse engineered sql for ROW SECURITY POLICY
|
||||||
|
########################################################
|
||||||
|
"""
|
||||||
|
if self.manager.version >= 90500:
|
||||||
|
SQL = \
|
||||||
|
render_template(
|
||||||
|
"/".join([self.row_security_policies_template_path,
|
||||||
|
'nodes.sql']), tid=tid)
|
||||||
|
status, rset = self.conn.execute_2darray(SQL)
|
||||||
|
if not status:
|
||||||
|
return internal_server_error(errormsg=rset)
|
||||||
|
|
||||||
|
for row in rset['rows']:
|
||||||
|
policy_sql = row_security_policies_utils. \
|
||||||
|
get_reverse_engineered_sql(
|
||||||
|
self.conn, schema, table, did, tid, row['oid'],
|
||||||
|
self.datlastsysoid,
|
||||||
|
template_path=None, with_header=json_resp)
|
||||||
|
policy_sql = u"\n" + policy_sql
|
||||||
|
|
||||||
|
# Add into main sql
|
||||||
|
policy_sql = re.sub('\n{2,}', '\n\n', policy_sql)
|
||||||
|
|
||||||
|
main_sql.append(policy_sql.strip('\n'))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
########################################
|
########################################
|
||||||
# 3) Reverse engineered sql for TRIGGERS
|
# 3) Reverse engineered sql for TRIGGERS
|
||||||
|
@ -460,6 +460,7 @@ module.exports = [{
|
|||||||
',pgadmin.node.type' +
|
',pgadmin.node.type' +
|
||||||
',pgadmin.node.rule' +
|
',pgadmin.node.rule' +
|
||||||
',pgadmin.node.index' +
|
',pgadmin.node.index' +
|
||||||
|
',pgadmin.node.row_security_policy' +
|
||||||
',pgadmin.node.trigger' +
|
',pgadmin.node.trigger' +
|
||||||
',pgadmin.node.catalog_object_column' +
|
',pgadmin.node.catalog_object_column' +
|
||||||
',pgadmin.node.view' +
|
',pgadmin.node.view' +
|
||||||
|
@ -261,6 +261,7 @@ var webpackShimConfig = {
|
|||||||
'pgadmin.node.unique_constraint': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/js/unique_constraint'),
|
'pgadmin.node.unique_constraint': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/static/js/unique_constraint'),
|
||||||
'pgadmin.node.user_mapping': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mappings/static/js/user_mapping'),
|
'pgadmin.node.user_mapping': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mappings/static/js/user_mapping'),
|
||||||
'pgadmin.node.view': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/view'),
|
'pgadmin.node.view': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/view'),
|
||||||
|
'pgadmin.node.row_security_policy': path.join(__dirname, './pgadmin/browser/server_groups/servers/databases/schemas/tables/row_security_policies/static/js/row_security_policy'),
|
||||||
'pgadmin.preferences': path.join(__dirname, './pgadmin/preferences/static/js/preferences'),
|
'pgadmin.preferences': path.join(__dirname, './pgadmin/preferences/static/js/preferences'),
|
||||||
'pgadmin.settings': path.join(__dirname, './pgadmin/settings/static/js/settings'),
|
'pgadmin.settings': path.join(__dirname, './pgadmin/settings/static/js/settings'),
|
||||||
'pgadmin.server.supported_servers': '/browser/server/supported_servers',
|
'pgadmin.server.supported_servers': '/browser/server/supported_servers',
|
||||||
|
Loading…
Reference in New Issue
Block a user