Skip to content

FINERACT-2720: Scope entity-to-entity mapping results to user office hierarchy - #6197

Open
aya-abdallah-FOO wants to merge 3 commits into
apache:developfrom
foodeveloper:FINERACT-2720/office-entity-mapping-hierarchy-scope
Open

FINERACT-2720: Scope entity-to-entity mapping results to user office hierarchy#6197
aya-abdallah-FOO wants to merge 3 commits into
apache:developfrom
foodeveloper:FINERACT-2720/office-entity-mapping-hierarchy-scope

Conversation

@aya-abdallah-FOO

@aya-abdallah-FOO aya-abdallah-FOO commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Description

When the All option is selected in the Office dropdown on the Entity-to-Entity Mapping screen (System → Entity to Entity Mapping), the API returns mappings across all offices
in the system, including branches the authenticated user has no access to. This violates office-level access restrictions.

Root cause: retrieveEntityToEntityMappings treats fromId = 0 (the "All" sentinel) as a pass-through, so the SQL returns every row regardless of the caller's office
hierarchy.

Fix

When fromId == 0 and the relation's from_entity_type is 1 (office), a recursive CTE (WITH RECURSIVE office_descendants) scopes results to only the authenticated user's
office and its descendants. Non-office relation types fall through to the existing query unchanged.

Testing

  • A user in a non-root office sees only their office (and child offices) in the Entity-to-Entity Mapping dropdown — not "All" or unrelated branches.
  • :fineract-provider:compileJava and :fineract-provider:compileTestJava pass clean

FINERACT-2720

@adamsaghy

Copy link
Copy Markdown
Contributor
Execution failed for task ':fineract-provider:spotlessJavaCheck'.
> The following files had format violations:
      src/main/java/org/apache/fineract/infrastructure/entityaccess/service/FineractEntityAccessReadServiceImpl.java
          @@ -213,8 +213,7 @@
           
           ················EntityToEntityMapper·entityToEntityMapper·=·new·EntityToEntityMapper();
           ················String·officeScopedSql·=·entityToEntityMapper.schemaWithOfficeScopedFromId();
          -················return·this.jdbcTemplate.query(officeScopedSql,·entityToEntityMapper,
          -························new·Object[]·{·userOfficeId,·mapId,·toId,·toId·});
          +················return·this.jdbcTemplate.query(officeScopedSql,·entityToEntityMapper,·new·Object[]·{·userOfficeId,·mapId,·toId,·toId·});
           ············}
           ········}
           
  Run './gradlew :fineract-provider:spotlessApply' to fix these violations.

@adamsaghy adamsaghy left a comment

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 you add an integration / E2E test case to cover this?

@aya-abdallah-FOO

Copy link
Copy Markdown
Contributor Author

Can you add an integration / E2E test case to cover this?

@adamsaghy Done! Added EntityToEntityMappingIntegrationTest with two integration tests covering this fix:

  1. testOfficeUserSeesOnlyOwnOfficeMappingsWhenFromIdIsZero — Creates two sibling child offices (A and B), maps both to a loan product, then queries GET
    /entitytoentitymapping/{relId}/0/0 as a user belonging to Office A. Asserts that only Office A's mapping is returned and Office B's is not visible.
  2. testHeadOfficeUserSeesAllDescendantOfficeMappingsWhenFromIdIsZero — Same setup, queried as the superadmin (Head Office). Asserts both mappings are visible since Head Office is
    the root of the hierarchy.

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.

2 participants