From 50c5c2d1cfd1ee6cb72feda95344e49bbb5642d5 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Wed, 10 Apr 2019 10:55:13 -0400 Subject: [PATCH] expose contacts via API, warn about email privacy #5724 --- doc/sphinx-guides/source/api/native-api.rst | 6 ++- .../source/installation/config.rst | 9 +++- .../iq/dataverse/util/json/JsonPrinter.java | 13 +++--- .../iq/dataverse/api/DataversesIT.java | 44 +++++++++++++++++-- 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/doc/sphinx-guides/source/api/native-api.rst b/doc/sphinx-guides/source/api/native-api.rst index 87d8d8fee88..28d408eb7cd 100644 --- a/doc/sphinx-guides/source/api/native-api.rst +++ b/doc/sphinx-guides/source/api/native-api.rst @@ -39,12 +39,14 @@ Download the :download:`JSON example <../_static/api/dataverse-complete.json>` f .. literalinclude:: ../_static/api/dataverse-complete.json +.. _view-dataverse: + View a Dataverse ~~~~~~~~~~~~~~~~ -|CORS| View data about the dataverse identified by ``$id``. ``$id`` can be the id number of the dataverse, its alias, or the special value ``:root``. :: +|CORS| View data about the dataverse identified by ``$id``. ``$id`` can be the id number of the dataverse, its identifier (a.k.a. alias), or the special value ``:root`` for the root dataverse. - GET http://$SERVER/api/dataverses/$id +``curl $SERVER_URL/api/dataverses/$id`` Delete a Dataverse ~~~~~~~~~~~~~~~~~~ diff --git a/doc/sphinx-guides/source/installation/config.rst b/doc/sphinx-guides/source/installation/config.rst index e9fb9ce4ec0..7476ddba974 100644 --- a/doc/sphinx-guides/source/installation/config.rst +++ b/doc/sphinx-guides/source/installation/config.rst @@ -33,10 +33,15 @@ Forcing HTTPS To avoid having your users send credentials in the clear, it's strongly recommended to force all web traffic to go through HTTPS (port 443) rather than HTTP (port 80). The ease with which one can install a valid SSL cert into Apache compared with the same operation in Glassfish might be a compelling enough reason to front Glassfish with Apache. In addition, Apache can be configured to rewrite HTTP to HTTPS with rules such as those found at https://wiki.apache.org/httpd/RewriteHTTPToHTTPS or in the section on :doc:`shibboleth`. +.. _PrivacyConsiderations: + Privacy Considerations ++++++++++++++++++++++ -Out of the box, Dataverse will list email addresses of the "contacts" for datasets when users visit a dataset page and click the "Export Metadata" button. If you prefer to exclude email addresses of dataset contacts from metadata export, set :ref:`:ExcludeEmailFromExport <:ExcludeEmailFromExport>` to true. +Email Privacy +^^^^^^^^^^^^^ + +Out of the box, Dataverse will list email addresses of the contacts for datasets when users visit a dataset page and click the "Export Metadata" button. Additionally, out of the box, Dataverse will list email addresses of dataverse contacts via API (see :ref:`View a Dataverse ` in the :doc:`/api/native-api` section of the API Guide). If you would like to exclude these email addresses from export, set :ref:`:ExcludeEmailFromExport <:ExcludeEmailFromExport>` to true. Additional Recommendations ++++++++++++++++++++++++++ @@ -1150,6 +1155,8 @@ API users can retrieve this URL from the SWORD Service Document or the "info" se :ExcludeEmailFromExport +++++++++++++++++++++++ +See also :ref:`Privacy Considerations ` above. + Set ``:ExcludeEmailFromExport`` to prevent email addresses for contacts from being exposed in XML or JSON representations of dataset and dataverse metadata. For a list exported formats such as DDI, see the :doc:`/admin/metadataexport` section of the Admin Guide. ``curl -X PUT -d true http://localhost:8080/api/admin/settings/:ExcludeEmailFromExport`` diff --git a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java index e432f0586ca..a5f2f2ea4bf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java +++ b/src/main/java/edu/harvard/iq/dataverse/util/json/JsonPrinter.java @@ -263,11 +263,14 @@ public static JsonObjectBuilder json(Dataverse dv, Boolean hideEmail) { } public static JsonArrayBuilder json(List dataverseContacts) { - return dataverseContacts.stream() - .map(dc -> jsonObjectBuilder() - .add("displayOrder", dc.getDisplayOrder()) - .add("contactEmail", dc.getContactEmail()) - ).collect(toJsonArray()); + JsonArrayBuilder jsonArrayOfContacts = Json.createArrayBuilder(); + for (DataverseContact dataverseContact : dataverseContacts) { + NullSafeJsonBuilder contactJsonObject = NullSafeJsonBuilder.jsonObjectBuilder(); + contactJsonObject.add("displayOrder", dataverseContact.getDisplayOrder()); + contactJsonObject.add("contactEmail", dataverseContact.getContactEmail()); + jsonArrayOfContacts.add(contactJsonObject); + } + return jsonArrayOfContacts; } public static JsonObjectBuilder json( DataverseTheme theme ) { diff --git a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java index 28f5b2c952a..89b4eae4592 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/DataversesIT.java @@ -14,6 +14,7 @@ import java.util.logging.Logger; import javax.json.Json; import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; import static javax.ws.rs.core.Response.Status.CREATED; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import javax.ws.rs.core.Response.Status; @@ -163,16 +164,44 @@ public void testReturnEmail() throws FileNotFoundException { createUser.prettyPrint(); String username = UtilIT.getUsernameFromResponse(createUser); String apiToken = UtilIT.getApiTokenFromResponse(createUser); - - Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); + String dataverseAlias = UtilIT.getRandomDvAlias(); + String emailAddressOfFirstDataverseContact = dataverseAlias + "@mailinator.com"; + JsonObjectBuilder jsonToCreateDataverse = Json.createObjectBuilder() + .add("name", dataverseAlias) + .add("alias", dataverseAlias) + .add("dataverseContacts", Json.createArrayBuilder() + .add(Json.createObjectBuilder() + .add("contactEmail", emailAddressOfFirstDataverseContact) + ) + ); + ; + + Response createDataverseResponse = UtilIT.createDataverse(jsonToCreateDataverse.build(), apiToken); createDataverseResponse.prettyPrint(); createDataverseResponse.then().assertThat().statusCode(CREATED.getStatusCode()); - String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + + createDataverseResponse.then().assertThat() + .statusCode(CREATED.getStatusCode()) + .body("data.alias", equalTo(dataverseAlias)) + .body("data.name", equalTo(dataverseAlias)) + .body("data.dataverseContacts[0].displayOrder", equalTo(0)) + .body("data.dataverseContacts[0].contactEmail", equalTo(emailAddressOfFirstDataverseContact)) + .body("data.permissionRoot", equalTo(true)) + .body("data.dataverseType", equalTo("UNCATEGORIZED")); Response exportDataverseAsJson = UtilIT.exportDataverse(dataverseAlias, apiToken); exportDataverseAsJson.prettyPrint(); exportDataverseAsJson.then().assertThat() .statusCode(OK.getStatusCode()); + + exportDataverseAsJson.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.alias", equalTo(dataverseAlias)) + .body("data.name", equalTo(dataverseAlias)) + .body("data.dataverseContacts", equalTo(null)) + .body("data.permissionRoot", equalTo(true)) + .body("data.dataverseType", equalTo("UNCATEGORIZED")); + RestAssured.unregisterParser("text/plain"); List dataverseEmailNotAllowed = with(exportDataverseAsJson.body().asString()) @@ -187,6 +216,15 @@ public void testReturnEmail() throws FileNotFoundException { exportDataverseAsJson2.prettyPrint(); exportDataverseAsJson2.then().assertThat() .statusCode(OK.getStatusCode()); + exportDataverseAsJson2.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.alias", equalTo(dataverseAlias)) + .body("data.name", equalTo(dataverseAlias)) + .body("data.dataverseContacts[0].displayOrder", equalTo(0)) + .body("data.dataverseContacts[0].contactEmail", equalTo(emailAddressOfFirstDataverseContact)) + .body("data.permissionRoot", equalTo(true)) + .body("data.dataverseType", equalTo("UNCATEGORIZED")); + RestAssured.unregisterParser("text/plain"); List dataverseEmailAllowed = with(exportDataverseAsJson2.body().asString()) .getJsonObject("data.dataverseContacts");