Skip to content

CDD-3173: add the base code for the DB permission filtering of privat…#3201

Open
dandammann wants to merge 6 commits into
task/CDD-3171-update-getpages-endpoint-for-non-public-ianfrom
CDD-3173-BE-Update-DB-queries-to-ensure-that-user-permissions-are-used-when-requesting-data
Open

CDD-3173: add the base code for the DB permission filtering of privat…#3201
dandammann wants to merge 6 commits into
task/CDD-3171-update-getpages-endpoint-for-non-public-ianfrom
CDD-3173-BE-Update-DB-queries-to-ensure-that-user-permissions-are-used-when-requesting-data

Conversation

@dandammann
Copy link
Copy Markdown
Contributor

Description

This PR includes the following:

CDD-3174: Similar to the changes that were implemented for the getPages endpoint as part of https://ukhsa.atlassian.net/browse/CDD-3171, this ticket concerns endpoints that are used for displaying data / generating charts should be updated to make use of the authorisation header. If the user provides an authorization header then the data returned from the endpoint should be customised depending on the permissions that the user has been granted.

CDD-3173: The database queries will need to be updated for non-public users so that they only return non-public data and they only return data that the user is permitted to view.

When a request is made by an authenticated user, the query to the DB should be made for only the data that the user is able to see. This will be driven from the user permission hierarchy

When a request is made by an authenticated user the returned data should only be for non-public data. it should not contain public data.


Type of change

Please select the options that are relevant.

  • [ ] Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • [ ] Tech debt item (this is focused solely on addressing any relevant technical debt)

Checklist:

  • I have commented my code, particularly in hard-to-understand areas
  • [ ] I have made corresponding changes to the documentation
  • I have added tests at the right levels to prove my change is effective
  • [ ] I have added screenshots or screen grabs where appropriate
  • I have added docstrings in the correct style (google)

@dandammann dandammann requested a review from a team as a code owner May 20, 2026 08:58
@sonarqubecloud
Copy link
Copy Markdown

Comment thread common/auth/cognito_jwt/user_manager.py
token_validator = self.get_token_validator(request)
jwt_payload = token_validator.validate(jwt_token)
except TokenError:
except TokenError as error:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Arguably unneccessary? It's already throwing an error and I'm worried there's a risk that some permission set info or user info could be spat out as part of the error log

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@dandammann Please can we avoid including work that is not related to the ticket in the same PR.
It makes it harder to review as reviewers have to figure out which code changes are related to the ticket, and which are achieving some other unknown goal.
If you find tech debt that need to be improved In existing code (and it's a quick fix), then these should be added to a seperate PR with a description that explains it and then it can be reviewed on it own merits.
Also in this instance, all these changes within the JWT code are going to cause a big headache of conflicts once the PR for CDD-3147 gets merged in too.

geography=geography,
)
else:
# THESE LEGACY RBAC PERMISSIONS ARE NOT IN USE AND TO BE REMOVED IN A FUTURE RELEASE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If they aren't in use in this file can we remove them as part of this work? I don't see any reason to keep them in, as you are essentially replacing what they are trying to do with the new solution :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I mentioned that RBAC permissions need removing (at some point), but you said that's out-of-scope, because there is a ticket for that in the backlog.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For the areas of the code you are already touching, it's fine to replace the RBAC parts with the new permission_sets bits, rather than adding if/else statements for code we know is going to disappear soon.
The endpoints are going to be thoroughly tested by updated unit tests and by the QA team anyway, so there's no issues with doing it that way, it's just that we don't need to make more work by extending the scope of the ticket to cover removing all the other areas of the codebase that have RBAC bits, along with all the additional updated tests and additional QA time that would go along with that work. That part can be done a future ticket.
We want to focus on what's required for our MVP deliverable, and keeping that work as simple as possible.

geography=geography,
)
else:
# THESE LEGACY RBAC PERMISSIONS ARE NOT IN USE AND TO BE REMOVED IN A FUTURE RELEASE
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same as above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same reply from me too.


@return {dict} example:
{
"permission_set_hierarchy": [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the value in this over using the raw permissions?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@dandammann I''m not sure what this is for. I was under the impression that the permission set hierarchy was already returning the permissions sets into the JWT in the most usable format for the endpoints to consume when filtering the data.
If the permission sets are not in the right format when we come to use them for filtering for pages, DB data etc, then we should be updating the format of the permission sets before they go into the JWT, so it happens just once, rather than on 100s of requests at the point it is being consumed (although there is also a tradeoff to consider here too, of avoiding making the JWT too large).

@return {bool}
"""

topic_record = None
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we not extend the function already created in CDD-3171? I find this hard to read (could just be me though)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree, we want to make sure we're not duplicating the core permissions checking functions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hi @kathryn-dale and @mattjreynolds . Please look at my comments and examples in this current function and filter_permissions() and let me know, if you think your check_permissions() can achieve that.

I myself think it is too simplistic for that, because it only checks permissions for EITHER theme, sub_theme or topic, but with the charts we need to check permissions cross-cutting (taking them all into consideration).

if you do think check_permissions() is adequate, please try it out ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is also that difference that with GetPages the input arguments are theme/sub_theme/topic IDS, whereas with charts they are theme/sub_theme/topic NAMES.

@mattjreynolds mattjreynolds force-pushed the task/CDD-3171-update-getpages-endpoint-for-non-public-ian branch from 2303ee5 to 5219d16 Compare May 22, 2026 07:06
token_validator = self.get_token_validator(request)
jwt_payload = token_validator.validate(jwt_token)
except TokenError:
except TokenError as error:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@dandammann Please can we avoid including work that is not related to the ticket in the same PR.
It makes it harder to review as reviewers have to figure out which code changes are related to the ticket, and which are achieving some other unknown goal.
If you find tech debt that need to be improved In existing code (and it's a quick fix), then these should be added to a seperate PR with a description that explains it and then it can be reviewed on it own merits.
Also in this instance, all these changes within the JWT code are going to cause a big headache of conflicts once the PR for CDD-3147 gets merged in too.


@return {dict} example:
{
"permission_set_hierarchy": [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@dandammann I''m not sure what this is for. I was under the impression that the permission set hierarchy was already returning the permissions sets into the JWT in the most usable format for the endpoints to consume when filtering the data.
If the permission sets are not in the right format when we come to use them for filtering for pages, DB data etc, then we should be updating the format of the permission sets before they go into the JWT, so it happens just once, rather than on 100s of requests at the point it is being consumed (although there is also a tradeoff to consider here too, of avoiding making the JWT too large).

Comment thread common/auth/cognito_jwt/user_manager.py


class EncodedChartsView(APIView):
authentication_classes = [SessionAuthentication, JSONWebTokenAuthentication]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should not be being set.
Authenticaion is already being handled for all views by the JWT token code, and the permission sets are being made available in the request object (request.user.permission_sets)

has_global_access = jwt_permissions.get("has_global_access", False)

if has_global_access:
has_access_to_non_public_data = True
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could simplify this has_global_access check to just be part of the return value from check_any_permissions_allow_access
This is how it's being done in 3171, are we not able to just reuse those functions for these endpoints too? They should be doing the same job and we don't want to have 2 different function that both check permissions

**plot_params, rbac_permissions=self.chart_request_params.rbac_permissions
**plot_params,
rbac_permissions=self.chart_request_params.rbac_permissions, # legacy permissions to be removed
jwt_permissions=extract_jwt_permissions(request=self.chart_request_params.request), # new permissions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

as with previous comment, you should be able to just use something like:
jwt_permissions=request.user.permission_sets if request.auth else None,

@return {bool}
"""

topic_record = None
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I agree, we want to make sure we're not duplicating the core permissions checking functions

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