Skip to content
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

Closes Issue #2153 - Limit how a user becomes an admin #2153 #2239

Closed
wants to merge 4 commits into from

Conversation

chrispinkney
Copy link
Contributor

@chrispinkney chrispinkney commented May 14, 2021

Co-authored-by: Josue manekenpix@fastmail.com

Issue This PR Addresses

Closes #2153

Type of Change

  • Bugfix: Change which fixes an issue
  • New Feature: Change which adds functionality
  • Documentation Update: Change which improves documentation
  • UI: Change which improves UI

Description

This PR limits how a user can become an admin:

  • It does this by forcing the PUT and POST routes to set user.isAdmin to false.
  • It also adds another route for admins to modify another user's isAdmin.

Checklist

  • Quality: This PR builds and passes our npm test and works locally
  • Tests: This PR includes thorough tests or an explanation of why it does not
  • Screenshots: This PR includes screenshots or GIFs of the changes made or an explanation of why it does not (if applicable)
  • Documentation: This PR includes updated/added documentation to user exposed functionality or configuration variables are added/changed or an explanation of why it does not(if applicable)

@chrispinkney chrispinkney added type: bug Something isn't working type: enhancement New feature or request type: security Security concerns area: microservices labels May 14, 2021
@chrispinkney chrispinkney added this to the 2.1 Release milestone May 14, 2021
@chrispinkney chrispinkney self-assigned this May 14, 2021
@chrispinkney chrispinkney linked an issue May 14, 2021 that may be closed by this pull request
Copy link
Contributor

@humphd humphd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also lacks tests, which I'd like to see get added with these changes.

@@ -111,6 +111,8 @@ router.post(
next(createError(409, `user with id ${id} already exists.`));
} else {
const user = new User(body);
// no user can be created as an admin by default
user.isAdmin = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this code into a new middleware function that happens just before the route's logic gets hit. Maybe call it validateUserRights() and it can simply set user.isAdmin to false.

The logic in the route should be focused on talking to the db and returning HTTP results, nothing more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateUserRights created.

next(createError(404, `user ${id} not found.`));
} else {
const user = new User(body);
// no user can be created as an admin by default
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, this can be done via middleware.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const userRef = db.doc(id);
const doc = await userRef.get();

if (!doc.exists) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code seems to be duplicated between a few put calls now. Can you extract it into middleware and share it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplication removed, code moved to updateUser in schema.js

// this route is only accessible by administrators
// it allows the modification of the isAdmin property
router.put(
'/:id/admin',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, but one question: the naming implies that you are only setting the admin aspect of this record vs. all fields, yet you are allowing other fields to be updated here. I would limit it to just the admin change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also done in updateUser

validateId(),
validateUser(),
validateEmailHash(),
isAuthorized((req, user) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arrow functions with body statements that immediately return a value should be rewritten as inline expressions:

isAuthorized((req, user) => user.roles.includes('admin')),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@PedroFonsecaDEV
Copy link
Contributor

Following.

@chrispinkney
Copy link
Contributor Author

Still have to add tests but I think this is heading in the right direction.

@@ -0,0 +1,8 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this file, and the other config/export/* files, get added?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the change to development.yml add a single user to the emulator up its bootup. This user as the isAdmin flag set to true, as without this we'd have no way to make a user an admin during testing.

The problem stems from having no way of creating an admin without first having an admin to create an admin.

@@ -45,7 +45,8 @@ services:
volumes:
# Copy firebase.config into the container so we get proper ip/port binding
- ../config/firebase.json:/home/node/firebase.json
command: firebase emulators:start --project telescope --only firestore
- ../config/export:/export
command: firebase emulators:start --project telescope --only firestore --import=/export
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

next(createError(404, `user ${id} not found.`));
} else {
// if makeAdmin is true turn the user into an admin, if not use body to update user.
const user = new User(makeAdmin ? { ...body, isAdmin: true } : body);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't allow downgrading a user from Admin to normal, which we should support. We should accept a value {isAdmin: true|false} on the body and use that instead of hard-coding here.

@chrispinkney
Copy link
Contributor Author

Given #2555, I wonder if this PR should be closed and migrated to a different issue at a later date (once the suprabase work has been merged)?

@manekenpix
@humphd

@humphd
Copy link
Contributor

humphd commented Jan 5, 2022

Agree, this can get closed for now; though, I think it's a good starting point for what needs to happen.

@humphd humphd closed this Jan 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: microservices type: bug Something isn't working type: enhancement New feature or request type: security Security concerns
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Limit how a user becomes an admin
4 participants