mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
This module overlooked this necessary fixup step on the results of transformWhereClause(). It accidentally worked anyway, because the constructed expression involved type "name" which is not collatable, but it fell over while I was experimenting with changing "name" to be collatable. Back-patch, not because there's any live bug here in back branches, but because somebody might use this code as a model for some real application and then not understand why it doesn't work.
181 lines
5.0 KiB
C
181 lines
5.0 KiB
C
/*--------------------------------------------------------------------------
|
|
*
|
|
* test_rls_hooks.c
|
|
* Code for testing RLS hooks.
|
|
*
|
|
* Copyright (c) 2015-2018, PostgreSQL Global Development Group
|
|
*
|
|
* IDENTIFICATION
|
|
* src/test/modules/test_rls_hooks/test_rls_hooks.c
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "fmgr.h"
|
|
#include "miscadmin.h"
|
|
|
|
#include "test_rls_hooks.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "nodes/makefuncs.h"
|
|
#include "parser/parse_clause.h"
|
|
#include "parser/parse_collate.h"
|
|
#include "parser/parse_node.h"
|
|
#include "parser/parse_relation.h"
|
|
#include "rewrite/rowsecurity.h"
|
|
#include "utils/acl.h"
|
|
#include "utils/rel.h"
|
|
#include "utils/relcache.h"
|
|
|
|
PG_MODULE_MAGIC;
|
|
|
|
/* Saved hook values in case of unload */
|
|
static row_security_policy_hook_type prev_row_security_policy_hook_permissive = NULL;
|
|
static row_security_policy_hook_type prev_row_security_policy_hook_restrictive = NULL;
|
|
|
|
void _PG_init(void);
|
|
void _PG_fini(void);
|
|
|
|
/* Install hooks */
|
|
void
|
|
_PG_init(void)
|
|
{
|
|
/* Save values for unload */
|
|
prev_row_security_policy_hook_permissive = row_security_policy_hook_permissive;
|
|
prev_row_security_policy_hook_restrictive = row_security_policy_hook_restrictive;
|
|
|
|
/* Set our hooks */
|
|
row_security_policy_hook_permissive = test_rls_hooks_permissive;
|
|
row_security_policy_hook_restrictive = test_rls_hooks_restrictive;
|
|
}
|
|
|
|
/* Uninstall hooks */
|
|
void
|
|
_PG_fini(void)
|
|
{
|
|
row_security_policy_hook_permissive = prev_row_security_policy_hook_permissive;
|
|
row_security_policy_hook_restrictive = prev_row_security_policy_hook_restrictive;
|
|
}
|
|
|
|
/*
|
|
* Return permissive policies to be added
|
|
*/
|
|
List *
|
|
test_rls_hooks_permissive(CmdType cmdtype, Relation relation)
|
|
{
|
|
List *policies = NIL;
|
|
RowSecurityPolicy *policy = palloc0(sizeof(RowSecurityPolicy));
|
|
Datum role;
|
|
FuncCall *n;
|
|
Node *e;
|
|
ColumnRef *c;
|
|
ParseState *qual_pstate;
|
|
RangeTblEntry *rte;
|
|
|
|
if (strcmp(RelationGetRelationName(relation), "rls_test_permissive")
|
|
&& strcmp(RelationGetRelationName(relation), "rls_test_both"))
|
|
return NIL;
|
|
|
|
qual_pstate = make_parsestate(NULL);
|
|
|
|
rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
|
|
NULL, false, false);
|
|
addRTEtoQuery(qual_pstate, rte, false, true, true);
|
|
|
|
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
|
|
|
|
policy->policy_name = pstrdup("extension policy");
|
|
policy->polcmd = '*';
|
|
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i');
|
|
|
|
/*
|
|
* policy->qual = (Expr *) makeConst(BOOLOID, -1, InvalidOid,
|
|
* sizeof(bool), BoolGetDatum(true), false, true);
|
|
*/
|
|
|
|
n = makeFuncCall(list_make2(makeString("pg_catalog"),
|
|
makeString("current_user")), NIL, 0);
|
|
|
|
c = makeNode(ColumnRef);
|
|
c->fields = list_make1(makeString("username"));
|
|
c->location = 0;
|
|
|
|
e = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) n, (Node *) c, 0);
|
|
|
|
policy->qual = (Expr *) transformWhereClause(qual_pstate, copyObject(e),
|
|
EXPR_KIND_POLICY,
|
|
"POLICY");
|
|
/* Fix up collation information */
|
|
assign_expr_collations(qual_pstate, (Node *) policy->qual);
|
|
|
|
policy->with_check_qual = copyObject(policy->qual);
|
|
policy->hassublinks = false;
|
|
|
|
policies = list_make1(policy);
|
|
|
|
return policies;
|
|
}
|
|
|
|
/*
|
|
* Return restrictive policies to be added
|
|
*
|
|
* Note that a permissive policy must exist or the default-deny policy
|
|
* will be included and nothing will be visible. If no filtering should
|
|
* be done except for the restrictive policy, then a single "USING (true)"
|
|
* permissive policy can be used; see the regression tests.
|
|
*/
|
|
List *
|
|
test_rls_hooks_restrictive(CmdType cmdtype, Relation relation)
|
|
{
|
|
List *policies = NIL;
|
|
RowSecurityPolicy *policy = palloc0(sizeof(RowSecurityPolicy));
|
|
Datum role;
|
|
FuncCall *n;
|
|
Node *e;
|
|
ColumnRef *c;
|
|
ParseState *qual_pstate;
|
|
RangeTblEntry *rte;
|
|
|
|
|
|
if (strcmp(RelationGetRelationName(relation), "rls_test_restrictive")
|
|
&& strcmp(RelationGetRelationName(relation), "rls_test_both"))
|
|
return NIL;
|
|
|
|
qual_pstate = make_parsestate(NULL);
|
|
|
|
rte = addRangeTableEntryForRelation(qual_pstate, relation, AccessShareLock,
|
|
NULL, false, false);
|
|
addRTEtoQuery(qual_pstate, rte, false, true, true);
|
|
|
|
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
|
|
|
|
policy->policy_name = pstrdup("extension policy");
|
|
policy->polcmd = '*';
|
|
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true, 'i');
|
|
|
|
n = makeFuncCall(list_make2(makeString("pg_catalog"),
|
|
makeString("current_user")), NIL, 0);
|
|
|
|
c = makeNode(ColumnRef);
|
|
c->fields = list_make1(makeString("supervisor"));
|
|
c->location = 0;
|
|
|
|
e = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", (Node *) n, (Node *) c, 0);
|
|
|
|
policy->qual = (Expr *) transformWhereClause(qual_pstate, copyObject(e),
|
|
EXPR_KIND_POLICY,
|
|
"POLICY");
|
|
/* Fix up collation information */
|
|
assign_expr_collations(qual_pstate, (Node *) policy->qual);
|
|
|
|
policy->with_check_qual = copyObject(policy->qual);
|
|
policy->hassublinks = false;
|
|
|
|
policies = list_make1(policy);
|
|
|
|
return policies;
|
|
}
|