This is an automated email from the ASF dual-hosted git repository.

ashishvijaywargiya pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new fbd3e76480 Improved: Authorization enforcement for HumanRes category 
tree data access (#1637)
fbd3e76480 is described below

commit fbd3e7648052f32c9a05d3af7ae8cf305dffad95
Author: Krishna Uprit <[email protected]>
AuthorDate: Thu Aug 13 16:20:13 2026 +0530

    Improved: Authorization enforcement for HumanRes category tree data access 
(#1637)
    
    - The getHRChild request now requires authentication.
    - The backing handler additionally verifies that the caller holds the
    HUMANRES_VIEW permission before returning any data.
    - Unit tests were added covering the denied and allowed cases.
    
    Thank you @Krishnauprit18 for your help in this contribution.
---
 .../humanres/config/HumanResErrorUiLabels.xml      |   3 +
 .../org/apache/ofbiz/humanres/HumanResEvents.java  |  11 +++
 .../ofbiz/humanres/HumanResEventsTest.groovy       | 107 +++++++++++++++++++++
 .../webapp/humanres/WEB-INF/controller.xml         |   2 +-
 4 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/applications/humanres/config/HumanResErrorUiLabels.xml 
b/applications/humanres/config/HumanResErrorUiLabels.xml
index 97751c0e8d..cbe8936f21 100644
--- a/applications/humanres/config/HumanResErrorUiLabels.xml
+++ b/applications/humanres/config/HumanResErrorUiLabels.xml
@@ -60,4 +60,7 @@
     <property key="HumanResFromDateAlreadyExist">
         <value xml:lang="en">This FromDate : ${parameters.estimatedStartDate} 
already exist.</value>
     </property>
+    <property key="HumanResViewPermissionError">
+        <value xml:lang="en">You do not have permission to view Human 
Resources organization data.</value>
+    </property>
 </resource>
\ No newline at end of file
diff --git 
a/applications/humanres/src/main/java/org/apache/ofbiz/humanres/HumanResEvents.java
 
b/applications/humanres/src/main/java/org/apache/ofbiz/humanres/HumanResEvents.java
index eaf02c015f..96a68f0825 100644
--- 
a/applications/humanres/src/main/java/org/apache/ofbiz/humanres/HumanResEvents.java
+++ 
b/applications/humanres/src/main/java/org/apache/ofbiz/humanres/HumanResEvents.java
@@ -28,6 +28,8 @@ import jakarta.servlet.http.HttpServletResponse;
 
 import org.apache.ofbiz.base.util.Debug;
 import org.apache.ofbiz.base.util.UtilGenerics;
+import org.apache.ofbiz.base.util.UtilHttp;
+import org.apache.ofbiz.base.util.UtilProperties;
 import org.apache.ofbiz.base.util.UtilValidate;
 import org.apache.ofbiz.entity.Delegator;
 import org.apache.ofbiz.entity.GenericEntityException;
@@ -36,6 +38,7 @@ import org.apache.ofbiz.entity.condition.EntityCondition;
 import org.apache.ofbiz.entity.condition.EntityOperator;
 import org.apache.ofbiz.entity.util.EntityQuery;
 import org.apache.ofbiz.party.party.PartyHelper;
+import org.apache.ofbiz.security.Security;
 
 public class HumanResEvents {
     private static final String MODULE = HumanResEvents.class.getName();
@@ -43,6 +46,14 @@ public class HumanResEvents {
 
     // Please note : the structure of map in this function is according to the 
JSON data map of the jsTree
     public static String getChildHRCategoryTree(HttpServletRequest request, 
HttpServletResponse response) {
+        Security security = (Security) request.getAttribute("security");
+        if (security == null || !security.hasEntityPermission("HUMANRES", 
"_VIEW", request.getSession())) {
+            String errMsg = UtilProperties.getMessage(RES_ERROR, 
"HumanResViewPermissionError", UtilHttp.getLocale(request));
+            request.setAttribute("_ERROR_MESSAGE_", errMsg);
+            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+            Debug.logWarning("Unauthorized attempt to access getHRChild by 
partyId param [%s]", MODULE, request.getParameter("partyId"));
+            return "error";
+        }
         Delegator delegator = (Delegator) request.getAttribute("delegator");
         String partyId = request.getParameter("partyId");
         String onclickFunction = request.getParameter("onclickFunction");
diff --git 
a/applications/humanres/src/test/groovy/org/apache/ofbiz/humanres/HumanResEventsTest.groovy
 
b/applications/humanres/src/test/groovy/org/apache/ofbiz/humanres/HumanResEventsTest.groovy
new file mode 100644
index 0000000000..16d5a6931e
--- /dev/null
+++ 
b/applications/humanres/src/test/groovy/org/apache/ofbiz/humanres/HumanResEventsTest.groovy
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ 
*******************************************************************************/
+package org.apache.ofbiz.humanres
+
+import static org.mockito.ArgumentMatchers.any
+import static org.mockito.ArgumentMatchers.anyBoolean
+import static org.mockito.ArgumentMatchers.anyString
+import static org.mockito.ArgumentMatchers.eq
+import static org.mockito.Mockito.mock
+import static org.mockito.Mockito.never
+import static org.mockito.Mockito.verify
+import static org.mockito.Mockito.when
+
+import jakarta.servlet.http.HttpServletRequest
+import jakarta.servlet.http.HttpServletResponse
+import jakarta.servlet.http.HttpSession
+
+import org.apache.ofbiz.entity.Delegator
+import org.apache.ofbiz.security.Security
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+/**
+ * Regression tests for the getHRChild fix: {@link 
HumanResEvents#getChildHRCategoryTree}
+ * must deny access unless the caller holds HUMANRES_VIEW, and must not query 
any
+ * HR/party entities before that check passes.
+ */
+// codenarc-disable JUnitLostTest
+class HumanResEventsTest {
+
+    private HttpServletRequest request
+    private HttpServletResponse response
+    private HttpSession session
+    private Security security
+    private Delegator delegator
+
+    @BeforeEach
+    void setupMocks() {
+        request = mock(HttpServletRequest)
+        response = mock(HttpServletResponse)
+        session = mock(HttpSession)
+        security = mock(Security)
+        delegator = mock(Delegator)
+        when(request.getSession()).thenReturn(session)
+        when(request.getLocale()).thenReturn(Locale.US)
+    }
+
+    @Test
+    void deniesAnonymousCallerWithNoSecurityAttribute() {
+        when(request.getAttribute('security')).thenReturn(null)
+
+        String result = HumanResEvents.getChildHRCategoryTree(request, 
response)
+
+        assert result == 'error'
+        verify(response).setStatus(HttpServletResponse.SC_FORBIDDEN)
+        verify(request, never()).setAttribute(eq('hrTree'), any())
+        verify(request, never()).getAttribute('delegator')
+    }
+
+    @Test
+    void deniesAuthenticatedCallerWithoutHumanresViewPermission() {
+        when(request.getAttribute('security')).thenReturn(security)
+        when(security.hasEntityPermission('HUMANRES', '_VIEW', 
session)).thenReturn(false)
+
+        String result = HumanResEvents.getChildHRCategoryTree(request, 
response)
+
+        assert result == 'error'
+        verify(response).setStatus(HttpServletResponse.SC_FORBIDDEN)
+        verify(request, never()).setAttribute(eq('hrTree'), any())
+        verify(request, never()).getAttribute('delegator')
+    }
+
+    @Test
+    void allowsCallerWithHumanresViewPermissionPastTheGate() {
+        when(request.getAttribute('security')).thenReturn(security)
+        when(request.getAttribute('delegator')).thenReturn(delegator)
+        when(request.getParameter('partyId')).thenReturn('Company')
+        when(security.hasEntityPermission('HUMANRES', '_VIEW', 
session)).thenReturn(true)
+        when(delegator.getDelegator()).thenReturn(delegator)
+        when(delegator.findList(anyString(), any(), any(), any(), any(), 
any(), anyBoolean()))
+                .thenReturn(Collections.emptyList())
+        when(delegator.findCountByCondition(anyString(), any(), any(), any(), 
any())).thenReturn(0L)
+
+        String result = HumanResEvents.getChildHRCategoryTree(request, 
response)
+
+        assert result == 'success'
+        verify(response, never()).setStatus(HttpServletResponse.SC_FORBIDDEN)
+        verify(request).setAttribute(eq('hrTree'), any())
+    }
+
+}
diff --git a/applications/humanres/webapp/humanres/WEB-INF/controller.xml 
b/applications/humanres/webapp/humanres/WEB-INF/controller.xml
index f446d070f0..d249671eb7 100644
--- a/applications/humanres/webapp/humanres/WEB-INF/controller.xml
+++ b/applications/humanres/webapp/humanres/WEB-INF/controller.xml
@@ -1052,7 +1052,7 @@ under the License.
         <response name="error" type="view" value="EditEmplLeaveStatus"/>
     </request-map>
     <request-map uri="getHRChild">
-        <security auth="false" https="true"/>
+        <security auth="true" https="true"/>
         <event type="java" path="org.apache.ofbiz.humanres.HumanResEvents" 
invoke="getChildHRCategoryTree"/>
         <response name="success" type="request" value="json"/>
         <response name="error" type="request" value="json"/>

Reply via email to