Skip to content

Commit 825aade

Browse files
committed
add simple README
1 parent 422bc18 commit 825aade

File tree

7 files changed

+144
-53
lines changed

7 files changed

+144
-53
lines changed

README.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# HR sample web application using Oso as AuthZ
2+
3+
A sample web application to show how you can integrate Oso.
4+
5+
Here are some demo Gifs to see how the app looks like:
6+
- [Login with HR user](assets/oso_demo_hr.gif)
7+
- [Login with Admin non-HR user](assets/oso_demo_admin.gif)
8+
- [Login with non-Admin non-HR user](assets/oso_demo_non_admin.gif)
9+
10+
The stack:
11+
12+
- Server
13+
- Node.js(TypeScript) + Express + TypeOrm
14+
- Client
15+
- React
16+
17+
## ER
18+
![Image](https://i.imgur.com/olrqc9g.png)
19+
20+
## Types of authorization
21+
22+
### Request-level authorization
23+
24+
- A request is authorized if it includes a `x-user-id` HTTP Header
25+
- Otherwise, `401` will be returned
26+
27+
### Resource-level authorization
28+
29+
- If the logged-in user is
30+
- a member of the HR department
31+
- the user
32+
- can view all the members of the organization
33+
- can edit all the members of the organization
34+
- not a member of the HR department
35+
- the user
36+
- can view members which belong to the same department
37+
- an admin user
38+
- the user
39+
- can use the admin features of the service (can be accessed from the user menu)
40+
41+
### Field-level authorization
42+
43+
- If the logged-in user is
44+
- a member of the HR department
45+
- the user
46+
- can view all the members' fields including private fields (such as salary)
47+
- can edit all the updatable fields including private fields (such as salary)
48+
- not a member of the HR department
49+
- the user
50+
- can view other members' public fields only
51+
- can view private fields of the logged in user
52+
- can edit public fields of the logged in user (not private fields such as salary)
53+
54+
## Architecture Overview
55+
56+
![Image](https://i.imgur.com/X1K9gIc.png)
57+
58+
Basically:
59+
1. The UseCaseController receives a request
60+
2. The UseCaseController invokes the UseCaseService's method
61+
1. The UseCaseService invokes the UseCaseRepository to fetch data
62+
1. The UseCaseRepository fetches data from SQLite (Calls the DataFilter if filtering is necessary)
63+
2. The UseCaseService enforces field-level authorization and returns results to the UseCaseController
64+
3. The UseCaseController sends the response to the requester
65+
66+
### Why use 2 Oso instances?
67+
68+
This example creates 2 Oso instances:
69+
70+
* 1 for the ORM models
71+
* 1 for the Core models
72+
73+
This is required because the ORM models' field names differ from the Core models. For example, the [MemberOrm](./server/src/members/shared/typeorm/memberOrm.ts) model has a `departmentId` fields but the [Member](./server/src/members/shared/member.ts) model does not. Hence, the Polar differs:
74+
75+
The ORM Polar:
76+
77+
```sh
78+
has_permission(user: User, "read", member: Member) if
79+
user.member.department.id = member.departmentId or
80+
user.member.department.name = "hr";
81+
```
82+
83+
The Core Polar:
84+
85+
```sh
86+
has_permission(user: User, "read", member: Member) if
87+
user.memberInfo.department.id = member.department.id or
88+
user.memberInfo.department.name = "hr";
89+
```
90+
91+
Look how the field names `user.member` and `user.memberInfo` differ. You can rename the Core models to use `user.member`, but, imo field names shouldn't depend on tools and frameworks. They should be isolated.
92+
93+
### Where Oso is used
94+
95+
#### Data filtering
96+
97+
**authorizedQuery**
98+
99+
You can see the [authorizedQuery](https://docs.osohq.com/node/guides/data_filtering.html) being used in [repository implementations](https://github.com/kenfdev/hr-sample-app/blob/422bc189b010d8896f3fef04b726392453b1d1ef/server/src/members/list-all-members/repository/listAllMembersSqliteRepository.ts#L21). By using the `authorizedQuery` you can add more query options such as sort.
100+
101+
**authorizedFields**
102+
103+
[authorizedFields](https://docs.osohq.com/node/reference/api/classes/oso.oso-1.html#authorizedfields) can be found in UseCaseServices. It is used to [authorize request bodies](https://github.com/kenfdev/hr-sample-app/blob/422bc189b010d8896f3fef04b726392453b1d1ef/server/src/members/edit-member-detail/editMemberDetailService.ts#L30-L34) when there is a mutation request such as PATCHES.
104+
105+
**authorizedActions**
106+
107+
[authorizedActions](https://docs.osohq.com/node/reference/api/classes/oso.oso-1.html#authorizedactions) can be found in UseCaseServices. It is used to [check if the requester has permission to do an action to a specific resource](https://github.com/kenfdev/hr-sample-app/blob/422bc189b010d8896f3fef04b726392453b1d1ef/server/src/members/show-member-detail/showMemberDetailService.ts#L40-L50) (e.g. can the user update the resource?)
108+
109+
## How to start
110+
111+
### Server
112+
113+
```sh
114+
cd server
115+
116+
# install dependencies
117+
npm install
118+
119+
# seed the SQLite database
120+
npm run seed:refresh
121+
122+
# start the server
123+
npm run dev
124+
```
125+
126+
### Client
127+
128+
```sh
129+
cd client
130+
131+
# install dependencies
132+
npm install
133+
134+
# start the front-end locally
135+
npm start
136+
```
137+
138+
### Start playing around
139+
140+
Access http://localhost:3000/login and you'll see a page like the one below:
141+
![Image](https://i.imgur.com/u58mPWf.png)
142+
143+
Select a user and you will be logged in as the selected user for further requests.

assets/diagrams/diagrams.drawio

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<mxfile host="Electron" modified="2021-11-01T08:30:55.002Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36" etag="o3AN0PZgIo75g6NRkDCu" version="15.4.0" type="device" pages="2"><diagram id="z6LndDBz4u9NAxwSlYlV" name="ER">7Zvbbts4EIafxpddWJJPuYwdt7vYtGg3wLa9KhhzLLGlRJWiYjtPv0OLtKxwc7ISMBcEDEQzPIScjxT/DJ1Bssi3HyQps4+CAh/EQ7odJBeDOI6i4QR/aM+u8czGceNIJaONa9g6rtgtmJbWWzMKlfE1LiUEV6zsOleiKGClOj4ipdh0q60Fpx1HSVJwHFcrwl3vV0ZVZuc1OWsL/gSWZuZXz+JpU5ATW9nMpMoIFZsjV7IcJAsphGqe8u0CuA5eNy7v7yk9DExCoZ7SgJ6pz3S+/Df5/YUvzz/cTr+M/n5nerkhvDYTriuQP3Io6h9MQV6ZsaudDUi1YTknBVrztSjUlSkZor3KGKeXZCdqPaBKkdUva80zIdkt1icciyJ0YLFUhnc86dS40i1NnxIqrPPZzjK64/pItp2Kl6RSdjSCc1JW7Ho/Pt0wJzJlxVwoJXJTiXCWFvi8wr5A2jk1o4pGaJv4gFSwvTfw0QEn7gMQOSi5wyq2wcSsALMFosTYm6MFZetkR2spGpnNQ8wiTg99t5zxwaB+BvbYwY7V75LGGas9KCl+wUJwgfG5KESDnnF+x1WVZMWK9BLWevij1vOPmZF2CYzkmu+3QcYohUKTE4oocn1YRqVghdrPeDzHDwZmMfxjPBjjmBZoR62NH11dqoUocJiE7YEAroEN6HXQoRk/leb9G8VFbJDGk6cRteRfHGjiAC1IDgHp6UjHvpGOHKRCUnxHBaYnM535Zjp237vVOc1ZEaieThXFmGesEwdrDvk1yKCe+qunUXSiekrGr6WepkE9PXMDT962epo5QMkNBjWctT2getdPZw7UNZOV+hR0cS+u3jWUPQ+OwHISuPbl6l9FRW4y6ifGEei5CmB7gB15B+umm8oMwXyqtUgObHuwnXpn62aeICeMB6o99PDQO1U3+VSGjdoHaeIdqZt70ldfgenpTCfembqJp4pwYnoOWE/DeuYdq5tgooCzUjnO66+QauoBN/Gea4rcZJO+cg+p4v6p4umpqeLXu2iP3CxUyBU/ctkze+TU9byBYzf/pDdwuG/vCdZ7wjh280/hdrY/V+8J49hNPzXXs0FK9QLrP2NsOz4CCDQFK5UwSJlIRUH4svVi6OuCAjWBb+tcClEa/fITlNqZGJJaCS2aVG4FFWyZ+maa6+fv+hnhNNbF9qjoYmeNAuf7zXagjaNW2myb7a22HT3X32Jtlxx63jMdpn15M3896Yc1E8ZI1HIFDwTTbhOUiyk8tCym/78qJHCi2E13IC+P3H1Jt38bBRH98iJ6NHyiiJ69loZO3Pd30NAPv7mTt/511fB91ReH6l0/2xS3n9PYPj/rND4Yb+40tjnAR0/j+1ZF3+MYzfZ/U/ZlR//hkyz/Aw==</diagram><diagram id="393Xqic9V_I5Ej20P6Q-" name="Architecture">7VrbcuI4EP0aV80+TMqSsUMeA2QuVUyRWXZrk6ctYQvQICyvEAH266dly9jGDpBMwCa7L4nUutjqPn26W8ZyuvP1Z0mi6TcRUG5hO1hbTs/CGCHbg39askkkbRcngolkgZmUCYbsX2qEtpEuWUAXhYlKCK5YVBT6IgyprwoyIqVYFaeNBS8+NSITWhIMfcLL0r9YoKbpubybbOALZZOpeXQbXycDc5JONidZTEkgVjmRc2c5XSmESlrzdZdyrbxULz8GSPVmg7+jDu88fFb+13l//DHZ7NNLlmyPIGmo3nZrY8snwpdGX8PvfaaoObHapGqEw0e66W84CwMqHcvprKYwcxgRXw+sAD4gm6o5hx6C5kgsYWbQH20FxJ9NpJYOlgq2oUa+SECDXGib96FS0fWOAQ+cHm1NAlimYk6V3MA6s4vTdpN9DIzdG2PVVQaKayOa5uCQyoiB4WS7c6ZqaBhtv0DzbknFNADgmq6QaiomIiT8LpN2ZKJRGLehl83pCxEZXf6gSm2MF5KlEkWT0DVTD7n2o97qyjW93trsHHc2aSeE4z7kO7lVupsti3vZuuBW+68+TUTDRPKJaS3F48n59aFfYWdQnFhKn+6Z5xiyIXJC9+3XqsaNpJwo9lR8uTdHAXLqhEFm+se85Q/AILP8Y7rfO4ABwnXiwCnx8J8L2iULOqTyifllPs5Z81SUiW27QJlOq0yZCFdwpnsqzmyVtGR1sXXbYaGicqzjEHQ7oBCPKx1vJLQmumWU+TuNxIIpYV7lzPp0vKbp8/o/RD4jLvzZ2dnHu4Qg1G4ODNCrYGAfhAH07qlkoC8qGxKYjoVGrXHppsS435c0fv4TI/D3j01EB3JeCaA+GUEtWTA64WwCmu75NIwN0dEsy6BYuzUDcxYECb4oVAVkFO+nrREJIPn4dG7Hcnv7aNpUkmaxta3fDlquvZe+P9pXdsspVhFp3D7aGGb3e32a3BQxHi8ABLvW2r7ELySYN//XGc3wY/QMvM7jyNityjDjCxVZzpd6RGnvBi1qN30Xzp04wl7vxm2v4N2o6c7tVdk0rhr+4WWjNiv7bbl1Z78IldRXC1fWzF/pRe1BAnPq5K/0LctY7woIB4LzCqI6A6xbTavp0AUWdS8N+A3M5hE+Ng3wanWj8oX/7RKsLcGwFXnAigGIsT1YiA9dIelv+zxsDMruCi5kPOKMx2Ps+/p2H7xzRnMjgTfyXO+MF1fYqd0py5H6XnBSofFn9Jx+fgmF0v566MvLMx9aAiJnA1jFVOxLV7Z2tfTrS+uUwR8XLYIqgr9bYRDvVAZJz3UJLLmf2F5/NVbBoidnyfaRLIl/lSV3cnGDQ28nXLfQDsCSFzOrMoyBBcgmN80ULCdI6XGDPggdeRmHrHcQvo8GZp3RG5c/gLzj6zj8TMGRVeweajX/Aq5dspm+XUmvVvZkXGDIC0m4XLdptT0+PuGqVPOF51vuzq9dnPTe+u3zLehmP4FKnCb7IZlz9xM=</diagram></mxfile>

assets/oso_demo_admin.gif

307 KB
Loading

assets/oso_demo_hr.gif

243 KB
Loading

assets/oso_demo_non_admin.gif

212 KB
Loading

client/README.md

Lines changed: 0 additions & 46 deletions
This file was deleted.

server/README.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)