This monorepo contains three projects:
- a react frontend for a Todo application (./todo-application)
- a node.js backend for the Todo application (./todo-node-js)
- a harness for the Topaz authorizer, which itself includes three different variations of an authorization policy for the Todo backend:
policy-todo-roles
,policy-todo-groups
, andpolicy-todo-rebac
.
Requirements:
- Docker running on your box (e.g. Docker desktop for Mac)
brew
(for mac or linux)node
(we tested with v20 but it should work with anything >16)yarn
(we tested with v1.22 but it should work with any v1)
Steps:
We'll first install and set up the Topaz authorizer locally, and then build and run the backend and frontend.
- Install topaz and policy CLIs:
cd ./topaz
brew tap aserto-dev/tap && brew install topaz
brew tap opcr-io/tap && brew install policy
- Run topaz install (gets the topaz container image):
make install
- Create three Topaz configurations, one for each policy target:
make all
This command will do the following for each of the policy targets (todo-roles
, todo-groups
, todo-rebac
):
- Build the policy
- Create a Topaz configurations for the policy
- Set the directory manifest
- Load the IDP data (users and groups)
- Run the test suite
The output should look like this:
make all
==> build-todo-roles
Created new image.
digest: sha256:ed40e022b2e77f121b8b4043c6902b98f2c9ca7a3f8f3a1d04ae307046bc75e0
Tagging image.
reference: ghcr.io/aserto-proj/pnw-appsec:roles
==> configure-todo-roles
>>> stopping topaz "pnw-appsec-groups"...
>>> configure policy
certs directory: /Users/ogazitt/.local/share/topaz/certs
FILE ACTION
gateway.crt skipped, file already exists
gateway-ca.crt skipped, file already exists
gateway.key skipped, file already exists
grpc.crt skipped, file already exists
grpc-ca.crt skipped, file already exists
grpc.key skipped, file already exists
A configuration file already exists.
Do you want to continue? (y/N) y
using local policy image: ghcr.io/aserto-proj/pnw-appsec:roles
Using configuration "pnw-appsec-roles"
>>> starting topaz "pnw-appsec-roles"...
fe74a14d5d3eb3c5f1f3da433f23f4565c53cd3702bb67e90ca4756796eea7a1
==> sleep-roles
==> manifest-roles
>>> set manifest to /Users/ogazitt/src/ogazitt/pnw-appsec-2024/topaz/model/manifest.yaml==> data-roles
>>> importing data from ./data
objects 19
relations 22
==> test-roles
0001 check PASS group:admin#member@user:[email protected] [true] (79.982875ms)
0002 check PASS group:evil_genius#member@user:[email protected] [true] (1.205375ms)
0003 check PASS group:editor#member@user:[email protected] [true] (976.667µs)
0004 check PASS group:viewer#member@user:[email protected] [true] (655.791µs)
0005 check PASS group:admin#member@user:[email protected] [false] (910.25µs)
0006 check PASS group:evil_genius#member@user:[email protected] [false] (855.375µs)
0007 check PASS group:editor#member@user:[email protected] [true] (1.233417ms)
0008 check PASS group:viewer#member@user:[email protected] [true] (715µs)
0009 check PASS group:admin#member@user:[email protected] [false] (924.333µs)
0010 check PASS group:evil_genius#member@user:[email protected] [false] (757.458µs)
0011 check PASS group:editor#member@user:[email protected] [true] (524.166µs)
0012 check PASS group:viewer#member@user:[email protected] [true] (696.375µs)
0013 check PASS group:admin#member@user:[email protected] [false] (830.625µs)
0014 check PASS group:evil_genius#member@user:[email protected] [false] (929.708µs)
0015 check PASS group:editor#member@user:[email protected] [false] (998.292µs)
0016 check PASS group:viewer#member@user:[email protected] [true] (689.041µs)
0017 check PASS group:admin#member@user:[email protected] [false] (618.959µs)
0018 check PASS group:evil_genius#member@user:[email protected] [false] (698.083µs)
0019 check PASS group:editor#member@user:[email protected] [false] (638.542µs)
0020 check PASS group:viewer#member@user:[email protected] [true] (636µs)
==> build-todo-groups
Created new image.
digest: sha256:cf881d4f62077cdeddc878b40b730ea9be924253f30f972a6cd743256d9861ca
Tagging image.
reference: ghcr.io/aserto-proj/pnw-appsec:groups
==> configure-todo-groups
>>> stopping topaz "pnw-appsec-roles"...
>>> configure policy
certs directory: /Users/ogazitt/.local/share/topaz/certs
FILE ACTION
gateway.crt skipped, file already exists
gateway-ca.crt skipped, file already exists
gateway.key skipped, file already exists
grpc.crt skipped, file already exists
grpc-ca.crt skipped, file already exists
grpc.key skipped, file already exists
A configuration file already exists.
Do you want to continue? (y/N) y
using local policy image: ghcr.io/aserto-proj/pnw-appsec:groups
Using configuration "pnw-appsec-groups"
>>> starting topaz "pnw-appsec-groups"...
51edb8298886c284526ddf7481550eec1f8e3299103b40f529259eb8fb27919a
==> sleep-groups
==> manifest-groups
>>> set manifest to /Users/ogazitt/src/ogazitt/pnw-appsec-2024/topaz/model/manifest.yaml==> data-groups
>>> importing data from ./data
objects 19
relations 22
==> test-groups
0001 check PASS group:admin#member@user:[email protected] [true] (65.271125ms)
0002 check PASS group:evil_genius#member@user:[email protected] [true] (905.041µs)
0003 check PASS group:editor#member@user:[email protected] [true] (536µs)
0004 check PASS group:viewer#member@user:[email protected] [true] (430.083µs)
0005 check PASS group:admin#member@user:[email protected] [false] (450.667µs)
0006 check PASS group:evil_genius#member@user:[email protected] [false] (604.167µs)
0007 check PASS group:editor#member@user:[email protected] [true] (550.083µs)
0008 check PASS group:viewer#member@user:[email protected] [true] (697.083µs)
0009 check PASS group:admin#member@user:[email protected] [false] (568.291µs)
0010 check PASS group:evil_genius#member@user:[email protected] [false] (600.375µs)
0011 check PASS group:editor#member@user:[email protected] [true] (670.333µs)
0012 check PASS group:viewer#member@user:[email protected] [true] (777.917µs)
0013 check PASS group:admin#member@user:[email protected] [false] (1.013208ms)
0014 check PASS group:evil_genius#member@user:[email protected] [false] (697.375µs)
0015 check PASS group:editor#member@user:[email protected] [false] (800.125µs)
0016 check PASS group:viewer#member@user:[email protected] [true] (858µs)
0017 check PASS group:admin#member@user:[email protected] [false] (538.959µs)
0018 check PASS group:evil_genius#member@user:[email protected] [false] (553.667µs)
0019 check PASS group:editor#member@user:[email protected] [false] (603.333µs)
0020 check PASS group:viewer#member@user:[email protected] [true] (939.334µs)
==> build-todo-rebac
Created new image.
digest: sha256:e7a95c6b7429165ec3d93b94ea6bf53043b45e434849d0e9ee9b4bf507b88f4e
Tagging image.
reference: ghcr.io/aserto-proj/pnw-appsec:rebac
==> configure-todo-rebac
>>> stopping topaz "pnw-appsec-groups"...
>>> configure policy
certs directory: /Users/ogazitt/.local/share/topaz/certs
FILE ACTION
gateway.crt skipped, file already exists
gateway-ca.crt skipped, file already exists
gateway.key skipped, file already exists
grpc.crt skipped, file already exists
grpc-ca.crt skipped, file already exists
grpc.key skipped, file already exists
A configuration file already exists.
Do you want to continue? (y/N) y
using local policy image: ghcr.io/aserto-proj/pnw-appsec:rebac
Using configuration "pnw-appsec-rebac"
>>> starting topaz "pnw-appsec-rebac"...
0da48b55acc2aa0b6888d960ded6d0f66bd37b5f84bbf366742063acddf98767
==> sleep-rebac
==> manifest-rebac
>>> set manifest to /Users/ogazitt/src/ogazitt/pnw-appsec-2024/topaz/model/manifest.yaml==> data-rebac
>>> importing data from ./data
objects 19
relations 22
==> test-rebac
0001 check PASS group:admin#member@user:[email protected] [true] (72.977291ms)
0002 check PASS group:evil_genius#member@user:[email protected] [true] (683.042µs)
0003 check PASS group:editor#member@user:[email protected] [true] (826.375µs)
0004 check PASS group:viewer#member@user:[email protected] [true] (1.205792ms)
0005 check PASS group:admin#member@user:[email protected] [false] (742.917µs)
0006 check PASS group:evil_genius#member@user:[email protected] [false] (640.916µs)
0007 check PASS group:editor#member@user:[email protected] [true] (870µs)
0008 check PASS group:viewer#member@user:[email protected] [true] (614.042µs)
0009 check PASS group:admin#member@user:[email protected] [false] (739.959µs)
0010 check PASS group:evil_genius#member@user:[email protected] [false] (589.083µs)
0011 check PASS group:editor#member@user:[email protected] [true] (944.875µs)
0012 check PASS group:viewer#member@user:[email protected] [true] (588.875µs)
0013 check PASS group:admin#member@user:[email protected] [false] (1.187084ms)
0014 check PASS group:evil_genius#member@user:[email protected] [false] (740.875µs)
0015 check PASS group:editor#member@user:[email protected] [false] (1.072416ms)
0016 check PASS group:viewer#member@user:[email protected] [true] (798.375µs)
0017 check PASS group:admin#member@user:[email protected] [false] (749.833µs)
0018 check PASS group:evil_genius#member@user:[email protected] [false] (655.5µs)
0019 check PASS group:editor#member@user:[email protected] [false] (931.292µs)
0020 check PASS group:viewer#member@user:[email protected] [true] (765.292µs)
- Bring up the topaz console:
make console
- To change configurations:
topaz config list
NAME CONFIG FILE
pnw-appsec-groups pnw-appsec-groups.yaml
* pnw-appsec-rebac pnw-appsec-rebac.yaml
pnw-appsec-roles pnw-appsec-roles.yaml
topaz stop
topaz config use pnw-appsec-groups
topaz start
Install the dependencies:
cd ./todo-node-js
yarn
Ensure you have the right .env
file and run the server in dev mode on port 3001:
cp .env.example .env
yarn start
You should see the server running in nodemon
.
The main
branch contains the code that uses Aserto for authorization.
The broken-access-control
branch contains the code that uses embedded if
/switch
statemetns for authorization, and is easy to trick by passing in a malformed payload into the PUT /todos/:id
route.
Install the dependencies and run the react frontend on port 3000:
cd ./todo-application
yarn
yarn start
At this point, the frontend should show an OIDC login screen. You can login with the following users:
- [email protected] - admin
- [email protected] - editor
- [email protected] - editor
- [email protected] - viewer
- [email protected] - viewer
Password for all: V@erySecre#t123!
- Rick the admin can do everything to all Todos
- Editors like Morty and Summer can create, edit, and delete their own Todos
- Viewers like Beth and Jerry can only see the todo list
See the todo app repo for more information about the Todo app.
The default policy we built (policy-todo-roles
) is an attribute-based policy. It uses the properties.roles[]
array to determine the role of the user.
There are two other policies we can use:
policy-todo-groups
: uses relationships to groups instead of roles as properties of the user. This demonstrates using the Topaz built-in functionds.check
for evaluating themember
relationship between a subject (user
) and and object (group
)policy-todo-rebac
: utilizes theresource
object type, permissions (can_read
,can_write
,can_delete
), and relationships (viewer
,editor
,owner
) to make the policy truly relationship-based.
topaz stop
topaz config use pnw-appsec-groups
topaz start
Once Topaz is restarted with the new policy, we'll switch to using group-based access control based on the groups the user is a member of. Behavior is basically the same, but you can change what each user can do by adding or removing them from groups.
topaz stop
topaz config use pnw-appsec-rebac
topaz start
One Topaz is restarted with this policy, you can go into the Properties of Jerry (who is a viewer), and give him the "creator" role (in addition to viewer).
Now Jerry can create Todos, and complete / delete his own Todos. The app code creates and removes relationships in Topaz, and the policy is written to take advantage of this and evaluate permissions (also) based on the relationship between the user and the Todo.