From 1171e00097c812bbe2f668cfa081c590e96b4b50 Mon Sep 17 00:00:00 2001 From: "Yi Wang(Data Infrastructure)" Date: Mon, 19 Sep 2016 11:19:48 -0700 Subject: [PATCH] Add REST proxy for Security API from backend to web --- .../controllers/DatasetInfoController.java | 41 +++++++++++++- .../app/models/daos/DatasetInfoDao.java | 28 ++++++---- web/app/controllers/api/v1/Dataset.java | 55 +++++++++++++++++++ web/conf/application.conf | 1 + web/conf/routes | 4 ++ .../common/schemas/AbstractRecord.java | 8 ++- .../DatasetGeographicAffinityRecord.java | 21 ------- .../common/schemas/DatasetLocaleRecord.java | 13 ----- .../schemas/DatasetRetentionRecord.java | 14 ----- .../common/schemas/DatasetSecurityRecord.java | 13 ++++- .../wherehows/common/utils/StringUtil.java | 13 +++++ 11 files changed, 148 insertions(+), 63 deletions(-) diff --git a/backend-service/app/controllers/DatasetInfoController.java b/backend-service/app/controllers/DatasetInfoController.java index d3f9ec6263..a77d2b0065 100644 --- a/backend-service/app/controllers/DatasetInfoController.java +++ b/backend-service/app/controllers/DatasetInfoController.java @@ -13,8 +13,11 @@ */ package controllers; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.Map; @@ -26,6 +29,10 @@ import play.libs.Json; import play.mvc.BodyParser; import play.mvc.Controller; import play.mvc.Result; +import wherehows.common.schemas.DatasetGeographicAffinityRecord; +import wherehows.common.schemas.DatasetRetentionRecord; +import wherehows.common.schemas.DatasetSecurityRecord; +import wherehows.common.utils.StringUtil; public class DatasetInfoController extends Controller { @@ -399,8 +406,10 @@ public class DatasetInfoController extends Controller { try { Map security = DatasetInfoDao.getDatasetSecurityByDatasetId(datasetId); + DatasetSecurityRecord record = convertToDatasetSecurityRecord(security); resultJson.put("return_code", 200); - resultJson.set("dataset_security", Json.toJson(security)); + resultJson.put("datasetId", record.getDatasetId()); + resultJson.set("securitySpec", Json.toJson(record)); } catch (EmptyResultDataAccessException e) { Logger.debug("DataAccessException dataset id: " + datasetId, e); resultJson.put("return_code", 404); @@ -418,8 +427,10 @@ public class DatasetInfoController extends Controller { } try { Map security = DatasetInfoDao.getDatasetSecurityByDatasetUrn(urn); + DatasetSecurityRecord record = convertToDatasetSecurityRecord(security); resultJson.put("return_code", 200); - resultJson.set("dataset_security", Json.toJson(security)); + resultJson.put("datasetId", record.getDatasetId()); + resultJson.set("securitySpec", Json.toJson(record)); } catch (EmptyResultDataAccessException e) { Logger.debug("DataAccessException urn: " + urn, e); resultJson.put("return_code", 404); @@ -434,6 +445,32 @@ public class DatasetInfoController extends Controller { return ok(resultJson); } + private static DatasetSecurityRecord convertToDatasetSecurityRecord(Map map) { + DatasetSecurityRecord record = new DatasetSecurityRecord(); + ObjectMapper om = new ObjectMapper(); + try { + record.setDatasetId(StringUtil.toInt(map.get("dataset_id"))); + record.setDatasetUrn((String) map.get("dataset_urn")); + record.setClassification( + om.readValue((String) map.get("classification"), new TypeReference>() { + })); + record.setRecordOwnerType((String) map.get("record_owner_type")); + record.setRecordOwner(om.readValue((String) map.get("record_owner"), new TypeReference>() { + })); + record.setComplianceType((String) map.get("compliance_type")); + record.setRetentionPolicy( + om.readValue((String) map.get("retention_policy"), new TypeReference() { + })); + record.setGeographicAffinity( + om.readValue((String) map.get("geographic_affinity"), new TypeReference() { + })); + record.setModifiedTime((Long) map.get("modified_time")); + } catch (IOException ex) { + Logger.debug("Can't serialize DB results: security " + map.toString(), ex); + } + return record; + } + @BodyParser.Of(BodyParser.Json.class) public static Result updateDatasetSecurity() { JsonNode root = request().body().asJson(); diff --git a/backend-service/app/models/daos/DatasetInfoDao.java b/backend-service/app/models/daos/DatasetInfoDao.java index c699c11f9a..a97fb87e95 100644 --- a/backend-service/app/models/daos/DatasetInfoDao.java +++ b/backend-service/app/models/daos/DatasetInfoDao.java @@ -512,31 +512,37 @@ public class DatasetInfoDao { public static void updateDatasetSecurity(JsonNode root) throws Exception { - final JsonNode auditHeader = root.path("auditHeader"); final JsonNode urnNode = root.path("urn"); + final JsonNode idNode = root.path("datasetId"); final JsonNode security = root.path("securitySpec"); - if (auditHeader.isMissingNode() || urnNode.isMissingNode() || security.isMissingNode()) { + if ((idNode.isMissingNode() && urnNode.isMissingNode()) || security.isMissingNode()) { throw new IllegalArgumentException( "Dataset security info update fail, " + "Json missing necessary fields: " + root.toString()); } - final String urn = urnNode.asText(); - final Long eventTime = auditHeader.path("time").asLong() / 1000; // millisecond to second - - final Integer datasetId = Integer.valueOf(DatasetDao.getDatasetByUrn(urn).get("id").toString()); + final Integer datasetId; + final String urn; + if (!idNode.isMissingNode()) { + datasetId = idNode.asInt(); + urn = DatasetDao.getDatasetById(datasetId).get("urn").toString(); + } else { + urn = urnNode.asText(); + datasetId = Integer.valueOf(DatasetDao.getDatasetByUrn(urn).get("id").toString()); + } ObjectMapper om = new ObjectMapper(); DatasetSecurityRecord record = om.convertValue(security, DatasetSecurityRecord.class); - record.setDataset(datasetId, urn); - record.setModifiedTime(eventTime); + record.setDatasetId(datasetId); + record.setDatasetUrn(urn); + record.setModifiedTime(System.currentTimeMillis() / 1000); try { - Map result = getDatasetSecurityByDatasetUrn(urn); + Map result = getDatasetSecurityByDatasetId(datasetId); String[] columns = record.getDbColumnNames(); Object[] columnValues = record.getAllValuesToString(); - String[] conditions = {"dataset_urn"}; - Object[] conditionValues = new Object[]{urn}; + String[] conditions = {"dataset_id"}; + Object[] conditionValues = new Object[]{datasetId}; SECURITY_WRITER.update(columns, columnValues, conditions, conditionValues); } catch (EmptyResultDataAccessException ex) { SECURITY_WRITER.append(record); diff --git a/web/app/controllers/api/v1/Dataset.java b/web/app/controllers/api/v1/Dataset.java index b3ad63447a..1777767820 100644 --- a/web/app/controllers/api/v1/Dataset.java +++ b/web/app/controllers/api/v1/Dataset.java @@ -20,8 +20,12 @@ import models.DatasetColumn; import models.DatasetDependency; import models.DatasetListViewNode; import models.ImpactDataset; +import play.Play; import play.api.libs.json.JsValue; +import play.api.mvc.SimpleResult; +import play.libs.F; import play.libs.Json; +import play.libs.WS; import play.mvc.BodyParser; import play.mvc.Controller; import play.mvc.Result; @@ -32,9 +36,15 @@ import dao.DatasetsDAO; import java.util.ArrayList; import java.util.List; import java.util.Map; +import scala.concurrent.Future; + public class Dataset extends Controller { + public static final String BACKEND_SERVICE_URL_KEY = "backend.service.url"; + + public static final String DATASET_SECURITY_PATH = "/dataset/security"; + public static Result getDatasetOwnerTypes() { ObjectNode result = Json.newObject(); @@ -831,4 +841,49 @@ public class Dataset extends Controller return ok(result); } + public static F.Promise getDatasetSecurity(int datasetId) { + final String backendUrl = Play.application().configuration().getString(BACKEND_SERVICE_URL_KEY); + final String queryUrl = backendUrl + DATASET_SECURITY_PATH; + final F.Promise resultPromise = WS.url(queryUrl) + .setQueryParameter("datasetId", Integer.toString(datasetId)) + .get() + .map(new F.Function() { + public Result apply(WS.Response response) { + return ok(response.asJson()); + } + }); + return resultPromise; + } + + public static F.Promise updateDatasetSecurity(int datasetId) { + String username = session("user"); + if (StringUtils.isNotBlank(username)) { + final String backendUrl = Play.application().configuration().getString(BACKEND_SERVICE_URL_KEY); + final String queryUrl = backendUrl + DATASET_SECURITY_PATH; + + final ObjectNode queryNode = Json.newObject(); + queryNode.put("datasetId", datasetId); + queryNode.put("securitySpec", request().body().asJson()); + + final F.Promise resultPromise = WS.url(queryUrl) + .post(queryNode) + .map(new F.Function() { + public Result apply(WS.Response response) { + return ok(response.asJson()); + } + }); + return resultPromise; + } else { + ObjectNode result = Json.newObject(); + result.put("status", "failed"); + result.put("error", "true"); + result.put("msg", "Unauthorized User."); + + return F.Promise.promise(new F.Function0() { + public Result apply() { + return ok(result); + } + }); + } + } } diff --git a/web/conf/application.conf b/web/conf/application.conf index ac228b2052..332281ae5c 100644 --- a/web/conf/application.conf +++ b/web/conf/application.conf @@ -79,6 +79,7 @@ search.engine = "default" elasticsearch.dataset.url = "$YOUR_DATASET_INDEX_URL" elasticsearch.flow.url = "$YOUR_FLOW_INDEX_URL" +backend.service.url = "$YOUR_BACKEND_SERVICE_URL" authentication.ldap.url = "$YOUR_LDAP_SERVER" authentication.ldap.context_factory_class = "com.sun.jndi.ldap.LdapCtxFactory" diff --git a/web/conf/routes b/web/conf/routes index a5ebd26368..3c18c777f3 100644 --- a/web/conf/routes +++ b/web/conf/routes @@ -109,6 +109,10 @@ POST /api/v1/datasets/:id/watch controllers.api.v1.Dataset.w DELETE /api/v1/datasets/:id/watch/:watchId controllers.api.v1.Dataset.unwatchDataset(id:Int, watchId:Int) +GET /api/v1/datasets/:id/security controllers.api.v1.Dataset.getDatasetSecurity(id:Int) + +POST /api/v1/datasets/:id/security controllers.api.v1.Dataset.updateDatasetSecurity(id:Int) + GET /api/v1/urn/watch controllers.api.v1.Dataset.getWatchedUrnId() POST /api/v1/urn/watch controllers.api.v1.Dataset.watchURN() diff --git a/wherehows-common/src/main/java/wherehows/common/schemas/AbstractRecord.java b/wherehows-common/src/main/java/wherehows/common/schemas/AbstractRecord.java index 66cdeb82e2..78ec584c3e 100644 --- a/wherehows-common/src/main/java/wherehows/common/schemas/AbstractRecord.java +++ b/wherehows-common/src/main/java/wherehows/common/schemas/AbstractRecord.java @@ -13,6 +13,7 @@ */ package wherehows.common.schemas; +import com.fasterxml.jackson.annotation.JsonIgnore; import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; @@ -56,6 +57,7 @@ public abstract class AbstractRecord implements Record { * return all declared fields of the class, exclude inherited fields * @return Field[] */ + @JsonIgnore public Field[] getAllFields() { return this.getClass().getDeclaredFields(); } @@ -65,6 +67,7 @@ public abstract class AbstractRecord implements Record { * @return Object[] * @throws IllegalAccessException */ + @JsonIgnore public Object[] getAllValues() throws IllegalAccessException { final Field[] fields = this.getAllFields(); @@ -80,6 +83,7 @@ public abstract class AbstractRecord implements Record { * return the corresponding database column names to the class fields * @return */ + @JsonIgnore public String[] getDbColumnNames() { return null; } @@ -90,11 +94,12 @@ public abstract class AbstractRecord implements Record { * @return Object[] * @throws IllegalAccessException */ + @JsonIgnore public Object[] getAllValuesToString() throws IllegalAccessException { final Object[] values = getAllValues(); for (int i = 0; i < values.length; i++) { - values[i] = StringUtil.objectToString(values[i]); + values[i] = StringUtil.objectToJsonString(values[i]); } return values; } @@ -105,6 +110,7 @@ public abstract class AbstractRecord implements Record { * @return Map: String-Object * @throws IllegalAccessException */ + @JsonIgnore public Map getFieldValueMap() throws IllegalAccessException { String[] columns = this.getDbColumnNames(); diff --git a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetGeographicAffinityRecord.java b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetGeographicAffinityRecord.java index d2a0e0f498..e7ac247084 100644 --- a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetGeographicAffinityRecord.java +++ b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetGeographicAffinityRecord.java @@ -13,11 +13,7 @@ */ package wherehows.common.schemas; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class DatasetGeographicAffinityRecord extends AbstractRecord { @@ -25,11 +21,6 @@ public class DatasetGeographicAffinityRecord extends AbstractRecord { String affinity; List locations; - @Override - public String[] getDbColumnNames() { - return new String[]{"affinity", "locations"}; - } - @Override public List fillAllFields() { return null; @@ -38,18 +29,6 @@ public class DatasetGeographicAffinityRecord extends AbstractRecord { public DatasetGeographicAffinityRecord() { } - @Override - public String toString() { - try { - Map valueMap = new HashMap<>(); - valueMap.put("affinity", affinity); - valueMap.put("locations", locations.toString()); - return new ObjectMapper().writeValueAsString(valueMap); - } catch (JsonProcessingException ex) { - return null; - } - } - public String getAffinity() { return affinity; } diff --git a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetLocaleRecord.java b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetLocaleRecord.java index e7c03a7b54..14e07033eb 100644 --- a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetLocaleRecord.java +++ b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetLocaleRecord.java @@ -13,10 +13,6 @@ */ package wherehows.common.schemas; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; - - public class DatasetLocaleRecord { String language; @@ -26,15 +22,6 @@ public class DatasetLocaleRecord { public DatasetLocaleRecord() { } - @Override - public String toString() { - try { - return new ObjectMapper().writeValueAsString(this); - } catch (JsonProcessingException ex) { - return null; - } - } - public String getLanguage() { return language; } diff --git a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetRetentionRecord.java b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetRetentionRecord.java index c0f490d7cc..43c7403c18 100644 --- a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetRetentionRecord.java +++ b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetRetentionRecord.java @@ -22,11 +22,6 @@ public class DatasetRetentionRecord extends AbstractRecord { Long retentionWindow; String retentionWindowUnit; - @Override - public String[] getDbColumnNames() { - return new String[]{"retention_type", "retention_window", "retention_window_unit"}; - } - @Override public List fillAllFields() { return null; @@ -35,15 +30,6 @@ public class DatasetRetentionRecord extends AbstractRecord { public DatasetRetentionRecord() { } - @Override - public String toString() { - try { - return this.getFieldValueMap().toString(); - } catch (IllegalAccessException ex) { - return null; - } - } - public String getRetentionType() { return retentionType; } diff --git a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetSecurityRecord.java b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetSecurityRecord.java index dcb689a72e..b70160f010 100644 --- a/wherehows-common/src/main/java/wherehows/common/schemas/DatasetSecurityRecord.java +++ b/wherehows-common/src/main/java/wherehows/common/schemas/DatasetSecurityRecord.java @@ -43,8 +43,19 @@ public class DatasetSecurityRecord extends AbstractRecord { public DatasetSecurityRecord() { } - public void setDataset(Integer datasetId, String datasetUrn) { + public Integer getDatasetId() { + return datasetId; + } + + public void setDatasetId(Integer datasetId) { this.datasetId = datasetId; + } + + public String getDatasetUrn() { + return datasetUrn; + } + + public void setDatasetUrn(String datasetUrn) { this.datasetUrn = datasetUrn; } diff --git a/wherehows-common/src/main/java/wherehows/common/utils/StringUtil.java b/wherehows-common/src/main/java/wherehows/common/utils/StringUtil.java index 1bbe93e0b4..b17caa54ae 100644 --- a/wherehows-common/src/main/java/wherehows/common/utils/StringUtil.java +++ b/wherehows-common/src/main/java/wherehows/common/utils/StringUtil.java @@ -13,6 +13,8 @@ */ package wherehows.common.utils; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Arrays; import java.util.Collection; import java.util.Map; @@ -57,6 +59,17 @@ public class StringUtil { return obj; } + public static Object objectToJsonString(Object obj) { + if (obj instanceof Collection || obj instanceof Map || obj instanceof Object[] || obj instanceof Record) { + try { + return new ObjectMapper().writeValueAsString(obj); + } catch (JsonProcessingException ex) { + return obj; + } + } + return obj; + } + public static String toStr(Object obj) { return obj != null ? obj.toString() : null; }