Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1u8IgB-000XMg-Qa for pgsql-general@arkaria.postgresql.org; Fri, 25 Apr 2025 13:01:20 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1u8Ig9-00Ah2M-2U for pgsql-general@arkaria.postgresql.org; Fri, 25 Apr 2025 13:01:17 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1u8Ig8-00Ah2E-MJ for pgsql-general@lists.postgresql.org; Fri, 25 Apr 2025 13:01:17 +0000 Received: from mail-ed1-x532.google.com ([2a00:1450:4864:20::532]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1u8Ig6-0020SW-0V for pgsql-general@lists.postgresql.org; Fri, 25 Apr 2025 13:01:17 +0000 Received: by mail-ed1-x532.google.com with SMTP id 4fb4d7f45d1cf-5f4aee67d24so301410a12.0 for ; Fri, 25 Apr 2025 06:01:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1745586074; x=1746190874; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=WFv9Z1E6XtaZPNqp8tbTiCB6x/iM1GpxN/dbvSFo9DU=; b=SyOdfD0bx9ZkS3Pn3TaHjF5o/vLPNQB9n5oZRhg7vdtS7uP45WGOD3De+utKqRd4Sc NIec7F6YaemVr4anl+4Ua+bO8miBfLx2EUHJbwa+UwwHMu5VXo6Cn42PyeAe9d+SAdP7 0e1odeA6+X/QbraXfudChVnhSvY/RPWN58G8sIfhD9E9nGKG8IyVph+pLhfUhN5RD6tg MNxLn8C0MvmRS/mUSQc77IonZ9JWF5UgxEoNKbsvZ9386BD8hgCfUGt0wH/4VlawCeOg PgfQZCz6kESKY7qorOU9wukM5H5aRjQT6EXAbyYRawgwMjKGOpSuChQ3ymqBApl+fxGm 2d+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745586074; x=1746190874; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=WFv9Z1E6XtaZPNqp8tbTiCB6x/iM1GpxN/dbvSFo9DU=; b=gZYGrUUggMG/li6Nk38du/ebwpRxpPGTtkzVzHsOpxkm7ubIyPEGYoeVlXLjlDFmWO IBIoEV7O+Gp6YE11uzlxBzMxGlm0e+VRPASYk0N8dbLI0nVgkWVMmWb6SbC9izz6luoy 9C08UH+DmbKaerLbtBtWYvRklPLWzpLxg5rDWTxv4x7oMpQ4jMo+aqvRU9InUF7fXN02 bkxCBbIu6JKd7qw0AEwSjyiWPkFedFbJFNuM+ln7iEbBKdvvkwEsdoxxPXnZv8mPHi/e eT/YNW5tIq512jKtiXpO3gRH8MOIHJ0OE/Vwfarn/l9I3SsOwY7cFTq77hZkL+daJ28s dVMw== X-Forwarded-Encrypted: i=1; AJvYcCXqU1QnW1LXaUNyrhZp2MjFmjWMJD48LFm8Yk9+z0H7T7JRC925DCeCjuG/2RfRMPzKAAaKkDfgqC+sIwHD@lists.postgresql.org X-Gm-Message-State: AOJu0Yxlb/4MixCE3whV0k/qzIj98j1RFRaGlHNcU7plXWaJ77XeKicM tfru1DJ4yAtJWtDiO63IKsSJmpghSrBjsFsh74mFwAkhu6f2dMgMAbUfsKDrBTgROQ6ZBpALnbn 0zDF6KtaKDwcqz3csaCExlgUtsac= X-Gm-Gg: ASbGncuztKVAH419/6nKw/Y+oKcuMWRrz6wBs2vA+aOoSZDo9uIuBpqmkE6CsauLXiu tg07LnMGceSRo3cFixCXcceYqptxw3LGtfBbIVQXDwsNLPg/VWGuGmAepGGcDsxi0RytvE1NYi/ ao1tfqKQ2GlVA4Sc3I8EXm2g== X-Google-Smtp-Source: AGHT+IGA5xJOuO4ufaCkM/ZuJ3N9ME9AO/NKHhyepo0Sg5HbljYS7/UD5yzq9rfwjxhzptMxSVyq65IEuG9pbSXZvLc= X-Received: by 2002:a17:907:3f22:b0:ac7:3911:2510 with SMTP id a640c23a62f3a-ace713bfd19mr75498966b.15.1745586073275; Fri, 25 Apr 2025 06:01:13 -0700 (PDT) MIME-Version: 1.0 References: <88804c921b425d37a3072b5698b558a763d80d63.camel@cybertec.at> In-Reply-To: From: Vydehi Ganti Date: Fri, 25 Apr 2025 18:31:00 +0530 X-Gm-Features: ATxdqUHo8smGdXDsAzWMNCXYXd-dCU4oMdwp9eAdozJpDifKb2eJWA6J-L-Rbwc Message-ID: Subject: Re: Clarification on RLS policy To: Dominique Devienne Cc: Laurenz Albe , pgsql-general@lists.postgresql.org Content-Type: multipart/alternative; boundary="000000000000d29256063399ed5c" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000d29256063399ed5c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable This is my Scenario: I would need a policy on table Activity which has a column country_code . In the policy i would need to call a function get_country as below which queries the users table based on current user and checks which country code that user has access to. Then it should build up the lPredicate with the filter condition and append to the query user runs on the Activity table. *Can you please guide how to achieve this?* CREATE OR REPLACE FUNCTION one.get_country( powner name, ptable_name name) RETURNS character varying LANGUAGE 'plpgsql' COST 100 STABLE PARALLEL UNSAFE AS $BODY$ DECLARE lOSUser varchar(4000) :=3D UPPER(SUBSTRING(current_user FROM POSITION('\' IN current_user) + 1)); lPredicate varchar(4000) :=3D NULL; lCount integer; i RECORD; BEGIN IF position('ro' in current_user) =3D 0 THEN lPredicate :=3D '1=3D1'; ELSE -- Users associated to explicit country_code FOR i IN (SELECT r.country_code AS country_code FROM one.users u where UPPER(SUBSTR(u.Login, INSTR(u.Login, '\', -1) + 1)) =3D lOSUser ) WHERE u.role_type =3D 'reader') LOOP lPredicate :=3D lPredicate||''''||i.country_code||''','; END LOOP; IF lPredicate IS NOT NULL THEN lPredicate :=3D 'SUBSTR("id",1,3) IN ('||SUBSTR(lPredicate, 1, LENGTH(lPredicate)-1)||')'; ELSE lPredicate :=3D '1=3D1'; END IF; END IF; RETURN lPredicate; END; $BODY$; For the below policy statement it created the policy but i cant call that CREATE POLICY "Codebase_Filter" ON one.activity FOR SELECT TO one USING (one.get_country('one','activity')); On Fri, Apr 25, 2025 at 6:23=E2=80=AFPM Dominique Devienne wrote: > On Fri, Apr 25, 2025 at 2:43=E2=80=AFPM Laurenz Albe > wrote: > > On Fri, 2025-04-25 at 12:38 +0530, Vydehi Ganti wrote: > > > We are presently using Postgresql:PostgreSQL 15.12 on > x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat > 8.5.0-23), 64-bit > > > 2.The function would return a character varying string which should b= e > appended > > > to the select as a filter. > > > > You cannot add whole WHERE conditions to a query dynamically. > > The only way to fix that is to solve the problem differently. > > Since you didn't tell us details, we cannot tell you how. > > Laurenz is right. That's not how RLS works in PostgreSQL, unlike Oracle. > In PostgreSQL, you must use a boolean SQL expression, often by calling > a function. > You don't simply return some SQL text that Oracle then "splices" into > the SELECT. > > E.g., if you use custom ROLEs as an implementation detail for your > security rules, > your policy can be as simple as calling the pg_has_role() built-in > function. FWIW. --DD > > CREATE POLICY ... USING (pg_has_role('SomeRole', 'MEMBER')) > --000000000000d29256063399ed5c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
This is my Scenario:

I would need a policy on table= Activity which has a column country_code .
In the policy i would need t= o call a function get_country as below which queries the users table based = on current user and checks which country code that user has access to.
T= hen it should build up the lPredicate with the filter condition and append = to the query user runs on the Activity table.
Can you please guide ho= w to achieve this?

CREATE OR REPLACE FUNCTION one.get_country( powner name,
ptable_name name)
=C2=A0 =C2=A0 RETURNS character va= rying
LANGUAGE 'plpgsql'
=C2=A0 =C2=A0 COST 100
=C2=A0 = =C2=A0 STABLE PARALLEL UNSAFE
AS $BODY$
DECLARE

=C2=A0 =C2=A0 = lOSUser =C2=A0 =C2=A0 =C2=A0 =C2=A0 varchar(4000) :=3D UPPER(SUBSTRING(curr= ent_user FROM POSITION('\' IN current_user) + 1));
=C2=A0 =C2=A0= lPredicate =C2=A0 =C2=A0 =C2=A0varchar(4000) :=3D NULL;
=C2=A0 =C2=A0 l= Count =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0integer;

=C2=A0 i RECORD;
BEGIN
=C2=A0 =C2=A0 IF position('ro' in current_user) =3D 0= THEN
=C2=A0 =C2=A0 =C2=A0 =C2=A0 lPredicate :=3D '1=3D1';
= =C2=A0 =C2=A0 ELSE
=C2=A0 =C2=A0 =C2=A0 =C2=A0 -- Users associated to ex= plicit country_code
=C2=A0 =C2=A0 =C2=A0 =C2=A0 FOR i IN (SELECT r.count= ry_code AS country_code
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 FROM one.users =C2=A0u
=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 where UPPER(SUBSTR= (u.Login, INSTR(u.Login, '\', -1) + 1)) =3D lOSUser )
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 WHERE u.role= _type =3D 'reader') LOOP
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 lPredicate :=3D lPredicate||''''||i.country_code||'= '',';
=C2=A0 =C2=A0 =C2=A0 =C2=A0 END LOOP;

=C2=A0 = =C2=A0 =C2=A0 =C2=A0 IF lPredicate IS NOT NULL THEN
=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 lPredicate :=3D 'SUBSTR("id",1,3) IN (&= #39;||SUBSTR(lPredicate, 1, LENGTH(lPredicate)-1)||')';
=C2=A0 = =C2=A0 =C2=A0 =C2=A0 ELSE
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 lPre= dicate :=3D '1=3D1';
=C2=A0 =C2=A0 =C2=A0 =C2=A0 END IF;
=C2= =A0 =C2=A0 END IF;

=C2=A0 =C2=A0 RETURN lPredicate;

END;
$= BODY$;

For the below policy statement it created the policy but i ca= nt call that
CREATE POLICY "Codebase_Filter"
=C2=A0 =C2=A0 = ON one.activity
=C2=A0 =C2=A0 FOR SELECT
=C2=A0 =C2=A0 TO one
=C2= =A0 =C2=A0 USING (one.get_country('one','activity'));
=
On Fri, Apr 25, 2025 at 6:23=E2=80=AFPM Dominique Devienne = <ddevienne@gmail.com> wrot= e:
On Fri, Apr 2= 5, 2025 at 2:43=E2=80=AFPM Laurenz Albe <laurenz.albe@cybertec.at> wrote:
> On Fri, 2025-04-25 at 12:38 +0530, Vydehi Ganti wrote:
> > We are presently using Postgresql:PostgreSQL 15.12 on x86_64-pc-l= inux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-23), 64-bit > > 2.The function would return a character varying string which shou= ld be appended
> >=C2=A0 =C2=A0to the select as a filter.
>
> You cannot add whole WHERE conditions to a query dynamically.
> The only way to fix that is to solve the problem differently.
> Since you didn't tell us details, we cannot tell you how.

Laurenz is right. That's not how RLS works in PostgreSQL, unlike Oracle= .
In PostgreSQL, you must use a boolean SQL expression, often by calling
a function.
You don't simply return some SQL text that Oracle then "splices&qu= ot; into
the SELECT.

E.g., if you use custom ROLEs as an implementation detail for your
security rules,
your policy can be as simple as calling the pg_has_role() built-in
function. FWIW. --DD

CREATE POLICY ... USING (pg_has_role('SomeRole', 'MEMBER'))=
--000000000000d29256063399ed5c--