-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Permissions revamp #471
base: main
Are you sure you want to change the base?
Permissions revamp #471
Conversation
[diff-counting] Significant lines: 958. |
backend/src/types/DataTypes.d.ts
Outdated
| 'ci_lead' | ||
| 'pm_lead'; | ||
|
||
export type AuthRole = 'admin' | 'dev' | 'tpm' | 'pm' | 'designer' | AuthLead; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think we need a role for business/PMMs. Probably the same level of permissions as a designer or PM.
frontend/src/API/ShoutoutsAPI.ts
Outdated
} | ||
|
||
public static async deleteShoutout(uuid: string): Promise<void> { | ||
await APIWrapper.post(`${backendURL}/deleteShoutout`, { uuid }); | ||
await APIWrapper.delete(`${backendURL}/deleteShoutout/${uuid}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/deleteShoutout
--> /shoutout
?
backend/src/utils/auth.ts
Outdated
|
||
if (userRole === 'admin') return true; | ||
|
||
if (req.method === 'GET') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you have another PR out to make our endpoints more RESTful. Hopefully all our endpoints follow the pattern of "GET" is for read-only, and everything else involves some kind of write operation.
backend/src/utils/auth.ts
Outdated
} | ||
// RBAC | ||
if ( | ||
resource && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be safer to reject the request if the resource is somehow not found in the config, rather than returning 200. It would alert us if we as the developer made a mistake/typo somewhere, or somehow messed up the config file. We could handle this check in isAuthorized
.
backend/src/utils/auth.ts
Outdated
|
||
const canWriteRoles = resourceRBACConfig.read_and_write; | ||
if (resourceRBACConfig.attributes.includes('email') && req.params.email) { | ||
if (req.params.email === user.email) return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, I understand this as if someone is requesting data specific to a person and they are that person, then this request overrides any role-based read/read-write permissions in the config. I personally think it reads better to put this check right under the admin userRole check.
Summary
This PR sets up more proper rbac and adds auth middleware to handle the rbac checking. This is obviously very big and I'm not doing this particularly meticulously so it's not well tested.
But - For the most part I like where the idea is at.
Summary of the permission change:
RBAC is role based access control. Within RBAC, there are roles, resources, and actions. Access control is based on which roles are allowed to perform what actions there are on what resources. For the case of IDOL, I think read and write actions are all that are needed.
Introducing auth roles
I added some auth roles here
These roles should be assigned to people as needed in a collection in a db. For the time being, probably only leads to need to be defined.
RBAC Config
The rbac config file has this schema:
For each resource, it defines which roles have read and which roles have write permissions to the resource. Being able to read does NOT necessarily mean that role also has write permissions.
The auth middleware
All of the auth stuff that used to be in
api.ts
got moved toauth.ts
. Each of the loginCheckedHttpVerb functions now have been changed to look like:There are a few parts to this:
router
param makes it so that the loginChecked can directly be called in the router's file so that we're not defining all the API routes in the same file as beforepath
andhandler
params stay the same as beforeresource
,action
, anduserHasAccess
resource
defines the type of resource being requestedaction
defines the type of action being take on the resource, either read or writeuserHasAccess
is a function that takes the request and the logged in user and returns whether or not the user has access to the desired resource. This is configurable by endpoint so when defining the function, you should be able to define a function that given the request and user, you can determine if they should have access. For example, if it's an endpoint for accessing someone's dev portfolio submission, a user has permissions for that resource becauseemail
should be a query param which should match the logged in user's email.async () => false
needs to be passed. I don't really like this but wasn't sure of a better way. It's done so that endpoints that don't need authorization don't need to specify this.async (req, user) => req.params.email === user.email || req.query.meta_only ===='true'
should cover most cases where it's needed.What still needs to be done?
I'm glad you asked :D
Make sure everything works!
Well first and foremost, I can't guarantee that I didn't break anything. This is probably a little sloppy so I'm sure there are places where things are broken and need to be fixed. This is to say there needs to be some manual testing for everything to make sure the whole app works. Ideally, tests should be written to test perms for all the endpoints but I acknowledge writing tests is somewhat boring so that probably is never going to happen.
I'm pretty confident some of the route paths are a bit messed up too... 🙃
Lead roles are still a bit scuffed
In terms of the lead roles, my idea was that the
lead
role encompassed all of the other lead roles (i.e. if a lead had permission for something, then all of lead roles would have that permission). But nobody should actually be assigned this role. All leads should be assigned their specific role lead role (e.g. dev_lead).When checking for rbac perms here:
this lead role situation isn't properly accounted for.
The remaining routers...
There are a few routers where rbac isn't setup:
I think team event images and sign in form APIs originally didn't match the original auth middlware and rbac implementation that relied on using
email
andmeta_only
. I wanna say there should be no problem adding rbac middleware to this now.For candidate decider, there is slightly more complex authorization that is involved. This originally couldn't be handled with that simple rbac logic. But the addition of that
userHasAccess
function param makes it so that it should be possible to move and define the authorization in that function for the endpoints that need it instead of in the API handlers themselves.loginCheckedHandler
This just basically doesn't do anything now except handle exception handling. It also still passes the user to the API handlers even though the auth middleware sets the user in
res.locals
. This can definitely be fixed up.Tips for dealing with this monstrosity
main
, the branch is from May 2023. There are lots of merge conflicts but hopefully shouldn't be too bad to resolve.