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

dhavalshah9131 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new caa4478d8 RANGER-5341: Capture opCode in KMS access logs for EEK_OP 
operations (#688)
caa4478d8 is described below

commit caa4478d89983f68a680cd52d74b1be4c02fe2b8
Author: Chinmay Hegde <[email protected]>
AuthorDate: Wed Dec 3 12:31:07 2025 +0530

    RANGER-5341: Capture opCode in KMS access logs for EEK_OP operations (#688)
---
 .../ranger/server/tomcat/EmbeddedServer.java       |  2 +-
 .../hadoop/crypto/key/kms/server/KMSMDCFilter.java | 54 ++++++++++++---
 .../crypto/key/kms/server/TestKMSMDCFilter.java    | 79 ++++++++++++++++++++++
 3 files changed, 126 insertions(+), 9 deletions(-)

diff --git 
a/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java
 
b/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java
index 4b4076687..7013f5d83 100644
--- 
a/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java
+++ 
b/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java
@@ -226,7 +226,7 @@ public void start() {
         
valve.setMaxDays(EmbeddedServerUtil.getIntConfig(ACCESS_LOG_ROTATE_MAX_DAYS, 
15));
         
valve.setRenameOnRotate(EmbeddedServerUtil.getBooleanConfig(ACCESS_LOG_ROTATE_RENAME_ON_ROTATE,
 false));
 
-        String defaultAccessLogPattern = 
servername.equalsIgnoreCase(KMS_SERVER_NAME) ? "%h %l %u %t \"%m %U\" %s %b %D" 
: "%h %l %u %t \"%r\" %s %b %D";
+        String defaultAccessLogPattern = 
servername.equalsIgnoreCase(KMS_SERVER_NAME) ? "%h %l %u %t \"%m %U\" %s %b %D 
%{eek_op}r" : "%h %l %u %t \"%r\" %s %b %D";
         String logPattern              = 
EmbeddedServerUtil.getConfig(ACCESS_LOG_PATTERN, defaultAccessLogPattern);
 
         valve.setPattern(logPattern);
diff --git 
a/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMSMDCFilter.java 
b/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMSMDCFilter.java
index 3116b4671..203f9078d 100644
--- 
a/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMSMDCFilter.java
+++ 
b/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMSMDCFilter.java
@@ -20,6 +20,8 @@
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.security.UserGroupInformation;
 import 
org.apache.hadoop.security.token.delegation.web.HttpUserGroupInformation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -31,6 +33,9 @@
 import javax.servlet.http.HttpServletResponse;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Servlet filter that captures context of the HTTP request to be use in the
@@ -38,8 +43,12 @@
  */
 @InterfaceAudience.Private
 public class KMSMDCFilter implements Filter {
+    static final Logger logger = LoggerFactory.getLogger(KMSMDCFilter.class);
+
     static final String RANGER_KMS_REST_API_PATH = "/kms/api/status";
 
+    private static final String EEK_OP_CODE = "eek_op";
+
     private static final ThreadLocal<Data> DATA_TL = new ThreadLocal<>();
 
     public static UserGroupInformation getUgi() {
@@ -54,6 +63,10 @@ public static String getURL() {
         return DATA_TL.get().url;
     }
 
+    public static String getOperation() {
+        return DATA_TL.get().operation;
+    }
+
     @Override
     public void init(FilterConfig config) throws ServletException {
     }
@@ -62,6 +75,7 @@ public void init(FilterConfig config) throws ServletException 
{
     public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws IOException, ServletException {
         try {
             String              path = ((HttpServletRequest) 
request).getRequestURI();
+            HttpServletRequest  req  = (HttpServletRequest) request;
             HttpServletResponse resp = (HttpServletResponse) response;
 
             if (path.startsWith(RANGER_KMS_REST_API_PATH)) {
@@ -70,15 +84,37 @@ public void doFilter(ServletRequest request, 
ServletResponse response, FilterCha
                 DATA_TL.remove();
 
                 UserGroupInformation ugi         = 
HttpUserGroupInformation.get();
-                String               method      = ((HttpServletRequest) 
request).getMethod();
-                StringBuffer         requestURL  = ((HttpServletRequest) 
request).getRequestURL();
-                String               queryString = ((HttpServletRequest) 
request).getQueryString();
+                String               method      = req.getMethod();
+                StringBuffer         requestURL  = req.getRequestURL();
+                String               queryString = req.getQueryString();
+
+                // Extract operation from query parameters if present
+                String operation = null;
+                if (path.contains("/_eek") && queryString != null) {
+                    for (String param : queryString.split("&")) {
+                        String[] kv = param.split("=", 2);
+                        if (kv.length == 2 && "eek_op".equals(kv[0])) {
+                            try {
+                                operation = URLDecoder.decode(kv[1], 
StandardCharsets.UTF_8.name());
+                            } catch (UnsupportedEncodingException | 
IllegalArgumentException e) {
+                                logger.error("Failed to decode eek_op 
parameter value using UTF-8 encoding: {}", kv[1], e);
+                                throw new ServletException("Failed to decode 
eek_op parameter: '" + kv[1] + "'. " + e.getClass().getSimpleName() + ": " + 
e.getMessage(), e);
+                            }
+                            break;
+                        }
+                    }
+                }
 
                 if (queryString != null) {
                     requestURL.append("?").append(queryString);
                 }
 
-                DATA_TL.set(new Data(ugi, method, requestURL.toString()));
+                // Store opCode in request attribute for Tomcat access logs
+                if (operation != null) {
+                    req.setAttribute(EEK_OP_CODE, operation);
+                }
+
+                DATA_TL.set(new Data(ugi, method, requestURL.toString(), 
operation));
 
                 chain.doFilter(request, resp);
             }
@@ -95,11 +131,13 @@ private static class Data {
         private final UserGroupInformation ugi;
         private final String               method;
         private final String               url;
+        private final String               operation;
 
-        private Data(UserGroupInformation ugi, String method, String url) {
-            this.ugi    = ugi;
-            this.method = method;
-            this.url    = url;
+        private Data(UserGroupInformation ugi, String method, String url, 
String operation) {
+            this.ugi       = ugi;
+            this.method    = method;
+            this.url       = url;
+            this.operation = operation;
         }
     }
 }
diff --git 
a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java
 
b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java
index c83fbb512..f73934668 100644
--- 
a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java
+++ 
b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMSMDCFilter.java
@@ -29,7 +29,11 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+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;
 
@@ -86,4 +90,79 @@ public void testDoFilter_withOtherPath() throws Exception {
 
         verify(chain).doFilter(request, response);
     }
+
+    @Test
+    public void testDoFilter_withEekOpParameter() throws Exception {
+        KMSMDCFilter filter = new KMSMDCFilter();
+
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain chain = mock(FilterChain.class);
+
+        when(request.getRequestURI()).thenReturn("/kms/v1/_eek");
+        when(request.getMethod()).thenReturn("POST");
+        when(request.getRequestURL()).thenReturn(new 
StringBuffer("http://localhost/kms/v1/_eek";));
+        when(request.getQueryString()).thenReturn("eek_op=generate");
+
+        filter.doFilter(request, response, chain);
+
+        verify(request).setAttribute("eek_op", "generate");
+        verify(chain).doFilter(request, response);
+    }
+
+    @Test
+    public void testDoFilter_withEekPathWithoutEekOp() throws Exception {
+        KMSMDCFilter filter = new KMSMDCFilter();
+
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain chain = mock(FilterChain.class);
+
+        when(request.getRequestURI()).thenReturn("/kms/v1/_eek");
+        when(request.getMethod()).thenReturn("POST");
+        when(request.getRequestURL()).thenReturn(new 
StringBuffer("http://localhost/kms/v1/_eek";));
+        when(request.getQueryString()).thenReturn("other_param=value");
+
+        filter.doFilter(request, response, chain);
+
+        verify(request, never()).setAttribute(eq("eek_op"), any());
+        verify(chain).doFilter(request, response);
+    }
+
+    @Test
+    public void testDoFilter_withMalformedEekOpEncoding() throws Exception {
+        KMSMDCFilter filter = new KMSMDCFilter();
+
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain chain = mock(FilterChain.class);
+
+        when(request.getRequestURI()).thenReturn("/kms/v1/_eek");
+        when(request.getMethod()).thenReturn("POST");
+        when(request.getRequestURL()).thenReturn(new 
StringBuffer("http://localhost/kms/v1/_eek";));
+        // Malformed percent encoding
+        when(request.getQueryString()).thenReturn("eek_op=%E0%A4%A");
+
+        assertThrows(ServletException.class, () -> {
+            filter.doFilter(request, response, chain);
+        });
+    }
+
+    @Test
+    public void testDoFilter_withOtherPathAndQueryString() throws Exception {
+        KMSMDCFilter filter = new KMSMDCFilter();
+
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain chain = mock(FilterChain.class);
+
+        when(request.getRequestURI()).thenReturn("/kms/v1/keys");
+        when(request.getMethod()).thenReturn("GET");
+        when(request.getRequestURL()).thenReturn(new 
StringBuffer("http://localhost/kms/v1/keys";));
+        when(request.getQueryString()).thenReturn("foo=bar");
+
+        filter.doFilter(request, response, chain);
+
+        verify(chain).doFilter(request, response);
+    }
 }

Reply via email to