Skip to content

Commit afb8fe9

Browse files
committed
RANGER-4175: REST API to find security-zone for a given resource
1 parent 67db8af commit afb8fe9

File tree

10 files changed

+143
-17
lines changed

10 files changed

+143
-17
lines changed

agents-common/src/main/java/org/apache/ranger/plugin/policyengine/PolicyEngine.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,10 @@ public RangerPolicyRepository getRepositoryForMatchedZone(RangerPolicy policy) {
370370
return ret;
371371
}
372372

373+
public Set<String> getMatchedZonesForResourceAndChildren(Map<String, ?> resource) {
374+
return getMatchedZonesForResourceAndChildren(convertToAccessResource(resource));
375+
}
376+
373377
public Set<String> getMatchedZonesForResourceAndChildren(RangerAccessResource accessResource) {
374378
if (LOG.isDebugEnabled()) {
375379
LOG.debug("==> PolicyEngine.getMatchedZonesForResourceAndChildren(" + accessResource + ")");

intg/src/main/java/org/apache/ranger/RangerClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public class RangerClient {
8282
private static final String URI_ZONE_BY_NAME = URI_ZONE + "/name/%s";
8383
private static final String URI_ZONE_HEADERS = URI_BASE + "/zone-headers";
8484
private static final String URI_ZONE_SERVICE_HEADERS = URI_ZONE + "/%d/service-headers";
85+
private static final String URI_ZONE_NAMES_FOR_RES = URI_BASE + "/zone-names/%s/resource";
8586

8687
private static final String URI_SERVICE_TAGS = URI_SERVICE + "/%s/tags";
8788
private static final String URI_PLUGIN_INFO = URI_BASE + "/plugins/info";
@@ -126,6 +127,7 @@ public class RangerClient {
126127
public static final API GET_ZONE_BY_NAME = new API(URI_ZONE_BY_NAME, HttpMethod.GET, Response.Status.OK);
127128
public static final API GET_ZONE_HEADERS = new API(URI_ZONE_HEADERS, HttpMethod.GET, Response.Status.OK);
128129
public static final API GET_ZONE_SERVICE_HEADERS = new API(URI_ZONE_SERVICE_HEADERS, HttpMethod.GET, Response.Status.OK);
130+
public static final API GET_ZONE_NAMES_FOR_RES = new API(URI_ZONE_NAMES_FOR_RES, HttpMethod.GET, Response.Status.OK);
129131
public static final API FIND_ZONES = new API(URI_ZONE, HttpMethod.GET, Response.Status.OK);
130132

131133
public static final API CREATE_ROLE = new API(URI_ROLE, HttpMethod.POST, Response.Status.OK);
@@ -359,6 +361,10 @@ public List<RangerServiceHeaderInfo> getSecurityZoneServiceHeaders(Map<String, S
359361
return callAPI(GET_ZONE_SERVICE_HEADERS, filter, null, new GenericType<List<RangerServiceHeaderInfo>>(){});
360362
}
361363

364+
public Set<String> getSecurityZoneNamesForResource(String serviceName, Map<String, String> resource) throws RangerServiceException {
365+
return callAPI(GET_ZONE_NAMES_FOR_RES.applyUrlFormat(serviceName), resource, null, new GenericType<Set<String>>(){});
366+
}
367+
362368
public List<RangerSecurityZone> findSecurityZones(Map<String, String> filter) throws RangerServiceException {
363369
return callAPI(FIND_ZONES, filter, null, new GenericType<List<RangerSecurityZone>>(){});
364370
}

intg/src/main/python/apache_ranger/client/ranger_client.py

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ def get_security_zone_service_headers(self, zoneId):
220220

221221
return type_coerce_list(resp, RangerServiceHeaderInfo)
222222

223+
def get_zone_names_for_resource(self, serviceName, resource):
224+
return self.client_http.call_api(RangerClient.GET_ZONE_NAMES_FOR_RESOURCE.format_path({ 'serviceName': serviceName }), query_params=resource_to_query_params(resource))
225+
223226
def find_security_zones(self, filter=None):
224227
resp = self.client_http.call_api(RangerClient.FIND_ZONES, filter)
225228

@@ -325,11 +328,12 @@ def delete_policy_deltas(self, days, reloadServicePoliciesCache):
325328
URI_GRANT_ROLE = URI_ROLE + "/grant/{name}"
326329
URI_REVOKE_ROLE = URI_ROLE + "/revoke/{name}"
327330

328-
URI_ZONE = URI_BASE + "/zones"
329-
URI_ZONE_BY_ID = URI_ZONE + "/{id}"
330-
URI_ZONE_BY_NAME = URI_ZONE + "/name/{name}"
331-
URI_ZONE_HEADERS = URI_BASE + "/zone-headers"
332-
URI_ZONE_SERVICE_HEADERS = URI_ZONE + "/{id}/service-headers"
331+
URI_ZONE = URI_BASE + "/zones"
332+
URI_ZONE_BY_ID = URI_ZONE + "/{id}"
333+
URI_ZONE_BY_NAME = URI_ZONE + "/name/{name}"
334+
URI_ZONE_HEADERS = URI_BASE + "/zone-headers"
335+
URI_ZONE_SERVICE_HEADERS = URI_ZONE + "/{id}/service-headers"
336+
URI_ZONE_NAMES_FOR_RESOURCE = URI_BASE + "/zone-names/{serviceName}/resource"
333337

334338
URI_SERVICE_TAGS = URI_SERVICE + "/{serviceName}/tags"
335339
URI_PLUGIN_INFO = URI_BASE + "/plugins/info"
@@ -365,16 +369,17 @@ def delete_policy_deltas(self, days, reloadServicePoliciesCache):
365369
GET_POLICIES_IN_SERVICE = API(URI_POLICIES_IN_SERVICE, HttpMethod.GET, HTTPStatus.OK)
366370
FIND_POLICIES = API(URI_POLICY, HttpMethod.GET, HTTPStatus.OK)
367371

368-
CREATE_ZONE = API(URI_ZONE, HttpMethod.POST, HTTPStatus.OK)
369-
UPDATE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.PUT, HTTPStatus.OK)
370-
UPDATE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.PUT, HTTPStatus.OK)
371-
DELETE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
372-
DELETE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
373-
GET_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.GET, HTTPStatus.OK)
374-
GET_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.GET, HTTPStatus.OK)
375-
FIND_ZONES = API(URI_ZONE, HttpMethod.GET, HTTPStatus.OK)
376-
GET_ZONE_HEADERS = API(URI_ZONE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
377-
GET_ZONE_SERVICE_HEADERS = API(URI_ZONE_SERVICE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
372+
CREATE_ZONE = API(URI_ZONE, HttpMethod.POST, HTTPStatus.OK)
373+
UPDATE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.PUT, HTTPStatus.OK)
374+
UPDATE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.PUT, HTTPStatus.OK)
375+
DELETE_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
376+
DELETE_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.DELETE, HTTPStatus.NO_CONTENT)
377+
GET_ZONE_BY_ID = API(URI_ZONE_BY_ID, HttpMethod.GET, HTTPStatus.OK)
378+
GET_ZONE_BY_NAME = API(URI_ZONE_BY_NAME, HttpMethod.GET, HTTPStatus.OK)
379+
FIND_ZONES = API(URI_ZONE, HttpMethod.GET, HTTPStatus.OK)
380+
GET_ZONE_HEADERS = API(URI_ZONE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
381+
GET_ZONE_SERVICE_HEADERS = API(URI_ZONE_SERVICE_HEADERS, HttpMethod.GET, HTTPStatus.OK)
382+
GET_ZONE_NAMES_FOR_RESOURCE = API(URI_ZONE_NAMES_FOR_RESOURCE, HttpMethod.GET, HTTPStatus.OK)
378383

379384
CREATE_ROLE = API(URI_ROLE, HttpMethod.POST, HTTPStatus.OK)
380385
UPDATE_ROLE_BY_ID = API(URI_ROLE_BY_ID, HttpMethod.PUT, HTTPStatus.OK)

intg/src/main/python/apache_ranger/utils.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919
import enum
2020

21-
APPLICATION_JSON = 'application/json'
21+
APPLICATION_JSON = 'application/json'
22+
QUERY_PARAM_PREFIX_RESOURCE = 'resource:'
2223

2324

2425
def non_null(obj, defValue):
@@ -62,6 +63,16 @@ def type_coerce_dict_list(obj, objType):
6263

6364
return ret
6465

66+
def resource_to_query_params(resource, query_params=None):
67+
if isinstance(resource, dict):
68+
if query_params is None:
69+
query_params = {}
70+
71+
for key, value in resource.items():
72+
query_params[QUERY_PARAM_PREFIX_RESOURCE + key] = value
73+
74+
return query_params
75+
6576
def type_coerce_list_dict(obj, objType):
6677
if isinstance(obj, list):
6778
return [ type_coerce_dict(entry, objType) for entry in obj ]

intg/src/test/java/org/apache/ranger/TestRangerClient.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
package org.apache.ranger;
2020

2121
import com.sun.jersey.api.client.ClientResponse;
22+
import com.sun.jersey.api.client.GenericType;
23+
import org.apache.ranger.plugin.model.RangerSecurityZone;
2224
import org.apache.ranger.plugin.model.RangerSecurityZoneHeaderInfo;
2325
import org.apache.ranger.plugin.model.RangerService;
2426
import org.apache.ranger.plugin.model.RangerServiceHeaderInfo;
@@ -173,4 +175,32 @@ public void testGetSecurityZoneServiceHeaders() throws RangerServiceException {
173175

174176
Assert.assertEquals(Collections.emptyList(), serviceHeaders);
175177
}
178+
179+
@Test
180+
public void testGetSecurityZoneNamesForResource() throws RangerServiceException {
181+
RangerClient client = Mockito.mock(RangerClient.class);
182+
String serviceName = "dev_hive";
183+
Map<String, String> resource = new HashMap<String, String>() {{
184+
put("database", "testdb");
185+
put("table", "testtbl1");
186+
}};
187+
188+
when(client.getSecurityZoneNamesForResource(serviceName, resource)).thenReturn(Collections.emptySet());
189+
190+
Set<String> zoneNames = client.getSecurityZoneNamesForResource(serviceName, resource);
191+
192+
Assert.assertEquals(Collections.emptySet(), zoneNames);
193+
}
194+
195+
@Test
196+
public void testFindSecurityZones() throws RangerServiceException {
197+
RangerClient client = Mockito.mock(RangerClient.class);
198+
Map<String, String> filter = Collections.emptyMap();
199+
200+
when(client.findSecurityZones(filter)).thenReturn(Collections.emptyList());
201+
202+
List<RangerSecurityZone> securityZones = client.findSecurityZones(filter);
203+
204+
Assert.assertEquals(Collections.emptyList(), securityZones);
205+
}
176206
}

security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdmin.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.apache.ranger.biz;
2121

22+
import java.util.Collection;
2223
import java.util.List;
2324
import java.util.Map;
2425
import java.util.Set;
@@ -57,6 +58,8 @@ public interface RangerPolicyAdmin {
5758

5859
Set<String> getRolesFromUserAndGroups(String user, Set<String> groups);
5960

61+
Collection<String> getZoneNamesForResource(Map<String, ?> resource);
62+
6063
String getUniquelyMatchedZoneName(GrantRevokeRequest grantRevokeRequest);
6164

6265
// This API is used only by test-code

security-admin/src/main/java/org/apache/ranger/biz/RangerPolicyAdminImpl.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,31 @@ public Set<String> getRolesFromUserAndGroups(String user, Set<String> groups) {
521521
return ret;
522522
}
523523

524+
@Override
525+
public Collection<String> getZoneNamesForResource(Map<String, ?> resource) {
526+
if (LOG.isDebugEnabled()) {
527+
LOG.debug("==> RangerPolicyAdminImpl.getSecurityZonesForResource(" + resource + ")");
528+
}
529+
530+
Collection<String> ret = null;
531+
532+
try (RangerReadWriteLock.RangerLock readLock = policyEngine.getReadLock()) {
533+
if (LOG.isDebugEnabled()) {
534+
if (readLock.isLockingEnabled()) {
535+
LOG.debug("Acquired lock - " + readLock);
536+
}
537+
}
538+
539+
ret = policyEngine.getMatchedZonesForResourceAndChildren(resource);
540+
}
541+
542+
if (LOG.isDebugEnabled()) {
543+
LOG.debug("<== RangerPolicyAdminImpl.getSecurityZonesForResource(" + resource + ") : " + ret);
544+
}
545+
546+
return ret;
547+
}
548+
524549
@Override
525550
public String getUniquelyMatchedZoneName(GrantRevokeRequest grantRevokeRequest) {
526551
if (LOG.isDebugEnabled()) {

security-admin/src/main/java/org/apache/ranger/rest/PublicAPIsv2.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import javax.ws.rs.core.Context;
6161

6262
import java.util.ArrayList;
63+
import java.util.Collection;
6364
import java.util.List;
6465

6566
@Path("public/v2")
@@ -205,6 +206,14 @@ public List<RangerServiceHeaderInfo> getServiceHeaderInfoListByZoneId(@PathParam
205206
return ret;
206207
}
207208

209+
@GET
210+
@Path("/api/zone-names/{serviceName}/resource")
211+
@Produces({ "application/json" })
212+
@PreAuthorize("@rangerPreAuthSecurityHandler.isAPISpnegoAccessible()")
213+
public Collection<String> getSecurityZoneNamesForResource(@PathParam("serviceName") String serviceName, @Context HttpServletRequest request) {
214+
return securityZoneRest.getZoneNamesForResource(serviceName, request);
215+
}
216+
208217
/*
209218
* ServiceDef Manipulation APIs
210219
*/

security-admin/src/main/java/org/apache/ranger/rest/SecurityZoneREST.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
package org.apache.ranger.rest;
2121

2222
import java.util.ArrayList;
23+
import java.util.Collection;
24+
import java.util.Collections;
2325
import java.util.HashMap;
2426
import java.util.HashSet;
2527
import java.util.Iterator;
@@ -41,6 +43,7 @@
4143
import javax.ws.rs.WebApplicationException;
4244
import javax.ws.rs.core.Context;
4345

46+
import org.apache.ranger.biz.RangerPolicyAdmin;
4447
import org.apache.ranger.biz.RangerBizUtil;
4548
import org.apache.ranger.biz.SecurityZoneDBStore;
4649
import org.apache.ranger.biz.ServiceDBStore;
@@ -326,6 +329,36 @@ public RangerSecurityZoneList getAllZones(@Context HttpServletRequest request) {
326329
return ret;
327330
}
328331

332+
@GET
333+
@Path("/zone-names/{serviceName}/resource")
334+
@Produces({ "application/json" })
335+
public Collection<String> getZoneNamesForResource(@PathParam("serviceName") String serviceName, @Context HttpServletRequest request) {
336+
if (LOG.isDebugEnabled()) {
337+
LOG.debug("==> SecurityZoneREST.getZoneNamesForResource(" + serviceName + ")");
338+
}
339+
340+
if (!serviceRest.isServiceAdmin(serviceName)) {
341+
throw restErrorUtil.createRESTException(HttpServletResponse.SC_FORBIDDEN,
342+
"User '" + bizUtil.getCurrentUserLoginId() + "' does not have privilege", true);
343+
}
344+
345+
Collection<String> ret = null;
346+
RangerPolicyAdmin policyAdmin = serviceRest.getPolicyAdminForDelegatedAdmin(serviceName);
347+
348+
if (policyAdmin != null) {
349+
SearchFilter filter = searchUtil.getSearchFilter(request, Collections.emptyList());
350+
Map<String, String> resource = filter.getParamsWithPrefix(SearchFilter.RESOURCE_PREFIX, true);
351+
352+
ret = policyAdmin.getZoneNamesForResource(resource);
353+
}
354+
355+
if (LOG.isDebugEnabled()) {
356+
LOG.debug("<== SecurityZoneREST.getZoneNamesForResource(" + serviceName + "): ret=" + ret);
357+
}
358+
359+
return ret;
360+
}
361+
329362
private void ensureAdminAccess(){
330363
if(!bizUtil.isAdmin()){
331364
String userName = bizUtil.getCurrentUserLoginId();

security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4539,7 +4539,7 @@ private String deleteServiceById(Long id) {
45394539
return deletedServiceName;
45404540
}
45414541

4542-
private boolean isServiceAdmin(String serviceName) {
4542+
boolean isServiceAdmin(String serviceName) {
45434543
boolean ret = bizUtil.isAdmin();
45444544

45454545
if (!ret && StringUtils.isNotEmpty(serviceName)) {

0 commit comments

Comments
 (0)