From 09280c1a1b57b9e6409d3516cd207280a9234b60 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Wed, 7 Aug 2024 08:08:22 +0200 Subject: [PATCH 1/7] update issue link (cherry picked from commit bd79adfbb094e8d5a17419e18695682987ce84eb) --- items.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/items.md b/items.md index 8cd852b..97e9461 100644 --- a/items.md +++ b/items.md @@ -14,7 +14,7 @@ Example: **/api/core/items/<:uuid>** *** -:warning: In the below example response, the existence of the `place` field for specific metadata values is still under analysis. We are determining whether it can be removed entirely in favor of using the array index (as the `place` field represents the index of each value in an ordered array). For more details see https://jira.duraspace.org/browse/DS-4242 +:warning: In the below example response, the existence of the `place` field for specific metadata values is still under analysis. We are determining whether it can be removed entirely in favor of using the array index (as the `place` field represents the index of each value in an ordered array). For more details see Github issue https://github.com/DSpace/DSpace/issues/7582 *** Provide detailed information about a specific item. The JSON response document is as follow From 26f48aba9d55a393731801d250e0c0e94a6dbe36 Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Tue, 13 Aug 2024 17:24:00 +0200 Subject: [PATCH 2/7] minor fix (cherry picked from commit 0a6e3f9a3b5c43f34a9652f287b9bf8178555cc8) --- workspaceitems.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workspaceitems.md b/workspaceitems.md index b85c0f1..16142bd 100644 --- a/workspaceitems.md +++ b/workspaceitems.md @@ -190,7 +190,7 @@ In addition, it allows in future to change the 1:1 association between collectio #### findBySubmitter **/api/submission/workspaceitems/search/findBySubmitter?uuid=<:submitter-uuid>** -It returns the workspaceitem created by the specified submitter +It returns the list of workspaceitems created by the specified submitter (eperson). ## Get Single Workspace Item from Item UUID From 8eab8b47bcb7daa7e46f27505375f1dc796e13ae Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Wed, 14 Aug 2024 11:54:04 +0200 Subject: [PATCH 3/7] add description of DELETE method (workspace items) (cherry picked from commit 728e37b96b381b790b3d955f0ea2329df21f4c76) --- workspaceitems.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/workspaceitems.md b/workspaceitems.md index 16142bd..6b3ce79 100644 --- a/workspaceitems.md +++ b/workspaceitems.md @@ -207,6 +207,15 @@ It would respond with: * 403 Forbidden - if you are not logged in with sufficient permissions to view the workspace item * 204 if the workspace item doesn't exist +## DELETE Method +**/api/submission/workspaceitems/<:ws-item-uuid>** +Deletes workspace item with the given UUID. The deletion includes the deletion of the item object that is associated to the given workspace item. +Available Response Codes are + +* 204 No content - if the operation succeed +* 401 Unauthorized - if the requester is not authenticated +* 403 Forbidden - if the requester does not have sufficient permissions ((deletion of workspace items can only be requested by the submitter of the workspace item or administrators) +* 404 Not found - if the workspace item doesn't exist From f7063a8096334533ef778fbbac5d68c9be2867eb Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Mon, 19 Aug 2024 15:13:28 +0200 Subject: [PATCH 4/7] improve layout of curl commands (cherry picked from commit db5a28acc47851958b732d9df5ebcfb2322bca61) --- resourcepolicies.md | 49 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/resourcepolicies.md b/resourcepolicies.md index befb883..37cf8a3 100644 --- a/resourcepolicies.md +++ b/resourcepolicies.md @@ -137,7 +137,14 @@ Return codes: The add operation allows to initialize or replace information with new one. To set a startDate -`curl --data '[ { "op": "add", "path": "/startDate", "value": "2019-10-31" }]' -H "Authorization: Bearer ..." -H "content-type: application/json" -X PATCH ${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}` + +``` +curl --data '[ { "op": "add", "path": "/startDate", "value": "2019-10-31" }]' \ + -H 'Authorization: Bearer ...' \ + -H 'content-type: application/json' \ + -X PATCH \ + '${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}' +``` ```json "id": 2844, @@ -164,8 +171,14 @@ the add operation will result in: ``` To set a name and a description -`curl --data '[ { "op": "add", "path": "/name", "value": "my name" }, { "op": "add", "path": "/description", "value": "my description"}]' -H "Authorization: Bearer ..." -H "content-type: application/json" -X PATCH ${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}` +``` +curl --data '[ { "op": "add", "path": "/name", "value": "my name" }, { "op": "add", "path": "/description", "value": "my description"}]' \ + -H 'Authorization: Bearer ...' \ + -H 'content-type: application/json' \ + -X PATCH \ + '${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}' +``` ```json "id": 2844, @@ -207,7 +220,14 @@ With the `remove` operation, you can delete: the other properties cannot be nullified. To remove an embargo you can for instance use the following -`curl --data '[ { "op": "remove", "path": "/startDate" }]' -H "Authorization: Bearer ..." -H "content-type: application/json" -X PATCH ${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}` + +``` +curl --data '[ { "op": "remove", "path": "/startDate" }]' + -H 'Authorization: Bearer ...' \ + -H 'content-type: application/json' \ + -X PATCH \ + '${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}' +``` that will transform @@ -245,7 +265,14 @@ Return codes, see also general [return codes for PATCH requests](patch.md#error- The replace operation allows to replace *existent* information with new one. Attempt to use the replace operation to set not yet initialized information must return an error. See [general errors on PATCH requests](patch.md) To change the startDate -`curl --data '[ { "op": "replace", "path": "/startDate", "value": "2020-01-01" }]' -H "Authorization: Bearer ..." -H "content-type: application/json" -X PATCH ${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}` + +``` +curl --data '[ { "op": "replace", "path": "/startDate", "value": "2020-01-01" }]' \ + -H 'Authorization: Bearer ...' \ + -H 'content-type: application/json' \ + -X PATCH \ + '${dspace7-url}/api/authz/resourcepolicies/${resourcepolicy-id}' +``` For example, starting with the following item data: @@ -310,9 +337,14 @@ Return codes: Update the eperson linked by this resource policy Sample CURL command: + ``` -curl -i -X PUT 'https://demo.dspace.org/server/api/authz/resourcepolicies/3/eperson' -H 'Authorization: Bearer eyJhbGciOiJ…' -H "Content-Type:text/uri-list" --data 'https://demo.dspace.org/server/api/eperson/epersons/ba05e3dd-aa20-4441-ac05-8ceef6f67ac7' +curl -X PUT '${dspace7-url}/api/authz/resourcepolicies/3/eperson' \ + -H 'Authorization: Bearer eyJhbGciOiJ…' \ + -H 'Content-Type:text/uri-list' \ + --data '${dspace7-url}/api/eperson/epersons/ba05e3dd-aa20-4441-ac05-8ceef6f67ac7' ``` + The uri-list should always contain exactly 1 eperson. This eperson will be assigned to the resource policy Return codes: @@ -342,9 +374,14 @@ Return codes: Update the group linked by this resource policy Sample CURL command: + ``` -curl -i -X PUT 'https://demo.dspace.org/server/api/authz/resourcepolicies/4/group' -H 'Authorization: Bearer eyJhbGciOiJ…' -H "Content-Type:text/uri-list" --data 'https://demo.dspace.org/server/api/eperson/groups/db337ae5-abd2-4a28-b4ad-918cf7779e25' +curl -X PUT '${dspace7-url}/api/authz/resourcepolicies/4/group' \ + -H 'Authorization: Bearer eyJhbGciOiJ…' \ + -H 'Content-Type:text/uri-list' \ + --data '${dspace7-url}/api/eperson/groups/db337ae5-abd2-4a28-b4ad-918cf7779e25' ``` + The uri-list should always contain exactly 1 group. This group will be assigned to the resource policy Return codes: From 8b131ba2e4e351079b28bd716606541c1d3b5e1a Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Mon, 26 Aug 2024 12:12:32 +0200 Subject: [PATCH 5/7] added /api/security/csrf endpoint (cherry picked from commit b48ed47621c01bcf6c4a912285cc8ea26737cfdd) --- endpoints.md | 1 + 1 file changed, 1 insertion(+) diff --git a/endpoints.md b/endpoints.md index 519434a..30cae18 100644 --- a/endpoints.md +++ b/endpoints.md @@ -49,6 +49,7 @@ * [/api/integration/suggestionsources](suggestionsources.md) * [/api/integration/suggestiontargets](suggestiontargets.md) * [/api/submission/duplicates](duplicates.md) +* [/api/security/csrf](csrf-tokens.md) (added in DS8) ## Endpoints Under Development/Discussion * [/api/authz/resourcepolicies](resourcepolicies.md) From 40764832abffa53ad0dfc4d6f2dee9b7c060283e Mon Sep 17 00:00:00 2001 From: Sascha Szott Date: Mon, 26 Aug 2024 17:13:11 +0200 Subject: [PATCH 6/7] better explain impact on perfomance degradation (cherry picked from commit 14e2ac8f3be8c4ad41b4067c60009bcce51e9ecf) --- csrf-tokens.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csrf-tokens.md b/csrf-tokens.md index ab29c3e..11e0815 100644 --- a/csrf-tokens.md +++ b/csrf-tokens.md @@ -13,7 +13,7 @@ A `GET` endpoint is also available to force a CSRF token refresh. See below. ### GET /api/security/csrf -Provides a new CSRF Token to the client for usage in later requests. This endpoint SHOULD BE USED SPARINGLY as every call to this endpoint will create a new CSRF token. The DSpace REST API automatically manages CSRF tokens and sends them back to the client _only when the token needs to be changed_ (e.g. on login/logout, etc). Using this endpoint to refresh CSRF tokens frequently may result in unexpected behaviors or even performance issues. The primary purpose of this endpoint is to obtain the *first* CSRF token (if not yet sent by the REST API). +Provides a new CSRF Token to the client for usage in later requests. This endpoint SHOULD BE USED SPARINGLY as every call to this endpoint will create a new CSRF token. The DSpace REST API automatically manages CSRF tokens and sends them back to the client _only when the token needs to be changed_ (e.g. on login/logout, etc). Using this endpoint to refresh CSRF tokens frequently may result in unexpected behaviors or even performance issues on the client side. The primary purpose of this endpoint is to obtain the *first* CSRF token (if not yet sent by the REST API). This endpoint returns an empty response with the newly generated CSRF Token in the `DSPACE-XSRF-TOKEN` HTTP Header. It will also save this CSRF Token to the `DSPACE-XSRF-COOKIE` server-side Cookie, for later verification. See [How does CSRF protection work in DSpace REST API?](#how-does-csrf-protection-work-in-dspace-rest-api) below for more details about this header and cookie. From 5b28089d2f760754f17c893d4f7ee9a8713b0326 Mon Sep 17 00:00:00 2001 From: Vincenzo Mecca Date: Tue, 24 Sep 2024 15:48:21 +0200 Subject: [PATCH 7/7] [CST-10704][CST-14902][CST-15073] Adds ORCID login flow with private email --- epersonregistrations.md | 150 +++++++++++++++++++++++++++++++++++++++- epersons.md | 28 ++++++++ 2 files changed, 175 insertions(+), 3 deletions(-) diff --git a/epersonregistrations.md b/epersonregistrations.md index a16a95e..da5b2f2 100644 --- a/epersonregistrations.md +++ b/epersonregistrations.md @@ -13,24 +13,168 @@ As we don't have a use case to retrieve an eperson registration based on the ema ## Search EPerson registration **/api/eperson/registrations/search/findByToken?token=<:token>** -Exposes the registered email address based on the token. -Also exposes whether it's a new user registration, or a password reset for an existing user. +Exposes the registered email address based on the token or the `netId`. +Also exposes whether it's a new user registration, or a password reset for an existing user. It can expose also `metadata` involved during the registration process, with the overridden values. Lastly, the `registrationType` fields is used to discriminate between the registration flow / procedure. +### Examples +1. User registration not linked to an eperson: ```json { + "id": 1, "email": "user@institution.edu", "user": null, "type": "registration" } ``` - +2. User registration linked to an eperson: ```json { + "id": 2, "email": "user@institution.edu", "user": "028dcbb8-0da2-4122-a0ea-254be49ca107", "type": "registration" } ``` +3. User registration done using **orcid** that didn't provide an email: +```json +{ + "id": 3, + "email": null, + "user": "028dcbb8-0da2-4122-a0ea-254be49ca107", + "type": "registration", + "registrationType": "orcid", + "netId": "0000-1111-2222-3333", + "registrationMetadata": { + "eperson.orcid": [ + { + "value": "0000-1111-2222-3333", + "language": null, + "authority": "", + "confidence": -1, + "place": -1 + } + ], + "eperson.firstname": [ + { + "value": "Power", + "language": null, + "authority": "", + "confidence": -1, + "place": -1, + "overrides": "Power U." + } + ], + "eperson.lastname": [ + { + "value": "User", + "language": null, + "authority": "", + "confidence": -1, + "place": -1 + } + ] + } +} +``` +> Note that the `registrationMetadata` is filled with metadata coming from the external login provider (i.e. **ORCID**) and enriched with the `overrides` field containg metadata value coming from the linked `user`. +> +> In the previous case the `eperson.firstname` metadata related to the `registration-data` **overrides** the value of the `metadata` previously setted for that related `user` (i.e. `Power U.`). + +4. User registration done using **orcid** that provided an email: +```json +{ + "id": 4, + "email": "power-user@orcid.org", + "user": "028dcbb8-0da2-4122-a0ea-254be49ca107", + "type": "registration", + "registrationType": "orcid", + "netId": "0000-1111-2222-3333", + "registrationMetadata": { + "email": [ + { + "value": "power-user@orcid.org", + "language": null, + "authority": "", + "confidence": -1, + "place": -1, + "overrides": "power-user@dspace.org" + } + ], + "eperson.orcid": [ + { + "value": "0000-1111-2222-3333", + "language": null, + "authority": "", + "confidence": -1, + "place": -1 + } + ], + "eperson.firstname": [ + { + "value": "Power", + "language": null, + "authority": "", + "confidence": -1, + "place": -1, + "overrides": "Power U." + } + ], + "eperson.lastname": [ + { + "value": "User", + "language": null, + "authority": "", + "confidence": -1, + "place": -1 + } + ] + } +} +``` +> In the previous case the registration has been confirmed by providing a valid email, or just because the orcid login provided an email-account. This email is treated as an additional metadata, but in fact it's just duplicating the `email` field to provide the `overrides` fields. + +## Updated EPerson registration +**PATCH /api/eperson/registrations/<:id>?token=<:token>** + +To update the EPerson registration, perform a patch with the JSON below to the eperson registrations endpoint, by providing the registration `token` and the `id` of the registration. + +1. Replace the existing email inside the registration: +```json +[ + { + "op": "replace", + "path": "/email", + "value": [ "vincenzo.mecca@4science.com" ] + } +] +``` +2. Add an email inside the registration: +```json +[ + { + "op": "add", + "path": "/email", + "value": [ "vincenzo.mecca@4science.com" ] + } +] +``` + +The allowed path is the one involving the `email` field, while the operation allowed are: + +- `replace` - if a different value was set +- `add` - if none already set + +This method, if successful, will renew the `token` and as a side effect it will send a new Email to the provided `email` value. + +We can have the following cases: +- `email` related to an account: a validation link for reviewing the information is sent to that email address. +- new `email`: a link to the same authentication method provided is sent to that email address + +Status codes: + +* 204 Created - if the operation succeed with a new token generated, and e new mail sent to the `email` provided in the request +* 401 Unauthorized - if registration is disabled the token provided is not valid or absent +* 422 Unprocessable Entity - if the email address was omitted or the operation is not valid ## Create new EPerson registration **POST /api/eperson/registrations?accountRequestType={requestType_forgot_or_register}** diff --git a/epersons.md b/epersons.md index 99c3401..c2a1dc6 100644 --- a/epersons.md +++ b/epersons.md @@ -279,6 +279,34 @@ Status codes: * 401 Unauthorized - if the token doesn't allow you to create this account * 422 Unprocessable Entity - If the provided password not respects the rules configured in the regular expression +## Merge eperson registration data +**POST /api/eperson/epersons/<:uuid>?token=<:token>&override=<:metadata-fields>** + +Allows the merge of some `registrationData` related to the provided *registration-token* (i.e. `<:token>`) into an already actived user account. +This action is permitted by: + - ***logged-user***: that has the same `uuid` as the one specified with the `<:uuid>` param. + - ***anonymous-user***: that provides a `validation-token` (i.e. a token obtained via email confirmation) + +The `override` parameter contains the list of *metadata-fields* that will be overwritten for that linked user. + +The token was previously sent via Email from the [Create new EPerson registration](epersonregistrations.md#create-new-eperson-registration). + +This example shows a simlpe request: + +```bash +curl -X POST http://${dspace.url}/api/eperson/epersons/${id-eperson}?token=${token}&override=${metadata-fields} \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer ${bearer-token}" \ +``` + +As you can see, the request has an ***empty body***. + +Status codes: +* 201 Created - if the operation succeed +* 400 Bad Request - if the `uuid` provided doesn't exist, or if some `override` element isn't found inside the linked user item. +* 401 Unauthorized - The user is anonymous, the `uuid` of the user is not the same as the one logged in, or if the `token` is not valid (i.e. expired or wrong type). +* 403 Forbidden - The user is authenticated, the `token` is not valid or the `uuid` is not the same as the one of the user. + ## Linked entities ### Groups **GET /api/eperson/epersons/<:uuid>/groups**