From 6cae3ecb6ab14495690a6460382908f8848d42dc Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Mon, 9 Dec 2024 15:22:22 -0500 Subject: [PATCH 1/5] add new apis for marketplace external tool registration --- .../10930-marketplace-external-tools-apis.md | 14 +++ .../source/admin/external-tools.rst | 14 ++- .../iq/dataverse/api/ExternalToolsApi.java | 62 +++++++++++++ .../iq/dataverse/api/ExternalToolsIT.java | 89 ++++++++++++++++++- .../edu/harvard/iq/dataverse/api/UtilIT.java | 36 ++++++++ 5 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 doc/release-notes/10930-marketplace-external-tools-apis.md create mode 100644 src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java diff --git a/doc/release-notes/10930-marketplace-external-tools-apis.md b/doc/release-notes/10930-marketplace-external-tools-apis.md new file mode 100644 index 00000000000..9e20c908823 --- /dev/null +++ b/doc/release-notes/10930-marketplace-external-tools-apis.md @@ -0,0 +1,14 @@ +## New APIs for External Tools Registration for Marketplace + +New API base path /api/externalTools created that mimics the admin APIs /api/admin/externalTools. These new apis require an authenticated superuser token. + +Example: +``` + API_TOKEN='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' + export TOOL_ID=1 + + curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools + curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID + curl -s -H "X-Dataverse-key:$API_TOKEN" -X POST -H 'Content-type: application/json' http://localhost:8080/api/externalTools --upload-file fabulousFileTool.json + curl -s -H "X-Dataverse-key:$API_TOKEN" -X DELETE http://localhost:8080/api/externalTools/$TOOL_ID +``` diff --git a/doc/sphinx-guides/source/admin/external-tools.rst b/doc/sphinx-guides/source/admin/external-tools.rst index 346ca0b15ee..50c2ec63c44 100644 --- a/doc/sphinx-guides/source/admin/external-tools.rst +++ b/doc/sphinx-guides/source/admin/external-tools.rst @@ -35,7 +35,10 @@ Configure the tool with the curl command below, making sure to replace the ``fab .. code-block:: bash - curl -X POST -H 'Content-type: application/json' http://localhost:8080/api/admin/externalTools --upload-file fabulousFileTool.json + curl -X POST -H 'Content-type: application/json' http://localhost:8080/api/admin/externalTools --upload-file fabulousFileTool.json + + This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + curl -s -H "X-Dataverse-key:$API_TOKEN" -X POST -H 'Content-type: application/json' http://localhost:8080/api/externalTools --upload-file fabulousFileTool.json Listing All External Tools in a Dataverse Installation ++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -46,6 +49,9 @@ To list all the external tools that are available in a Dataverse installation: curl http://localhost:8080/api/admin/externalTools + This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools + Showing an External Tool in a Dataverse Installation ++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -56,6 +62,9 @@ To show one of the external tools that are available in a Dataverse installation export TOOL_ID=1 curl http://localhost:8080/api/admin/externalTools/$TOOL_ID + This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID + Removing an External Tool From a Dataverse Installation +++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -66,6 +75,9 @@ Assuming the external tool database id is "1", remove it with the following comm export TOOL_ID=1 curl -X DELETE http://localhost:8080/api/admin/externalTools/$TOOL_ID + This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + curl -s -H "X-Dataverse-key:$API_TOKEN" -X DELETE http://localhost:8080/api/externalTools/$TOOL_ID + .. _testing-external-tools: Testing External Tools diff --git a/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java b/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java new file mode 100644 index 00000000000..bf5634e09a8 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java @@ -0,0 +1,62 @@ +package edu.harvard.iq.dataverse.api; + +import edu.harvard.iq.dataverse.api.auth.AuthRequired; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import jakarta.inject.Inject; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; + +@Path("externalTools") +public class ExternalToolsApi extends AbstractApiBean { + + @Inject + ExternalTools externalTools; + + @GET + @AuthRequired + public Response getExternalTools(@Context ContainerRequestContext crc) { + Response notAuthorized = authorize(crc); + return notAuthorized == null ? externalTools.getExternalTools() : notAuthorized; + } + + @GET + @AuthRequired + @Path("{id}") + public Response getExternalTool(@Context ContainerRequestContext crc, @PathParam("id") long externalToolIdFromUser) { + Response notAuthorized = authorize(crc); + return notAuthorized == null ? externalTools.getExternalTool(externalToolIdFromUser) : notAuthorized; + } + + @POST + @AuthRequired + public Response addExternalTool(@Context ContainerRequestContext crc, String manifest) { + Response notAuthorized = authorize(crc); + return notAuthorized == null ? externalTools.addExternalTool(manifest) : notAuthorized; + } + + @DELETE + @AuthRequired + @Path("{id}") + public Response deleteExternalTool(@Context ContainerRequestContext crc, @PathParam("id") long externalToolIdFromUser) { + Response notAuthorized = authorize(crc); + return notAuthorized == null ? externalTools.deleteExternalTool(externalToolIdFromUser) : notAuthorized; + } + + private Response authorize(ContainerRequestContext crc) { + try { + AuthenticatedUser user = getRequestAuthenticatedUserOrDie(crc); + if (!user.isSuperuser()) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + } catch (WrappedResponse ex) { + return error(Response.Status.FORBIDDEN, "Superusers only."); + } + return null; + } +} diff --git a/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java index 22abf6fa2e3..a3e2cca329d 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java @@ -11,11 +11,11 @@ import java.nio.file.Paths; import jakarta.json.Json; import jakarta.json.JsonArray; -import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; import jakarta.json.JsonReader; import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST; import static jakarta.ws.rs.core.Response.Status.CREATED; +import static jakarta.ws.rs.core.Response.Status.FORBIDDEN; import static jakarta.ws.rs.core.Response.Status.OK; import org.hamcrest.CoreMatchers; import org.hamcrest.Matchers; @@ -37,6 +37,93 @@ public void testGetExternalTools() { getExternalTools.prettyPrint(); } + @Test + public void testExternalToolsNonAdminEndpoint() { + Response createUser = UtilIT.createRandomUser(); + createUser.prettyPrint(); + createUser.then().assertThat() + .statusCode(OK.getStatusCode()); + String username = UtilIT.getUsernameFromResponse(createUser); + String apiToken = UtilIT.getApiTokenFromResponse(createUser); + UtilIT.setSuperuserStatus(username, true); + + Response createDataverseResponse = UtilIT.createRandomDataverse(apiToken); + createDataverseResponse.prettyPrint(); + createDataverseResponse.then().assertThat() + .statusCode(CREATED.getStatusCode()); + + String dataverseAlias = UtilIT.getAliasFromResponse(createDataverseResponse); + + Response createDataset = UtilIT.createRandomDatasetViaNativeApi(dataverseAlias, apiToken); + createDataset.prettyPrint(); + createDataset.then().assertThat() + .statusCode(CREATED.getStatusCode()); + + Integer datasetId = JsonPath.from(createDataset.getBody().asString()).getInt("data.id"); + String datasetPid = JsonPath.from(createDataset.getBody().asString()).getString("data.persistentId"); + + String toolManifest = """ +{ + "displayName": "Dataset Configurator", + "description": "Slices! Dices! More info.", + "types": [ + "configure" + ], + "scope": "dataset", + "toolUrl": "https://datasetconfigurator.com", + "toolParameters": { + "queryParameters": [ + { + "datasetPid": "{datasetPid}" + }, + { + "localeCode": "{localeCode}" + } + ] + } + } +"""; + + Response addExternalTool = UtilIT.addExternalTool(JsonUtil.getJsonObject(toolManifest), apiToken); + addExternalTool.prettyPrint(); + addExternalTool.then().assertThat() + .statusCode(OK.getStatusCode()) + .body("data.displayName", CoreMatchers.equalTo("Dataset Configurator")); + + Long toolId = JsonPath.from(addExternalTool.getBody().asString()).getLong("data.id"); + Response getExternalToolsByDatasetId = UtilIT.getExternalToolForDatasetById(datasetId.toString(), "configure", apiToken, toolId.toString()); + getExternalToolsByDatasetId.prettyPrint(); + getExternalToolsByDatasetId.then().assertThat() + .body("data.displayName", CoreMatchers.equalTo("Dataset Configurator")) + .body("data.scope", CoreMatchers.equalTo("dataset")) + .body("data.types[0]", CoreMatchers.equalTo("configure")) + .body("data.toolUrlWithQueryParams", CoreMatchers.equalTo("https://datasetconfigurator.com?datasetPid=" + datasetPid)) + .statusCode(OK.getStatusCode()); + + Response getExternalTools = UtilIT.getExternalTools(apiToken); + getExternalTools.prettyPrint(); + getExternalTools.then().assertThat() + .statusCode(OK.getStatusCode()); + Response getExternalTool = UtilIT.getExternalTool(toolId, apiToken); + getExternalTool.prettyPrint(); + getExternalTool.then().assertThat() + .statusCode(OK.getStatusCode()); + + //Delete the tool added by this test... + Response deleteExternalTool = UtilIT.deleteExternalTool(toolId, apiToken); + deleteExternalTool.prettyPrint(); + deleteExternalTool.then().assertThat() + .statusCode(OK.getStatusCode()); + + // non superuser has no access + UtilIT.setSuperuserStatus(username, false); + getExternalTools = UtilIT.getExternalTools(apiToken); + getExternalTools.prettyPrint(); + getExternalTools.then().assertThat() + .statusCode(FORBIDDEN.getStatusCode()) + .body("message", CoreMatchers.equalTo("Superusers only.")); + } + @Test public void testFileLevelTool1() { diff --git a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java index 1930610532a..c6762c83bac 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/UtilIT.java @@ -2538,6 +2538,42 @@ static Response deleteExternalTool(long externalToolid) { .delete("/api/admin/externalTools/" + externalToolid); } +// ExternalTools with token + static Response getExternalTools(String apiToken) { + RequestSpecification requestSpecification = given(); + if (apiToken != null) { + requestSpecification.header(UtilIT.API_TOKEN_HTTP_HEADER, apiToken); + } + return requestSpecification.get("/api/externalTools"); + } + + static Response getExternalTool(long id, String apiToken) { + RequestSpecification requestSpecification = given(); + if (apiToken != null) { + requestSpecification.header(UtilIT.API_TOKEN_HTTP_HEADER, apiToken); + } + return requestSpecification.get("/api/externalTools/" + id); + } + + static Response addExternalTool(JsonObject jsonObject, String apiToken) { + RequestSpecification requestSpecification = given(); + if (apiToken != null) { + requestSpecification.header(UtilIT.API_TOKEN_HTTP_HEADER, apiToken); + } + return requestSpecification + .body(jsonObject.toString()) + .contentType(ContentType.JSON) + .post("/api/externalTools"); + } + + static Response deleteExternalTool(long externalToolid, String apiToken) { + RequestSpecification requestSpecification = given(); + if (apiToken != null) { + requestSpecification.header(UtilIT.API_TOKEN_HTTP_HEADER, apiToken); + } + return requestSpecification.delete("/api/externalTools/" + externalToolid); + } + static Response getExternalToolsForDataset(String idOrPersistentIdOfDataset, String type, String apiToken) { String idInPath = idOrPersistentIdOfDataset; // Assume it's a number. String optionalQueryParam = ""; // If idOrPersistentId is a number we'll just put it in the path. From 133b1db69b30da1d132c554e9b16f530925cc272 Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Tue, 17 Dec 2024 09:41:04 -0500 Subject: [PATCH 2/5] fix doc formatting --- doc/sphinx-guides/source/admin/external-tools.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/sphinx-guides/source/admin/external-tools.rst b/doc/sphinx-guides/source/admin/external-tools.rst index 50c2ec63c44..1669398e349 100644 --- a/doc/sphinx-guides/source/admin/external-tools.rst +++ b/doc/sphinx-guides/source/admin/external-tools.rst @@ -37,7 +37,8 @@ Configure the tool with the curl command below, making sure to replace the ``fab curl -X POST -H 'Content-type: application/json' http://localhost:8080/api/admin/externalTools --upload-file fabulousFileTool.json - This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +.. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" -X POST -H 'Content-type: application/json' http://localhost:8080/api/externalTools --upload-file fabulousFileTool.json Listing All External Tools in a Dataverse Installation @@ -49,7 +50,8 @@ To list all the external tools that are available in a Dataverse installation: curl http://localhost:8080/api/admin/externalTools - This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +.. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools Showing an External Tool in a Dataverse Installation @@ -62,7 +64,8 @@ To show one of the external tools that are available in a Dataverse installation export TOOL_ID=1 curl http://localhost:8080/api/admin/externalTools/$TOOL_ID - This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +.. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID Removing an External Tool From a Dataverse Installation @@ -75,7 +78,8 @@ Assuming the external tool database id is "1", remove it with the following comm export TOOL_ID=1 curl -X DELETE http://localhost:8080/api/admin/externalTools/$TOOL_ID - This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +.. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" -X DELETE http://localhost:8080/api/externalTools/$TOOL_ID .. _testing-external-tools: From a8ee025eaa093be993394742f24c6395c27f8dd4 Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Tue, 17 Dec 2024 10:04:42 -0500 Subject: [PATCH 3/5] fix doc formatting --- doc/sphinx-guides/source/admin/external-tools.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/sphinx-guides/source/admin/external-tools.rst b/doc/sphinx-guides/source/admin/external-tools.rst index 1669398e349..d654bcd1e8d 100644 --- a/doc/sphinx-guides/source/admin/external-tools.rst +++ b/doc/sphinx-guides/source/admin/external-tools.rst @@ -39,6 +39,7 @@ Configure the tool with the curl command below, making sure to replace the ``fab This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). .. code-block:: bash + curl -s -H "X-Dataverse-key:$API_TOKEN" -X POST -H 'Content-type: application/json' http://localhost:8080/api/externalTools --upload-file fabulousFileTool.json Listing All External Tools in a Dataverse Installation @@ -52,6 +53,7 @@ To list all the external tools that are available in a Dataverse installation: This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). .. code-block:: bash + curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools Showing an External Tool in a Dataverse Installation @@ -66,6 +68,7 @@ To show one of the external tools that are available in a Dataverse installation This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). .. code-block:: bash + curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID Removing an External Tool From a Dataverse Installation @@ -80,6 +83,7 @@ Assuming the external tool database id is "1", remove it with the following comm This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). .. code-block:: bash + curl -s -H "X-Dataverse-key:$API_TOKEN" -X DELETE http://localhost:8080/api/externalTools/$TOOL_ID .. _testing-external-tools: From a65dbde46453a3cda2f0f4dee4644be2c6464eb2 Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:54:55 -0500 Subject: [PATCH 4/5] fix doc formatting --- doc/sphinx-guides/source/admin/external-tools.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/sphinx-guides/source/admin/external-tools.rst b/doc/sphinx-guides/source/admin/external-tools.rst index d654bcd1e8d..3d7c057bda5 100644 --- a/doc/sphinx-guides/source/admin/external-tools.rst +++ b/doc/sphinx-guides/source/admin/external-tools.rst @@ -38,6 +38,7 @@ Configure the tool with the curl command below, making sure to replace the ``fab curl -X POST -H 'Content-type: application/json' http://localhost:8080/api/admin/externalTools --upload-file fabulousFileTool.json This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + .. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" -X POST -H 'Content-type: application/json' http://localhost:8080/api/externalTools --upload-file fabulousFileTool.json @@ -52,6 +53,7 @@ To list all the external tools that are available in a Dataverse installation: curl http://localhost:8080/api/admin/externalTools This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + .. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools @@ -67,6 +69,7 @@ To show one of the external tools that are available in a Dataverse installation curl http://localhost:8080/api/admin/externalTools/$TOOL_ID This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + .. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID @@ -82,6 +85,7 @@ Assuming the external tool database id is "1", remove it with the following comm curl -X DELETE http://localhost:8080/api/admin/externalTools/$TOOL_ID This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). + .. code-block:: bash curl -s -H "X-Dataverse-key:$API_TOKEN" -X DELETE http://localhost:8080/api/externalTools/$TOOL_ID From 4faadf6e9a881569bcafc44123c736bcfff353f8 Mon Sep 17 00:00:00 2001 From: Steven Winship <39765413+stevenwinship@users.noreply.github.com> Date: Tue, 17 Dec 2024 14:39:29 -0500 Subject: [PATCH 5/5] open up get apis for non-superuser --- .../10930-marketplace-external-tools-apis.md | 6 ++-- .../source/admin/external-tools.rst | 8 ++--- .../iq/dataverse/api/ExternalToolsApi.java | 12 +++---- .../iq/dataverse/api/ExternalToolsIT.java | 31 ++++++++++++++----- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/doc/release-notes/10930-marketplace-external-tools-apis.md b/doc/release-notes/10930-marketplace-external-tools-apis.md index 9e20c908823..e3350a8b2d2 100644 --- a/doc/release-notes/10930-marketplace-external-tools-apis.md +++ b/doc/release-notes/10930-marketplace-external-tools-apis.md @@ -1,14 +1,14 @@ ## New APIs for External Tools Registration for Marketplace -New API base path /api/externalTools created that mimics the admin APIs /api/admin/externalTools. These new apis require an authenticated superuser token. +New API base path /api/externalTools created that mimics the admin APIs /api/admin/externalTools. These new add and delete apis require an authenticated superuser token. Example: ``` API_TOKEN='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' export TOOL_ID=1 - curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools - curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID + curl http://localhost:8080/api/externalTools + curl http://localhost:8080/api/externalTools/$TOOL_ID curl -s -H "X-Dataverse-key:$API_TOKEN" -X POST -H 'Content-type: application/json' http://localhost:8080/api/externalTools --upload-file fabulousFileTool.json curl -s -H "X-Dataverse-key:$API_TOKEN" -X DELETE http://localhost:8080/api/externalTools/$TOOL_ID ``` diff --git a/doc/sphinx-guides/source/admin/external-tools.rst b/doc/sphinx-guides/source/admin/external-tools.rst index 3d7c057bda5..c3e71c13ac6 100644 --- a/doc/sphinx-guides/source/admin/external-tools.rst +++ b/doc/sphinx-guides/source/admin/external-tools.rst @@ -52,11 +52,11 @@ To list all the external tools that are available in a Dataverse installation: curl http://localhost:8080/api/admin/externalTools -This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +This API is open to any user. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). .. code-block:: bash - curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools + curl http://localhost:8080/api/externalTools Showing an External Tool in a Dataverse Installation ++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -68,11 +68,11 @@ To show one of the external tools that are available in a Dataverse installation export TOOL_ID=1 curl http://localhost:8080/api/admin/externalTools/$TOOL_ID -This API is Superuser only. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). +This API is open to any user. Note the endpoint difference (/api/externalTools instead of /api/admin/externalTools). .. code-block:: bash - curl -s -H "X-Dataverse-key:$API_TOKEN" http://localhost:8080/api/externalTools/$TOOL_ID + curl http://localhost:8080/api/externalTools/$TOOL_ID Removing an External Tool From a Dataverse Installation +++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java b/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java index bf5634e09a8..92139d86caf 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/ExternalToolsApi.java @@ -19,18 +19,14 @@ public class ExternalToolsApi extends AbstractApiBean { ExternalTools externalTools; @GET - @AuthRequired - public Response getExternalTools(@Context ContainerRequestContext crc) { - Response notAuthorized = authorize(crc); - return notAuthorized == null ? externalTools.getExternalTools() : notAuthorized; + public Response getExternalTools() { + return externalTools.getExternalTools(); } @GET - @AuthRequired @Path("{id}") - public Response getExternalTool(@Context ContainerRequestContext crc, @PathParam("id") long externalToolIdFromUser) { - Response notAuthorized = authorize(crc); - return notAuthorized == null ? externalTools.getExternalTool(externalToolIdFromUser) : notAuthorized; + public Response getExternalTool(@PathParam("id") long externalToolIdFromUser) { + return externalTools.getExternalTool(externalToolIdFromUser); } @POST diff --git a/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java b/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java index a3e2cca329d..1956e0eb8df 100644 --- a/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java +++ b/src/test/java/edu/harvard/iq/dataverse/api/ExternalToolsIT.java @@ -109,19 +109,34 @@ public void testExternalToolsNonAdminEndpoint() { getExternalTool.then().assertThat() .statusCode(OK.getStatusCode()); - //Delete the tool added by this test... - Response deleteExternalTool = UtilIT.deleteExternalTool(toolId, apiToken); - deleteExternalTool.prettyPrint(); - deleteExternalTool.then().assertThat() - .statusCode(OK.getStatusCode()); - - // non superuser has no access + // non superuser can only view tools UtilIT.setSuperuserStatus(username, false); getExternalTools = UtilIT.getExternalTools(apiToken); - getExternalTools.prettyPrint(); getExternalTools.then().assertThat() + .statusCode(OK.getStatusCode()); + getExternalToolsByDatasetId = UtilIT.getExternalToolForDatasetById(datasetId.toString(), "configure", apiToken, toolId.toString()); + getExternalToolsByDatasetId.prettyPrint(); + getExternalToolsByDatasetId.then().assertThat() + .statusCode(OK.getStatusCode()); + + //Add by non-superuser will fail + addExternalTool = UtilIT.addExternalTool(JsonUtil.getJsonObject(toolManifest), apiToken); + addExternalTool.then().assertThat() + .statusCode(FORBIDDEN.getStatusCode()) + .body("message", CoreMatchers.equalTo("Superusers only.")); + + //Delete by non-superuser will fail + Response deleteExternalTool = UtilIT.deleteExternalTool(toolId, apiToken); + deleteExternalTool.then().assertThat() .statusCode(FORBIDDEN.getStatusCode()) .body("message", CoreMatchers.equalTo("Superusers only.")); + + //Delete the tool added by this test... + UtilIT.setSuperuserStatus(username, true); + deleteExternalTool = UtilIT.deleteExternalTool(toolId, apiToken); + deleteExternalTool.prettyPrint(); + deleteExternalTool.then().assertThat() + .statusCode(OK.getStatusCode()); } @Test