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

abhi 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 2345c1d79 RANGER-5499: Add support for header based authentication 
(#873)
2345c1d79 is described below

commit 2345c1d79d63f632bab237a8b08426d056b30f6c
Author: Abhishek Kumar <[email protected]>
AuthorDate: Wed Mar 18 12:25:53 2026 -0700

    RANGER-5499: Add support for header based authentication (#873)
    
    
    Co-authored-by: Madhan Neethiraj <[email protected]>
    Co-authored-by: Cursor AI (assisted) <[email protected]>
---
 mkdocs/.gitignore                                  |   1 +
 .../web/filter/RangerAuthenticationToken.java      |  55 +++++++
 .../web/filter/RangerHeaderPreAuthFilter.java      | 117 ++++++++++++++
 .../RangerSecurityContextFormationFilter.java      |  44 +++--
 .../main/resources/conf.dist/ranger-admin-site.xml |  14 ++
 .../conf.dist/security-applicationContext.xml      |   4 +
 .../web/filter/TestRangerHeaderPreAuthFilter.java  | 179 +++++++++++++++++++++
 .../TestRangerSecurityContextFormationFilter.java  | 177 +++++++++++---------
 8 files changed, 498 insertions(+), 93 deletions(-)

diff --git a/mkdocs/.gitignore b/mkdocs/.gitignore
new file mode 100644
index 000000000..988107fe1
--- /dev/null
+++ b/mkdocs/.gitignore
@@ -0,0 +1 @@
+.cache/
\ No newline at end of file
diff --git 
a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerAuthenticationToken.java
 
b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerAuthenticationToken.java
new file mode 100644
index 000000000..ccf43a417
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerAuthenticationToken.java
@@ -0,0 +1,55 @@
+/*
+ * 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.ranger.security.web.filter;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+public class RangerAuthenticationToken extends AbstractAuthenticationToken {
+    private static final long serialVersionUID = 1L;
+
+    private final Object principal;
+    private final int    authType;
+
+    public RangerAuthenticationToken(UserDetails principal, Collection<? 
extends GrantedAuthority> authorities, int authType) {
+        super(authorities);
+
+        this.principal = principal;
+        this.authType  = authType;
+
+        super.setAuthenticated(true);
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return principal;
+    }
+
+    @Override
+    public Object getCredentials() {
+        return null;
+    }
+
+    public int getAuthType() {
+        return authType;
+    }
+}
diff --git 
a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerHeaderPreAuthFilter.java
 
b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerHeaderPreAuthFilter.java
new file mode 100644
index 000000000..89bb78750
--- /dev/null
+++ 
b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerHeaderPreAuthFilter.java
@@ -0,0 +1,117 @@
+/*
+ * 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.ranger.security.web.filter;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ranger.biz.UserMgr;
+import org.apache.ranger.common.PropertiesUtil;
+import org.apache.ranger.entity.XXAuthSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import 
org.springframework.security.web.authentication.WebAuthenticationDetails;
+import org.springframework.web.filter.GenericFilterBean;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class RangerHeaderPreAuthFilter extends GenericFilterBean {
+    private static final Logger LOG = 
LoggerFactory.getLogger(RangerHeaderPreAuthFilter.class);
+
+    public static final String PROP_HEADER_AUTH_ENABLED        = 
"ranger.admin.authn.header.enabled";
+    public static final String PROP_USERNAME_HEADER_NAME       = 
"ranger.admin.authn.header.username";
+    public static final String PROP_REQUEST_ID_HEADER_NAME     = 
"ranger.admin.authn.header.requestid";
+
+    private boolean headerAuthEnabled;
+    private String  userNameHeaderName;
+
+    @Autowired
+    UserMgr userMgr;
+
+    @PostConstruct
+    public void initialize(FilterConfig filterConfig) throws ServletException {
+        headerAuthEnabled  = 
PropertiesUtil.getBooleanProperty(PROP_HEADER_AUTH_ENABLED, false);
+        userNameHeaderName = 
PropertiesUtil.getProperty(PROP_USERNAME_HEADER_NAME);
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain) throws IOException, ServletException {
+        HttpServletRequest  httpRequest  = (HttpServletRequest) request;
+
+        if (headerAuthEnabled) {
+            Authentication existingAuthn = 
SecurityContextHolder.getContext().getAuthentication();
+
+            if (existingAuthn == null || !existingAuthn.isAuthenticated()) {
+                String username = 
StringUtils.trimToNull(httpRequest.getHeader(userNameHeaderName));
+
+                if (StringUtils.isNotBlank(username)) {
+                    List<GrantedAuthority>    grantedAuthorities = 
getAuthoritiesFromRanger(username);
+                    final UserDetails         principal          = new 
User(username, "", grantedAuthorities);
+                    RangerAuthenticationToken authToken          = new 
RangerAuthenticationToken(principal, grantedAuthorities, 
XXAuthSession.AUTH_TYPE_TRUSTED_PROXY);
+
+                    authToken.setDetails(new 
WebAuthenticationDetails(httpRequest));
+
+                    
SecurityContextHolder.getContext().setAuthentication(authToken);
+
+                    LOG.debug("Authenticated request using trusted headers for 
user={}", username);
+                } else {
+                    LOG.debug("Username header '{}' is missing or empty in the 
request!", userNameHeaderName);
+                }
+            }
+        } else {
+            LOG.debug("Header-based authentication is disabled!");
+        }
+
+        chain.doFilter(request, response);
+    }
+
+    /**
+     * Loads authorities from Ranger DB
+     */
+    private List<GrantedAuthority> getAuthoritiesFromRanger(String username) {
+        List<GrantedAuthority> ret = new ArrayList<>();
+        Collection<String>    roleList = userMgr.getRolesByLoginId(username);
+
+        if (roleList != null) {
+            for (String role : roleList) {
+                if (StringUtils.isNotBlank(role)) {
+                    ret.add(new SimpleGrantedAuthority(role));
+                }
+            }
+        }
+
+        return ret;
+    }
+}
diff --git 
a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerSecurityContextFormationFilter.java
 
b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerSecurityContextFormationFilter.java
index 9951960e5..cf03c6cbd 100644
--- 
a/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerSecurityContextFormationFilter.java
+++ 
b/security-admin/src/main/java/org/apache/ranger/security/web/filter/RangerSecurityContextFormationFilter.java
@@ -22,6 +22,7 @@
  */
 package org.apache.ranger.security.web.filter;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.ranger.biz.SessionMgr;
 import org.apache.ranger.biz.XUserMgr;
 import org.apache.ranger.common.GUIDUtil;
@@ -33,6 +34,8 @@
 import org.apache.ranger.security.context.RangerContextHolder;
 import org.apache.ranger.security.context.RangerSecurityContext;
 import org.apache.ranger.util.RestUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import 
org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.core.Authentication;
@@ -50,6 +53,8 @@
 import java.io.IOException;
 
 public class RangerSecurityContextFormationFilter extends GenericFilterBean {
+    private static final Logger LOG = 
LoggerFactory.getLogger(RangerSecurityContextFormationFilter.class);
+
     public static final String AKA_SC_SESSION_KEY = "AKA_SECURITY_CONTEXT";
     public static final String USER_AGENT         = "User-Agent";
 
@@ -65,10 +70,12 @@ public class RangerSecurityContextFormationFilter extends 
GenericFilterBean {
     @Autowired
     GUIDUtil guidUtil;
 
-    String testIP;
+    private final String testIP;
+    private final String requestIdHeaderName;
 
     public RangerSecurityContextFormationFilter() {
-        testIP = PropertiesUtil.getProperty("xa.env.ip");
+        this.testIP              = PropertiesUtil.getProperty("xa.env.ip");
+        this.requestIdHeaderName = 
PropertiesUtil.getProperty(RangerHeaderPreAuthFilter.PROP_REQUEST_ID_HEADER_NAME);
     }
 
     /*
@@ -113,7 +120,7 @@ public void doFilter(ServletRequest request, 
ServletResponse response, FilterCha
                 requestContext.setIpAddress(reqIP);
                 requestContext.setUserAgent(userAgent);
                 
requestContext.setDeviceType(httpUtil.getDeviceType(httpRequest));
-                requestContext.setServerRequestId(guidUtil.genGUID());
+                requestContext.setServerRequestId(getRequestId(auth, 
httpRequest));
                 requestContext.setRequestURL(httpRequest.getRequestURI());
                 requestContext.setClientTimeOffsetInMinute(clientTimeOffset);
 
@@ -121,7 +128,7 @@ public void doFilter(ServletRequest request, 
ServletResponse response, FilterCha
 
                 RangerContextHolder.setSecurityContext(context);
 
-                int             authType    = getAuthType(httpRequest);
+                int             authType    = getAuthType(auth, httpRequest);
                 UserSessionBase userSession = 
sessionMgr.processSuccessLogin(authType, userAgent, httpRequest);
 
                 if (userSession != null) {
@@ -160,25 +167,36 @@ private void setupAdminOpContext(ServletRequest request) {
         }
     }
 
-    private int getAuthType(HttpServletRequest request) {
-        int     authType;
+    private int getAuthType(Authentication auth, HttpServletRequest request) {
+        if (auth instanceof RangerAuthenticationToken) {
+            return ((RangerAuthenticationToken) auth).getAuthType();
+        }
+
         Object  ssoEnabledObj = request.getAttribute("ssoEnabled");
         boolean ssoEnabled    = ssoEnabledObj != null ? 
Boolean.parseBoolean(String.valueOf(ssoEnabledObj)) : 
PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);
 
         if (ssoEnabled) {
-            authType = XXAuthSession.AUTH_TYPE_SSO;
+            return XXAuthSession.AUTH_TYPE_SSO;
         } else if (request.getAttribute("spnegoEnabled") != null && 
Boolean.parseBoolean(String.valueOf(request.getAttribute("spnegoEnabled")))) {
             if (request.getAttribute("trustedProxyEnabled") != null && 
Boolean.parseBoolean(String.valueOf(request.getAttribute("trustedProxyEnabled"))))
 {
-                logger.debug("Setting auth type as trusted proxy");
+                LOG.debug("Setting auth type as trusted proxy");
 
-                authType = XXAuthSession.AUTH_TYPE_TRUSTED_PROXY;
+                return XXAuthSession.AUTH_TYPE_TRUSTED_PROXY;
             } else {
-                authType = XXAuthSession.AUTH_TYPE_KERBEROS;
+                return XXAuthSession.AUTH_TYPE_KERBEROS;
             }
-        } else {
-            authType = XXAuthSession.AUTH_TYPE_PASSWORD;
         }
 
-        return authType;
+        return XXAuthSession.AUTH_TYPE_PASSWORD;
+    }
+
+    private String getRequestId(Authentication auth, HttpServletRequest 
request) {
+        String ret = null;
+
+        if (requestIdHeaderName != null && auth instanceof 
RangerAuthenticationToken && ((RangerAuthenticationToken) auth).getAuthType() 
== XXAuthSession.AUTH_TYPE_TRUSTED_PROXY) {
+            ret = 
StringUtils.trimToNull(request.getHeader(requestIdHeaderName));
+        }
+
+        return ret != null ? ret : guidUtil.genGUID();
     }
 }
diff --git a/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml 
b/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
index 2da6f1c43..d1fccc27d 100644
--- a/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
+++ b/security-admin/src/main/resources/conf.dist/ranger-admin-site.xml
@@ -271,6 +271,20 @@
                <value>Mozilla,chrome</value>
        </property>
        <!-- SSO Properties Ends-->
+       <!-- Trusted header auth properties start -->
+       <property>
+               <name>ranger.admin.authn.header.enabled</name>
+               <value>false</value>
+       </property>
+       <property>
+               <name>ranger.admin.authn.header.username</name>
+               <value>x-awc-username</value>
+       </property>
+       <property>
+               <name>ranger.admin.authn.header.requestid</name>
+               <value>x-awc-requestid</value>
+       </property>
+       <!-- Trusted header auth properties end -->
        <!-- Kerberos Properties starts-->      
        <property>
                <name>ranger.admin.kerberos.token.valid.seconds</name>
diff --git 
a/security-admin/src/main/resources/conf.dist/security-applicationContext.xml 
b/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
index c9fd0ae8d..bbb94a3a4 100644
--- 
a/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
+++ 
b/security-admin/src/main/resources/conf.dist/security-applicationContext.xml
@@ -64,6 +64,7 @@ 
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd";>
                </security:headers>
                <security:session-management 
session-fixation-protection="newSession" />
                <intercept-url pattern="/**" access="isAuthenticated()"/>
+               <security:custom-filter position="PRE_AUTH_FILTER" 
ref="headerPreAuthFilter" />
                <custom-filter ref="ssoAuthenticationFilter" 
after="BASIC_AUTH_FILTER" />
                <security:custom-filter ref="rangerJwtAuthWrapper" 
before="SERVLET_API_SUPPORT_FILTER" />
                <security:custom-filter ref="krbAuthenticationFilter" 
after="SERVLET_API_SUPPORT_FILTER" />
@@ -115,6 +116,9 @@ 
http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd";>
        <beans:bean id="mdcFilter" 
class="org.apache.ranger.security.web.filter.RangerMDCFilter">
     </beans:bean>
 
+       <beans:bean id="headerPreAuthFilter" 
class="org.apache.ranger.security.web.filter.RangerHeaderPreAuthFilter">
+    </beans:bean>
+
     <beans:bean id="ssoAuthenticationFilter" 
class="org.apache.ranger.security.web.filter.RangerSSOAuthenticationFilter">
     </beans:bean>
        
diff --git 
a/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerHeaderPreAuthFilter.java
 
b/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerHeaderPreAuthFilter.java
new file mode 100644
index 000000000..2ed69a6fb
--- /dev/null
+++ 
b/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerHeaderPreAuthFilter.java
@@ -0,0 +1,179 @@
+/*
+ * 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.ranger.security.web.filter;
+
+import org.apache.ranger.biz.UserMgr;
+import org.apache.ranger.common.PropertiesUtil;
+import org.apache.ranger.entity.XXAuthSession;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+@TestMethodOrder(MethodOrderer.MethodName.class)
+public class TestRangerHeaderPreAuthFilter {
+    @BeforeEach
+    public void setUp() {
+        SecurityContextHolder.clearContext();
+    }
+
+    @AfterEach
+    public void tearDown() {
+        SecurityContextHolder.clearContext();
+
+        
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED);
+        
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME);
+        
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_REQUEST_ID_HEADER_NAME);
+    }
+
+    @Test
+    public void testDoFilter_disabled_passesThrough() throws Exception {
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize(null);
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain         chain    = mock(FilterChain.class);
+
+        filter.doFilter(request, response, chain);
+
+        verify(chain).doFilter(request, response);
+        verify(userMgr, never()).getRolesByLoginId(anyString());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
+    }
+
+    @Test
+    public void testDoFilter_enabled_missingUsername_passesThrough() throws 
Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "x-awc-username");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize(null);
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain         chain    = mock(FilterChain.class);
+
+        // no username header — getHeader returns null by default
+
+        filter.doFilter(request, response, chain);
+
+        verify(chain).doFilter(request, response);
+        verify(userMgr, never()).getRolesByLoginId(anyString());
+        assertNull(SecurityContextHolder.getContext().getAuthentication());
+    }
+
+    @Test
+    public void 
testDoFilter_enabled_withUsername_setsAuthenticationFromRangerDbRoles() throws 
Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "x-awc-username");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize(null);
+
+        
when(userMgr.getRolesByLoginId("joeuser")).thenReturn(Arrays.asList("ROLE_SYS_ADMIN",
 "ROLE_USER"));
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+
+        when(request.getHeader("x-awc-username")).thenReturn("joeuser");
+
+        FilterChain chain = new FilterChain() {
+            @Override
+            public void doFilter(ServletRequest req, ServletResponse res) {
+                org.springframework.security.core.Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+
+                assertNotNull(auth);
+                assertTrue(auth instanceof RangerAuthenticationToken);
+                RangerAuthenticationToken rangerAuth = 
(RangerAuthenticationToken) auth;
+                assertEquals(XXAuthSession.AUTH_TYPE_TRUSTED_PROXY, 
rangerAuth.getAuthType());
+                assertEquals("joeuser", auth.getName());
+
+                Collection<?> authorities = auth.getAuthorities();
+                assertEquals(2, authorities.size());
+                assertTrue(authorities.stream().anyMatch(a -> 
"ROLE_SYS_ADMIN".equals(a.toString())));
+                assertTrue(authorities.stream().anyMatch(a -> 
"ROLE_USER".equals(a.toString())));
+            }
+        };
+
+        filter.doFilter(request, response, chain);
+    }
+
+    @Test
+    public void 
testDoFilter_enabled_existingAuthenticatedContext_doesNotOverrideAuthentication()
 throws Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "x-awc-username");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize(null);
+
+        UsernamePasswordAuthenticationToken existingAuth = new 
UsernamePasswordAuthenticationToken("existing-user", "pwd", 
Collections.singletonList(new SimpleGrantedAuthority("test-role")));
+
+        SecurityContextHolder.getContext().setAuthentication(existingAuth);
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+        FilterChain         chain    = mock(FilterChain.class);
+
+        filter.doFilter(request, response, chain);
+
+        verify(chain).doFilter(request, response);
+        verify(userMgr, never()).getRolesByLoginId(anyString());
+        assertEquals(existingAuth, 
SecurityContextHolder.getContext().getAuthentication());
+    }
+}
diff --git 
a/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerSecurityContextFormationFilter.java
 
b/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerSecurityContextFormationFilter.java
index 8672bfe15..ff9f059bc 100644
--- 
a/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerSecurityContextFormationFilter.java
+++ 
b/security-admin/src/test/java/org/apache/ranger/security/web/filter/TestRangerSecurityContextFormationFilter.java
@@ -22,6 +22,7 @@
 import org.apache.ranger.biz.XUserMgr;
 import org.apache.ranger.common.GUIDUtil;
 import org.apache.ranger.common.HTTPUtil;
+import org.apache.ranger.common.PropertiesUtil;
 import org.apache.ranger.common.RangerCommonEnums;
 import org.apache.ranger.common.UserSessionBase;
 import org.apache.ranger.entity.XXAuthSession;
@@ -35,11 +36,11 @@
 import org.mockito.Mockito;
 import org.mockito.junit.jupiter.MockitoExtension;
 import 
org.springframework.security.authentication.AnonymousAuthenticationToken;
-import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
 
 import javax.servlet.FilterChain;
 import javax.servlet.ServletException;
@@ -52,6 +53,7 @@
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.util.Collections;
+import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -140,94 +142,109 @@ public void doFilter(ServletRequest servletRequest, 
ServletResponse servletRespo
     @Test
     public void testGetAuthType_reflectionVariants() throws Exception {
         RangerSecurityContextFormationFilter filter = new 
RangerSecurityContextFormationFilter();
-        Method m = 
RangerSecurityContextFormationFilter.class.getDeclaredMethod("getAuthType", 
HttpServletRequest.class);
+        Method m = 
RangerSecurityContextFormationFilter.class.getDeclaredMethod("getAuthType", 
Authentication.class, HttpServletRequest.class);
         m.setAccessible(true);
 
-        // SSO enabled
+        List<GrantedAuthority> authorities  = Collections.singletonList(new 
SimpleGrantedAuthority("ROLE_USER"));
+        UserDetails            userDetails  = new 
org.springframework.security.core.userdetails.User("u", "", authorities);
+        HttpServletRequest     emptyRequest = 
Mockito.mock(HttpServletRequest.class);
+
+        // Header-based trusted proxy — identified via 
RangerAuthenticationToken, no request attributes needed
+        assertEquals(XXAuthSession.AUTH_TYPE_TRUSTED_PROXY,
+                m.invoke(filter, new RangerAuthenticationToken(userDetails, 
authorities, XXAuthSession.AUTH_TYPE_TRUSTED_PROXY), emptyRequest));
+
+        // SSO — identified via request attribute 
(RangerSSOAuthenticationFilter sets UsernamePasswordAuthenticationToken)
         HttpServletRequest reqSso = Mockito.mock(HttpServletRequest.class);
-        when(reqSso.getAttribute("ssoEnabled")).thenReturn(true);
-        int sso = (int) m.invoke(filter, reqSso);
-        assertEquals(XXAuthSession.AUTH_TYPE_SSO, sso);
+        Mockito.when(reqSso.getAttribute("ssoEnabled")).thenReturn(true);
+        assertEquals(XXAuthSession.AUTH_TYPE_SSO,
+                m.invoke(filter, new 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken("u",
 "pwd", authorities), reqSso));
 
-        // Kerberos
+        // Kerberos — identified via spnegoEnabled attribute
         HttpServletRequest reqKrb = Mockito.mock(HttpServletRequest.class);
-        when(reqKrb.getAttribute("ssoEnabled")).thenReturn(false);
-        when(reqKrb.getAttribute("spnegoEnabled")).thenReturn(true);
-        when(reqKrb.getAttribute("trustedProxyEnabled")).thenReturn(false);
-        int krb = (int) m.invoke(filter, reqKrb);
-        assertEquals(XXAuthSession.AUTH_TYPE_KERBEROS, krb);
-
-        // Trusted proxy
-        HttpServletRequest reqTp = Mockito.mock(HttpServletRequest.class);
-        when(reqTp.getAttribute("ssoEnabled")).thenReturn(false);
-        when(reqTp.getAttribute("spnegoEnabled")).thenReturn(true);
-        when(reqTp.getAttribute("trustedProxyEnabled")).thenReturn(true);
-        int tp = (int) m.invoke(filter, reqTp);
-        assertEquals(XXAuthSession.AUTH_TYPE_TRUSTED_PROXY, tp);
-
-        // Password default
+        Mockito.when(reqKrb.getAttribute("ssoEnabled")).thenReturn(false);
+        Mockito.when(reqKrb.getAttribute("spnegoEnabled")).thenReturn(true);
+        
Mockito.when(reqKrb.getAttribute("trustedProxyEnabled")).thenReturn(false);
+        assertEquals(XXAuthSession.AUTH_TYPE_KERBEROS,
+                m.invoke(filter, new 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken("u",
 "pwd", authorities), reqKrb));
+
+        // Kerberos trusted proxy — both spnegoEnabled and trustedProxyEnabled
+        HttpServletRequest reqKrbTp = Mockito.mock(HttpServletRequest.class);
+        Mockito.when(reqKrbTp.getAttribute("ssoEnabled")).thenReturn(false);
+        Mockito.when(reqKrbTp.getAttribute("spnegoEnabled")).thenReturn(true);
+        
Mockito.when(reqKrbTp.getAttribute("trustedProxyEnabled")).thenReturn(true);
+        assertEquals(XXAuthSession.AUTH_TYPE_TRUSTED_PROXY,
+                m.invoke(filter, new 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken("u",
 "pwd", authorities), reqKrbTp));
+
+        // Password — no RangerAuthenticationToken, ssoEnabled explicitly 
false, no Kerberos attributes
         HttpServletRequest reqPwd = Mockito.mock(HttpServletRequest.class);
-        when(reqPwd.getAttribute("ssoEnabled")).thenReturn(false);
-        when(reqPwd.getAttribute("spnegoEnabled")).thenReturn(false);
-        int pwd = (int) m.invoke(filter, reqPwd);
-        assertEquals(XXAuthSession.AUTH_TYPE_PASSWORD, pwd);
+        Mockito.when(reqPwd.getAttribute("ssoEnabled")).thenReturn(false);
+        assertEquals(XXAuthSession.AUTH_TYPE_PASSWORD,
+                m.invoke(filter, new 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken("u",
 "pwd", authorities), reqPwd));
     }
 
     @Test
     public void 
testDoFilter_authenticated_createsSecurityContextAndUserSession() throws 
Exception {
-        RangerSecurityContextFormationFilter filter = new 
RangerSecurityContextFormationFilter();
-
-        // Inject dependencies
-        SessionMgr sessionMgr = Mockito.mock(SessionMgr.class);
-        HTTPUtil httpUtil = Mockito.mock(HTTPUtil.class);
-        GUIDUtil guidUtil = Mockito.mock(GUIDUtil.class);
-        XUserMgr xUserMgr = Mockito.mock(XUserMgr.class);
-        filter.sessionMgr = sessionMgr;
-        filter.httpUtil = httpUtil;
-        filter.guidUtil = guidUtil;
-        filter.xUserMgr = xUserMgr;
-
-        // Authenticated user (non-anonymous)
-        UsernamePasswordAuthenticationToken authentication =
-                new UsernamePasswordAuthenticationToken("user", "pwd",
-                        Collections.singletonList(new 
SimpleGrantedAuthority("ROLE_USER")));
-        SecurityContextHolder.getContext().setAuthentication(authentication);
-
-        HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
-        HttpServletResponse res = Mockito.mock(HttpServletResponse.class);
-        HttpSession session = Mockito.mock(HttpSession.class);
-
-        Mockito.when(req.getSession(false)).thenReturn(session);
-        
Mockito.when(session.getAttribute(RangerSecurityContextFormationFilter.AKA_SC_SESSION_KEY)).thenReturn(null);
-        
Mockito.when(req.getHeader(RangerSecurityContextFormationFilter.USER_AGENT)).thenReturn("Mozilla/5.0");
-        Mockito.when(req.getRequestURI()).thenReturn("/secure");
-        
Mockito.when(httpUtil.getDeviceType(req)).thenReturn(RangerCommonEnums.DEVICE_BROWSER);
-        Mockito.when(guidUtil.genGUID()).thenReturn("guid-1");
-
-        UserSessionBase userSession = Mockito.mock(UserSessionBase.class);
-        Mockito.when(userSession.getClientTimeOffsetInMinute()).thenReturn(0);
-        Mockito.when(sessionMgr.processSuccessLogin(Mockito.anyInt(), 
Mockito.anyString(), Mockito.any(HttpServletRequest.class)))
-                .thenReturn(userSession);
-
-        FilterChain chain = new FilterChain() {
-            @Override
-            public void doFilter(ServletRequest servletRequest, 
ServletResponse servletResponse) {
-                RangerSecurityContext ctx = 
RangerContextHolder.getSecurityContext();
-                assertNotNull(ctx);
-                assertNotNull(ctx.getRequestContext());
-                assertSame(userSession, ctx.getUserSession());
-            }
-        };
-
-        filter.doFilter(req, res, chain);
-
-        Mockito.verify(session, 
Mockito.times(1)).setAttribute(Mockito.eq(RangerSecurityContextFormationFilter.AKA_SC_SESSION_KEY),
 Mockito.any());
-        Mockito.verify(res).setHeader("X-Frame-Options", "DENY");
-        Mockito.verify(sessionMgr, 
Mockito.times(1)).processSuccessLogin(Mockito.anyInt(), Mockito.anyString(), 
Mockito.any(HttpServletRequest.class));
-        Mockito.verify(userSession, 
Mockito.times(1)).setClientTimeOffsetInMinute(Mockito.anyInt());
-
-        // cleaned up after the call
-        assertNull(RangerContextHolder.getSecurityContext());
-        assertNull(RangerContextHolder.getOpContext());
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_REQUEST_ID_HEADER_NAME,
 "x-awc-requestid");
+
+        try {
+            RangerSecurityContextFormationFilter filter = new 
RangerSecurityContextFormationFilter();
+
+            SessionMgr sessionMgr = Mockito.mock(SessionMgr.class);
+            HTTPUtil   httpUtil   = Mockito.mock(HTTPUtil.class);
+            GUIDUtil   guidUtil   = Mockito.mock(GUIDUtil.class);
+            XUserMgr   xUserMgr   = Mockito.mock(XUserMgr.class);
+
+            filter.sessionMgr = sessionMgr;
+            filter.httpUtil   = httpUtil;
+            filter.guidUtil   = guidUtil;
+            filter.xUserMgr   = xUserMgr;
+
+            List<GrantedAuthority>   authorities    = 
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
+            UserDetails              userDetails    = new 
org.springframework.security.core.userdetails.User("user", "", authorities);
+            RangerAuthenticationToken authentication = new 
RangerAuthenticationToken(userDetails, authorities, 
XXAuthSession.AUTH_TYPE_TRUSTED_PROXY);
+
+            
SecurityContextHolder.getContext().setAuthentication(authentication);
+
+            HttpServletRequest  req     = 
Mockito.mock(HttpServletRequest.class);
+            HttpServletResponse res     = 
Mockito.mock(HttpServletResponse.class);
+            HttpSession         session = Mockito.mock(HttpSession.class);
+
+            Mockito.when(req.getSession(false)).thenReturn(session);
+            
Mockito.when(session.getAttribute(RangerSecurityContextFormationFilter.AKA_SC_SESSION_KEY)).thenReturn(null);
+            
Mockito.when(req.getHeader(RangerSecurityContextFormationFilter.USER_AGENT)).thenReturn("Mozilla/5.0");
+            
Mockito.when(req.getHeader("x-awc-requestid")).thenReturn("awc-request-1");
+            Mockito.when(req.getRequestURI()).thenReturn("/secure");
+            
Mockito.when(httpUtil.getDeviceType(req)).thenReturn(RangerCommonEnums.DEVICE_BROWSER);
+
+            UserSessionBase userSession = Mockito.mock(UserSessionBase.class);
+
+            
Mockito.when(userSession.getClientTimeOffsetInMinute()).thenReturn(0);
+            Mockito.when(sessionMgr.processSuccessLogin(Mockito.anyInt(), 
Mockito.anyString(), Mockito.any(HttpServletRequest.class)))
+                    .thenReturn(userSession);
+
+            FilterChain chain = new FilterChain() {
+                @Override
+                public void doFilter(ServletRequest servletRequest, 
ServletResponse servletResponse) {
+                    RangerSecurityContext ctx = 
RangerContextHolder.getSecurityContext();
+
+                    assertNotNull(ctx);
+                    assertNotNull(ctx.getRequestContext());
+                    assertEquals("awc-request-1", 
ctx.getRequestContext().getServerRequestId());
+                    assertSame(userSession, ctx.getUserSession());
+                }
+            };
+
+            filter.doFilter(req, res, chain);
+
+            Mockito.verify(session, 
Mockito.times(1)).setAttribute(Mockito.eq(RangerSecurityContextFormationFilter.AKA_SC_SESSION_KEY),
 Mockito.any());
+            Mockito.verify(res).setHeader("X-Frame-Options", "DENY");
+            Mockito.verify(sessionMgr, 
Mockito.times(1)).processSuccessLogin(Mockito.anyInt(), Mockito.anyString(), 
Mockito.any(HttpServletRequest.class));
+            Mockito.verify(userSession, 
Mockito.times(1)).setClientTimeOffsetInMinute(Mockito.anyInt());
+
+            assertNull(RangerContextHolder.getSecurityContext());
+            assertNull(RangerContextHolder.getOpContext());
+        } finally {
+            
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_REQUEST_ID_HEADER_NAME);
+        }
     }
 }


Reply via email to