Refactor to simplified structure
This commit is contained in:
parent
e5ab33a513
commit
5583f4e5a8
42
README.md
42
README.md
@ -1,29 +1,35 @@
|
|||||||
c77_rbac PostgreSQL Extension
|
# 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
|
|
||||||
|
|
||||||
Scoped role assignments (e.g., campus-specific access).
|
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`).
|
||||||
Admin access via global/all scope for any user ID.
|
|
||||||
RLS policies via c77_rbac_apply_policy.
|
|
||||||
Compatible with PostgreSQL 14+ and Laravel.
|
|
||||||
|
|
||||||
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:
|
1. Ensure PostgreSQL 14 or later is installed.
|
||||||
CREATE EXTENSION c77_rbac SCHEMA public;
|
|
||||||
|
|
||||||
|
2. Place `c77_rbac.control` and `c77_rbac--1.1.0.sql` in `/usr/share/postgresql/17/extension/`.
|
||||||
|
|
||||||
|
3. Run as a superuser:
|
||||||
|
|
||||||
Usage
|
```sql
|
||||||
See USAGE.md for beginner-friendly instructions on securing tables and assigning roles.
|
CREATE EXTENSION c77_rbac SCHEMA public;
|
||||||
Requirements
|
```
|
||||||
|
|
||||||
PostgreSQL 14 or later.
|
## Usage
|
||||||
Superuser access for installation.
|
|
||||||
|
See `USAGE.md` for beginner-friendly instructions on securing tables and assigning roles.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- PostgreSQL 14 or later.
|
||||||
|
- Superuser access for installation.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
License
|
|
||||||
MIT License
|
MIT License
|
235
USAGE.md
235
USAGE.md
@ -1,150 +1,199 @@
|
|||||||
c77_rbac Usage Guide
|
# 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
|
|
||||||
|
|
||||||
PostgreSQL 14 or later.
|
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`).
|
||||||
A superuser (e.g., homestead) for installation.
|
|
||||||
A database (e.g., c77_rbac_test).
|
|
||||||
Basic SQL knowledge.
|
|
||||||
|
|
||||||
Step 1: Install the Extension
|
## What is c77_rbac?
|
||||||
|
|
||||||
Log in as the superuser:
|
`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.
|
||||||
psql -h 192.168.49.115 -p 5432 -U homestead -d c77_rbac_test
|
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
Create the extension:
|
- PostgreSQL 14 or later.
|
||||||
CREATE EXTENSION c77_rbac SCHEMA public;
|
- 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:
|
1. **Log in as the superuser**:
|
||||||
\q
|
|
||||||
|
|
||||||
|
```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
|
```sql
|
||||||
Use a custom schema (e.g., myapp) for your tables.
|
CREATE EXTENSION c77_rbac SCHEMA public;
|
||||||
|
```
|
||||||
|
|
||||||
Log in as your application user (e.g., app_user):
|
This sets up `c77_rbac_` tables and functions in `public`.
|
||||||
psql -h 192.168.49.115 -p 5432 -U app_user -d c77_rbac_test
|
|
||||||
|
|
||||||
|
3. **Exit**:
|
||||||
|
|
||||||
Create the myapp schema:
|
```sql
|
||||||
CREATE SCHEMA myapp;
|
\q
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 2: Set Up Your Application Schema
|
||||||
|
|
||||||
Create a test table:
|
Use a custom schema (e.g., `myapp`) for your tables.
|
||||||
CREATE TABLE myapp.orders (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
campus TEXT NOT NULL,
|
|
||||||
amount NUMERIC
|
|
||||||
);
|
|
||||||
|
|
||||||
|
1. **Log in as your application user** (e.g., `app_user`):
|
||||||
|
|
||||||
Insert test data:
|
```bash
|
||||||
INSERT INTO myapp.orders (campus, amount) VALUES ('chicago', 500), ('miami', 1500);
|
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:
|
```sql
|
||||||
SELECT public.c77_rbac_apply_policy('myapp.orders', 'view_sales_page', 'campus', 'campus');
|
CREATE TABLE myapp.orders (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
campus TEXT NOT NULL,
|
||||||
|
amount NUMERIC
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Insert test data**:
|
||||||
|
|
||||||
myapp.orders: Table to secure.
|
```sql
|
||||||
view_sales_page: Required permission.
|
INSERT INTO myapp.orders (campus, amount) VALUES ('chicago', 500), ('miami', 1500);
|
||||||
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 3: Apply Row-Level Security (RLS)
|
||||||
|
|
||||||
Check the policy:
|
1. **Apply an RLS policy**:
|
||||||
\dp myapp.orders
|
|
||||||
|
|
||||||
Expect c77_rbac_policy with:
|
```sql
|
||||||
c77_rbac_can_access('view_sales_page'::text, current_setting('c77_rbac.external_id'::text, true), 'campus'::text, campus)
|
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
|
2. **Check the policy**:
|
||||||
Users have an external_id (e.g., '1', '2'). Admin rights use global/all.
|
|
||||||
|
|
||||||
Assign a sales manager role (Chicago):
|
```sql
|
||||||
SELECT public.c77_rbac_assign_subject('1', 'sales_manager', 'campus', 'chicago');
|
\dp myapp.orders
|
||||||
SELECT public.c77_rbac_grant_feature('sales_manager', 'view_sales_page');
|
```
|
||||||
|
|
||||||
|
Expect `c77_rbac_policy` with:
|
||||||
|
|
||||||
Assign an admin role (all data):
|
```
|
||||||
SELECT public.c77_rbac_assign_subject('999', 'admin', 'global', 'all');
|
c77_rbac_can_access('view_sales_page'::text, current_setting('c77_rbac.external_id'::text, true), 'campus'::text, campus)
|
||||||
SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page');
|
```
|
||||||
|
|
||||||
For another admin (e.g., '2'):
|
## Step 4: Assign Roles to Users
|
||||||
SELECT public.c77_rbac_assign_subject('2', 'admin', 'global', 'all');
|
|
||||||
SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page');
|
|
||||||
|
|
||||||
|
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:
|
2. **Assign an admin role** (all data):
|
||||||
SET "c77_rbac.external_id" TO '1';
|
|
||||||
SELECT * FROM myapp.orders;
|
|
||||||
|
|
||||||
Expected:
|
```sql
|
||||||
id | campus | amount
|
SELECT public.c77_rbac_assign_subject('999', 'admin', 'global', 'all');
|
||||||
----+---------+--------
|
SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page');
|
||||||
1 | chicago | 500
|
```
|
||||||
|
|
||||||
|
For another admin (e.g., `'2'`):
|
||||||
|
|
||||||
Admin (e.g., '2'):
|
```sql
|
||||||
SET "c77_rbac.external_id" TO '2';
|
SELECT public.c77_rbac_assign_subject('2', 'admin', 'global', 'all');
|
||||||
SELECT * FROM myapp.orders;
|
SELECT public.c77_rbac_grant_feature('admin', 'view_sales_page');
|
||||||
|
```
|
||||||
|
|
||||||
Expected:
|
## Step 5: Test Access
|
||||||
id | campus | amount
|
|
||||||
----+---------+--------
|
|
||||||
1 | chicago | 500
|
|
||||||
2 | miami | 1500
|
|
||||||
|
|
||||||
|
1. **Chicago manager**:
|
||||||
|
|
||||||
Unauthorized user:
|
```sql
|
||||||
SET "c77_rbac.external_id" TO 'unknown';
|
SET "c77_rbac.external_id" TO '1';
|
||||||
SELECT * FROM myapp.orders;
|
SELECT * FROM myapp.orders;
|
||||||
|
```
|
||||||
|
|
||||||
Expected:
|
**Expected**:
|
||||||
id | campus | amount
|
|
||||||
----+--------+--------
|
|
||||||
|
|
||||||
|
```
|
||||||
|
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:
|
For Laravel:
|
||||||
|
|
||||||
Set user ID:
|
1. **Set user ID**:
|
||||||
DB::statement("SET c77_rbac.external_id TO '1'");
|
|
||||||
|
|
||||||
|
```php
|
||||||
|
DB::statement("SET c77_rbac.external_id TO '1'");
|
||||||
|
```
|
||||||
|
|
||||||
Query:
|
2. **Query**:
|
||||||
SELECT * FROM myapp.orders;
|
|
||||||
|
|
||||||
|
```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).
|
## Notes
|
||||||
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
|
- 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.
|
For help, ask your database administrator or the `c77_rbac` community.
|
||||||
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.
|
|
Loading…
x
Reference in New Issue
Block a user