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

madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ranger.git


The following commit(s) were added to refs/heads/master by this push:
     new 3c8e5323c RANGER-5393: updated RangerOzoneAuthorizer to support 
AssumeRole (#766)
3c8e5323c is described below

commit 3c8e5323c0d8a8cb4ece3be486f311f2535dfe1e
Author: Madhan Neethiraj <[email protected]>
AuthorDate: Mon Dec 15 16:25:55 2025 -0800

    RANGER-5393: updated RangerOzoneAuthorizer to support AssumeRole (#766)
---
 .../service-defs/ranger-servicedef-ozone.json      |  27 ++-
 plugin-ozone/pom.xml                               |  18 +-
 .../ozone/authorizer/RangerOzoneAuthorizer.java    | 190 ++++++++++++++++++--
 .../authorizer/TestRangerOzoneAuthorizer.java      | 196 +++++++++++++++++++++
 plugin-ozone/src/test/resources/om_dev_ozone.json  |  46 +++++
 .../src/test/resources/ranger-ozone-security.xml   |  29 +++
 pom.xml                                            |   7 +-
 .../ozone/authorizer/RangerOzoneAuthorizer.java    |  16 ++
 8 files changed, 508 insertions(+), 21 deletions(-)

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 2bff90d47..025e5fa08 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 400924297..d11974521 100644
--- a/plugin-ozone/pom.xml
+++ b/plugin-ozone/pom.xml
@@ -145,9 +145,21 @@ limitations under the License.
             <version>${org.bouncycastle.bcpkix-jdk18on}</version>
         </dependency>
         <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>log4j-over-slf4j</artifactId>
-            <version>${slf4j.version}</version>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit.jupiter.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-inline</artifactId>
+            <version>${mockito.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>${mockito.version}</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
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 c08e9c0f9..4414f22ad 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.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;
@@ -27,31 +31,48 @@
 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.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+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 ACCESS_TYPE_ALL         = "all";
+
+    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 final String S3_VOLUME_NAME = "s3Vol";
 
     private static volatile RangerBasePlugin rangerPlugin;
 
@@ -77,6 +98,11 @@ public RangerOzoneAuthorizer() {
         }
     }
 
+    // for testing only
+    RangerOzoneAuthorizer(RangerBasePlugin plugin) {
+        rangerPlugin = plugin;
+    }
+
     @Override
     public boolean checkAccess(IOzoneObj ozoneObject, RequestContext context) {
         boolean returnValue = false;
@@ -149,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) {
@@ -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,61 @@ 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()) {
+                final Set<OzoneGrant>                ozoneGrants = 
assumeRoleRequest.getGrants();
+                final List<RangerInlinePolicy.Grant> inlineGrants;
+
+                if (ozoneGrants == null) { // allow all permissions
+                    inlineGrants = null;
+                } else if (ozoneGrants.isEmpty()) { // don't allow any 
permission
+                    inlineGrants = Collections.singletonList(new 
RangerInlinePolicy.Grant());
+                } 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());
+                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 +301,82 @@ private String mapToRangerAccessType(ACLType operation) {
 
         return rangerAccessType;
     }
+
+    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.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<String, String> 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 ? 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 ? S3_VOLUME_NAME : 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 ACCESS_TYPE_READ;
+            case WRITE:
+                return ACCESS_TYPE_WRITE;
+            case CREATE:
+                return ACCESS_TYPE_CREATE;
+            case LIST:
+                return ACCESS_TYPE_LIST;
+            case DELETE:
+                return ACCESS_TYPE_DELETE;
+            case READ_ACL:
+                return ACCESS_TYPE_READ_ACL;
+            case WRITE_ACL:
+                return ACCESS_TYPE_WRITE_ACL;
+            case ALL:
+                return ACCESS_TYPE_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 000000000..df3aa65ac
--- /dev/null
+++ 
b/plugin-ozone/src/test/java/org/apache/ranger/authorization/ozone/authorizer/TestRangerOzoneAuthorizer.java
@@ -0,0 +1,196 @@
+/*
+ * 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.service.RangerBasePlugin;
+import org.apache.ranger.plugin.util.JsonUtilsV2;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+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";
+    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();
+    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();
+    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));
+
+    @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);
+
+        // loads policies from om_dev_ozone.json, by 
EmbeddedResourcePolicySource configured in ranger-ozone-security.xml
+        plugin.init();
+
+        ozoneAuthorizer = new RangerOzoneAuthorizer(plugin);
+
+        assertNotNull(ozoneAuthorizer);
+    }
+
+    @Test
+    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);
+
+        assertThrows(OMException.class, () -> 
ozoneAuthorizer.generateAssumeRoleSessionPolicy(request));
+    }
+
+    @Test
+    public void testAssumeRoleWithEmptyGrants() throws Exception {
+        Set<OzoneGrant>   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);
+        assertNotEquals("", sessionPolicy);
+
+        RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, 
RangerInlinePolicy.class);
+
+        assertEquals("r:role1", inlinePolicy.getGrantor());
+        assertEquals("user1", inlinePolicy.getCreatedBy());
+        assertEquals(RangerInlinePolicy.Mode.INLINE, inlinePolicy.getMode());
+        assertNotNull(inlinePolicy.getGrants());
+
+        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(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(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
+    public void testAssumeRoleWithNullGrants() throws Exception {
+        Set<OzoneGrant>   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, 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(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(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
+    public void testAssumeRoleWithGrants() throws Exception {
+        Set<OzoneGrant>   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);
+        assertNotEquals("", sessionPolicy);
+
+        RangerInlinePolicy inlinePolicy = JsonUtilsV2.jsonToObj(sessionPolicy, 
RangerInlinePolicy.class);
+
+        assertEquals("r:role1", inlinePolicy.getGrantor());
+        assertEquals("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, 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(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");
+    }
+}
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 000000000..e8d761801
--- /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": [ "user1" ] }
+      ]
+    },
+    { "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 000000000..05c47ff82
--- /dev/null
+++ b/plugin-ozone/src/test/resources/ranger-ozone-security.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<configuration xmlns:xi="http://www.w3.org/2001/XInclude";>
+    <property>
+        <name>ranger.plugin.ozone.service.name</name>
+        <value>dev_ozone</value>
+    </property>
+
+    <property>
+        <name>ranger.plugin.ozone.policy.source.impl</name>
+        
<value>org.apache.ranger.admin.client.EmbeddedResourcePolicySource</value>
+    </property>
+</configuration>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index d12acce9e..db387ca01 100644
--- a/pom.xml
+++ b/pom.xml
@@ -180,7 +180,7 @@
         <org.bouncycastle.bcpkix-jdk18on>1.79</org.bouncycastle.bcpkix-jdk18on>
         <org.bouncycastle.bcprov-jdk18on>1.79</org.bouncycastle.bcprov-jdk18on>
         
<owasp-java-html-sanitizer.version>20211018.2</owasp-java-html-sanitizer.version>
-        <ozone.version>1.4.0</ozone.version>
+        <ozone.version>2.1.0</ozone.version>
         <paranamer.version>2.3</paranamer.version>
         <poi.version>5.2.2</poi.version>
         <!-- presto plugin deps -->
@@ -793,6 +793,11 @@
             <name>jetbrains-intellij-dependencies</name>
             
<url>https://packages.jetbrains.team/maven/p/ij/intellij-dependencies</url>
         </repository>
+        <repository>
+            <id>ozone-2.1.0-rc</id>
+            <name>ozone-2.1.0-rc</name>
+            
<url>https://repository.apache.org/content/repositories/orgapacheozone-1061</url>
+        </repository>
     </repositories>
     <distributionManagement>
         <repository>
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 0b461d3b0..7658d4aea 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()");
 


Reply via email to