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

fix: Allow granting temporary access only when user in search scope [DHIS2-18784] #19670

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

muilpp
Copy link
Contributor

@muilpp muilpp commented Jan 15, 2025

There are two conditions required to be granted temporary access to an enrollment:
1. The program must be protected.
2. The TE/program owner must be within the user's search scope.

Currently, it is possible to gain temporary access to an enrollment even if the user is not within the search scope. This PR addresses and fixes that issue. After the fix, if the org unit is not within the search scope, an exception will be thrown.
Similarly, if the program is not protected, it will also throw an exception. Previously, access was denied in such cases, but no clear feedback was provided, which was confusing.

Additionally, I am removing the assignOwnership method, as it was only used in tests and is no longer necessary.

Finally, when transferring ownerships, I am including the program parameter when searching for the TE. Since the program is available in the request, it makes more sense to check the access to that TE/program directly when transferring an enrollment to another org unit.

Ticket: https://dhis2.atlassian.net/browse/DHIS2-18784

@muilpp muilpp changed the title fix: Allow temp access only when user in search scope [DHIS2-18784] fix: Allow granting temporary access only when user in search scope [DHIS2-18784] Jan 15, 2025
if (canSkipOwnershipCheck(user, program) || trackedEntity == null) {
return;
}

if (program.isProtected()) {
if (!isOwnerInUserSearchScope(user, trackedEntity, program)) {
throw new ForbiddenException(
"The owner of the entity-program combination is not in the user's search scope");
Copy link
Contributor Author

@muilpp muilpp Jan 15, 2025

Choose a reason for hiding this comment

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

Better to say TE not found? It could be the TE is just registered and not enrolled, but more often than not, the TE will be enrolled.

Same could apply here

if (canSkipOwnershipCheck(user, program) || trackedEntity == null) {
return;
}

if (program.isProtected()) {
if (!isOwnerInUserSearchScope(user, trackedEntity, program)) {
throw new ForbiddenException(
"The owner of the entity-program combination is not in the user's search scope.");
Copy link
Contributor Author

@muilpp muilpp Jan 15, 2025

Choose a reason for hiding this comment

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

Better saying TE not found? It could be the TE is just registered and not enrolled, but more often than not, the TE will be enrolled.
Same would apply here I think

@muilpp muilpp marked this pull request as ready for review January 15, 2025 13:05
@muilpp muilpp requested a review from a team as a code owner January 15, 2025 13:05
programService.getProgram(program),
organisationUnitService.getOrganisationUnit(ou));
return ok("Ownership transferred");
}

@PostMapping(value = "/override", produces = APPLICATION_JSON_VALUE)
@ResponseBody
public WebMessage overrideOwnershipAccess(
public WebMessage grantTemporaryAccess(
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean the path /override is also not accurate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To me, grantTemporaryAccess better represents the logic behind it.
I'd change the endpoint value too, but maybe @ameenhere has something to say here.

Copy link
Contributor

Choose a reason for hiding this comment

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

From a strict RESTful naming convention, I guess having a verb is odd for the API path. APIs could have been api/tracker/ownership/permanent and api/tracker/ownership/temporary

But apart from that, override is not inaccurate. The functionality for this API is called "Breaking the glass" which is pretty much overriding/bypassing existing access check mechanisms. Atleast for now, I guess we really don't have to change API paths for this. Unless there is very strong reasonings, which I don't see at this point.

…sp/dhis/tracker/acl/DefaultTrackerOwnershipManager.java

Co-authored-by: Enrico Colasante <enrico@dhis2.org>
@Nonnull TrackedEntity trackedEntity, Program program, UserDetails user, String reason)
throws ForbiddenException {
if (canSkipOwnershipCheck(user, program)) {
throw new ForbiddenException(
Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't this break the API?
I feel it may be intrusive to throw an exception for the scenario were the check itself could be skipped? Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

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

The issue was that the check was used to skip the actual action that is granting temporary access.
In my opinion the API was just wrong because when the user was asking access for a not existent program, the API would return with a positive answer even though nothing happened.

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.

4 participants