Advertisement
Guest User

Untitled

a guest
Jun 20th, 2024
260
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PL/SQL 4.59 KB | Source Code | 0 0
  1. ROLLBACK;
  2. BEGIN transaction;
  3.  
  4. -- setup a role which cannot bypass rls
  5. CREATE role authenticated;
  6. grant usage ON schema PUBLIC TO authenticated;
  7.  
  8. ALTER DEFAULT privileges IN schema PUBLIC grant SELECT ON tables TO authenticated;
  9.  
  10. -- helper function to get user id
  11. CREATE FUNCTION getUserId()
  12.     returns int
  13.     stable strict parallel safe leakproof
  14. BEGIN atomic;
  15.     RETURN current_setting('app.user_id')::int;
  16. END;
  17.  
  18. -- users table
  19. CREATE TABLE users (
  20.     id int primary key generated always AS identity,
  21.     name text
  22. );
  23.  
  24. -- permission table
  25. CREATE TABLE permissions (
  26.     id int primary key generated always AS identity,
  27.     user_id int references users(id),
  28.     can_access_assets BOOLEAN
  29. );
  30. CREATE INDEX ON permissions (user_id);
  31. CREATE INDEX ON permissions (user_id, can_access_assets);
  32.  
  33. -- assets table
  34. CREATE TABLE assets (
  35.     id int primary key generated always AS identity,
  36.     owner_id int references users(id),
  37.     url text
  38. );
  39. CREATE INDEX ON assets (owner_id);
  40.  
  41. -- setup rls for assets
  42. ALTER TABLE assets enable ROW LEVEL security;
  43. CREATE policy assets_policy ON assets FOR ALL using (
  44.     EXISTS (
  45.         SELECT 1
  46.         FROM permissions p
  47.         WHERE p.user_id = getUserId() AND p.can_access_assets
  48.     ) AND (
  49.         owner_id IS NULL OR
  50.         owner_id = getUserId()
  51.     )
  52. );
  53.  
  54. -- insert example users
  55. INSERT INTO users (name) VALUES
  56.     ('Alice can access assets'),
  57.     ('Bob cannot access assets');
  58.  
  59. -- insert example assets using generate_series
  60. INSERT INTO assets (owner_id, url)
  61. SELECT
  62.     FLOOR(random() * 2 + 1),
  63.     'http://example.com/asset/' || i
  64. FROM generate_series(1, 1000000) AS i;
  65.  
  66. -- set user id (eg. from session)
  67. SET local app.user_id = '1';
  68.  
  69. -- query as superuser with bypassrls
  70. explain analyze
  71. SELECT COUNT(*) FROM assets
  72. WHERE (
  73.     EXISTS (
  74.         SELECT 1
  75.         FROM permissions p
  76.         WHERE p.user_id = 1 AND p.can_access_assets
  77.     ) AND (
  78.         owner_id IS NULL OR
  79.         owner_id = 1
  80.     )
  81. );
  82. /*
  83. Aggregate  (cost=9029.74..9029.75 rows=1 width=8) (actual time=0.016..0.017 rows=1 loops=1)
  84.   InitPlan 1 (returns $0)
  85.     ->  Index Only Scan using permissions_user_id_can_access_assets_idx on permissions p  (cost=0.15..24.27 rows=6 width=0) (actual time=0.003..0.003 rows=0 loops=1)
  86.           Index Cond: ((user_id = 1) AND (can_access_assets = true))
  87.           Heap Fetches: 0
  88.   ->  Result  (cost=112.84..9000.63 rows=9976 width=0) (actual time=0.004..0.004 rows=0 loops=1)
  89.         One-Time Filter: $0
  90.         ->  Bitmap Heap Scan on assets  (cost=112.84..9000.63 rows=9976 width=0) (never executed)
  91.               Recheck Cond: ((owner_id IS NULL) OR (owner_id = 1))
  92.               ->  BitmapOr  (cost=112.84..112.84 rows=10001 width=0) (never executed)
  93.                     ->  Bitmap Index Scan on assets_owner_id_idx  (cost=0.00..53.92 rows=5000 width=0) (never executed)
  94.                           Index Cond: (owner_id IS NULL)
  95.                     ->  Bitmap Index Scan on assets_owner_id_idx  (cost=0.00..53.92 rows=5000 width=0) (never executed)
  96.                           Index Cond: (owner_id = 1)
  97. Planning Time: 0.206 ms
  98. Execution Time: 0.038 ms
  99. */
  100.  
  101. -- perform query as authenticated user with rls
  102. SET local role authenticated;
  103.  
  104. explain analyze
  105. SELECT COUNT(*) FROM assets;
  106. /*
  107. Aggregate  (cost=9089.80..9089.81 rows=1 width=8) (actual time=34.791..34.794 rows=1 loops=1)
  108.   InitPlan 1 (returns $0)
  109.     ->  Index Only Scan using permissions_user_id_can_access_assets_idx on permissions p  (cost=0.16..24.28 rows=6 width=0) (actual time=0.004..0.004 rows=0 loops=1)
  110.           Index Cond: ((user_id = (current_setting('app.user_id'::text))::integer) AND (can_access_assets = true))
  111.           Heap Fetches: 0
  112.   ->  Bitmap Heap Scan on assets  (cost=110.35..9073.15 rows=4988 width=0) (actual time=34.787..34.789 rows=0 loops=1)
  113.         Recheck Cond: ((owner_id IS NULL) OR (owner_id = (current_setting('app.user_id'::text))::integer))
  114.         Filter: $0
  115.         Rows Removed by Filter: 499840
  116.         Heap Blocks: exact=8334
  117.         ->  BitmapOr  (cost=110.35..110.35 rows=10001 width=0) (actual time=7.306..7.308 rows=0 loops=1)
  118.               ->  Bitmap Index Scan on assets_owner_id_idx  (cost=0.00..53.92 rows=5000 width=0) (actual time=0.005..0.005 rows=0 loops=1)
  119.                     Index Cond: (owner_id IS NULL)
  120.               ->  Bitmap Index Scan on assets_owner_id_idx  (cost=0.00..53.93 rows=5000 width=0) (actual time=7.301..7.301 rows=499840 loops=1)
  121.                     Index Cond: (owner_id = (current_setting('app.user_id'::text))::integer)
  122. Planning Time: 0.080 ms
  123. Execution Time: 34.815 ms
  124. */
  125.  
  126. ROLLBACK;
  127.  
Tags: postgresql
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement