Request-a-copy: Better error / auth flag handling

* New "isAccessExpired" flag for REST model
  (set by converter before responding)
* No changes to bitstream handling - that
  is still a hard auth check which fails
  on any authZ failure or error
This commit is contained in:
Kim Shepherd
2025-03-27 16:56:40 +01:00
parent 51e21a8c98
commit ce127785b3
3 changed files with 23 additions and 12 deletions

View File

@@ -8,6 +8,8 @@
package org.dspace.app.rest.converter; package org.dspace.app.rest.converter;
import java.time.Instant;
import jakarta.inject.Named; import jakarta.inject.Named;
import org.dspace.app.requestitem.RequestItem; import org.dspace.app.requestitem.RequestItem;
import org.dspace.app.rest.model.RequestItemRest; import org.dspace.app.rest.model.RequestItemRest;
@@ -47,6 +49,12 @@ public class RequestItemConverter
requestItemRest.setToken(requestItem.getToken()); requestItemRest.setToken(requestItem.getToken());
requestItemRest.setAccessToken(requestItem.getAccess_token()); requestItemRest.setAccessToken(requestItem.getAccess_token());
requestItemRest.setAccessExpiry(requestItem.getAccess_expiry()); requestItemRest.setAccessExpiry(requestItem.getAccess_expiry());
if ( requestItem.getAccess_expiry() == null ||
requestItem.getAccess_expiry().isBefore(Instant.now())) {
requestItemRest.setAccessExpired(true);
} else {
requestItemRest.setAccessExpired(false);
}
return requestItemRest; return requestItemRest;
} }

View File

@@ -58,6 +58,9 @@ public class RequestItemRest extends BaseObjectRest<Integer> {
protected Instant accessExpiry; protected Instant accessExpiry;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
protected boolean accessExpired;
/** /**
* @return the bitstream requested. * @return the bitstream requested.
*/ */
@@ -240,6 +243,13 @@ public class RequestItemRest extends BaseObjectRest<Integer> {
this.accessExpiry = accessExpiry; this.accessExpiry = accessExpiry;
} }
public boolean isAccessExpired() {
return accessExpired;
}
public void setAccessExpired(boolean accessExpired) {
this.accessExpired = accessExpired;
}
/* /*
* Common REST object methods. * Common REST object methods.
*/ */

View File

@@ -51,7 +51,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.util.HtmlUtils; import org.springframework.web.util.HtmlUtils;
@@ -346,17 +345,11 @@ public class RequestItemRepository
Context context = obtainContext(); Context context = obtainContext();
RequestItem requestItem = requestItemService.findByAccessToken(context, accessToken); RequestItem requestItem = requestItemService.findByAccessToken(context, accessToken);
// Send 404 NOT FOUND if request item is null // Previously, a 404 was thrown if the request item was not found, and a 401 or 403 was thrown depending
if (null == requestItem) { // on authorization and validity checks. These checks are still strictly enforced in the BitstreamContoller
throw new ResourceNotFoundException("No such request item for accessToken=" + accessToken); // and BitstreamResourceAccessByToken classes for actual downloads, but here we continue to pass a 200 OK
} // response so that we can display more meaningful alerts to users in the item page rather than serve hard
// redirects or lose information like expiry dates and access status
// Send 403 FORBIDDEN if request access has not been granted or access period is null or in the past
if (!requestItem.isAccept_request() ||
requestItem.getAccess_expiry() == null ||
requestItem.getAccess_expiry().isBefore(Instant.now())) {
throw new AccessDeniedException("Access has not been granted for this item request");
}
// Sanitize the request item (stripping personal data) for privacy // Sanitize the request item (stripping personal data) for privacy
requestItemService.sanitizeRequestItem(context, requestItem); requestItemService.sanitizeRequestItem(context, requestItem);