-
Notifications
You must be signed in to change notification settings - Fork 1.1k
RANGER-5539: Add Authorisation Check for doAsUser Parameter #915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,10 @@ | |||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||
| package org.apache.ranger.security.web.filter; | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| import org.apache.hadoop.conf.Configuration; | ||||||||||||||||||||||||||||||||||||||||||
| import org.apache.hadoop.security.UserGroupInformation; | ||||||||||||||||||||||||||||||||||||||||||
| import org.apache.hadoop.security.authorize.AuthorizationException; | ||||||||||||||||||||||||||||||||||||||||||
| import org.apache.hadoop.security.authorize.ProxyUsers; | ||||||||||||||||||||||||||||||||||||||||||
| import org.apache.ranger.authz.handler.RangerAuth; | ||||||||||||||||||||||||||||||||||||||||||
| import org.apache.ranger.authz.handler.jwt.RangerDefaultJwtAuthHandler; | ||||||||||||||||||||||||||||||||||||||||||
| import org.apache.ranger.authz.handler.jwt.RangerJwtAuthHandler; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -75,6 +79,9 @@ public void initialize() { | |||||||||||||||||||||||||||||||||||||||||
| config.setProperty(RangerJwtAuthHandler.KEY_JWT_AUDIENCES, PropertiesUtil.getProperty(RangerSSOAuthenticationFilter.JWT_AUDIENCES, "")); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| super.initialize(config); | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| Configuration conf = getProxyuserConfiguration(); | ||||||||||||||||||||||||||||||||||||||||||
| ProxyUsers.refreshSuperUserGroupsConfiguration(conf, "ranger.proxyuser."); | ||||||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||
| LOG.error("Failed to initialize Ranger Admin JWT Auth Filter.", e); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -117,6 +124,36 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha | |||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||
| protected boolean isProxyEnabled() { | ||||||||||||||||||||||||||||||||||||||||||
| return PropertiesUtil.getBooleanProperty("ranger.authentication.allow.trustedproxy", false); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||
| protected boolean authorizeProxyUser(String realUser, String doAsUser, String remoteAddr) { | ||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||
| UserGroupInformation ugi = UserGroupInformation.createRemoteUser(realUser); | ||||||||||||||||||||||||||||||||||||||||||
| ugi = UserGroupInformation.createProxyUser(doAsUser, ugi); | ||||||||||||||||||||||||||||||||||||||||||
| ProxyUsers.authorize(ugi, remoteAddr); | ||||||||||||||||||||||||||||||||||||||||||
| LOG.debug("RangerJwtAuthFilter.authorizeProxyUser(): ProxyUsers.authorize SUCCEEDED for realUser=[{}], doAs=[{}]", | ||||||||||||||||||||||||||||||||||||||||||
| realUser, doAsUser); | ||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||
| } catch (AuthorizationException ex) { | ||||||||||||||||||||||||||||||||||||||||||
| LOG.warn("JWT ProxyUsers.authorize failed for doAs=[{}], realUser=[{}]: {}", doAsUser, realUser, ex.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+134
to
+142
|
||||||||||||||||||||||||||||||||||||||||||
| try { | |
| UserGroupInformation ugi = UserGroupInformation.createRemoteUser(realUser); | |
| ugi = UserGroupInformation.createProxyUser(doAsUser, ugi); | |
| ProxyUsers.authorize(ugi, remoteAddr); | |
| LOG.debug("RangerJwtAuthFilter.authorizeProxyUser(): ProxyUsers.authorize SUCCEEDED for realUser=[{}], doAs=[{}]", | |
| realUser, doAsUser); | |
| return true; | |
| } catch (AuthorizationException ex) { | |
| LOG.warn("JWT ProxyUsers.authorize failed for doAs=[{}], realUser=[{}]: {}", doAsUser, realUser, ex.getMessage()); | |
| String trimmedDoAsUser = doAsUser == null ? null : doAsUser.trim(); | |
| try { | |
| UserGroupInformation ugi = UserGroupInformation.createRemoteUser(realUser); | |
| ugi = UserGroupInformation.createProxyUser(trimmedDoAsUser, ugi); | |
| ProxyUsers.authorize(ugi, remoteAddr); | |
| LOG.debug("RangerJwtAuthFilter.authorizeProxyUser(): ProxyUsers.authorize SUCCEEDED for realUser=[{}], doAs=[{}]", | |
| realUser, trimmedDoAsUser); | |
| return true; | |
| } catch (AuthorizationException ex) { | |
| LOG.warn("JWT ProxyUsers.authorize failed for doAs=[{}], realUser=[{}]: {}", trimmedDoAsUser, realUser, ex.getMessage()); |
Copilot
AI
Apr 22, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getProxyuserConfiguration() is introduced as private, which forces tests to use reflection and prevents reuse/overrides. Consider making this method protected (similar to RangerKRBAuthenticationFilter#getProxyuserConfiguration) or package-private so it can be unit-tested and extended without reflection.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,9 @@ | |
| */ | ||
| package org.apache.ranger.security.web.filter; | ||
|
|
||
| import org.apache.hadoop.conf.Configuration; | ||
| import org.apache.ranger.authz.handler.RangerAuth; | ||
| import org.apache.ranger.common.PropertiesUtil; | ||
| import org.junit.jupiter.api.AfterEach; | ||
| import org.junit.jupiter.api.MethodOrderer; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
@@ -38,6 +40,7 @@ | |
| import javax.servlet.http.HttpServletRequest; | ||
|
|
||
| import java.io.IOException; | ||
| import java.lang.reflect.Method; | ||
| import java.util.Collection; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | ||
|
|
@@ -120,4 +123,54 @@ public void testDoFilter_leavesAuthenticationNullWhenAuthenticateReturnsNull() | |
|
|
||
| assertNull(SecurityContextHolder.getContext().getAuthentication()); | ||
| } | ||
|
|
||
| @Test | ||
| void testIsProxyEnabled_defaultFalse() { | ||
| PropertiesUtil.getPropertiesMap().remove("ranger.authentication.allow.trustedproxy"); | ||
| RangerJwtAuthFilter filter = new RangerJwtAuthFilter(); | ||
| assertFalse(filter.isProxyEnabled()); | ||
| } | ||
|
|
||
| @Test | ||
| void testIsProxyEnabled_trueWhenConfigured() { | ||
| PropertiesUtil.getPropertiesMap().put("ranger.authentication.allow.trustedproxy", "true"); | ||
| RangerJwtAuthFilter filter = new RangerJwtAuthFilter(); | ||
| assertTrue(filter.isProxyEnabled()); | ||
| PropertiesUtil.getPropertiesMap().remove("ranger.authentication.allow.trustedproxy"); | ||
| } | ||
|
|
||
| @Test | ||
| void testAuthorizeProxyUser_returnsFalseWhenNoProxyConfigLoaded() { | ||
| RangerJwtAuthFilter filter = new RangerJwtAuthFilter(); | ||
| // no proxyuser config loaded into ProxyUsers -> should fail safely | ||
| assertFalse(filter.authorizeProxyUser("knoxui", "admin", "10.0.0.1")); | ||
| } | ||
|
Comment on lines
+142
to
+147
|
||
|
|
||
| @Test | ||
| void testGetProxyuserConfiguration_copiesOnlyProxyuserKeys() throws Exception { | ||
| // Arrange: put both proxyuser keys and non-proxyuser keys | ||
| PropertiesUtil.getPropertiesMap().put("ranger.proxyuser.knoxui.hosts", "*"); | ||
| PropertiesUtil.getPropertiesMap().put("ranger.proxyuser.knoxui.groups", "*"); | ||
| PropertiesUtil.getPropertiesMap().put("ranger.some.other.key", "shouldNotBeCopied"); | ||
|
|
||
| RangerJwtAuthFilter filter = new RangerJwtAuthFilter(); | ||
|
|
||
| // Call private getProxyuserConfiguration() via reflection | ||
| Method m = RangerJwtAuthFilter.class.getDeclaredMethod("getProxyuserConfiguration"); | ||
| m.setAccessible(true); | ||
|
|
||
| Configuration conf = (Configuration) m.invoke(filter); | ||
|
Comment on lines
+158
to
+162
|
||
|
|
||
| // Assert: proxyuser keys copied | ||
| assertEquals("*", conf.get("ranger.proxyuser.knoxui.hosts")); | ||
| assertEquals("*", conf.get("ranger.proxyuser.knoxui.groups")); | ||
|
|
||
| // Assert: non-proxyuser keys NOT copied | ||
| assertNull(conf.get("ranger.some.other.key")); | ||
|
|
||
| // Cleanup | ||
| PropertiesUtil.getPropertiesMap().remove("ranger.proxyuser.knoxui.hosts"); | ||
| PropertiesUtil.getPropertiesMap().remove("ranger.proxyuser.knoxui.groups"); | ||
| PropertiesUtil.getPropertiesMap().remove("ranger.some.other.key"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -29,16 +29,21 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.jupiter.api.extension.ExtendWith; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.mockito.Mockito; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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.ServletException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.servlet.ServletRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.servlet.ServletResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.servlet.http.Cookie; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.servlet.http.HttpServletRequest; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import javax.servlet.http.HttpServletResponse; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.lang.reflect.Field; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Collections; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static org.mockito.ArgumentMatchers.any; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import static org.mockito.Mockito.atLeastOnce; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -124,4 +129,124 @@ public void testDoFilter_skipsJwtWhenSsoEnabled() throws IOException, ServletExc | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(jwtFilter, never()).doFilter(any(ServletRequest.class), any(ServletResponse.class), any(FilterChain.class)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(chain, times(1)).doFilter(req, res); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void testDoFilter_invokesJwtFilter_whenBearerHeaderPresent() throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerContextHolder.resetSecurityContext(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecurityContextHolder.clearContext(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PropertiesUtil.getPropertiesMap().put("ranger.sso.enabled", "false"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FilterChain chain = Mockito.mock(FilterChain.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getHeader("Authorization")).thenReturn("Bearer token"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setField(wrapper, "rangerJwtAuthFilter", jwt); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wrapper.doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(jwt, times(1)).doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(chain, times(1)).doFilter(req, res); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void testDoFilter_skipsJwt_whenAlreadyAuthenticated_evenIfBearerHeaderPresent() throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PropertiesUtil.getPropertiesMap().put("ranger.sso.enabled", "false"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // mark request authenticated | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecurityContextHolder.getContext().setAuthentication( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new UsernamePasswordAuthenticationToken( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "kafka", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FilterChain chain = Mockito.mock(FilterChain.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setField(wrapper, "rangerJwtAuthFilter", jwt); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wrapper.doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(jwt, never()).doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(chain, times(1)).doFilter(req, res); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void testDoFilter_skipsJwtFilter_whenNoBearerAndNoCookie() throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PropertiesUtil.getPropertiesMap().put("ranger.sso.enabled", "false"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FilterChain chain = Mockito.mock(FilterChain.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // no bearer header, no cookies | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getHeader("Authorization")).thenReturn(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getCookies()).thenReturn(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setField(wrapper, "rangerJwtAuthFilter", jwt); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wrapper.doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(jwt, never()).doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(chain, times(1)).doFilter(req, res); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void testDoFilter_invokesJwtFilter_whenJwtCookiePresent() throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PropertiesUtil.getPropertiesMap().put("ranger.sso.enabled", "false"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FilterChain chain = Mockito.mock(FilterChain.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getHeader("Authorization")).thenReturn(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getCookies()).thenReturn(new Cookie[] {new Cookie("hadoop-jwt", "abc")}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setField(wrapper, "rangerJwtAuthFilter", jwt); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wrapper.doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(jwt, times(1)).doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(chain, times(1)).doFilter(req, res); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void testDoFilter_redirectsToLogin_whenJwtAttemptedButUnauthenticated_andBrowserAgent() throws Exception { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PropertiesUtil.getPropertiesMap().put("ranger.sso.enabled", "false"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.setProperty("ranger.default.browser-useragents", "Mozilla"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FilterChain chain = Mockito.mock(FilterChain.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getHeader("Authorization")).thenReturn("Bearer token"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.when(req.getHeader("User-Agent")).thenReturn("Mozilla/5.0"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Mockito.doNothing().when(jwt).doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wrapper.initialize(); // loads browser agents from properties/system property | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setField(wrapper, "rangerJwtAuthFilter", jwt); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wrapper.doFilter(req, res, chain); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(res, times(1)).sendRedirect("/login.jsp"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| verify(chain, times(1)).doFilter(req, res); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+225
to
+244
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.setProperty("ranger.default.browser-useragents", "Mozilla"); | |
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | |
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | |
| FilterChain chain = Mockito.mock(FilterChain.class); | |
| Mockito.when(req.getHeader("Authorization")).thenReturn("Bearer token"); | |
| Mockito.when(req.getHeader("User-Agent")).thenReturn("Mozilla/5.0"); | |
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | |
| Mockito.doNothing().when(jwt).doFilter(req, res, chain); | |
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | |
| wrapper.initialize(); // loads browser agents from properties/system property | |
| setField(wrapper, "rangerJwtAuthFilter", jwt); | |
| wrapper.doFilter(req, res, chain); | |
| verify(res, times(1)).sendRedirect("/login.jsp"); | |
| verify(chain, times(1)).doFilter(req, res); | |
| String previousBrowserUserAgents = System.getProperty("ranger.default.browser-useragents"); | |
| System.setProperty("ranger.default.browser-useragents", "Mozilla"); | |
| try { | |
| HttpServletRequest req = Mockito.mock(HttpServletRequest.class); | |
| HttpServletResponse res = Mockito.mock(HttpServletResponse.class); | |
| FilterChain chain = Mockito.mock(FilterChain.class); | |
| Mockito.when(req.getHeader("Authorization")).thenReturn("Bearer token"); | |
| Mockito.when(req.getHeader("User-Agent")).thenReturn("Mozilla/5.0"); | |
| RangerJwtAuthFilter jwt = Mockito.mock(RangerJwtAuthFilter.class); | |
| Mockito.doNothing().when(jwt).doFilter(req, res, chain); | |
| RangerJwtAuthWrapper wrapper = new RangerJwtAuthWrapper(); | |
| wrapper.initialize(); // loads browser agents from properties/system property | |
| setField(wrapper, "rangerJwtAuthFilter", jwt); | |
| wrapper.doFilter(req, res, chain); | |
| verify(res, times(1)).sendRedirect("/login.jsp"); | |
| verify(chain, times(1)).doFilter(req, res); | |
| } finally { | |
| if (previousBrowserUserAgents == null) { | |
| System.clearProperty("ranger.default.browser-useragents"); | |
| } else { | |
| System.setProperty("ranger.default.browser-useragents", previousBrowserUserAgents); | |
| } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doAsUseris trimmed only after the proxy authorization check, but the authorization call uses the untrimmed request parameter. This can cause legitimate impersonation to be rejected (or mismatched) when the parameter has leading/trailing whitespace. Trim (and ideally normalize)doAsUseronce up-front and use the trimmed value consistently forauthorizeProxyUser(...), logging, andeffectiveUser.