RANGER-4448: updated GDS CRUD APIs to return appropriate status code on failure
Signed-off-by: Madhan Neethiraj <madhan@apache.org>
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
index 03de8e0..38b302e 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
@@ -163,7 +163,7 @@
GDS_VALIDATION_ERR_INVALID_STATUS_CHANGE(4125, "invalid status change from [{0}] to [{1}]"),
GDS_VALIDATION_ERR_UPDATE_IMMUTABLE_FIELD(4126, "[{0}] can't be updated"),
GDS_VALIDATION_ERR_DATASET_IN_PROJECT_ID_NOT_FOUND(4127, "Dataset-in-project with ID [{0}] does not exist"),
-
+ GDS_VALIDATION_ERR_SHARED_RESOURCE_CONFLICT(4128, "Shared resource with resources [{0}] already exists for data share [{1}]"),
;
diff --git a/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java b/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java
index 4aaf364..ed3ed5e 100644
--- a/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java
@@ -22,6 +22,7 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -130,7 +131,25 @@
return restException;
}
-
+ public WebApplicationException create403RESTException(VXResponse gjResponse) {
+ gjResponse.setStatusCode(VXResponse.STATUS_ERROR);
+ gjResponse.setMessageList(Collections.singletonList(MessageEnums.OPER_NO_PERMISSION.getMessage()));
+
+ Response errorResponse = Response.status(javax.servlet.http.HttpServletResponse.SC_FORBIDDEN).entity(gjResponse).build();
+ WebApplicationException restException = new WebApplicationException(errorResponse);
+
+ restException.fillInStackTrace();
+
+ if (logger.isInfoEnabled()) {
+ UserSessionBase userSession = ContextUtil.getCurrentUserSession();
+ String loginId = (userSession != null) ? userSession.getLoginId() : null;
+
+ logger.info("Request failed. loginId=" + loginId + ", logMessage=" + gjResponse.getMsgDesc(), restException);
+ }
+
+ return restException;
+ }
+
public WebApplicationException createGrantRevokeRESTException(String logMessage) {
RESTResponse resp = new RESTResponse();
resp.setMsgDesc(logMessage);
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java
index d3bd4d6..c7acd81 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java
@@ -130,4 +130,21 @@
return ret;
}
+
+ public Long getIdByDataShareIdAndResourceSignature(Long dataShareId, String resourceSignature) {
+ Long ret = null;
+
+ if (dataShareId != null && resourceSignature != null) {
+ try {
+ ret = getEntityManager()
+ .createNamedQuery("XXGdsSharedResource.getIdByDataShareIdAndResourceSignature", Long.class)
+ .setParameter("dataShareId", dataShareId).setParameter("resourceSignature", resourceSignature)
+ .getSingleResult();
+ } catch (NoResultException e) {
+ LOG.debug("getIdByDataShareIdAndName({}, {}): ", dataShareId, resourceSignature, e);
+ }
+ }
+
+ return ret;
+ }
}
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java b/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java
index eadcf07..b1a0053 100755
--- a/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java
@@ -222,6 +222,7 @@
@DELETE
@Path("/dataset/{id}")
+ @Produces({ "application/json" })
@PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.DELETE_DATASET + "\")")
public void deleteDataset(@PathParam("id") Long datasetId, @Context HttpServletRequest request) {
LOG.debug("==> deleteDataset({})", datasetId);
@@ -580,6 +581,7 @@
@DELETE
@Path("/project/{id}")
+ @Produces({ "application/json" })
@PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.DELETE_PROJECT + "\")")
public void deleteProject(@PathParam("id") Long projectId, @Context HttpServletRequest request) {
LOG.debug("==> deleteProject({})", projectId);
@@ -904,6 +906,7 @@
@DELETE
@Path("/datashare/{id}")
+ @Produces({ "application/json" })
@PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.DELETE_DATA_SHARE + "\")")
public void deleteDataShare(@PathParam("id") Long dataShareId, @Context HttpServletRequest request) {
LOG.debug("==> GdsREST.deleteDataShare({})", dataShareId);
@@ -1094,6 +1097,7 @@
@DELETE
@Path("/resource/{id}")
+ @Produces({ "application/json" })
@PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.REMOVE_SHARED_RESOURCE + "\")")
public void removeSharedResource(@PathParam("id") Long resourceId) {
LOG.debug("==> GdsREST.removeSharedResource({})", resourceId);
diff --git a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java
index da41daa..30d2317 100644
--- a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java
+++ b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java
@@ -27,6 +27,7 @@
import org.apache.ranger.plugin.model.RangerGds.RangerDataShare;
import org.apache.ranger.plugin.model.RangerGds.RangerDataset;
import org.apache.ranger.plugin.model.RangerGds.RangerProject;
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.plugin.util.RangerRoles;
import org.apache.ranger.plugin.util.RangerRolesUtil;
@@ -231,6 +232,11 @@
return ret;
}
+ public Long getSharedResourceId(Long dataShareId, RangerPolicyResourceSignature signature) {
+ Long ret = daoMgr.getXXGdsSharedResource().getIdByDataShareIdAndResourceSignature(dataShareId, signature.getSignature());
+
+ return ret;
+ }
private RangerRolesUtil initGetRolesUtil() {
RangerRolesUtil ret = this.rolesUtil;
diff --git a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java
index ab74e90..2c8721e 100644
--- a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java
+++ b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java
@@ -18,6 +18,7 @@
package org.apache.ranger.validation;
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
import org.apache.ranger.plugin.model.RangerGds.RangerDataShare;
import org.apache.ranger.plugin.model.RangerGds.RangerDataset;
import org.apache.ranger.plugin.model.RangerGds.RangerProject;
@@ -67,4 +68,6 @@
public abstract RangerDataShare getDataShare(Long id);
public abstract Long getSharedResourceId(Long dataShareId, String name);
+
+ public abstract Long getSharedResourceId(Long dataShareId, RangerPolicyResourceSignature signature);
}
diff --git a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java
index c5a3f38..27e7cc1 100755
--- a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java
+++ b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java
@@ -36,7 +36,9 @@
import org.apache.ranger.plugin.model.RangerGds.RangerSharedResource;
import org.apache.ranger.plugin.model.RangerGds.RangerTagDataMaskInfo;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo;
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
import org.apache.ranger.plugin.model.validation.ValidationFailureDetails;
+import org.apache.ranger.view.VXResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -87,6 +89,16 @@
} else {
validateDatasetAdmin(existing, result);
validateAcl(dataset.getAcl(), "acl", result);
+
+ boolean renamed = !StringUtils.equalsIgnoreCase(dataset.getName(), existing.getName());
+
+ if (renamed) {
+ Long existingDatasetNameId = dataProvider.getDatasetId(dataset.getName());
+
+ if (existingDatasetNameId != null) {
+ result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_DATASET_NAME_CONFLICT, "name", dataset.getName(), existingDatasetNameId));
+ }
+ }
}
if (!result.isSuccess()) {
@@ -143,6 +155,16 @@
} else {
validateProjectAdmin(existing, result);
validateAcl(project.getAcl(), "acl", result);
+
+ boolean renamed = !StringUtils.equalsIgnoreCase(project.getName(), existing.getName());
+
+ if (renamed) {
+ Long existingProjectNameId = dataProvider.getProjectId(project.getName());
+
+ if (existingProjectNameId != null) {
+ result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_PROJECT_NAME_CONFLICT, "name", project.getName(), existingProjectNameId));
+ }
+ }
}
if (!result.isSuccess()) {
@@ -205,6 +227,16 @@
validateAcl(dataShare.getAcl(), "acl", result);
validateAccessTypes(dataShare.getService(), "defaultAccessTypes", dataShare.getDefaultAccessTypes(), result);
validateMaskTypes(dataShare.getService(), "defaultTagMasks", dataShare.getDefaultTagMasks(), result);
+
+ boolean renamed = !StringUtils.equalsIgnoreCase(dataShare.getName(), existing.getName());
+
+ if (renamed) {
+ Long existingDataShareNameId = dataProvider.getDataShareId(dataShare.getName());
+
+ if (existingDataShareNameId != null) {
+ result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_DATA_SHARE_NAME_CONFLICT, "name", dataShare.getName(), existingDataShareNameId));
+ }
+ }
}
if (!result.isSuccess()) {
@@ -246,7 +278,15 @@
if (existing != null) {
result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_NAME_CONFLICT, "name", resource.getName(), dataShare.getName(), existing));
} else {
- validateSharedResourceCreateAndUpdate(dataShare, result);
+ validateSharedResourceCreateAndUpdate(dataShare, result);
+
+ if (result.isSuccess()) {
+ existing = dataProvider.getSharedResourceId(resource.getDataShareId(), new RangerPolicyResourceSignature(resource));
+
+ if (existing != null) {
+ result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_CONFLICT, "resource", resource.getResource(), dataShare.getName()));
+ }
+ }
}
}
@@ -270,7 +310,27 @@
if (dataShare == null) {
result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_DATA_SHARE_ID_NOT_FOUND, "dataShareId", resource.getDataShareId()));
} else {
- validateSharedResourceCreateAndUpdate(dataShare, result);
+ validateSharedResourceCreateAndUpdate(dataShare, result);
+
+ if (result.isSuccess()) {
+ boolean renamed = !StringUtils.equalsIgnoreCase(resource.getName(), existing.getName());
+
+ if (renamed) {
+ Long existingSharedResourceNameId = dataProvider.getSharedResourceId(resource.getDataShareId(), resource.getName());
+
+ if (existingSharedResourceNameId != null) {
+ result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_NAME_CONFLICT, "name", resource.getName(), dataShare.getName(), existing));
+ }
+ }
+
+ if (result.isSuccess()) {
+ Long existingSharedResourceNameId = dataProvider.getSharedResourceId(resource.getDataShareId(),new RangerPolicyResourceSignature(resource));
+
+ if (existingSharedResourceNameId != null && !existingSharedResourceNameId.equals(existing.getId())) {
+ result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_CONFLICT, "resource", resource.getResource(), dataShare.getName()));
+ }
+ }
+ }
}
}
@@ -1031,5 +1091,13 @@
public void throwRESTException() {
throw restErrorUtil.createRESTException(validationFailures.toString(), MessageEnums.INVALID_INPUT_DATA);
}
+
+ public void throwREST403Exception() {
+ VXResponse gjResponse = new VXResponse();
+
+ gjResponse.setMsgDesc(validationFailures.toString());
+
+ throw restErrorUtil.create403RESTException(gjResponse);
+ }
}
}
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index 0502512..ae6788b 100755
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -2260,6 +2260,13 @@
</query>
</named-query>
+ <named-query name="XXGdsSharedResource.getIdByDataShareIdAndResourceSignature">
+ <query>select obj.id from XXGdsSharedResource obj
+ where obj.dataShareId = :dataShareId
+ and obj.resourceSignature = :resourceSignature
+ </query>
+ </named-query>
+
<named-query name="XXGdsDataShareInDataset.findByGuid">
<query>select obj from XXGdsDataShareInDataset obj where obj.guid = :guid</query>
</named-query>