From 7691ace1d79d52dac370193d7e4a5eb5a9c2661a Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Fri, 21 Nov 2025 14:22:33 -0800 Subject: [PATCH 1/9] RANGER-5393: updated RangerOzoneAuthorizer to support AssumeRole --- .../service-defs/ranger-servicedef-ozone.json | 27 ++- plugin-ozone/pom.xml | 24 ++- .../authorizer/RangerOzoneAuthorizer.java | 178 +++++++++++++++++- .../authorizer/TestRangerOzoneAuthorizer.java | 153 +++++++++++++++ .../src/test/resources/om_dev_ozone.json | 46 +++++ .../test/resources/ranger-ozone-security.xml | 29 +++ pom.xml | 7 +- .../authorizer/RangerOzoneAuthorizer.java | 16 ++ 8 files changed, 465 insertions(+), 15 deletions(-) create mode 100644 plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java create mode 100644 plugin-ozone/src/test/resources/om_dev_ozone.json create mode 100644 plugin-ozone/src/test/resources/ranger-ozone-security.xml diff --git a/agents-common/src/main/resources/service-defs/ranger-servicedef-ozone.json b/agents-common/src/main/resources/service-defs/ranger-servicedef-ozone.json index 2bff90d47b..025e5fa08e 100755 --- a/agents-common/src/main/resources/service-defs/ranger-servicedef-ozone.json +++ b/agents-common/src/main/resources/service-defs/ranger-servicedef-ozone.json @@ -25,6 +25,7 @@ "uiHint":"", "label": "Ozone Volume", "description": "Ozone Volume", + "accessTypeRestrictions": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl", "all" ], "isValidLeaf": true }, { @@ -44,9 +45,9 @@ "uiHint":"", "label": "Ozone Bucket", "description": "Ozone Bucket", + "accessTypeRestrictions": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl", "all" ], "isValidLeaf": true }, - { "itemId": 3, "name": "key", @@ -64,7 +65,25 @@ "uiHint":"", "label": "Ozone Key", "description": "Ozone Key", + "accessTypeRestrictions": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl", "all" ], "isValidLeaf": true + }, + { + "itemId": 4, + "name": "role", + "type": "string", + "level": 10, + "parent": "", + "mandatory": true, + "lookupSupported": true, + "recursiveSupported": false, + "excludesSupported": false, + "matcher": "org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", + "matcherOptions": { "wildCard":true, "ignoreCase":false }, + "label": "Role", + "description": "Role", + "accessTypeRestrictions": [ "assume_role" ], + "isValidLeaf": true } ], @@ -130,6 +149,12 @@ "name": "write_acl", "label": "Write_ACL", "category": "UPDATE" + }, + { + "itemId": 8, + "name": "assume_role", + "label": "Assume_Role", + "category": "MANAGE" } ], diff --git a/plugin-ozone/pom.xml b/plugin-ozone/pom.xml index 4009242978..767867cd76 100644 --- a/plugin-ozone/pom.xml +++ b/plugin-ozone/pom.xml @@ -145,9 +145,27 @@ limitations under the License. ${org.bouncycastle.bcpkix-jdk18on} - org.slf4j - log4j-over-slf4j - ${slf4j.version} + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.junit.vintage + junit-vintage-engine + ${junit.jupiter.version} + test + + + org.mockito + mockito-inline + ${mockito.version} + test + + + org.mockito + mockito-junit-jupiter + ${mockito.version} test diff --git a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index c08e9c0f91..18aea781cc 100644 --- a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -20,6 +20,10 @@ package org.apache.ranger.authorization.ozone.authorizer; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.hadoop.ozone.om.exceptions.OMException; +import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest; import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer; import org.apache.hadoop.ozone.security.acl.IOzoneObj; import org.apache.hadoop.ozone.security.acl.OzoneObj; @@ -27,31 +31,43 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.thirdparty.com.google.common.collect.Sets; import org.apache.ranger.audit.provider.MiscUtil; +import org.apache.ranger.authz.util.RangerResourceNameParser; import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; +import org.apache.ranger.plugin.model.RangerInlinePolicy; +import org.apache.ranger.plugin.model.RangerPrincipal; import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; import org.apache.ranger.plugin.policyengine.RangerAccessResult; import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.ranger.plugin.util.JsonUtilsV2; import org.apache.ranger.plugin.util.RangerPerfTracer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; public class RangerOzoneAuthorizer implements IAccessAuthorizer { private static final Logger LOG = LoggerFactory.getLogger(RangerOzoneAuthorizer.class); private static final Logger PERF_OZONEAUTH_REQUEST_LOG = RangerPerfTracer.getPerfLogger("ozoneauth.request"); - public static final String ACCESS_TYPE_READ = "read"; - public static final String ACCESS_TYPE_WRITE = "write"; - public static final String ACCESS_TYPE_CREATE = "create"; - public static final String ACCESS_TYPE_LIST = "list"; - public static final String ACCESS_TYPE_DELETE = "delete"; - public static final String ACCESS_TYPE_READ_ACL = "read_acl"; - public static final String ACCESS_TYPE_WRITE_ACL = "write_acl"; - public static final String KEY_RESOURCE_VOLUME = "volume"; - public static final String KEY_RESOURCE_BUCKET = "bucket"; - public static final String KEY_RESOURCE_KEY = "key"; + public static final String ACCESS_TYPE_READ = "read"; + public static final String ACCESS_TYPE_WRITE = "write"; + public static final String ACCESS_TYPE_CREATE = "create"; + public static final String ACCESS_TYPE_LIST = "list"; + public static final String ACCESS_TYPE_DELETE = "delete"; + public static final String ACCESS_TYPE_READ_ACL = "read_acl"; + public static final String ACCESS_TYPE_WRITE_ACL = "write_acl"; + public static final String ACCESS_TYPE_ASSUME_ROLE = "assume_role"; + + public static final String KEY_RESOURCE_VOLUME = "volume"; + public static final String KEY_RESOURCE_BUCKET = "bucket"; + public static final String KEY_RESOURCE_KEY = "key"; + public static final String KEY_RESOURCE_ROLE = "role"; private static volatile RangerBasePlugin rangerPlugin; @@ -77,6 +93,11 @@ public RangerOzoneAuthorizer() { } } + // for testing only + RangerOzoneAuthorizer(RangerBasePlugin plugin) { + rangerPlugin = plugin; + } + @Override public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) { boolean returnValue = false; @@ -170,6 +191,10 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) { } try { + if (StringUtils.isNotBlank(context.getSessionPolicy())) { + rangerRequest.setInlinePolicy(JsonUtilsV2.jsonToObj(context.getSessionPolicy(), RangerInlinePolicy.class)); + } + RangerAccessResult result = plugin.isAccessAllowed(rangerRequest); if (result == null) { @@ -188,6 +213,55 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) { return returnValue; } + @Override + public String generateAssumeRoleSessionPolicy(AssumeRoleRequest assumeRoleRequest) throws OMException { + LOG.debug("==> RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy(assumeRoleRequest={})", assumeRoleRequest); + + if (assumeRoleRequest == null) { + throw new OMException("invalid request: null", OMException.ResultCodes.INVALID_REQUEST); + } else if (assumeRoleRequest.getClientUgi() == null) { + throw new OMException("invalid request: request.clientUgi null", OMException.ResultCodes.INVALID_REQUEST); + } else if (assumeRoleRequest.getTargetRoleName() == null) { + throw new OMException("invalid request: request.targetRoleName null", OMException.ResultCodes.INVALID_REQUEST); + } + + RangerBasePlugin plugin = rangerPlugin; + + if (plugin == null) { + throw new OMException("Ranger authorizer not initialized", OMException.ResultCodes.INTERNAL_ERROR); + } + + UserGroupInformation ugi = assumeRoleRequest.getClientUgi(); + RangerAccessResourceImpl resource = new RangerAccessResourceImpl(Collections.singletonMap(KEY_RESOURCE_ROLE, assumeRoleRequest.getTargetRoleName())); + RangerAccessRequestImpl request = new RangerAccessRequestImpl(resource, ACCESS_TYPE_ASSUME_ROLE, ugi.getShortUserName(), Sets.newHashSet(ugi.getGroupNames()), null); + + try { + RangerAccessResult result = plugin.isAccessAllowed(request); + + if (result != null && result.getIsAccessDetermined() && result.getIsAllowed()) { + RangerInlinePolicy inlinePolicy = new RangerInlinePolicy(RangerPrincipal.PREFIX_ROLE + assumeRoleRequest.getTargetRoleName(), RangerInlinePolicy.Mode.INLINE, null, ugi.getShortUserName()); + + if (CollectionUtils.isNotEmpty(assumeRoleRequest.getGrants())) { + inlinePolicy.setGrants(assumeRoleRequest.getGrants().stream().map(g -> toRangerGrant(g, plugin)).filter(Objects::nonNull).collect(Collectors.toList())); + } + + String ret = JsonUtilsV2.objToJson(inlinePolicy); + + LOG.debug("<== RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy(assumeRoleRequest={}): ret={}", assumeRoleRequest, ret); + + return ret; + } else { + throw new OMException("Permission denied", OMException.ResultCodes.ACCESS_DENIED); + } + } catch (OMException excp) { + throw excp; + } catch (Throwable t) { + LOG.error("isAccessAllowed() failed. request = {}", request, t); + + throw new OMException("Ranger authorizer failed", t, OMException.ResultCodes.INTERNAL_ERROR); + } + } + private String mapToRangerAccessType(ACLType operation) { final String rangerAccessType; @@ -221,4 +295,88 @@ private String mapToRangerAccessType(ACLType operation) { return rangerAccessType; } + + private static RangerInlinePolicy.Grant toRangerGrant(AssumeRoleRequest.OzoneGrant ozoneGrant, RangerBasePlugin plugin) { + RangerInlinePolicy.Grant ret; + + if (CollectionUtils.isEmpty(ozoneGrant.getObjects()) && CollectionUtils.isEmpty(ozoneGrant.getPermissions())) { + ret = null; + } else { + ret = new RangerInlinePolicy.Grant(); + + if (ozoneGrant.getObjects() != null) { + ret.setResources(ozoneGrant.getObjects().stream().map(o -> toRrn(o, plugin)).filter(Objects::nonNull).collect(Collectors.toSet())); + } + + if (ozoneGrant.getPermissions() != null) { + ret.setPermissions(ozoneGrant.getPermissions().stream().map(RangerOzoneAuthorizer::toRangerPermission).filter(Objects::nonNull).collect(Collectors.toSet())); + } + } + + LOG.debug("toRangerGrant(ozoneGrant={}): ret={}", ozoneGrant, ret); + + return ret; + } + + private static String toRrn(IOzoneObj obj, RangerBasePlugin plugin) { + OzoneObj ozoneObj = (OzoneObj) obj; + Map resource = new HashMap<>(); + String resType = null; + + switch (ozoneObj.getResourceType()) { + case VOLUME: + resType = KEY_RESOURCE_VOLUME; + + resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getVolumeName()); + break; + + case BUCKET: + resType = KEY_RESOURCE_BUCKET; + + resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? "s3Vol" : ozoneObj.getVolumeName()); + resource.put(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName()); + break; + + case KEY: + resType = KEY_RESOURCE_KEY; + + resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? "s3Vol" : ozoneObj.getVolumeName()); + resource.put(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName()); + resource.put(KEY_RESOURCE_KEY, ozoneObj.getKeyName()); + break; + } + + RangerResourceNameParser rrnParser = resType != null ? plugin.getServiceDefHelper().getRrnParser(resType) : null; + String ret = rrnParser != null ? (resType + RangerResourceNameParser.RRN_RESOURCE_TYPE_SEP + rrnParser.toResourceName(resource)) : null; + + LOG.debug("toRrn(ozoneObj={}): ret={}", ozoneObj, ret); + + return ret; + } + + private static String toRangerPermission(ACLType acl) { + switch (acl) { + case READ: + return "read"; + case WRITE: + return "write"; + case CREATE: + return "create"; + case LIST: + return "list"; + case DELETE: + return "delete"; + case READ_ACL: + return "read_acl"; + case WRITE_ACL: + return "write_acl"; + case ALL: + return "all"; + case NONE: + case ASSUME_ROLE: // ASSUME_ROLE is not supported in session policy + return null; + } + + return null; + } } diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java new file mode 100644 index 0000000000..27480d0960 --- /dev/null +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -0,0 +1,153 @@ +/* + * 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.ozone.authorizer; + +import org.apache.hadoop.ozone.om.exceptions.OMException; +import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest; +import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest.OzoneGrant; +import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer; +import org.apache.hadoop.ozone.security.acl.OzoneObj; +import org.apache.hadoop.ozone.security.acl.OzoneObjInfo; +import org.apache.hadoop.ozone.security.acl.RequestContext; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; +import org.apache.ranger.plugin.model.RangerInlinePolicy; +import org.apache.ranger.plugin.policyengine.RangerPluginContext; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.ranger.plugin.util.JsonUtilsV2; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.net.InetAddress; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class TestRangerOzoneAuthorizer { + static RangerOzoneAuthorizer ozoneAuthorizer; + + private final String hostname = "localhost"; + private final InetAddress ipAddress = InetAddress.getLoopbackAddress(); + private final UserGroupInformation user1 = UserGroupInformation.createRemoteUser("user1"); + private final UserGroupInformation user2 = UserGroupInformation.createRemoteUser("user2"); + private final String role1 = "role1"; + + private final OzoneObj vol1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.VOLUME).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").build(); + private final OzoneObj buck1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.BUCKET).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").setBucketName("buck1").build(); + private final OzoneObj key1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.KEY).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").setBucketName("buck1").setKeyName("key1").build(); + private final OzoneObj vol2 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.VOLUME).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol2").build(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + RangerPluginContext pluginContext = new RangerPluginContext(new RangerPluginConfig("ozone", null, "om", null, null, null)); + RangerBasePlugin plugin = new RangerBasePlugin(pluginContext.getConfig()); + + plugin.init(); + + ozoneAuthorizer = new RangerOzoneAuthorizer(plugin); + + assertNotNull(ozoneAuthorizer); + } + + @Test + public void testAssumeRoleDeny() throws Exception { + // user1 should not be allowed to assume role1 + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user1, role1, null); + + assertThrows(OMException.class, () -> ozoneAuthorizer.generateAssumeRoleSessionPolicy(request)); + } + + @Test + public void testAssumeRoleWithNoGrants() throws Exception { + // user2 should be allowed to assume role1 + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user2, role1, Collections.emptySet()); + + String sessionPolicy = ozoneAuthorizer.generateAssumeRoleSessionPolicy(request); + + assertNotNull(sessionPolicy); + assertNotEquals("", sessionPolicy); + + RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); + + assertEquals("r:role1", inlinePolicy.getGrantor()); + assertNotNull("user1", inlinePolicy.getCreatedBy()); + assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); + assertNull(inlinePolicy.getGrants()); + + RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone"); + RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone"); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + + // user2 doesn't have access without session-policy + assertFalse("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy)); + assertFalse("session-policy should not allow list on vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy)); + + // user2 should have access with session-policy + assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); + assertTrue("session-policy should allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); + assertTrue("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); + assertTrue("session-policy should allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy)); + } + + @Test + public void testAssumeRoleWithGrants() throws Exception { + OzoneGrant grant1 = new OzoneGrant(new HashSet<>(Arrays.asList(vol1, buck1)), Collections.singleton(IAccessAuthorizer.ACLType.LIST)); + OzoneGrant grant2 = new OzoneGrant(Collections.singleton(key1), Collections.singleton(IAccessAuthorizer.ACLType.READ)); + + // user2 should be allowed to assume role1 + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user2, role1, new HashSet<>(Arrays.asList(grant1, grant2))); + + String sessionPolicy = ozoneAuthorizer.generateAssumeRoleSessionPolicy(request); + + assertNotNull(sessionPolicy); + assertNotEquals("", sessionPolicy); + + RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); + + assertEquals("r:role1", inlinePolicy.getGrantor()); + assertNotNull("user1", inlinePolicy.getCreatedBy()); + assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); + assertNotNull(inlinePolicy.getGrants()); + assertEquals(2, inlinePolicy.getGrants().size()); + + assertTrue(inlinePolicy.getGrants().contains(new RangerInlinePolicy.Grant(null, new HashSet<>(Arrays.asList("volume:vol1", "bucket:vol1/buck1")), Collections.singleton("list")))); + assertTrue(inlinePolicy.getGrants().contains(new RangerInlinePolicy.Grant(null, Collections.singleton("key:vol1/buck1/key1"), Collections.singleton("read")))); + + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + + // user2 should have access with sessionPolicy + assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); + assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); + assertTrue("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); + assertTrue("session-policy should allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy)); + } +} diff --git a/plugin-ozone/src/test/resources/om_dev_ozone.json b/plugin-ozone/src/test/resources/om_dev_ozone.json new file mode 100644 index 0000000000..840df48773 --- /dev/null +++ b/plugin-ozone/src/test/resources/om_dev_ozone.json @@ -0,0 +1,46 @@ +{ + "serviceName": "dev_ozone", "serviceId": 1, + "serviceDef": { + "id": 1, "name":"ozone", + "resources":[ + { "name": "volume", "level": 1, "parent": "", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Volume", "description": "Volume" }, + { "name": "bucket", "level": 2, "parent": "volume", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerURLResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Bucket", "description": "Bucket" }, + { "name": "key", "level": 3, "parent": "bucket", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": true }, "label": "Key", "description": "Key" }, + { "name": "role", "level": 4, "parent": "", "matcher":"org.apache.ranger.plugin.resourcematcher.RangerDefaultResourceMatcher", "matcherOptions": { "wildCard": true, "ignoreCase": false }, "label": "Role", "description": "Role" } + ], + "accessTypes":[ + { "name": "read", "label": "Read" }, + { "name": "write", "label": "Write" }, + { "name": "create", "label": "Create" }, + { "name": "list", "label": "List" }, + { "name": "delete", "label": "Delete" }, + { "name": "read_acl", "label": "Read_ACL" }, + { "name": "write_acl", "label": "Write_ACL" }, + { "name": "all", "label": "All", "impliedGrants": [ "read", "write", "create", "list", "delete", "read_acl", "write_acl" ] }, + { "name": "assume_role", "label": "Assume_Role" } + ] + }, + "policies": [ + { "id": 100, "name": "role: role1", "isEnabled": true, "isAuditEnabled": true, + "resources": { "role": { "values": [ "role1" ] } }, + "policyItems":[ + { "accesses": [ { "type": "assume_role" } ], "users": [ "user2" ] } + ] + }, + { "id": 101, "name": "volume: vol1, bucket: vol1/buck1", "isEnabled": true, "isAuditEnabled": true, + "resources": { "volume": { "values": [ "vol1", "vol2" ] } }, + "additionalResources": [ + { "volume": { "values": [ "vol1" ] }, "bucket": { "values": [ "buck1" ] } } + ], + "policyItems":[ + { "accesses": [ { "type": "list" } ], "roles": [ "role1" ] } + ] + }, + { "id": 102, "name": "key: vol1/buck1/key1", "isEnabled": true, "isAuditEnabled": true, + "resources": { "volume": { "values": [ "vol1" ] }, "bucket": { "values": [ "buck1" ] }, "key": { "values": [ "key1" ] } }, + "policyItems":[ + { "accesses": [ { "type": "read" } ], "roles": [ "role1" ] } + ] + } + ] +} \ No newline at end of file diff --git a/plugin-ozone/src/test/resources/ranger-ozone-security.xml b/plugin-ozone/src/test/resources/ranger-ozone-security.xml new file mode 100644 index 0000000000..05c47ff828 --- /dev/null +++ b/plugin-ozone/src/test/resources/ranger-ozone-security.xml @@ -0,0 +1,29 @@ + + + + + + ranger.plugin.ozone.service.name + dev_ozone + + + + ranger.plugin.ozone.policy.source.impl + org.apache.ranger.admin.client.EmbeddedResourcePolicySource + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index d12acce9e9..db387ca011 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 1.79 1.79 20211018.2 - 1.4.0 + 2.1.0 2.3 5.2.2 @@ -793,6 +793,11 @@ jetbrains-intellij-dependencies https://packages.jetbrains.team/maven/p/ij/intellij-dependencies + + ozone-2.1.0-rc + ozone-2.1.0-rc + https://repository.apache.org/content/repositories/orgapacheozone-1061 + diff --git a/ranger-ozone-plugin-shim/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/ranger-ozone-plugin-shim/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index 0b461d3b08..7658d4aeaf 100644 --- a/ranger-ozone-plugin-shim/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/ranger-ozone-plugin-shim/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -20,6 +20,7 @@ package org.apache.ranger.authorization.ozone.authorizer; import org.apache.hadoop.ozone.om.exceptions.OMException; +import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest; import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer; import org.apache.hadoop.ozone.security.acl.IOzoneObj; import org.apache.hadoop.ozone.security.acl.RequestContext; @@ -59,6 +60,21 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) throws } } + @Override + public String generateAssumeRoleSessionPolicy(AssumeRoleRequest assumeRoleRequest) throws OMException { + LOG.debug("==> RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy()"); + + try { + activatePluginClassLoader(); + + return ozoneAuthorizationProviderImpl.generateAssumeRoleSessionPolicy(assumeRoleRequest); + } finally { + deactivatePluginClassLoader(); + + LOG.debug("<== RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy()"); + } + } + private void init() { LOG.debug("==> RangerOzoneAuthorizer.init()"); From 85e6dd263b4771d536c05212299d3165df0a9d21 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Wed, 10 Dec 2025 09:21:27 -0800 Subject: [PATCH 2/9] RANGER-5393: addressed review comments --- .../ozone/authorizer/TestRangerOzoneAuthorizer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java index 27480d0960..6801634dfd 100644 --- a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -95,7 +95,7 @@ public void testAssumeRoleWithNoGrants() throws Exception { RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); assertEquals("r:role1", inlinePolicy.getGrantor()); - assertNotNull("user1", inlinePolicy.getCreatedBy()); + assertEquals("user2", inlinePolicy.getCreatedBy()); assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); assertNull(inlinePolicy.getGrants()); @@ -133,7 +133,7 @@ public void testAssumeRoleWithGrants() throws Exception { RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); assertEquals("r:role1", inlinePolicy.getGrantor()); - assertNotNull("user1", inlinePolicy.getCreatedBy()); + assertEquals("user2", inlinePolicy.getCreatedBy()); assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); assertNotNull(inlinePolicy.getGrants()); assertEquals(2, inlinePolicy.getGrants().size()); From cc1904d8e912fc5abe39e5f623de72d2542db0b9 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Wed, 10 Dec 2025 13:09:46 -0800 Subject: [PATCH 3/9] RANGER-5393: updated Ozone authorizer handling of empty grants and null grants --- .../authorizer/RangerOzoneAuthorizer.java | 2 + .../authorizer/TestRangerOzoneAuthorizer.java | 96 +++++++++++++------ .../src/test/resources/om_dev_ozone.json | 2 +- 3 files changed, 70 insertions(+), 30 deletions(-) diff --git a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index 18aea781cc..240b6fd897 100644 --- a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -243,6 +243,8 @@ public String generateAssumeRoleSessionPolicy(AssumeRoleRequest assumeRoleReques if (CollectionUtils.isNotEmpty(assumeRoleRequest.getGrants())) { inlinePolicy.setGrants(assumeRoleRequest.getGrants().stream().map(g -> toRangerGrant(g, plugin)).filter(Objects::nonNull).collect(Collectors.toList())); + } else if (assumeRoleRequest.getGrants() != null && assumeRoleRequest.getGrants().isEmpty()) { // empty grants list => no permission via session policy + inlinePolicy.setGrants(Collections.singletonList(new RangerInlinePolicy.Grant())); } String ret = JsonUtilsV2.objToJson(inlinePolicy); diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java index 6801634dfd..55ebf77386 100644 --- a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -39,6 +39,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -57,10 +58,12 @@ public class TestRangerOzoneAuthorizer { private final UserGroupInformation user2 = UserGroupInformation.createRemoteUser("user2"); private final String role1 = "role1"; - private final OzoneObj vol1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.VOLUME).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").build(); - private final OzoneObj buck1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.BUCKET).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").setBucketName("buck1").build(); - private final OzoneObj key1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.KEY).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").setBucketName("buck1").setKeyName("key1").build(); - private final OzoneObj vol2 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.VOLUME).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol2").build(); + private final OzoneObj vol1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.VOLUME).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").build(); + private final OzoneObj buck1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.BUCKET).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").setBucketName("buck1").build(); + private final OzoneObj key1 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.KEY).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol1").setBucketName("buck1").setKeyName("key1").build(); + private final OzoneObj vol2 = new OzoneObjInfo.Builder().setResType(OzoneObj.ResourceType.VOLUME).setStoreType(OzoneObj.StoreType.OZONE).setVolumeName("vol2").build(); + private final OzoneGrant grantList = new OzoneGrant(new HashSet<>(Arrays.asList(vol1, buck1)), Collections.singleton(IAccessAuthorizer.ACLType.LIST)); + private final OzoneGrant grantRead = new OzoneGrant(Collections.singleton(key1), Collections.singleton(IAccessAuthorizer.ACLType.READ)); @BeforeClass public static void setUpBeforeClass() throws Exception { @@ -76,17 +79,18 @@ public static void setUpBeforeClass() throws Exception { @Test public void testAssumeRoleDeny() throws Exception { - // user1 should not be allowed to assume role1 - AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user1, role1, null); + // user2 should not be allowed to assume role1 - no Ranger policy grants this permission + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user2, role1, null); assertThrows(OMException.class, () -> ozoneAuthorizer.generateAssumeRoleSessionPolicy(request)); } @Test - public void testAssumeRoleWithNoGrants() throws Exception { - // user2 should be allowed to assume role1 - AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user2, role1, Collections.emptySet()); + public void testAssumeRoleWithEmptyGrants() throws Exception { + Set grants = Collections.emptySet(); + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user1, role1, grants); + // user1 should be allowed to assume role1 - Ranger policy #100 grants this permission String sessionPolicy = ozoneAuthorizer.generateAssumeRoleSessionPolicy(request); assertNotNull(sessionPolicy); @@ -95,22 +99,58 @@ public void testAssumeRoleWithNoGrants() throws Exception { RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); assertEquals("r:role1", inlinePolicy.getGrantor()); - assertEquals("user2", inlinePolicy.getCreatedBy()); + assertEquals("user1", inlinePolicy.getCreatedBy()); + assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); + assertNotNull(inlinePolicy.getGrants()); + + RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone"); + RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone"); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + + // user1 doesn't have access without session-policy + assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should not allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should not allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy)); + + // user1 should not have access with session-policy as well, due to empty grants + assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); + assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); + assertFalse("session-policy should not allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); + assertFalse("session-policy should not allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy)); + } + + @Test + public void testAssumeRoleWithNullGrants() throws Exception { + Set grants = null; + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user1, role1, grants); + + // user1 should be allowed to assume role1 - Ranger policy #100 grants this permission + String sessionPolicy = ozoneAuthorizer.generateAssumeRoleSessionPolicy(request); + + assertNotNull(sessionPolicy); + assertNotEquals("", sessionPolicy); + + RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); + + assertEquals("r:role1", inlinePolicy.getGrantor()); + assertEquals("user1", inlinePolicy.getCreatedBy()); assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); assertNull(inlinePolicy.getGrants()); - RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone"); - RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone"); - RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); - RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone"); + RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone"); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); - // user2 doesn't have access without session-policy - assertFalse("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy)); - assertFalse("session-policy should not allow list on vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy)); + // user1 doesn't have access without session-policy + assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should not allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy)); + assertFalse("session-policy should not allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy)); - // user2 should have access with session-policy + // user1 should have access with session-policy, due to null grants which allows all accesses granted to role1 assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); assertTrue("session-policy should allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); assertTrue("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); @@ -119,12 +159,10 @@ public void testAssumeRoleWithNoGrants() throws Exception { @Test public void testAssumeRoleWithGrants() throws Exception { - OzoneGrant grant1 = new OzoneGrant(new HashSet<>(Arrays.asList(vol1, buck1)), Collections.singleton(IAccessAuthorizer.ACLType.LIST)); - OzoneGrant grant2 = new OzoneGrant(Collections.singleton(key1), Collections.singleton(IAccessAuthorizer.ACLType.READ)); - - // user2 should be allowed to assume role1 - AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user2, role1, new HashSet<>(Arrays.asList(grant1, grant2))); + Set grants = new HashSet<>(Arrays.asList(grantList, grantRead)); + AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user1, role1, grants); + // user1 should be allowed to assume role1 - Ranger policy #100 grants this permission String sessionPolicy = ozoneAuthorizer.generateAssumeRoleSessionPolicy(request); assertNotNull(sessionPolicy); @@ -133,7 +171,7 @@ public void testAssumeRoleWithGrants() throws Exception { RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, RangerInlinePolicy.class); assertEquals("r:role1", inlinePolicy.getGrantor()); - assertEquals("user2", inlinePolicy.getCreatedBy()); + assertEquals("user1", inlinePolicy.getCreatedBy()); assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); assertNotNull(inlinePolicy.getGrants()); assertEquals(2, inlinePolicy.getGrants().size()); @@ -141,10 +179,10 @@ public void testAssumeRoleWithGrants() throws Exception { assertTrue(inlinePolicy.getGrants().contains(new RangerInlinePolicy.Grant(null, new HashSet<>(Arrays.asList("volume:vol1", "bucket:vol1/buck1")), Collections.singleton("list")))); assertTrue(inlinePolicy.getGrants().contains(new RangerInlinePolicy.Grant(null, Collections.singleton("key:vol1/buck1/key1"), Collections.singleton("read")))); - RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); - RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user2, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); - // user2 should have access with sessionPolicy + // user1 should have access with sessionPolicy assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); assertTrue("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); diff --git a/plugin-ozone/src/test/resources/om_dev_ozone.json b/plugin-ozone/src/test/resources/om_dev_ozone.json index 840df48773..e8d761801a 100644 --- a/plugin-ozone/src/test/resources/om_dev_ozone.json +++ b/plugin-ozone/src/test/resources/om_dev_ozone.json @@ -24,7 +24,7 @@ { "id": 100, "name": "role: role1", "isEnabled": true, "isAuditEnabled": true, "resources": { "role": { "values": [ "role1" ] } }, "policyItems":[ - { "accesses": [ { "type": "assume_role" } ], "users": [ "user2" ] } + { "accesses": [ { "type": "assume_role" } ], "users": [ "user1" ] } ] }, { "id": 101, "name": "volume: vol1, bucket: vol1/buck1", "isEnabled": true, "isAuditEnabled": true, From 600c64873223c0208c205922f787aa51a90ae655 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Wed, 10 Dec 2025 15:21:13 -0800 Subject: [PATCH 4/9] RANGER-5393: replaced hardcoded permission names with constants --- .../ozone/authorizer/RangerOzoneAuthorizer.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index 240b6fd897..c203ded085 100644 --- a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -63,6 +63,7 @@ public class RangerOzoneAuthorizer implements IAccessAuthorizer { public static final String ACCESS_TYPE_READ_ACL = "read_acl"; public static final String ACCESS_TYPE_WRITE_ACL = "write_acl"; public static final String ACCESS_TYPE_ASSUME_ROLE = "assume_role"; + public static final String ACCESS_TYPE_ALL = "all"; public static final String KEY_RESOURCE_VOLUME = "volume"; public static final String KEY_RESOURCE_BUCKET = "bucket"; @@ -359,21 +360,21 @@ private static String toRrn(IOzoneObj obj, RangerBasePlugin plugin) { private static String toRangerPermission(ACLType acl) { switch (acl) { case READ: - return "read"; + return ACCESS_TYPE_READ; case WRITE: - return "write"; + return ACCESS_TYPE_WRITE; case CREATE: - return "create"; + return ACCESS_TYPE_CREATE; case LIST: - return "list"; + return ACCESS_TYPE_LIST; case DELETE: - return "delete"; + return ACCESS_TYPE_DELETE; case READ_ACL: - return "read_acl"; + return ACCESS_TYPE_READ_ACL; case WRITE_ACL: - return "write_acl"; + return ACCESS_TYPE_WRITE_ACL; case ALL: - return "all"; + return ACCESS_TYPE_ALL; case NONE: case ASSUME_ROLE: // ASSUME_ROLE is not supported in session policy return null; From fb72d8a69eed813470c671a50629733a0b9bb9b6 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Fri, 12 Dec 2025 08:45:05 -0800 Subject: [PATCH 5/9] RANGER-5393: readability improvement in handling of null and empty grants --- .../authorizer/RangerOzoneAuthorizer.java | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index c203ded085..14bd7fbe72 100644 --- a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -20,10 +20,10 @@ package org.apache.ranger.authorization.ozone.authorizer; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest; +import org.apache.hadoop.ozone.security.acl.AssumeRoleRequest.OzoneGrant; import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer; import org.apache.hadoop.ozone.security.acl.IOzoneObj; import org.apache.hadoop.ozone.security.acl.OzoneObj; @@ -47,6 +47,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -240,15 +241,18 @@ public String generateAssumeRoleSessionPolicy(AssumeRoleRequest assumeRoleReques RangerAccessResult result = plugin.isAccessAllowed(request); if (result != null && result.getIsAccessDetermined() && result.getIsAllowed()) { - RangerInlinePolicy inlinePolicy = new RangerInlinePolicy(RangerPrincipal.PREFIX_ROLE + assumeRoleRequest.getTargetRoleName(), RangerInlinePolicy.Mode.INLINE, null, ugi.getShortUserName()); - - if (CollectionUtils.isNotEmpty(assumeRoleRequest.getGrants())) { - inlinePolicy.setGrants(assumeRoleRequest.getGrants().stream().map(g -> toRangerGrant(g, plugin)).filter(Objects::nonNull).collect(Collectors.toList())); - } else if (assumeRoleRequest.getGrants() != null && assumeRoleRequest.getGrants().isEmpty()) { // empty grants list => no permission via session policy - inlinePolicy.setGrants(Collections.singletonList(new RangerInlinePolicy.Grant())); + final List inlineGrants; + + if (assumeRoleRequest.getGrants() == null) { // inlinePolicy allows all permissions + inlineGrants = null; + } else if (assumeRoleRequest.getGrants().isEmpty()) { // inlinePolicy doesn't allow any permission + inlineGrants = Collections.singletonList(new RangerInlinePolicy.Grant()); + } else { // inlinePolicy allows explicitly specified permissions + inlineGrants = assumeRoleRequest.getGrants().stream().map(g -> toRangerGrant(g, plugin)).collect(Collectors.toList()); } - String ret = JsonUtilsV2.objToJson(inlinePolicy); + RangerInlinePolicy inlinePolicy = new RangerInlinePolicy(RangerPrincipal.PREFIX_ROLE + assumeRoleRequest.getTargetRoleName(), RangerInlinePolicy.Mode.INLINE, inlineGrants, ugi.getShortUserName()); + String ret = JsonUtilsV2.objToJson(inlinePolicy); LOG.debug("<== RangerOzoneAuthorizer.generateAssumeRoleSessionPolicy(assumeRoleRequest={}): ret={}", assumeRoleRequest, ret); @@ -299,21 +303,15 @@ private String mapToRangerAccessType(ACLType operation) { return rangerAccessType; } - private static RangerInlinePolicy.Grant toRangerGrant(AssumeRoleRequest.OzoneGrant ozoneGrant, RangerBasePlugin plugin) { - RangerInlinePolicy.Grant ret; - - if (CollectionUtils.isEmpty(ozoneGrant.getObjects()) && CollectionUtils.isEmpty(ozoneGrant.getPermissions())) { - ret = null; - } else { - ret = new RangerInlinePolicy.Grant(); + private static RangerInlinePolicy.Grant toRangerGrant(OzoneGrant ozoneGrant, RangerBasePlugin plugin) { + RangerInlinePolicy.Grant ret = new RangerInlinePolicy.Grant(); - if (ozoneGrant.getObjects() != null) { - ret.setResources(ozoneGrant.getObjects().stream().map(o -> toRrn(o, plugin)).filter(Objects::nonNull).collect(Collectors.toSet())); - } + if (ozoneGrant.getObjects() != null) { + ret.setResources(ozoneGrant.getObjects().stream().map(o -> toRrn(o, plugin)).filter(Objects::nonNull).collect(Collectors.toSet())); + } - if (ozoneGrant.getPermissions() != null) { - ret.setPermissions(ozoneGrant.getPermissions().stream().map(RangerOzoneAuthorizer::toRangerPermission).filter(Objects::nonNull).collect(Collectors.toSet())); - } + if (ozoneGrant.getPermissions() != null) { + ret.setPermissions(ozoneGrant.getPermissions().stream().map(RangerOzoneAuthorizer::toRangerPermission).filter(Objects::nonNull).collect(Collectors.toSet())); } LOG.debug("toRangerGrant(ozoneGrant={}): ret={}", ozoneGrant, ret); From 71c06d2ad477869ad23da23cad1f5d9ab1542b38 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Fri, 12 Dec 2025 12:14:26 -0800 Subject: [PATCH 6/9] RANGER-5393: updated TestRangerOzoneAuthorizer to avoid unnecessary RangerPluginContext instance --- .../ozone/authorizer/TestRangerOzoneAuthorizer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java index 55ebf77386..0930a0b6e7 100644 --- a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -29,7 +29,6 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig; import org.apache.ranger.plugin.model.RangerInlinePolicy; -import org.apache.ranger.plugin.policyengine.RangerPluginContext; import org.apache.ranger.plugin.service.RangerBasePlugin; import org.apache.ranger.plugin.util.JsonUtilsV2; import org.junit.BeforeClass; @@ -67,9 +66,10 @@ public class TestRangerOzoneAuthorizer { @BeforeClass public static void setUpBeforeClass() throws Exception { - RangerPluginContext pluginContext = new RangerPluginContext(new RangerPluginConfig("ozone", null, "om", null, null, null)); - RangerBasePlugin plugin = new RangerBasePlugin(pluginContext.getConfig()); + RangerPluginConfig pluginConfig = new RangerPluginConfig("ozone", null, "om", null, null, null); // loads ranger-ozone-security.xml + RangerBasePlugin plugin = new RangerBasePlugin(pluginConfig); + // loads policies from om_dev_ozone.json, by EmbeddedResourcePolicySource configured in ranger-ozone-security.xml plugin.init(); ozoneAuthorizer = new RangerOzoneAuthorizer(plugin); From 20833cbe50c424454535329836416b8c7cf9651d Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Fri, 12 Dec 2025 12:52:15 -0800 Subject: [PATCH 7/9] RANGER-5393: addressed review suggestions --- .../authorizer/RangerOzoneAuthorizer.java | 10 ++++--- .../authorizer/TestRangerOzoneAuthorizer.java | 29 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index 14bd7fbe72..d15a45887a 100644 --- a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -50,6 +50,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; public class RangerOzoneAuthorizer implements IAccessAuthorizer { @@ -241,14 +242,15 @@ public String generateAssumeRoleSessionPolicy(AssumeRoleRequest assumeRoleReques RangerAccessResult result = plugin.isAccessAllowed(request); if (result != null && result.getIsAccessDetermined() && result.getIsAllowed()) { + final Set ozoneGrants = assumeRoleRequest.getGrants(); final List inlineGrants; - if (assumeRoleRequest.getGrants() == null) { // inlinePolicy allows all permissions + if (ozoneGrants == null) { // allow all permissions inlineGrants = null; - } else if (assumeRoleRequest.getGrants().isEmpty()) { // inlinePolicy doesn't allow any permission + } else if (ozoneGrants.isEmpty()) { // don't allow any permission inlineGrants = Collections.singletonList(new RangerInlinePolicy.Grant()); - } else { // inlinePolicy allows explicitly specified permissions - inlineGrants = assumeRoleRequest.getGrants().stream().map(g -> toRangerGrant(g, plugin)).collect(Collectors.toList()); + } else { // allow explicitly specified permissions + inlineGrants = ozoneGrants.stream().map(g -> toRangerGrant(g, plugin)).collect(Collectors.toList()); } RangerInlinePolicy inlinePolicy = new RangerInlinePolicy(RangerPrincipal.PREFIX_ROLE + assumeRoleRequest.getTargetRoleName(), RangerInlinePolicy.Mode.INLINE, inlineGrants, ugi.getShortUserName()); diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java index 0930a0b6e7..0dfe64ca66 100644 --- a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -49,7 +49,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class TestRangerOzoneAuthorizer { - static RangerOzoneAuthorizer ozoneAuthorizer; + private static final String RANGER_SERVICE_TYPE = "ozone"; + private static final String RANGER_APP_ID = "om"; + private static final String OZONE_SERVICE_ID = "om"; + private static final String OWNER_NAME = "ozone"; + + private static RangerOzoneAuthorizer ozoneAuthorizer; private final String hostname = "localhost"; private final InetAddress ipAddress = InetAddress.getLoopbackAddress(); @@ -66,7 +71,7 @@ public class TestRangerOzoneAuthorizer { @BeforeClass public static void setUpBeforeClass() throws Exception { - RangerPluginConfig pluginConfig = new RangerPluginConfig("ozone", null, "om", null, null, null); // loads ranger-ozone-security.xml + RangerPluginConfig pluginConfig = new RangerPluginConfig(RANGER_SERVICE_TYPE, null, RANGER_APP_ID, null, null, null); // loads ranger-ozone-security.xml RangerBasePlugin plugin = new RangerBasePlugin(pluginConfig); // loads policies from om_dev_ozone.json, by EmbeddedResourcePolicySource configured in ranger-ozone-security.xml @@ -103,10 +108,10 @@ public void testAssumeRoleWithEmptyGrants() throws Exception { assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); assertNotNull(inlinePolicy.getGrants()); - RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone"); - RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone"); - RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); - RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, OWNER_NAME); + RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, OWNER_NAME, false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME, false, sessionPolicy); // user1 doesn't have access without session-policy assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); @@ -139,10 +144,10 @@ public void testAssumeRoleWithNullGrants() throws Exception { assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode()); assertNull(inlinePolicy.getGrants()); - RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone"); - RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone"); - RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); - RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + RequestContext ctxListWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, OWNER_NAME); + RequestContext ctxReadWithoutSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, OWNER_NAME, false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME, false, sessionPolicy); // user1 doesn't have access without session-policy assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); @@ -179,8 +184,8 @@ public void testAssumeRoleWithGrants() throws Exception { assertTrue(inlinePolicy.getGrants().contains(new RangerInlinePolicy.Grant(null, new HashSet<>(Arrays.asList("volume:vol1", "bucket:vol1/buck1")), Collections.singleton("list")))); assertTrue(inlinePolicy.getGrants().contains(new RangerInlinePolicy.Grant(null, Collections.singleton("key:vol1/buck1/key1"), Collections.singleton("read")))); - RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, "ozone", false, sessionPolicy); - RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, "om", IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, "ozone", false, sessionPolicy); + RequestContext ctxListWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.LIST, OWNER_NAME, false, sessionPolicy); + RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME, false, sessionPolicy); // user1 should have access with sessionPolicy assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); From 0486dce6a637b5adeafec43087f73ed8fa8f470f Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Fri, 12 Dec 2025 13:00:34 -0800 Subject: [PATCH 8/9] RANGER-5393: addressed review suggestions --- .../ozone/authorizer/RangerOzoneAuthorizer.java | 13 +++++-------- .../ozone/authorizer/TestRangerOzoneAuthorizer.java | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java index d15a45887a..4414f22ada 100644 --- a/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java +++ b/plugin-ozone/src/main/java/org/apache/ranger/authorization/ozone/authorizer/RangerOzoneAuthorizer.java @@ -72,6 +72,8 @@ public class RangerOzoneAuthorizer implements IAccessAuthorizer { public static final String KEY_RESOURCE_KEY = "key"; public static final String KEY_RESOURCE_ROLE = "role"; + private static final String S3_VOLUME_NAME = "s3Vol"; + private static volatile RangerBasePlugin rangerPlugin; public RangerOzoneAuthorizer() { @@ -173,12 +175,7 @@ public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) { if (ozoneObj.getResourceType() == OzoneObj.ResourceType.VOLUME) { rangerResource.setValue(KEY_RESOURCE_VOLUME, ozoneObj.getVolumeName()); } else if (ozoneObj.getResourceType() == OzoneObj.ResourceType.BUCKET || ozoneObj.getResourceType() == OzoneObj.ResourceType.KEY) { - if (ozoneObj.getStoreType() == OzoneObj.StoreType.S3) { - rangerResource.setValue(KEY_RESOURCE_VOLUME, "s3Vol"); - } else { - rangerResource.setValue(KEY_RESOURCE_VOLUME, ozoneObj.getVolumeName()); - } - + rangerResource.setValue(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? S3_VOLUME_NAME : ozoneObj.getVolumeName()); rangerResource.setValue(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName()); if (ozoneObj.getResourceType() == OzoneObj.ResourceType.KEY) { @@ -336,14 +333,14 @@ private static String toRrn(IOzoneObj obj, RangerBasePlugin plugin) { case BUCKET: resType = KEY_RESOURCE_BUCKET; - resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? "s3Vol" : ozoneObj.getVolumeName()); + resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? S3_VOLUME_NAME : ozoneObj.getVolumeName()); resource.put(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName()); break; case KEY: resType = KEY_RESOURCE_KEY; - resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? "s3Vol" : ozoneObj.getVolumeName()); + resource.put(KEY_RESOURCE_VOLUME, ozoneObj.getStoreType() == OzoneObj.StoreType.S3 ? S3_VOLUME_NAME : ozoneObj.getVolumeName()); resource.put(KEY_RESOURCE_BUCKET, ozoneObj.getBucketName()); resource.put(KEY_RESOURCE_KEY, ozoneObj.getKeyName()); break; diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java index 0dfe64ca66..4963cac113 100644 --- a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -70,7 +70,7 @@ public class TestRangerOzoneAuthorizer { private final OzoneGrant grantRead = new OzoneGrant(Collections.singleton(key1), Collections.singleton(IAccessAuthorizer.ACLType.READ)); @BeforeClass - public static void setUpBeforeClass() throws Exception { + public static void setUpBeforeClass() { RangerPluginConfig pluginConfig = new RangerPluginConfig(RANGER_SERVICE_TYPE, null, RANGER_APP_ID, null, null, null); // loads ranger-ozone-security.xml RangerBasePlugin plugin = new RangerBasePlugin(pluginConfig); @@ -83,7 +83,7 @@ public static void setUpBeforeClass() throws Exception { } @Test - public void testAssumeRoleDeny() throws Exception { + public void testAssumeRoleDeny() { // user2 should not be allowed to assume role1 - no Ranger policy grants this permission AssumeRoleRequest request = new AssumeRoleRequest(hostname, ipAddress, user2, role1, null); From ad556190fd9d3c418853bcd10015781466b9e390 Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Fri, 12 Dec 2025 13:12:04 -0800 Subject: [PATCH 9/9] RANGER-5393: removed JUnit4 usage --- plugin-ozone/pom.xml | 6 -- .../authorizer/TestRangerOzoneAuthorizer.java | 58 +++++++++---------- 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/plugin-ozone/pom.xml b/plugin-ozone/pom.xml index 767867cd76..d119745218 100644 --- a/plugin-ozone/pom.xml +++ b/plugin-ozone/pom.xml @@ -150,12 +150,6 @@ limitations under the License. ${junit.jupiter.version} test - - org.junit.vintage - junit-vintage-engine - ${junit.jupiter.version} - test - org.mockito mockito-inline diff --git a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java index 4963cac113..df3aa65ac5 100644 --- a/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java +++ b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java @@ -31,8 +31,8 @@ import org.apache.ranger.plugin.model.RangerInlinePolicy; import org.apache.ranger.plugin.service.RangerBasePlugin; import org.apache.ranger.plugin.util.JsonUtilsV2; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import java.net.InetAddress; import java.util.Arrays; @@ -40,13 +40,13 @@ import java.util.HashSet; import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class TestRangerOzoneAuthorizer { private static final String RANGER_SERVICE_TYPE = "ozone"; @@ -69,7 +69,7 @@ public class TestRangerOzoneAuthorizer { private final OzoneGrant grantList = new OzoneGrant(new HashSet<>(Arrays.asList(vol1, buck1)), Collections.singleton(IAccessAuthorizer.ACLType.LIST)); private final OzoneGrant grantRead = new OzoneGrant(Collections.singleton(key1), Collections.singleton(IAccessAuthorizer.ACLType.READ)); - @BeforeClass + @BeforeAll public static void setUpBeforeClass() { RangerPluginConfig pluginConfig = new RangerPluginConfig(RANGER_SERVICE_TYPE, null, RANGER_APP_ID, null, null, null); // loads ranger-ozone-security.xml RangerBasePlugin plugin = new RangerBasePlugin(pluginConfig); @@ -114,16 +114,16 @@ public void testAssumeRoleWithEmptyGrants() throws Exception { RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME, false, sessionPolicy); // user1 doesn't have access without session-policy - assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should not allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should not allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy)); + assertFalse(ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy), "session-policy should not allow list on volume vol1"); + assertFalse(ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy), "session-policy should not allow list on volume vol2"); + assertFalse(ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy), "session-policy should not allow list on bucket vol1/buck1"); + assertFalse(ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy), "session-policy should not allow read on key vol1/buck1/key1"); // user1 should not have access with session-policy as well, due to empty grants - assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); - assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); - assertFalse("session-policy should not allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); - assertFalse("session-policy should not allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy)); + assertFalse(ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy), "session-policy should not allow list on volume vol1"); + assertFalse(ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy), "session-policy should not allow list on volume vol2"); + assertFalse(ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy), "session-policy should not allow list on bucket vol1/buck1"); + assertFalse(ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy), "session-policy should not allow read on key vol1/buck1/key1"); } @Test @@ -150,16 +150,16 @@ public void testAssumeRoleWithNullGrants() throws Exception { RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME, false, sessionPolicy); // user1 doesn't have access without session-policy - assertFalse("session-policy should not allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should not allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy)); - assertFalse("session-policy should not allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy)); + assertFalse(ozoneAuthorizer.checkAccess(vol1, ctxListWithoutSessionPolicy), "session-policy should not allow list on volume vol1"); + assertFalse(ozoneAuthorizer.checkAccess(vol2, ctxListWithoutSessionPolicy), "session-policy should not allow list on volume vol2"); + assertFalse(ozoneAuthorizer.checkAccess(buck1, ctxListWithoutSessionPolicy), "session-policy should not allow list on bucket vol1/buck1"); + assertFalse(ozoneAuthorizer.checkAccess(key1, ctxReadWithoutSessionPolicy), "session-policy should not allow read on key vol1/buck1/key1"); // user1 should have access with session-policy, due to null grants which allows all accesses granted to role1 - assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); - assertTrue("session-policy should allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); - assertTrue("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); - assertTrue("session-policy should allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy)); + assertTrue(ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy), "session-policy should allow list on volume vol1"); + assertTrue(ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy), "session-policy should allow list on volume vol2"); + assertTrue(ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy), "session-policy should allow list on bucket vol1/buck1"); + assertTrue(ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy), "session-policy should allow read on key vol1/buck1/key1"); } @Test @@ -188,9 +188,9 @@ public void testAssumeRoleWithGrants() throws Exception { RequestContext ctxReadWithSessionPolicy = new RequestContext(hostname, ipAddress, user1, OZONE_SERVICE_ID, IAccessAuthorizer.ACLIdentityType.ANONYMOUS, IAccessAuthorizer.ACLType.READ, OWNER_NAME, false, sessionPolicy); // user1 should have access with sessionPolicy - assertTrue("session-policy should allow list on volume vol1", ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy)); - assertFalse("session-policy should not allow list on volume vol2", ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy)); - assertTrue("session-policy should allow list on bucket vol1/buck1", ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy)); - assertTrue("session-policy should allow read on key vol1/buck1/key1", ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy)); + assertTrue(ozoneAuthorizer.checkAccess(vol1, ctxListWithSessionPolicy), "session-policy should allow list on volume vol1"); + assertFalse(ozoneAuthorizer.checkAccess(vol2, ctxListWithSessionPolicy), "session-policy should not allow list on volume vol2"); + assertTrue(ozoneAuthorizer.checkAccess(buck1, ctxListWithSessionPolicy), "session-policy should allow list on bucket vol1/buck1"); + assertTrue(ozoneAuthorizer.checkAccess(key1, ctxReadWithSessionPolicy), "session-policy should allow read on key vol1/buck1/key1"); } }