Summary:
For a public dataset with a guestbook assigned, anonymous guestbook download through the access API behaves differently depending on the dataset identifier used. The :persistentId guestbook-signing path returns a signed URL that immediately fails with 401 Bad signed URL, while the numeric dataset id path returns a signed URL that works. The logged-in :persistentId path also works.
What steps does it take to reproduce the issue?
Create or use a published public dataset with a guestbook assigned.
As an anonymous user, submit a guestbook response to the access API using the :persistentId endpoint with signed=true.
Take the exact signedUrl returned by the API response.
Fetch that exact returned URL.
Repeat the same test using the numeric dataset id endpoint instead of :persistentId.
Repeat the :persistentId test as a logged-in user with a bearer token.
-
When does this issue occur?
When an anonymous user downloads a public dataset that requires a guestbook response and the signed URL is generated through the :persistentId guestbook access endpoint.
-
Which page(s) does it occurs on?
It is visible from the SPA dataset page download flow for public datasets with guestbooks assigned. It is also reproducible directly at the API level via the access endpoints.
-
What happens?
The anonymous POST /api/v1/access/dataset/:persistentId?...&signed=true request returns status: OK and returns a signedUrl, but fetching that exact returned signed URL immediately fails with:
{"status":"ERROR","message":"Bad signed URL"}
and HTTP status 401 Unauthorized.
By contrast:
anonymous POST /api/v1/access/dataset/2?signed=true succeeds and the returned signed URL works
logged-in POST /api/v1/access/dataset/:persistentId?...&signed=true succeeds and the returned signed URL works
- To whom does it occur (all users, curators, superusers)?
It occurs for anonymous users (guest) downloading a public dataset with a guestbook through the :persistentId guestbook-signing path.
It does not reproduce for:
logged-in users using the :persistentId guestbook-signing path
anonymous users using the numeric dataset id guestbook-signing path
- What did you expect to happen?
The exact signed URL returned by the anonymous :persistentId guestbook access POST should be valid and should download the dataset successfully, just like:
the numeric dataset id version for anonymous users
the :persistentId version for logged-in users
Which version of Dataverse are you using?
Latest develop branch version
Any related open or closed issues to this bug report?
Screenshots:
API-level reproduction commands and results:
Anonymous :persistentId path, fails:
PID='doi:10.5072/FK2/I0NJBF'
RESP=$(curl -sS -X POST "http://localhost:8000/api/v1/access/dataset/:persistentId?persistentId=${PID}&signed=true"
-H 'Content-Type: application/json'
-d '{
"guestbookResponse": {
"name": "Guest User",
"email": "guest@example.com",
"institution": "Test Institution",
"position": "Researcher",
"answers": []
}
}')
echo "$RESP" | jq .
SIGNED_URL=$(echo "$RESP" | jq -r '.data.signedUrl // empty')
if [ -n "$SIGNED_URL" ]; then
curl -i "$SIGNED_URL"
fi
Observed:
POST returns status: OK
GET on exact returned signed URL returns 401 Unauthorized
body: {"status":"ERROR","message":"Bad signed URL"}
Anonymous numeric dataset id path, succeeds:
RESP=$(curl -sS -X POST "http://localhost:8000/api/v1/access/dataset/2?signed=true"
-H 'Content-Type: application/json'
-d '{
"guestbookResponse": {
"name": "Guest User",
"email": "guest@example.com",
"institution": "Test Institution",
"position": "Researcher",
"answers": []
}
}')
echo "$RESP" | jq .
SIGNED_URL=$(echo "$RESP" | jq -r '.data.signedUrl // empty')
if [ -n "$SIGNED_URL" ]; then
curl -i "$SIGNED_URL"
fi
Observed:
POST returns status: OK
GET on exact returned signed URL returns 200 OK
Logged-in :persistentId path, succeeds:
TOKEN=''
PID='doi:10.5072/FK2/I0NJBF'
RESP=$(curl -sS -X POST "http://localhost:8000/api/v1/access/dataset/:persistentId?persistentId=${PID}&signed=true"
-H "Authorization: Bearer ${TOKEN}"
-H 'Content-Type: application/json'
-d '{
"guestbookResponse": {
"name": "Dataverse Admin",
"email": "dataverse@mailinator.com",
"institution": "IQSS",
"position": "Admin",
"answers": []
}
}')
echo "$RESP" | jq .
SIGNED_URL=$(echo "$RESP" | jq -r '.data.signedUrl // empty')
if [ -n "$SIGNED_URL" ]; then
curl -i "$SIGNED_URL"
fi
Observed:
POST returns status: OK
GET on exact returned signed URL returns 200 OK
Summary:
For a public dataset with a guestbook assigned, anonymous guestbook download through the access API behaves differently depending on the dataset identifier used. The :persistentId guestbook-signing path returns a signed URL that immediately fails with 401 Bad signed URL, while the numeric dataset id path returns a signed URL that works. The logged-in :persistentId path also works.
What steps does it take to reproduce the issue?
Create or use a published public dataset with a guestbook assigned.
As an anonymous user, submit a guestbook response to the access API using the :persistentId endpoint with signed=true.
Take the exact signedUrl returned by the API response.
Fetch that exact returned URL.
Repeat the same test using the numeric dataset id endpoint instead of :persistentId.
Repeat the :persistentId test as a logged-in user with a bearer token.
When does this issue occur?
When an anonymous user downloads a public dataset that requires a guestbook response and the signed URL is generated through the :persistentId guestbook access endpoint.
Which page(s) does it occurs on?
It is visible from the SPA dataset page download flow for public datasets with guestbooks assigned. It is also reproducible directly at the API level via the access endpoints.
What happens?
The anonymous POST /api/v1/access/dataset/:persistentId?...&signed=true request returns status: OK and returns a signedUrl, but fetching that exact returned signed URL immediately fails with:
{"status":"ERROR","message":"Bad signed URL"}
and HTTP status 401 Unauthorized.
By contrast:
anonymous POST /api/v1/access/dataset/2?signed=true succeeds and the returned signed URL works
logged-in POST /api/v1/access/dataset/:persistentId?...&signed=true succeeds and the returned signed URL works
It occurs for anonymous users (guest) downloading a public dataset with a guestbook through the :persistentId guestbook-signing path.
It does not reproduce for:
logged-in users using the :persistentId guestbook-signing path
anonymous users using the numeric dataset id guestbook-signing path
The exact signed URL returned by the anonymous :persistentId guestbook access POST should be valid and should download the dataset successfully, just like:
the numeric dataset id version for anonymous users
the :persistentId version for logged-in users
Which version of Dataverse are you using?
Latest develop branch version
Any related open or closed issues to this bug report?
Screenshots:
API-level reproduction commands and results:
Anonymous :persistentId path, fails:
PID='doi:10.5072/FK2/I0NJBF'
RESP=$(curl -sS -X POST "http://localhost:8000/api/v1/access/dataset/:persistentId?persistentId=${PID}&signed=true"
-H 'Content-Type: application/json'
-d '{
"guestbookResponse": {
"name": "Guest User",
"email": "guest@example.com",
"institution": "Test Institution",
"position": "Researcher",
"answers": []
}
}')
echo "$RESP" | jq .
SIGNED_URL=$(echo "$RESP" | jq -r '.data.signedUrl // empty')
if [ -n "$SIGNED_URL" ]; then
curl -i "$SIGNED_URL"
fi
Observed:
POST returns status: OK
GET on exact returned signed URL returns 401 Unauthorized
body: {"status":"ERROR","message":"Bad signed URL"}
Anonymous numeric dataset id path, succeeds:
RESP=$(curl -sS -X POST "http://localhost:8000/api/v1/access/dataset/2?signed=true"
-H 'Content-Type: application/json'
-d '{
"guestbookResponse": {
"name": "Guest User",
"email": "guest@example.com",
"institution": "Test Institution",
"position": "Researcher",
"answers": []
}
}')
echo "$RESP" | jq .
SIGNED_URL=$(echo "$RESP" | jq -r '.data.signedUrl // empty')
if [ -n "$SIGNED_URL" ]; then
curl -i "$SIGNED_URL"
fi
Observed:
POST returns status: OK
GET on exact returned signed URL returns 200 OK
Logged-in :persistentId path, succeeds:
TOKEN=''
PID='doi:10.5072/FK2/I0NJBF'
RESP=$(curl -sS -X POST "http://localhost:8000/api/v1/access/dataset/:persistentId?persistentId=${PID}&signed=true"
-H "Authorization: Bearer ${TOKEN}"
-H 'Content-Type: application/json'
-d '{
"guestbookResponse": {
"name": "Dataverse Admin",
"email": "dataverse@mailinator.com",
"institution": "IQSS",
"position": "Admin",
"answers": []
}
}')
echo "$RESP" | jq .
SIGNED_URL=$(echo "$RESP" | jq -r '.data.signedUrl // empty')
if [ -n "$SIGNED_URL" ]; then
curl -i "$SIGNED_URL"
fi
Observed:
POST returns status: OK
GET on exact returned signed URL returns 200 OK