This is an automated email from the ASF dual-hosted git repository. dineshkumar-yadav pushed a commit to branch sandbox/dineshkumar-yadav/master-RANGER-5824 in repository https://gitbox.apache.org/repos/asf/ranger.git
commit 000f64c9eb2f67b3258df9fc427bacf8d230258c Author: Dineshkumar Yadav <[email protected]> AuthorDate: Wed Oct 7 10:22:56 2026 +0530 RANGER-5824 : Align Sqoop Ranger authorizer with other plugins --- .../sqoop/authorizer/RangerSqoopAuthorizer.java | 24 +++- .../RangerSqoopAuthorizerFailClosedTest.java | 150 +++++++++++++++++++++ 2 files changed, 167 insertions(+), 7 deletions(-) diff --git a/plugin-sqoop/src/main/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizer.java b/plugin-sqoop/src/main/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizer.java index fe74eb640..1ea3d0be0 100644 --- a/plugin-sqoop/src/main/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizer.java +++ b/plugin-sqoop/src/main/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizer.java @@ -90,14 +90,24 @@ public void checkPrivileges(MPrincipal principal, List<MPrivilege> privileges) t RangerSqoopPlugin plugin = sqoopPlugin; - if (plugin != null) { - for (MPrivilege privilege : privileges) { - RangerSqoopAccessRequest request = new RangerSqoopAccessRequest(principal, privilege, clientIPAddress); - RangerAccessResult result = plugin.isAccessAllowed(request); + if (plugin == null) { + LOG.error("Ranger Sqoop plugin is not initialized; denying access for principal={}", principal); - if (result != null && !result.getIsAllowed()) { - throw new SqoopException(SecurityError.AUTH_0014, "principal = " + principal + " does not have privileges for: " + privilege); - } + throw new SqoopException(SecurityError.AUTH_0014, "Ranger authorization plugin is not initialized"); + } + + for (MPrivilege privilege : privileges) { + RangerSqoopAccessRequest request = new RangerSqoopAccessRequest(principal, privilege, clientIPAddress); + RangerAccessResult result = plugin.isAccessAllowed(request); + + if (result == null) { + LOG.error("Ranger plugin returned null for request={}; denying access for principal={}", request, principal); + + throw new SqoopException(SecurityError.AUTH_0014, "principal = " + principal + " does not have privileges for: " + privilege); + } + + if (!result.getIsAllowed()) { + throw new SqoopException(SecurityError.AUTH_0014, "principal = " + principal + " does not have privileges for: " + privilege); } } diff --git a/plugin-sqoop/src/test/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizerFailClosedTest.java b/plugin-sqoop/src/test/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizerFailClosedTest.java new file mode 100644 index 000000000..edfacd6b1 --- /dev/null +++ b/plugin-sqoop/src/test/java/org/apache/ranger/authorization/sqoop/authorizer/RangerSqoopAuthorizerFailClosedTest.java @@ -0,0 +1,150 @@ +/* + * 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.authorization.sqoop.authorizer; + +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.sqoop.common.SqoopException; +import org.apache.sqoop.model.MPrincipal; +import org.apache.sqoop.model.MPrivilege; +import org.apache.sqoop.model.MResource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Verifies fail-closed behavior when the Ranger plugin is unavailable or returns no decision. + */ +public class RangerSqoopAuthorizerFailClosedTest { + private static final String TEST_USER = "test-user"; + + private RangerSqoopAuthorizer authorizer; + + private Object sqoopPluginBefore; + + @BeforeEach + public void setUp() throws Exception { + sqoopPluginBefore = getSqoopPluginField().get(null); + authorizer = new RangerSqoopAuthorizer(); + } + + @AfterEach + public void tearDown() throws Exception { + getSqoopPluginField().set(null, sqoopPluginBefore); + } + + @Test + public void checkPrivilegesDeniesWhenPluginReturnsNull() throws Exception { + Object plugin = mockSqoopPlugin(); + + when(((RangerBasePlugin) plugin).isAccessAllowed(any(RangerAccessRequest.class))).thenReturn(null); + + setSqoopPlugin(plugin); + + assertThrows(SqoopException.class, () -> authorizer.checkPrivileges(buildUserPrincipal(), buildReadConnectorPrivilege())); + } + + @Test + public void checkPrivilegesDeniesWhenPluginIsNull() throws Exception { + setSqoopPlugin(null); + + assertThrows(SqoopException.class, () -> authorizer.checkPrivileges(buildUserPrincipal(), buildReadConnectorPrivilege())); + } + + @Test + public void checkPrivilegesDeniesWhenPluginReturnsNotAllowed() throws Exception { + Object plugin = mockSqoopPlugin(); + RangerAccessResult result = mock(RangerAccessResult.class); + + when(result.getIsAllowed()).thenReturn(false); + wireIsAccessAllowed(plugin, result); + + setSqoopPlugin(plugin); + + assertThrows(SqoopException.class, () -> authorizer.checkPrivileges(buildUserPrincipal(), buildReadConnectorPrivilege())); + } + + @Test + public void checkPrivilegesAllowsWhenPluginReturnsAllowed() throws Exception { + Object plugin = mockSqoopPlugin(); + RangerAccessResult result = mock(RangerAccessResult.class); + + when(result.getIsAllowed()).thenReturn(true); + wireIsAccessAllowed(plugin, result); + + setSqoopPlugin(plugin); + + assertDoesNotThrow(() -> authorizer.checkPrivileges(buildUserPrincipal(), buildReadConnectorPrivilege())); + } + + private static Field getSqoopPluginField() throws NoSuchFieldException { + Field field = RangerSqoopAuthorizer.class.getDeclaredField("sqoopPlugin"); + + field.setAccessible(true); + + return field; + } + + private static void setSqoopPlugin(Object plugin) throws Exception { + getSqoopPluginField().set(null, plugin); + } + + private static Object mockSqoopPlugin() throws ClassNotFoundException { + Class<?> pluginClass = Class.forName("org.apache.ranger.authorization.sqoop.authorizer.RangerSqoopAuthorizer$RangerSqoopPlugin"); + + return mock(pluginClass); + } + + private static void wireIsAccessAllowed(Object plugin, RangerAccessResult result) { + when(((RangerBasePlugin) plugin).isAccessAllowed(any(RangerAccessRequest.class))).thenReturn(result); + } + + private static MPrincipal buildUserPrincipal() { + MPrincipal principal = mock(MPrincipal.class); + + when(principal.getType()).thenReturn(MPrincipal.TYPE.USER.name()); + when(principal.getName()).thenReturn(TEST_USER); + + return principal; + } + + private static List<MPrivilege> buildReadConnectorPrivilege() { + MResource resource = mock(MResource.class); + + when(resource.getType()).thenReturn(MResource.TYPE.CONNECTOR.name()); + when(resource.getName()).thenReturn("hdfs-connector"); + + MPrivilege privilege = mock(MPrivilege.class); + + when(privilege.getResource()).thenReturn(resource); + when(privilege.getAction()).thenReturn("read"); + + return Collections.singletonList(privilege); + } +}
