You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2023/05/01 08:00:37 UTC
[ranger] branch ranger-2.4 updated: RANGER-4175: REST API to find security-zone for a given resource
This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch ranger-2.4
in repository https://gitbox.apache.org/repos/asf/ranger.git
The following commit(s) were added to refs/heads/ranger-2.4 by this push:
new d5b67652a RANGER-4175: REST API to find security-zone for a given resource
d5b67652a is described below
commit d5b67652ac014705a784b549d089e0a351dc1b9b
Author: Madhan Neethiraj <ma...@apache.org>
AuthorDate: Wed Apr 5 15:33:57 2023 -0700
RANGER-4175: REST API to find security-zone for a given resource
(cherry picked from commit afb8fe95c28f53cc81631f02f94c200875afee9e)
---
.../ranger/plugin/policyengine/PolicyEngine.java | 4 +++
.../main/java/org/apache/ranger/RangerClient.java | 6 ++++
.../python/apache_ranger/client/ranger_client.py | 35 ++++++++++++----------
intg/src/main/python/apache_ranger/utils.py | 13 +++++++-
.../java/org/apache/ranger/TestRangerClient.java | 30 +++++++++++++++++++
.../org/apache/ranger/biz/RangerPolicyAdmin.java | 3 ++
.../apache/ranger/biz/RangerPolicyAdminImpl.java | 25 ++++++++++++++++
.../java/org/apache/ranger/rest/PublicAPIsv2.java | 9 ++++++
.../org/apache/ranger/rest/SecurityZoneREST.java | 33 ++++++++++++++++++++
.../java/org/apache/ranger/rest/ServiceREST.java | 2 +-
10 files changed, 143 insertions(+), 17 deletions(-)
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
index 3864f30d2..cebdb9cea 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java
@@ -362,6 +362,10 @@ public class PolicyEngine {
return ret;
}
+ public Set<String> getMatchedZonesForResourceAndChildren(Map<String, ?> resource) {
+ return getMatchedZonesForResourceAndChildren(convertToAccessResource(resource));
+ }
+
public Set<String> getMatchedZonesForResourceAndChildren(RangerAccessResource accessResource) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> PolicyEngine.getMatchedZonesForResourceAndChildren(" + accessResource + ")");
diff --git a/intg/src/main/java/org/apache/ranger/RangerClient.java b/intg/src/main/java/org/apache/ranger/RangerClient.java
index 92149c9e0..838dfa52c 100644
--- a/intg/src/main/java/org/apache/ranger/RangerClient.java
+++ b/intg/src/main/java/org/apache/ranger/RangerClient.java
@@ -82,6 +82,7 @@ public class RangerClient {
private static final String URI_ZONE_BY_NAME = URI_ZONE + "/name/%s";
private static final String URI_ZONE_HEADERS = URI_BASE + "/zone-headers";
private static final String URI_ZONE_SERVICE_HEADERS = URI_ZONE + "/%d/service-headers";
+ private static final String URI_ZONE_NAMES_FOR_RES = URI_BASE + "/zone-names/%s/resource";
private static final String URI_SERVICE_TAGS = URI_SERVICE + "/%s/tags";
private static final String URI_PLUGIN_INFO = URI_BASE + "/plugins/info";
@@ -126,6 +127,7 @@ public class RangerClient {
public static final API GET_ZONE_BY_NAME = new API(URI_ZONE_BY_NAME, HttpMethod.GET, Response.Status.OK);
public static final API GET_ZONE_HEADERS = new API(URI_ZONE_HEADERS, HttpMethod.GET, Response.Status.OK);
public static final API GET_ZONE_SERVICE_HEADERS = new API(URI_ZONE_SERVICE_HEADERS, HttpMethod.GET, Response.Status.OK);
+ public static final API GET_ZONE_NAMES_FOR_RES = new API(URI_ZONE_NAMES_FOR_RES, HttpMethod.GET, Response.Status.OK);
public static final API FIND_ZONES = new API(URI_ZONE, HttpMethod.GET, Response.Status.OK);
public static final API CREATE_ROLE = new API(URI_ROLE, HttpMethod.POST, Response.Status.OK);
@@ -359,6 +361,10 @@ public class RangerClient {
return callAPI(GET_ZONE_SERVICE_HEADERS, filter, null, new GenericType<List<RangerServiceHeaderInfo>>(){});
}
+ public Set<String> getSecurityZoneNamesForResource(String serviceName, Map<String, String> resource) throws RangerServiceException {
+ return callAPI(GET_ZONE_NAMES_FOR_RES.applyUrlFormat(serviceName), resource, null, new GenericType<Set<String>>(){});
+ }
+
public List<RangerSecurityZone> findSecurityZones(Map<String, String> filter) throws RangerServiceException {
return callAPI(FIND_ZONES, filter, null, new GenericType<List<RangerSecurityZone>>(){});
}
diff --git a/intg/src/main/python/apache_ranger/client/ranger_client.py b/intg/src/main/python/apache_ranger/client/ranger_client.py
index 4680e2d8e..a544ccc69 100644
--- a/intg/src/main/python/apache_ranger/client/ranger_client.py
+++ b/intg/src/main/python/apache_ranger/client/ranger_client.py
@@ -220,6 +220,9 @@ class RangerClient:
return type_coerce_list(resp, RangerServiceHeaderInfo)
+ def get_zone_names_for_resource(self, serviceName, resource):
+ return self.client_http.call_api(RangerClient.GET_ZONE_NAMES_FOR_RESOURCE.format_path({ 'serviceName': serviceName }), query_params=resource_to_query_params(resource))
+
def find_security_zones(self, filter=None):
resp = self.client_http.call_api(RangerClient.FIND_ZONES, filter)
@@ -325,11 +328,12 @@ class RangerClient:
URI_GRANT_ROLE = URI_ROLE + "/grant/{name}"
URI_REVOKE_ROLE = URI_ROLE + "/revoke/{name}"
- URI_ZONE = URI_BASE + "/zones"
- URI_ZONE_BY_ID = URI_ZONE + "/{id}"
- URI_ZONE_BY_NAME = URI_ZONE + "/name/{name}"
- URI_ZONE_HEADERS = URI_BASE + "/zone-headers"
- URI_ZONE_SERVICE_HEADERS = URI_ZONE + "/{id}/service-headers"
+ URI_ZONE = URI_BASE + "/zones"
+ URI_ZONE_BY_ID = URI_ZONE + "/{id}"
+ URI_ZONE_BY_NAME = URI_ZONE + "/name/{name}"
+ URI_ZONE_HEADERS = URI_BASE + "/zone-headers"
+ URI_ZONE_SERVICE_HEADERS = URI_ZONE + "/{id}/service-headers"
+ URI_ZONE_NAMES_FOR_RESOURCE = URI_BASE + "/zone-names/{serviceName}/resource"
URI_SERVICE_TAGS = URI_SERVICE + "/{serviceName}/tags"
URI_PLUGIN_INFO = URI_BASE + "/plugins/info"
@@ -365,16 +369,17 @@ class RangerClient:
GET_POLICIES_IN_SERVICE = API(URI_POLICIES_IN_SERVICE, HttpMethod.GET, HTTPStatus.OK)
FIND_POLICIES = API(URI_POLICY, HttpMethod.GET, HTTPStatus.OK)
- CREATE_ZONE = API(URI_ZONE, HttpMethod.POST, HTTPStatus.OK)
- UPDATE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.PUT, HTTPStatus.OK)
- UPDATE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.PUT, HTTPStatus.OK)
- DELETE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
- DELETE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
- GET_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.GET, HTTPStatus.OK)
- GET_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.GET, HTTPStatus.OK)
- FIND_ZONES = API(URI_ZONE, HttpMethod.GET, HTTPStatus.OK)
- GET_ZONE_HEADERS = API(URI_ZONE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
- GET_ZONE_SERVICE_HEADERS = API(URI_ZONE_SERVICE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
+ CREATE_ZONE = API(URI_ZONE, HttpMethod.POST, HTTPStatus.OK)
+ UPDATE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.PUT, HTTPStatus.OK)
+ UPDATE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.PUT, HTTPStatus.OK)
+ DELETE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
+ DELETE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
+ GET_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.GET, HTTPStatus.OK)
+ GET_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.GET, HTTPStatus.OK)
+ FIND_ZONES = API(URI_ZONE, HttpMethod.GET, HTTPStatus.OK)
+ GET_ZONE_HEADERS = API(URI_ZONE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
+ GET_ZONE_SERVICE_HEADERS = API(URI_ZONE_SERVICE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
+ GET_ZONE_NAMES_FOR_RESOURCE = API(URI_ZONE_NAMES_FOR_RESOURCE, HttpMethod.GET, HTTPStatus.OK)
CREATE_ROLE = API(URI_ROLE, HttpMethod.POST, HTTPStatus.OK)
UPDATE_ROLE_BY_ID = API(URI_ROLE_BY_ID, HttpMethod.PUT, HTTPStatus.OK)
diff --git a/intg/src/main/python/apache_ranger/utils.py b/intg/src/main/python/apache_ranger/utils.py
index 28e0e4b60..2611a1bf0 100644
--- a/intg/src/main/python/apache_ranger/utils.py
+++ b/intg/src/main/python/apache_ranger/utils.py
@@ -18,7 +18,8 @@
import enum
-APPLICATION_JSON = 'application/json'
+APPLICATION_JSON = 'application/json'
+QUERY_PARAM_PREFIX_RESOURCE = 'resource:'
def non_null(obj, defValue):
@@ -62,6 +63,16 @@ def type_coerce_dict_list(obj, objType):
return ret
+def resource_to_query_params(resource, query_params=None):
+ if isinstance(resource, dict):
+ if query_params is None:
+ query_params = {}
+
+ for key, value in resource.items():
+ query_params[QUERY_PARAM_PREFIX_RESOURCE + key] = value
+
+ return query_params
+
def type_coerce_list_dict(obj, objType):
if isinstance(obj, list):
return [ type_coerce_dict(entry, objType) for entry in obj ]
diff --git a/intg/src/test/java/org/apache/ranger/TestRangerClient.java b/intg/src/test/java/org/apache/ranger/TestRangerClient.java
index 054881f4b..c63b3ab20 100644
--- a/intg/src/test/java/org/apache/ranger/TestRangerClient.java
+++ b/intg/src/test/java/org/apache/ranger/TestRangerClient.java
@@ -19,6 +19,8 @@
package org.apache.ranger;
import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.GenericType;
+import org.apache.ranger.plugin.model.RangerSecurityZone;
import org.apache.ranger.plugin.model.RangerSecurityZoneHeaderInfo;
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.model.RangerServiceHeaderInfo;
@@ -173,4 +175,32 @@ public class TestRangerClient {
Assert.assertEquals(Collections.emptyList(), serviceHeaders);
}
+
+ @Test
+ public void testGetSecurityZoneNamesForResource() throws RangerServiceException {
+ RangerClient client = Mockito.mock(RangerClient.class);
+ String serviceName = "dev_hive";
+ Map<String, String> resource = new HashMap<String, String>() {{
+ put("database", "testdb");
+ put("table", "testtbl1");
+ }};
+
+ when(client.getSecurityZoneNamesForResource(serviceName, resource)).thenReturn(Collections.emptySet());
+
+ Set<String> zoneNames = client.getSecurityZoneNamesForResource(serviceName, resource);
+
+ Assert.assertEquals(Collections.emptySet(), zoneNames);
+ }
+
+ @Test
+ public void testFindSecurityZones() throws RangerServiceException {
+ RangerClient client = Mockito.mock(RangerClient.class);
+ Map<String, String> filter = Collections.emptyMap();
+
+ when(client.findSecurityZones(filter)).thenReturn(Collections.emptyList());
+
+ List<RangerSecurityZone> securityZones = client.findSecurityZones(filter);
+
+ Assert.assertEquals(Collections.emptyList(), securityZones);
+ }
}
\ No newline at end of file
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdmin.java b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdmin.java
index f975287f9..15a1e7118 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdmin.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdmin.java
@@ -19,6 +19,7 @@
package org.apache.ranger.biz;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -57,6 +58,8 @@ public interface RangerPolicyAdmin {
Set<String> getRolesFromUserAndGroups(String user, Set<String> groups);
+ Collection<String> getZoneNamesForResource(Map<String, ?> resource);
+
String getUniquelyMatchedZoneName(GrantRevokeRequest grantRevokeRequest);
// This API is used only by test-code
diff --git a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java
index 97a384f30..6799be200 100644
--- a/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java
+++ b/security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java
@@ -521,6 +521,31 @@ public class RangerPolicyAdminImpl implements RangerPolicyAdmin {
return ret;
}
+ @Override
+ public Collection<String> getZoneNamesForResource(Map<String, ?> resource) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> RangerPolicyAdminImpl.getSecurityZonesForResource(" + resource + ")");
+ }
+
+ Collection<String> ret = null;
+
+ try (RangerReadWriteLock.RangerLock readLock = policyEngine.getReadLock()) {
+ if (LOG.isDebugEnabled()) {
+ if (readLock.isLockingEnabled()) {
+ LOG.debug("Acquired lock - " + readLock);
+ }
+ }
+
+ ret = policyEngine.getMatchedZonesForResourceAndChildren(resource);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== RangerPolicyAdminImpl.getSecurityZonesForResource(" + resource + ") : " + ret);
+ }
+
+ return ret;
+ }
+
@Override
public String getUniquelyMatchedZoneName(GrantRevokeRequest grantRevokeRequest) {
if (LOG.isDebugEnabled()) {
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
index 85cd7dd67..7f00e9dcb 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java
@@ -60,6 +60,7 @@ import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
@Path("public/v2")
@@ -205,6 +206,14 @@ public class PublicAPIsv2 {
return ret;
}
+ @GET
+ @Path("/api/zone-names/{serviceName}/resource")
+ @Produces({ "application/json" })
+ @PreAuthorize("@rangerPreAuthSecurityHandler.isAPISpnegoAccessible()")
+ public Collection<String> getSecurityZoneNamesForResource(@PathParam("serviceName") String serviceName, @Context HttpServletRequest request) {
+ return securityZoneRest.getZoneNamesForResource(serviceName, request);
+ }
+
/*
* ServiceDef Manipulation APIs
*/
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/SecurityZoneREST.java b/security-admin/src/main/java/org/apache/ranger/rest/SecurityZoneREST.java
index e35dc12cc..54c8b22f0 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/SecurityZoneREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/SecurityZoneREST.java
@@ -20,6 +20,8 @@
package org.apache.ranger.rest;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -41,6 +43,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
+import org.apache.ranger.biz.RangerPolicyAdmin;
import org.apache.ranger.biz.RangerBizUtil;
import org.apache.ranger.biz.SecurityZoneDBStore;
import org.apache.ranger.biz.ServiceDBStore;
@@ -326,6 +329,36 @@ public class SecurityZoneREST {
return ret;
}
+ @GET
+ @Path("/zone-names/{serviceName}/resource")
+ @Produces({ "application/json" })
+ public Collection<String> getZoneNamesForResource(@PathParam("serviceName") String serviceName, @Context HttpServletRequest request) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> SecurityZoneREST.getZoneNamesForResource(" + serviceName + ")");
+ }
+
+ if (!serviceRest.isServiceAdmin(serviceName)) {
+ throw restErrorUtil.createRESTException(HttpServletResponse.SC_FORBIDDEN,
+ "User '" + bizUtil.getCurrentUserLoginId() + "' does not have privilege", true);
+ }
+
+ Collection<String> ret = null;
+ RangerPolicyAdmin policyAdmin = serviceRest.getPolicyAdminForDelegatedAdmin(serviceName);
+
+ if (policyAdmin != null) {
+ SearchFilter filter = searchUtil.getSearchFilter(request, Collections.emptyList());
+ Map<String, String> resource = filter.getParamsWithPrefix(SearchFilter.RESOURCE_PREFIX, true);
+
+ ret = policyAdmin.getZoneNamesForResource(resource);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== SecurityZoneREST.getZoneNamesForResource(" + serviceName + "): ret=" + ret);
+ }
+
+ return ret;
+ }
+
private void ensureAdminAccess(){
if(!bizUtil.isAdmin()){
String userName = bizUtil.getCurrentUserLoginId();
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
index e11d8efd8..2b4acbcbf 100644
--- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java
@@ -4534,7 +4534,7 @@ public class ServiceREST {
return deletedServiceName;
}
- private boolean isServiceAdmin(String serviceName) {
+ boolean isServiceAdmin(String serviceName) {
boolean ret = bizUtil.isAdmin();
if (!ret && StringUtils.isNotEmpty(serviceName)) {