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..d119745218 100644
--- a/plugin-ozone/pom.xml
+++ b/plugin-ozone/pom.xml
@@ -145,9 +145,21 @@ 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.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..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
@@ -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 ozoneGrants = assumeRoleRequest.getGrants();
+ final List 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 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 0000000000..df3aa65ac5
--- /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 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 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 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 0000000000..e8d761801a
--- /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 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()");