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

kumaab pushed a commit to branch ranger-2.10
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/ranger-2.10 by this push:
     new 5fc403c44 RANGER-5767: Extend header based authn to support ROLEs in 
Ranger Admin (#1206)
5fc403c44 is described below

commit 5fc403c4473d0540fa64f9d0c3f86ff2201a7b15
Author: Abhishek Kumar <[email protected]>
AuthorDate: Thu Sep 3 17:35:27 2026 -0700

    RANGER-5767: Extend header based authn to support ROLEs in Ranger Admin 
(#1206)
    
    Co-authored-by: Madhan Neethiraj <[email protected]>
    (cherry picked from commit d9d2c44d23b669b68b7cee14b1a959fa498a2a51)
---
 .../java/org/apache/ranger/biz/SessionMgr.java     |  37 +++-
 .../main/java/org/apache/ranger/biz/XUserMgr.java  |  90 +++++++++-
 .../org/apache/ranger/common/RangerConstants.java  |   4 -
 .../web/filter/RangerHeaderPreAuthFilter.java      |  99 ++++++++++-
 .../main/resources/conf.dist/ranger-admin-site.xml |   5 +
 .../web/filter/TestRangerHeaderPreAuthFilter.java  | 198 +++++++++++++++++++++
 6 files changed, 411 insertions(+), 22 deletions(-)

diff --git a/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java 
b/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java
index c31ed4e51..d60e327d6 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/SessionMgr.java
@@ -31,6 +31,7 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 
+import javax.annotation.PostConstruct;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
@@ -72,6 +73,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static 
org.apache.ranger.security.web.filter.RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED;
+
 @Component
 @Transactional
 public class SessionMgr {
@@ -103,11 +106,20 @@ public class SessionMgr {
 
        @Autowired
        StringUtil stringUtil;
-       
+
+       boolean ssoEnabled;
+       boolean headerAuthEnabled;
+
        public SessionMgr() {
                logger.debug("SessionManager created");
        }
 
+       @PostConstruct
+       public void init() {
+               ssoEnabled        = 
PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);
+               headerAuthEnabled = 
PropertiesUtil.getBooleanProperty(PROP_HEADER_AUTH_ENABLED, false);
+       }
+
        private static final Long SESSION_UPDATE_INTERVAL_IN_MILLIS = 30 * 
DateUtils.MILLIS_PER_MINUTE;
 
        public UserSessionBase processSuccessLogin(int authType, String 
userAgent,
@@ -246,17 +258,24 @@ else if 
(!StringUtils.isEmpty(httpRequest.getRequestURI()) && !isPluginOrSecureD
        }
 
        private void getSSOSpnegoAuthCheckForAPI(String currentLoginId, 
HttpServletRequest request) {
+               XXPortalUser gjUser = 
daoManager.getXXPortalUser().findByLoginId(currentLoginId);
 
-               RangerSecurityContext context = 
RangerContextHolder.getSecurityContext();
-               UserSessionBase session = context != null ? 
context.getUserSession() : null;
-               boolean ssoEnabled = session != null ? session.isSSOEnabled() : 
PropertiesUtil.getBooleanProperty("ranger.sso.enabled", false);
+               if (gjUser == null) {
+                       if (headerAuthEnabled) {
+                               logger.debug("User : {} doesn't exist in Ranger 
DB. Creating user as it's header-auth authenticated", currentLoginId);
 
-               XXPortalUser gjUser = 
daoManager.getXXPortalUser().findByLoginId(currentLoginId);
-               if (gjUser == null && ((request.getAttribute("spnegoEnabled") 
!= null && (boolean)request.getAttribute("spnegoEnabled")) || (ssoEnabled))) {
-                       if(logger.isDebugEnabled()){
-                               logger.debug("User : "+currentLoginId+" doesn't 
exist in Ranger DB So creating user as it's SSO or Spnego authenticated");
+                               
xUserMgr.createServiceConfigUserSynchronously(currentLoginId);
+                       } else {
+                               RangerSecurityContext context    = 
RangerContextHolder.getSecurityContext();
+                               UserSessionBase       session    = context != 
null ? context.getUserSession() : null;
+                               boolean               ssoEnabled = session != 
null ? session.isSSOEnabled() : this.ssoEnabled;
+
+                               if (ssoEnabled || 
(request.getAttribute("spnegoEnabled") != null && (boolean) 
request.getAttribute("spnegoEnabled"))) {
+                                       logger.debug("User : {} doesn't exist 
in Ranger DB. Creating user as it's SSO or Spnego", currentLoginId);
+
+                                       
xUserMgr.createServiceConfigUser(currentLoginId);
+                               }
                        }
-                       xUserMgr.createServiceConfigUser(currentLoginId);
                }
        }
 
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java 
b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
index 61c781090..13e614d65 100755
--- a/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/XUserMgr.java
@@ -67,6 +67,7 @@
 import org.apache.ranger.db.XXUserDao;
 import org.apache.ranger.db.XXUserPermissionDao;
 import org.apache.ranger.entity.XXAuditMap;
+import org.apache.ranger.entity.XXAuthSession;
 import org.apache.ranger.entity.XXGroup;
 import org.apache.ranger.entity.XXGroupUser;
 import org.apache.ranger.entity.XXPermMap;
@@ -81,10 +82,17 @@
 import org.apache.ranger.entity.XXSecurityZoneRefUser;
 import org.apache.ranger.entity.XXTrxLogV2;
 import org.apache.ranger.entity.XXUser;
+import org.apache.ranger.security.context.RangerContextHolder;
+import org.apache.ranger.security.context.RangerSecurityContext;
+import org.apache.ranger.security.web.filter.RangerAuthenticationToken;
+import org.apache.ranger.security.web.filter.RangerHeaderPreAuthFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.TransactionDefinition;
@@ -3268,6 +3276,72 @@ public Map<String, Long> getUserCountByRole() {
                return daoManager.getXXPortalUser().getCountByUserRole();
        }
 
+       /**
+        * Resolves the roles to assign to a freshly auto-provisioned external 
user. When header-based
+        * authentication is enabled and the current request was authenticated 
through the trusted proxy,
+        * the (validated) roles carried in the {@link 
RangerAuthenticationToken} authorities are used.
+        * Returns {@code null} otherwise, in which case the caller falls back 
to the default ROLE_USER.
+        */
+       private List<String> getHeaderAuthRoles() {
+               List<String> ret = null;
+
+               if 
(PropertiesUtil.getBooleanProperty(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 false)) {
+                       Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+
+                       if (auth instanceof RangerAuthenticationToken && 
((RangerAuthenticationToken) auth).getAuthType() == 
XXAuthSession.AUTH_TYPE_TRUSTED_PROXY) {
+                               List<String> roles = new ArrayList<>();
+
+                               for (GrantedAuthority authority : 
auth.getAuthorities()) {
+                                       String role = (authority != null) ? 
StringUtils.trimToNull(authority.getAuthority()) : null;
+
+                                       if (role != null && 
RangerConstants.VALID_USER_ROLE_LIST.contains(role)) {
+                                               roles.add(role);
+                                       }
+                               }
+
+                               if (!roles.isEmpty()) {
+                                       ret = roles;
+                               }
+                       }
+               }
+
+               return ret;
+       }
+
+       /**
+        * Creates the portal user with the supplied roles. When the roles 
originate from the trusted
+        * roles header ({@code trustedHeaderRoles}), the creation runs under a 
trusted system session
+        * (an admin session with no interactive user attached) so that 
non-public roles such as
+        * ROLE_SYS_ADMIN carried in the header are permitted during 
provisioning. No real user account
+        * is impersonated and the previous security context is always restored.
+        */
+       private XXPortalUser createExternalPortalUser(XXPortalUser 
xXPortalUser, List<String> roleList, boolean trustedHeaderRoles) {
+               if (!trustedHeaderRoles) {
+                       return userMgr.createUser(xXPortalUser, 
RangerCommonEnums.STATUS_ENABLED, roleList);
+               }
+
+               RangerSecurityContext context         = 
RangerContextHolder.getSecurityContext();
+               UserSessionBase       originalSession = context != null ? 
context.getUserSession() : null;
+
+               if (context == null) {
+                       context = new RangerSecurityContext();
+
+                       RangerContextHolder.setSecurityContext(context);
+               }
+
+               try {
+                       UserSessionBase systemSession = new UserSessionBase();
+
+                       systemSession.setUserAdmin(true);
+
+                       context.setUserSession(systemSession);
+
+                       return userMgr.createUser(xXPortalUser, 
RangerCommonEnums.STATUS_ENABLED, roleList);
+               } finally {
+                       context.setUserSession(originalSession);
+               }
+       }
+
        private class ExternalUserCreator implements Runnable {
                private String userName;
 
@@ -3293,15 +3367,19 @@ private void createExternalUser() {
                                VXPortalUser vXPortalUser = new VXPortalUser();
                                vXPortalUser.setLoginId(userName);
                                
vXPortalUser.setUserSource(RangerCommonEnums.USER_EXTERNAL);
-                               ArrayList<String> roleList = new 
ArrayList<String>();
-                               roleList.add(RangerConstants.ROLE_USER);
+                               List<String>      headerRoles        = 
getHeaderAuthRoles();
+                               boolean           trustedHeaderRoles = 
CollectionUtils.isNotEmpty(headerRoles);
+                               ArrayList<String> roleList           = new 
ArrayList<String>();
+                               if (trustedHeaderRoles) {
+                                       roleList.addAll(headerRoles);
+                               } else {
+                                       roleList.add(RangerConstants.ROLE_USER);
+                               }
                                vXPortalUser.setUserRoleList(roleList);
                                xXPortalUser = 
userMgr.mapVXPortalUserToXXPortalUser(vXPortalUser);
                                try {
-                                       xXPortalUser = 
userMgr.createUser(xXPortalUser, RangerCommonEnums.STATUS_ENABLED, roleList);
-                                       if (logger.isDebugEnabled()) {
-                                               
logger.debug("createExternalUser(): Successfully created user in x_portal_user 
table " + xXPortalUser.getLoginId());
-                                       }
+                                       xXPortalUser = 
createExternalPortalUser(xXPortalUser, roleList, trustedHeaderRoles);
+                                       logger.debug("createExternalUser(): 
Successfully created user {} in x_portal_user table with roles {}", 
xXPortalUser.getLoginId(), roleList);
                                } catch (Exception ex) {
                                        throw new RuntimeException("Failed to 
create user " + userName + " in x_portal_user table. retrying", ex);
                                }
diff --git 
a/security-admin/src/main/java/org/apache/ranger/common/RangerConstants.java 
b/security-admin/src/main/java/org/apache/ranger/common/RangerConstants.java
index e4f05f51a..9f07e0520 100644
--- a/security-admin/src/main/java/org/apache/ranger/common/RangerConstants.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/RangerConstants.java
@@ -32,12 +32,8 @@ public class RangerConstants extends RangerCommonEnums {
        // Default Roles
        public final static String ROLE_SYS_ADMIN = "ROLE_SYS_ADMIN";
        public final static String ROLE_ADMIN = "ROLE_ADMIN";
-       public final static String ROLE_INTEGRATOR = "ROLE_INTEGRATOR";
-       public final static String ROLE_DATA_ANALYST = "ROLE_DATA_ANALYST";
-       public final static String ROLE_BIZ_MGR = "ROLE_BIZ_MGR";
        public final static String ROLE_KEY_ADMIN = "ROLE_KEY_ADMIN";
        public final static String ROLE_USER = "ROLE_USER";
-       public final static String ROLE_ANON = "ROLE_ANON";
        public final static String ROLE_OTHER = "ROLE_OTHER";
        public final static String GROUP_PUBLIC = "public";
     public final static String ROLE_ADMIN_AUDITOR = "ROLE_ADMIN_AUDITOR";
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
index 800bf92f5..4352519a1 100644
--- 
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
@@ -21,6 +21,7 @@
 import org.apache.commons.lang3.StringUtils;
 import org.apache.ranger.biz.UserMgr;
 import org.apache.ranger.common.PropertiesUtil;
+import org.apache.ranger.common.RangerConstants;
 import org.apache.ranger.entity.XXAuthSession;
 import org.apache.ranger.plugin.util.SpiffeIdUtil;
 import org.slf4j.Logger;
@@ -45,7 +46,10 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class RangerHeaderPreAuthFilter extends GenericFilterBean {
     private static final Logger LOG = 
LoggerFactory.getLogger(RangerHeaderPreAuthFilter.class);
@@ -54,10 +58,30 @@ public class RangerHeaderPreAuthFilter extends 
GenericFilterBean {
     public static final String PROP_USERNAME_HEADER_NAME   = 
"ranger.admin.authn.header.username";
     public static final String PROP_SPIFFE_HEADER_NAME     = 
"ranger.admin.authn.header.spiffe";
     public static final String PROP_REQUEST_ID_HEADER_NAME = 
"ranger.admin.authn.header.requestid";
+    public static final String PROP_ROLES_HEADER_NAME      = 
"ranger.admin.authn.header.roles";
+
+    /**
+     * External-facing role names accepted in the configured roles header, 
mapped to Ranger's
+     * internal role constants (see {@link 
RangerConstants#VALID_USER_ROLE_LIST}).
+     */
+    private static final Map<String, String> EXTERNAL_ROLE_TO_RANGER_ROLE;
+
+    static {
+        Map<String, String> roleMap = new HashMap<>();
+
+        roleMap.put("RANGER_ROLE_ADMIN", RangerConstants.ROLE_SYS_ADMIN);
+        roleMap.put("RANGER_ROLE_AUDITOR", RangerConstants.ROLE_ADMIN_AUDITOR);
+        roleMap.put("RANGER_ROLE_USER", RangerConstants.ROLE_USER);
+        roleMap.put("RANGER_ROLE_KEY_ADMIN", RangerConstants.ROLE_KEY_ADMIN);
+        roleMap.put("RANGER_ROLE_KEY_ADMIN_AUDITOR", 
RangerConstants.ROLE_KEY_ADMIN_AUDITOR);
+
+        EXTERNAL_ROLE_TO_RANGER_ROLE = Collections.unmodifiableMap(roleMap);
+    }
 
     private boolean      headerAuthEnabled;
     private String       userNameHeaderName;
     private List<String> spiffeHeaderNames;
+    private String       rolesHeaderName;
 
     @Autowired
     UserMgr userMgr;
@@ -69,6 +93,7 @@ protected void initialize() {
         if (headerAuthEnabled) {
             userNameHeaderName = 
PropertiesUtil.getProperty(PROP_USERNAME_HEADER_NAME);
             spiffeHeaderNames  = 
SpiffeIdUtil.parseHeaderNames(PropertiesUtil.getProperty(PROP_SPIFFE_HEADER_NAME));
+            rolesHeaderName    = 
PropertiesUtil.getProperty(PROP_ROLES_HEADER_NAME);
 
             if (StringUtils.isBlank(userNameHeaderName) && 
spiffeHeaderNames.isEmpty()) {
                 LOG.warn("Disabling header-based authentication, as neither {} 
nor {} is set", PROP_USERNAME_HEADER_NAME, PROP_SPIFFE_HEADER_NAME);
@@ -88,7 +113,7 @@ public void doFilter(ServletRequest request, ServletResponse 
response, FilterCha
                 String              username    = 
resolvePrincipal(httpRequest);
 
                 if (StringUtils.isNotBlank(username)) {
-                    List<GrantedAuthority>    grantedAuthorities = 
getAuthoritiesFromRanger(username);
+                    List<GrantedAuthority>    grantedAuthorities = 
getAuthorities(httpRequest, username);
                     final UserDetails         principal          = new 
User(username, "", grantedAuthorities);
                     RangerAuthenticationToken authToken          = new 
RangerAuthenticationToken(principal, grantedAuthorities, 
XXAuthSession.AUTH_TYPE_TRUSTED_PROXY);
 
@@ -135,14 +160,82 @@ private String resolvePrincipal(HttpServletRequest 
httpRequest) {
         return null;
     }
 
+    /**
+     * Resolves the authorities to assign to the authenticated user. When the 
trusted proxy
+     * supplies roles via the configured roles header, those roles are 
honored; otherwise the
+     * roles persisted for the user in the Ranger DB are used.
+     */
+    private List<GrantedAuthority> getAuthorities(HttpServletRequest 
httpRequest, String username) {
+        List<GrantedAuthority> ret = getAuthoritiesFromHeader(httpRequest);
+
+        if (ret == null || ret.isEmpty()) {
+            ret = getAuthoritiesFromRanger(username);
+        }
+
+        return ret == null ? Collections.emptyList() : ret;
+    }
+
+    /**
+     * Loads authorities from the configured roles header. External-facing 
role names
+     * ({@code RANGER_ROLE_ADMIN}, {@code RANGER_ROLE_AUDITOR}, etc.) are 
mapped to Ranger's
+     * internal role constants before being added to the authentication token. 
Internal role
+     * names from {@link RangerConstants#VALID_USER_ROLE_LIST} are also 
accepted; any other
+     * value is ignored.
+     */
+    private List<GrantedAuthority> getAuthoritiesFromHeader(HttpServletRequest 
httpRequest) {
+        List<GrantedAuthority> ret = null;
+
+        if (StringUtils.isNotBlank(rolesHeaderName)) {
+            String rolesHeaderValue = httpRequest.getHeader(rolesHeaderName);
+
+            if (StringUtils.isNotBlank(rolesHeaderValue)) {
+                ret = new ArrayList<>();
+
+                for (String role : rolesHeaderValue.split(",")) {
+                    String trimmedRole = StringUtils.trimToNull(role);
+
+                    if (trimmedRole != null) {
+                        String rangerRole = resolveRoleFromHeader(trimmedRole);
+
+                        if (rangerRole != null) {
+                            ret.add(new SimpleGrantedAuthority(rangerRole));
+                        } else {
+                            LOG.warn("Ignoring unrecognized role '{}' received 
in header '{}'", trimmedRole, rolesHeaderName);
+                        }
+                    }
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    /**
+     * Maps an external-facing role name from the roles header to a Ranger 
internal role constant,
+     * or returns the value unchanged when it is already a recognized internal 
role name.
+     */
+    private String resolveRoleFromHeader(String headerRole) {
+        String ret = EXTERNAL_ROLE_TO_RANGER_ROLE.get(headerRole);
+
+        if (ret == null) {
+            if (RangerConstants.VALID_USER_ROLE_LIST.contains(headerRole)) {
+                ret = headerRole;
+            }
+        }
+
+        return ret;
+    }
+
     /**
      * Loads authorities from Ranger DB
      */
     private List<GrantedAuthority> getAuthoritiesFromRanger(String username) {
-        List<GrantedAuthority> ret      = new ArrayList<>();
+        List<GrantedAuthority> ret      = null;
         Collection<String>     roleList = userMgr.getRolesByLoginId(username);
 
-        if (roleList != null) {
+        if (roleList != null && !roleList.isEmpty()) {
+            ret = new ArrayList<>();
+
             for (String role : roleList) {
                 if (StringUtils.isNotBlank(role)) {
                     ret.add(new SimpleGrantedAuthority(role));
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 1a9c40caf..d8533051f 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
@@ -332,6 +332,11 @@
                <name>ranger.admin.authn.header.requestid</name>
                <value></value>
        </property>
+       <property>
+               <name>ranger.admin.authn.header.roles</name>
+               <value></value>
+               <description>Name of the HTTP header (e.g. X-Forwarded-Roles) 
carrying a comma-separated list of roles to assign to the authenticated user. 
Accepted values are role names RANGER_ROLE_ADMIN, RANGER_ROLE_AUDITOR, 
RANGER_ROLE_USER, RANGER_ROLE_KEY_ADMIN, and RANGER_ROLE_KEY_ADMIN_AUDITOR. 
Values that are not recognized are ignored.</description>
+       </property>
        <property>
                <name>ranger.admin.spiffe.as.username.enabled</name>
                <value>false</value>
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
index 5103d836b..d70135035 100644
--- 
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
@@ -68,6 +68,7 @@ public void tearDown() {
         
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME);
         
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_SPIFFE_HEADER_NAME);
         
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_REQUEST_ID_HEADER_NAME);
+        
PropertiesUtil.getPropertiesMap().remove(RangerHeaderPreAuthFilter.PROP_ROLES_HEADER_NAME);
     }
 
     @Test
@@ -372,4 +373,201 @@ public void 
testDoFilter_enabled_existingAuthenticatedContext_doesNotOverrideAut
         verify(userMgr, never()).getRolesByLoginId(anyString());
         assertEquals(existingAuth, 
SecurityContextHolder.getContext().getAuthentication());
     }
+
+    @Test
+    public void 
testDoFilter_enabled_withExternalRolesHeader_mapsToInternalRoles() throws 
Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "X-Forwarded-User");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_ROLES_HEADER_NAME,
 "X-Forwarded-Roles");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize();
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+
+        when(request.getHeader("X-Forwarded-User")).thenReturn("joeuser");
+        
when(request.getHeader("X-Forwarded-Roles")).thenReturn("RANGER_ROLE_ADMIN, 
RANGER_ROLE_USER");
+
+        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);
+
+        verify(userMgr, never()).getRolesByLoginId(anyString());
+    }
+
+    @Test
+    public void 
testDoFilter_enabled_withRolesHeader_setsAuthenticationFromHeaderRoles() throws 
Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "X-Forwarded-User");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_ROLES_HEADER_NAME,
 "X-Forwarded-Roles");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize();
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+
+        when(request.getHeader("X-Forwarded-User")).thenReturn("joeuser");
+        
when(request.getHeader("X-Forwarded-Roles")).thenReturn("ROLE_SYS_ADMIN, 
ROLE_USER");
+
+        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);
+
+        // roles came from the trusted header, so the Ranger DB must not be 
consulted
+        verify(userMgr, never()).getRolesByLoginId(anyString());
+    }
+
+    @Test
+    public void 
testDoFilter_enabled_rolesHeaderWithUnknownRoles_ignoresInvalidAndKeepsValid() 
throws Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "X-Forwarded-User");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_ROLES_HEADER_NAME,
 "X-Forwarded-Roles");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize();
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+
+        when(request.getHeader("X-Forwarded-User")).thenReturn("joeuser");
+        
when(request.getHeader("X-Forwarded-Roles")).thenReturn("ROLE_ADMIN_AUDITOR, 
ROLE_BOGUS, , ROLE_USER");
+
+        FilterChain chain = new FilterChain() {
+            @Override
+            public void doFilter(ServletRequest req, ServletResponse res) {
+                org.springframework.security.core.Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+
+                assertNotNull(auth);
+
+                Collection<?> authorities = auth.getAuthorities();
+                assertEquals(2, authorities.size());
+                assertTrue(authorities.stream().anyMatch(a -> 
"ROLE_ADMIN_AUDITOR".equals(a.toString())));
+                assertTrue(authorities.stream().anyMatch(a -> 
"ROLE_USER".equals(a.toString())));
+            }
+        };
+
+        filter.doFilter(request, response, chain);
+
+        verify(userMgr, never()).getRolesByLoginId(anyString());
+    }
+
+    @Test
+    public void 
testDoFilter_enabled_rolesHeaderWithNoValidRoles_fallsBackToRangerDbRoles() 
throws Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "X-Forwarded-User");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_ROLES_HEADER_NAME,
 "X-Forwarded-Roles");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize();
+
+        
when(userMgr.getRolesByLoginId("joeuser")).thenReturn(Collections.singletonList("ROLE_USER"));
+
+        HttpServletRequest  request  = mock(HttpServletRequest.class);
+        HttpServletResponse response = mock(HttpServletResponse.class);
+
+        when(request.getHeader("X-Forwarded-User")).thenReturn("joeuser");
+        when(request.getHeader("X-Forwarded-Roles")).thenReturn("ROLE_BOGUS");
+
+        FilterChain chain = new FilterChain() {
+            @Override
+            public void doFilter(ServletRequest req, ServletResponse res) {
+                org.springframework.security.core.Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+
+                assertNotNull(auth);
+
+                Collection<?> authorities = auth.getAuthorities();
+                assertEquals(1, authorities.size());
+                assertTrue(authorities.stream().anyMatch(a -> 
"ROLE_USER".equals(a.toString())));
+            }
+        };
+
+        filter.doFilter(request, response, chain);
+
+        verify(userMgr).getRolesByLoginId("joeuser");
+    }
+
+    @Test
+    public void 
testDoFilter_enabled_rolesHeaderConfiguredButAbsent_fallsBackToRangerDbRoles() 
throws Exception {
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_HEADER_AUTH_ENABLED,
 "true");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_USERNAME_HEADER_NAME,
 "X-Forwarded-User");
+        
PropertiesUtil.getPropertiesMap().put(RangerHeaderPreAuthFilter.PROP_ROLES_HEADER_NAME,
 "X-Forwarded-Roles");
+
+        RangerHeaderPreAuthFilter filter  = new RangerHeaderPreAuthFilter();
+        UserMgr                   userMgr = mock(UserMgr.class);
+
+        filter.userMgr = userMgr;
+        filter.initialize();
+
+        
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-Forwarded-User")).thenReturn("joeuser");
+        // roles header configured but not present in the request
+
+        FilterChain chain = new FilterChain() {
+            @Override
+            public void doFilter(ServletRequest req, ServletResponse res) {
+                org.springframework.security.core.Authentication auth = 
SecurityContextHolder.getContext().getAuthentication();
+
+                assertNotNull(auth);
+
+                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);
+
+        verify(userMgr).getRolesByLoginId("joeuser");
+    }
 }

Reply via email to