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

[feat] Super User Privilege Toggle #2111

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

shubhdevelop
Copy link
Contributor

Date: 30 Aug 2024

Developer Name: Shubham Raj


Issue Ticket Number

#2110

Description

This Solution involves the mutating the userData Object returned from the database before adding it to the response object, which then is used in authenticateRoles middleware for authentication of roles.

Added two routes, one that will help us get the current value of SuperUserAccess as the jwt token in user browser are encrypted

2nd route's purpose would be to send an updated jwt token, with the SuperUserAccess property in addition with the id of the user.

In the authenticateUser middleware if the value of the SuperUserAccess === false, we’ll remove the super_user property or either set it to false, from the userData Object this should make the authorizeRoles middleware return an unauthorised user response back to the user.

If the cookie’s value is either true or undefined(not present in the request), we shouldn’t be tampering with the user_object and add the returned userData object as it is to the Response object, this should make the authorizeRoles middleware to authorise if the roles exist and call to next().

Depending up the value of SuperUserAccess we also modify the user object in the /users/self and the super_user value accordingly before sending it to the user.

Documentation Updated?

  • Yes
  • No

Once this PR gets merged I'll update the the api-contract documentation as well

Under Feature Flag

  • Yes
  • No

Database Changes

  • Yes
  • No

Breaking Changes

  • Yes
  • No

Development Tested?

  • Yes
  • No

Screens Capture

Development Testing

`/users/:userId/intro is an routes accessible only when super_user role is present on the user

Screencast.from.30-08-24.02.39.43.PM.IST.webm
Screencast.from.30-08-24.02.43.28.PM.IST.webm

Test Coverage

Screenshot 1

Test coverage for the changes in /users/self route
image

Test coverage for 2 routes that were added
image

Additional Notes

For more Detail one can refer to this design doc
https://docs.google.com/document/d/17khsviClkNVNYH4Xy5Pkk98Xvrid1jH1jL9QtfGp7aw/edit?usp=sharing

router.patch("/self", authenticate, userValidator.updateUser, users.updateSelf);
router.get("/", userValidator.getUsers, users.getUsers);
router.get("/self", authenticate, users.getSelfDetails);
router.get("/set-super-user-access", authenticate, users.setSuperUserAccessLimiter);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
router.patch("/self", authenticate, userValidator.updateUser, users.updateSelf);
router.get("/", userValidator.getUsers, users.getUsers);
router.get("/self", authenticate, users.getSelfDetails);
router.get("/set-super-user-access", authenticate, users.setSuperUserAccessLimiter);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
router.patch("/self", authenticate, userValidator.updateUser, users.updateSelf);
router.get("/", userValidator.getUsers, users.getUsers);
router.get("/self", authenticate, users.getSelfDetails);
router.get("/set-super-user-access", authenticate, users.setSuperUserAccessLimiter);
router.get("/get-super-user-access-status", authenticate, users.getSuperUserAccessStatus);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
Comment on lines +53 to +70
const { userId, superUserAccess } = authService.verifyAuthToken(token);
const userDoc = await dataAccess.retrieveUsers({ id: userId });
let userData;

// add user data to `req.userData` for further use
const userData = await dataAccess.retrieveUsers({ id: userId });
req.userData = userData.user;

if (superUserAccess === false) {
userData = userDoc.user;
userData.roles.super_user = false;
userData.superUserAccess = false;
} else if (superUserAccess === true || superUserAccess === undefined) {
userData = userDoc.user;
if (superUserAccess === true) {
userData.superUserAccess = true;
} else {
userData.superUserAccess = undefined;
}
}
req.userData = userData;
Copy link
Member

Choose a reason for hiding this comment

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

Middleware tests are missing

@@ -19,6 +19,8 @@ router.get("/userId/:userId", users.getUserById);
router.patch("/self", authenticate, userValidator.updateUser, users.updateSelf);
router.get("/", userValidator.getUsers, users.getUsers);
router.get("/self", authenticate, users.getSelfDetails);
router.get("/set-super-user-access", authenticate, users.setSuperUserAccessLimiter);
Copy link
Member

Choose a reason for hiding this comment

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

Can you change the route name to be more descriptive?
as this is a GET request and route name is kind on weird

Comment on lines +846 to +880
const setSuperUserAccessLimiter = async (req, res) => {
try {
let value;
switch (req.query.value) {
case "true":
value = true;
break;
case "false":
value = false;
break;
default:
break;
}
if (value !== undefined) {
const token = req.cookies[config.get("userToken.cookieName")];
const { userId } = authService.decodeAuthToken(token);
const newToken = authService.generateAuthToken({ userId, superUserAccess: value });
const rdsUiUrl = new URL(config.get("services.rdsUi.baseUrl"));
res.cookie(config.get("userToken.cookieName"), newToken, {
domain: rdsUiUrl.hostname,
expires: new Date(Date.now() + config.get("userToken.ttl") * 1000),
httpOnly: true,
secure: true,
sameSite: "lax",
});
return res.json({ message: "Super User Privilege Access Set!", currentAccess: value });
} else {
return res.boom.badRequest("Wrong value in query param, value can be either true or false");
}
} catch (error) {
logger.error(`Error while Setting Super Privilege Access Limiter: ${error}`);
return res.boom.badImplementation({ message: INTERNAL_SERVER_ERROR });
}
};

Copy link
Member

Choose a reason for hiding this comment

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

This function become complex and not readable so fix this

@prakashchoudhary07
Copy link
Contributor

We need to discuss the approach to it. I am not in favor of this approach. Let's discuss about it with the team before processing please

@prakashchoudhary07
Copy link
Contributor

Also, let's not restrict ourselves to superuser privileges. Lets take a step back and discuss about it

@shubhdevelop
Copy link
Contributor Author

We need to discuss the approach to it. I am not in favor of this approach. Let's discuss about it with the team before processing please

Sure, whenever you free to discuss

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants