From 5583f4e5a81ddc51526e3186c92ea55e74b7db5e Mon Sep 17 00:00:00 2001 From: trogers1884 Date: Sat, 19 Apr 2025 10:53:26 -0500 Subject: [PATCH] Refactor to simplified structure --- README.md | 44 +++++----- USAGE.md | 235 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 167 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index 00adbc2..233714f 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,35 @@ -c77_rbac PostgreSQL Extension -The c77_rbac extension provides role-based access control (RBAC) for PostgreSQL, securing tables with row-level security (RLS) for multi-campus applications. All objects are in the public schema with c77_rbac_ prefixes (e.g., c77_rbac_subjects, c77_rbac_apply_policy) to coexist with Laravel and third-party packages. Application tables use custom schemas (e.g., myapp.orders). -Features +# c77_rbac PostgreSQL Extension -Scoped role assignments (e.g., campus-specific access). -Admin access via global/all scope for any user ID. -RLS policies via c77_rbac_apply_policy. -Compatible with PostgreSQL 14+ and Laravel. +The `c77_rbac` extension provides role-based access control (RBAC) for PostgreSQL, securing tables with row-level security (RLS) for multi-campus applications. All objects are in the `public` schema with `c77_rbac_` prefixes (e.g., `c77_rbac_subjects`, `c77_rbac_apply_policy`) to coexist with Laravel and third-party packages. Application tables use custom schemas (e.g., `myapp.orders`). -Installation +## Features -Ensure PostgreSQL 14 or later is installed. +- Scoped role assignments (e.g., campus-specific access). +- Admin access via `global/all` scope for any user ID. +- RLS policies via `c77_rbac_apply_policy`. +- Compatible with PostgreSQL 14+ and Laravel. -Place c77_rbac.control and c77_rbac--1.1.0.sql in /usr/share/postgresql/17/extension/. +## Installation -Run as a superuser: -CREATE EXTENSION c77_rbac SCHEMA public; +1. Ensure PostgreSQL 14 or later is installed. +2. Place `c77_rbac.control` and `c77_rbac--1.1.0.sql` in `/usr/share/postgresql/17/extension/`. +3. Run as a superuser: -Usage -See USAGE.md for beginner-friendly instructions on securing tables and assigning roles. -Requirements + ```sql + CREATE EXTENSION c77_rbac SCHEMA public; + ``` -PostgreSQL 14 or later. -Superuser access for installation. +## Usage -License -MIT License +See `USAGE.md` for beginner-friendly instructions on securing tables and assigning roles. + +## Requirements + +- PostgreSQL 14 or later. +- Superuser access for installation. + +## License + +MIT License \ No newline at end of file diff --git a/USAGE.md b/USAGE.md index c0ff08e..b1d4c15 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,150 +1,199 @@ -c77_rbac Usage Guide -This guide helps beginner developers use the c77_rbac PostgreSQL extension to secure database tables with role-based access control (RBAC). All tables and functions are in the public schema with c77_rbac_ prefixes (e.g., c77_rbac_subjects, c77_rbac_apply_policy) to avoid conflicts with Laravel or other packages. Your application tables should use custom schemas (e.g., myapp.orders). -What is c77_rbac? -c77_rbac uses row-level security (RLS) to control table access. For example, a Chicago manager sees only Chicago orders, while an admin sees all orders. Admin rights use a global/all scope, so any user ID (e.g., '2', '999') can be an admin. -Prerequisites +# c77_rbac Usage Guide -PostgreSQL 14 or later. -A superuser (e.g., homestead) for installation. -A database (e.g., c77_rbac_test). -Basic SQL knowledge. +This guide helps beginner developers use the `c77_rbac` PostgreSQL extension to secure database tables with role-based access control (RBAC). All tables and functions are in the `public` schema with `c77_rbac_` prefixes (e.g., `c77_rbac_subjects`, `c77_rbac_apply_policy`) to avoid conflicts with Laravel or other packages. Your application tables should use custom schemas (e.g., `myapp.orders`). -Step 1: Install the Extension +## What is c77_rbac? -Log in as the superuser: -psql -h 192.168.49.115 -p 5432 -U homestead -d c77_rbac_test +`c77_rbac` uses row-level security (RLS) to control table access. For example, a Chicago manager sees only Chicago orders, while an admin sees all orders. Admin rights use a `global/all` scope, so any user ID (e.g., `'2'`, `'999'`) can be an admin. +## Prerequisites -Create the extension: -CREATE EXTENSION c77_rbac SCHEMA public; +- PostgreSQL 14 or later. +- A superuser (e.g., `homestead`) for installation. +- A database (e.g., `c77_rbac_test`). +- Basic SQL knowledge. -This sets up c77_rbac_ tables and functions in public. +## Step 1: Install the Extension -Exit: -\q +1. **Log in as the superuser**: + ```bash + psql -h 192.168.49.115 -p 5432 -U homestead -d c77_rbac_test + ``` +2. **Create the extension**: -Step 2: Set Up Your Application Schema -Use a custom schema (e.g., myapp) for your tables. + ```sql + CREATE EXTENSION c77_rbac SCHEMA public; + ``` -Log in as your application user (e.g., app_user): -psql -h 192.168.49.115 -p 5432 -U app_user -d c77_rbac_test + This sets up `c77_rbac_` tables and functions in `public`. +3. **Exit**: -Create the myapp schema: -CREATE SCHEMA myapp; + ```sql + \q + ``` +## Step 2: Set Up Your Application Schema -Create a test table: -CREATE TABLE myapp.orders ( -id SERIAL PRIMARY KEY, -campus TEXT NOT NULL, -amount NUMERIC -); +Use a custom schema (e.g., `myapp`) for your tables. +1. **Log in as your application user** (e.g., `app_user`): -Insert test data: -INSERT INTO myapp.orders (campus, amount) VALUES ('chicago', 500), ('miami', 1500); + ```bash + psql -h 192.168.49.115 -p 5432 -U app_user -d c77_rbac_test + ``` +2. **Create the myapp schema**: + ```sql + CREATE SCHEMA myapp; + ``` -Step 3: Apply Row-Level Security (RLS) +3. **Create a test table**: -Apply an RLS policy: -SELECT public.c77_rbac_apply_policy('myapp.orders', 'view_sales_page', 'campus', 'campus'); + ```sql + CREATE TABLE myapp.orders ( + id SERIAL PRIMARY KEY, + campus TEXT NOT NULL, + amount NUMERIC + ); + ``` +4. **Insert test data**: -myapp.orders: Table to secure. -view_sales_page: Required permission. -campus: Scope type. -campus: Column for scope (e.g., chicago). + ```sql + INSERT INTO myapp.orders (campus, amount) VALUES ('chicago', 500), ('miami', 1500); + ``` -A NOTICE: policy "c77_rbac_policy" ... does not exist is normal for new tables. +## Step 3: Apply Row-Level Security (RLS) -Check the policy: -\dp myapp.orders +1. **Apply an RLS policy**: -Expect c77_rbac_policy with: -c77_rbac_can_access('view_sales_page'::text, current_setting('c77_rbac.external_id'::text, true), 'campus'::text, campus) + ```sql + SELECT public.c77_rbac_apply_policy('myapp.orders', 'view_sales_page', 'campus', 'campus'); + ``` + - `myapp.orders`: Table to secure. + - `view_sales_page`: Required permission. + - `campus`: Scope type. + - `campus`: Column for scope (e.g., `chicago`). + A `NOTICE: policy "c77_rbac_policy" ... does not exist` is normal for new tables. -Step 4: Assign Roles to Users -Users have an external_id (e.g., '1', '2'). Admin rights use global/all. +2. **Check the policy**: -Assign a sales manager role (Chicago): -SELECT public.c77_rbac_assign_subject('1', 'sales_manager', 'campus', 'chicago'); -SELECT public.c77_rbac_grant_feature('sales_manager', 'view_sales_page'); + ```sql + \dp myapp.orders + ``` + Expect `c77_rbac_policy` with: -Assign an admin role (all data): -SELECT public.c77_rbac_assign_subject('999', 'admin', 'global', 'all'); -SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page'); + ``` + c77_rbac_can_access('view_sales_page'::text, current_setting('c77_rbac.external_id'::text, true), 'campus'::text, campus) + ``` -For another admin (e.g., '2'): -SELECT public.c77_rbac_assign_subject('2', 'admin', 'global', 'all'); -SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page'); +## Step 4: Assign Roles to Users +Users have an `external_id` (e.g., `'1'`, `'2'`). Admin rights use `global/all`. +1. **Assign a sales manager role** (Chicago): -Step 5: Test Access + ```sql + SELECT public.c77_rbac_assign_subject('1', 'sales_manager', 'campus', 'chicago'); + SELECT public.c77_rbac_grant_feature('sales_manager', 'view_sales_page'); + ``` -Chicago manager: -SET "c77_rbac.external_id" TO '1'; -SELECT * FROM myapp.orders; +2. **Assign an admin role** (all data): -Expected: -id | campus | amount -----+---------+-------- -1 | chicago | 500 + ```sql + SELECT public.c77_rbac_assign_subject('999', 'admin', 'global', 'all'); + SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page'); + ``` + For another admin (e.g., `'2'`): -Admin (e.g., '2'): -SET "c77_rbac.external_id" TO '2'; -SELECT * FROM myapp.orders; + ```sql + SELECT public.c77_rbac_assign_subject('2', 'admin', 'global', 'all'); + SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page'); + ``` -Expected: -id | campus | amount -----+---------+-------- -1 | chicago | 500 -2 | miami | 1500 +## Step 5: Test Access +1. **Chicago manager**: -Unauthorized user: -SET "c77_rbac.external_id" TO 'unknown'; -SELECT * FROM myapp.orders; + ```sql + SET "c77_rbac.external_id" TO '1'; + SELECT * FROM myapp.orders; + ``` -Expected: -id | campus | amount -----+--------+-------- + **Expected**: + ``` + id | campus | amount + ----+---------+-------- + 1 | chicago | 500 + ``` +2. **Admin** (e.g., `'2'`): + + ```sql + SET "c77_rbac.external_id" TO '2'; + SELECT * FROM myapp.orders; + ``` + + **Expected**: + + ``` + id | campus | amount + ----+---------+-------- + 1 | chicago | 500 + 2 | miami | 1500 + ``` + +3. **Unauthorized user**: + + ```sql + SET "c77_rbac.external_id" TO 'unknown'; + SELECT * FROM myapp.orders; + ``` + + **Expected**: + + ``` + id | campus | amount + ----+--------+-------- + ``` + +## Step 6: Use in Your Application -Step 6: Use in Your Application For Laravel: -Set user ID: -DB::statement("SET c77_rbac.external_id TO '1'"); +1. **Set user ID**: + ```php + DB::statement("SET c77_rbac.external_id TO '1'"); + ``` -Query: -SELECT * FROM myapp.orders; +2. **Query**: + ```sql + SELECT * FROM myapp.orders; + ``` +## Troubleshooting -Troubleshooting +- **No rows**: Check role (`c77_rbac_assign_subject`) and feature (`c77_rbac_grant_feature`). +- **Policy missing**: Verify `\dp myapp.orders`. Re-run `c77_rbac_apply_policy`. +- **NOTICE messages**: Normal for new tables. +- **Display quirk**: `\dp` may show `campus` instead of `myapp.orders.campus`. This is cosmetic. -No rows: Check role (c77_rbac_assign_subject) and feature (c77_rbac_grant_feature). -Policy missing: Verify \dp myapp.orders. Re-run c77_rbac_apply_policy. -NOTICE messages: Normal for new tables. -Display quirk: \dp may show campus instead of myapp.orders.campus. This is cosmetic. +## Notes -Notes +- Use `schema.table` (e.g., `myapp.orders`) with `c77_rbac_apply_policy`. +- `public` is for `c77_rbac_`, Laravel, and third-party packages. Use `myapp` for app tables. +- `c77_rbac_` tables are accessible to all database users. Manage roles responsibly. +- This covers `c77_rbac` only, not `c77_rbac_laravel`. -Use schema.table (e.g., myapp.orders) with c77_rbac_apply_policy. -public is for c77_rbac_, Laravel, and third-party packages. Use myapp for app tables. -c77_rbac_ tables are accessible to all database users. Manage roles responsibly. -This covers c77_rbac only, not c77_rbac_laravel. - -For help, ask your database administrator or the c77_rbac community. +For help, ask your database administrator or the `c77_rbac` community. \ No newline at end of file