Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customer UK update 15.11.-6.12. #465

Merged
merged 6 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package org.dspace.app.statistics.clarin;

import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -22,6 +23,7 @@
import org.dspace.content.service.ItemService;
import org.dspace.content.service.clarin.ClarinItemService;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.matomo.java.tracking.CustomVariable;
Expand Down Expand Up @@ -132,6 +134,24 @@ public void trackBitstreamDownload(Context context, HttpServletRequest request,
return;
}

// Log the user which is downloading the bitstream
this.logUserDownloadingBitstream(context, bit);
// Track the bitstream downloading event
trackPage(context, request, item, "Bitstream Download / Single File");
}

/**
* Log the user which is downloading the bitstream
* @param context DSpace context object
* @param bit Bitstream which is downloading
*/
private void logUserDownloadingBitstream(Context context, Bitstream bit) {
EPerson eperson = context.getCurrentUser();
String pattern = "The user name: {0}, uuid: {1} is downloading bitstream name: {2}, uuid: {3}.";
String logMessage = Objects.isNull(eperson)
? MessageFormat.format(pattern, "ANONYMOUS", "null", bit.getName(), bit.getID())
: MessageFormat.format(pattern, eperson.getFullName(), eperson.getID(), bit.getName(), bit.getID());

log.info(logMessage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -695,8 +695,8 @@ protected EPerson registerNewEPerson(Context context, HttpServletRequest request
// Header values
String netid = Util.formatNetId(findSingleAttribute(request, netidHeader), org);
String email = findSingleAttribute(request, emailHeader);
String fname = findSingleAttribute(request, fnameHeader);
String lname = findSingleAttribute(request, lnameHeader);
String fname = Headers.updateValueByCharset(findSingleAttribute(request, fnameHeader));
String lname = Headers.updateValueByCharset(findSingleAttribute(request, lnameHeader));

// If the values are not in the request headers try to retrieve it from `shibheaders`.
if (StringUtils.isEmpty(netid)) {
Expand Down Expand Up @@ -817,8 +817,8 @@ protected void updateEPerson(Context context, HttpServletRequest request, EPerso

String netid = Util.formatNetId(findSingleAttribute(request, netidHeader), shibheaders.get_idp());
String email = findSingleAttribute(request, emailHeader);
String fname = findSingleAttribute(request, fnameHeader);
String lname = findSingleAttribute(request, lnameHeader);
String fname = Headers.updateValueByCharset(findSingleAttribute(request, fnameHeader));
String lname = Headers.updateValueByCharset(findSingleAttribute(request, lnameHeader));

// If the values are not in the request headers try to retrieve it from `shibheaders`.
if (StringUtils.isEmpty(netid)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@
package org.dspace.authenticate.clarin;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;

/**
* Helper class for request headers.
Expand All @@ -29,9 +33,11 @@ public class Headers {
private static final Logger log = LogManager.getLogger(org.dspace.authenticate.clarin.Headers.class);
// variables
//
private static ConfigurationService configurationService = new DSpace().getConfigurationService();

private HashMap<String, List<String>> headers_ = new HashMap<String, List<String>>();
private String header_separator_ = null;
private static String EMPTY_STRING = "";


// ctors
Expand Down Expand Up @@ -157,17 +163,53 @@ private List<String> header2values(String header) {


/**
* Convert ISO header value to UTF-8
* @param value ISO header value String
* @return
* Convert ISO header value to UTF-8 or return UTF-8 value if it is not ISO.
* @param value ISO/UTF-8 header value String
* @return Converted ISO value to UTF-8 or UTF-8 value from input
*/
private String updateValueByCharset(String value) {
public static String updateValueByCharset(String value) {
String inputEncoding = configurationService.getProperty("shibboleth.name.conversion.inputEncoding",
"ISO-8859-1");
String outputEncoding = configurationService.getProperty("shibboleth.name.conversion.outputEncoding",
"UTF-8");

if (StringUtils.isBlank(value)) {
value = EMPTY_STRING;
}

// If the value is not ISO-8859-1, then it is already UTF-8
if (!isISOType(value)) {
return value;
}

try {
return new String(value.getBytes("ISO-8859-1"), "UTF-8");
// Encode the string to UTF-8
return new String(value.getBytes(inputEncoding), outputEncoding);
} catch (UnsupportedEncodingException ex) {
log.warn("Failed to reconvert shibboleth attribute with value ("
+ value + ").", ex);
log.warn("Cannot convert the value: " + value + " from " + inputEncoding + " to " + outputEncoding +
" because of: " + ex.getMessage());
return value;
}
}

/**
* Check if the value is ISO-8859-1 encoded.
* @param value String to check
* @return true if the value is ISO-8859-1 encoded, false otherwise
*/
private static boolean isISOType(String value) {
try {
// Encode the string to ISO-8859-1
byte[] iso8859Bytes = value.getBytes(StandardCharsets.ISO_8859_1);

// Decode the bytes back to a string using ISO-8859-1
String decodedString = new String(iso8859Bytes, StandardCharsets.ISO_8859_1);

// Compare the original string with the decoded string
return StringUtils.equals(value, decodedString);
} catch (Exception e) {
// An exception occurred, so the input is not ISO-8859-1
return false;
}
return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import org.dspace.content.Bitstream;
import org.dspace.content.Item;
import org.dspace.content.clarin.ClarinLicense;
import org.dspace.content.clarin.ClarinLicenseLabel;
import org.dspace.content.clarin.ClarinLicenseResourceMapping;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService;
Expand Down Expand Up @@ -93,15 +92,15 @@ public boolean authorizeBitstream(Context context, Bitstream bitstream) throws S
}

/**
* If the bitstream has RES or ACA license and the user is Anonymous do not authorize that user.
* The user will be redirected to the login.
* Do not allow download for anonymous users. Allow it only if the bitstream has Clarin License and the license has
* confirmation = 3 (allow anonymous).
*
* @param context DSpace context object
* @param bitstreamID downloading Bitstream UUID
* @return if the current user is authorized
*/
public boolean authorizeLicenseWithUser(Context context, UUID bitstreamID) throws SQLException {
// If the current user is null that means that the user is not signed in and cannot download the bitstream
// with RES or ACA license
// If the current user is null that means that the user is not signed
if (Objects.nonNull(context.getCurrentUser())) {
// User is signed
return true;
Expand All @@ -118,16 +117,13 @@ public boolean authorizeLicenseWithUser(Context context, UUID bitstreamID) throw

// Bitstream should have only one type of the Clarin license, so we could get first record
ClarinLicense clarinLicense = Objects.requireNonNull(clarinLicenseResourceMappings.get(0)).getLicense();
// Get License Labels from clarin license and check if one of them is ACA or RES
List<ClarinLicenseLabel> clarinLicenseLabels = clarinLicense.getLicenseLabels();
for (ClarinLicenseLabel clarinLicenseLabel : clarinLicenseLabels) {
if (StringUtils.equals(clarinLicenseLabel.getLabel(), "RES") ||
StringUtils.equals(clarinLicenseLabel.getLabel(), "ACA")) {
return false;
}
// 3 - Allow download for anonymous users, but with license confirmation
// 0 - License confirmation is not required
if (Objects.equals(clarinLicense.getConfirmation(), 3) ||
Objects.equals(clarinLicense.getConfirmation(), 0)) {
return true;
}

return true;
return false;
}

private boolean userIsSubmitter(Context context, Bitstream bitstream, EPerson currentUser, UUID userID) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@
@Table(name = "user_registration")
public class ClarinUserRegistration implements ReloadableEntity<Integer> {

// Anonymous user
public static final String ANONYMOUS_USER_REGISTRATION = "anonymous";

// Registered user without organization
public static final String UNKNOWN_USER_REGISTRATION = "Unknown";

private static Logger log = org.apache.logging.log4j.LogManager.getLogger(ClarinUserRegistration.class);

@Id
Expand Down
2 changes: 2 additions & 0 deletions dspace-api/src/test/data/dspaceFolder/config/local.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,5 @@ lr.pid.community.configurations = community=*, prefix=123456789, type=local, can

#### Authority configuration `authority.cfg`
authority.controlled.dc.relation = true

handle.canonical.prefix = ${dspace.ui.url}/handle/
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.dspace.content.Bitstream;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.clarin.ClarinLicenseResourceMappingService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -84,28 +85,30 @@ public ResponseEntity authrn(@PathVariable String id, HttpServletResponse respon
return null;
}

// If the bitstream has RES or ACA license and the user is Anonymous return NotAuthorized exception
// Do not allow download for anonymous users. Allow it only if the bitstream has Clarin License and the license
// has confirmation = 3 (allow anonymous).
if (!authorizationBitstreamUtils.authorizeLicenseWithUser(context, bitstream.getID())) {
response.sendError(HttpStatus.UNAUTHORIZED.value(),
"Anonymous user cannot download bitstream with REC or ACA license");
"Anonymous user cannot download this bitstream");
return null;
}

// Wrap exceptions to the AuthrnRest object.
String errorMessage = "User is not authorized to download the bitstream.";
boolean isAuthorized = false;
String errorMessage = "";

try {
isAuthorized = authorizationBitstreamUtils.authorizeBitstream(context, bitstream);
authorizeService.authorizeAction(context, bitstream, Constants.READ);
} catch (AuthorizeException e) {
if (e instanceof MissingLicenseAgreementException) {
errorMessage = MissingLicenseAgreementException.NAME;
} else if (e instanceof DownloadTokenExpiredException) {
errorMessage = DownloadTokenExpiredException.NAME;
} else {
errorMessage = e.getMessage();
}
}

if (!isAuthorized) {
if (StringUtils.isNotBlank(errorMessage)) {
// If the user is not authorized return response with the error message
response.sendError(HttpStatus.UNAUTHORIZED.value(), errorMessage);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,10 @@ public BitstreamRest importBitstreamForExistingFile(HttpServletRequest request)
log.info("SequenceId is null. Bitstream UUID: " + bitstream.getID());
}
//add bitstream format
String bitstreamFormatIdString = request.getParameter("bitstreamFormat");
Integer bitstreamFormatId = getIntegerFromString(bitstreamFormatIdString);
String bitstreamFormatMimeType = request.getParameter("bitstreamFormat");
BitstreamFormat bitstreamFormat = null;
if (!Objects.isNull(bitstreamFormatId)) {
bitstreamFormat = bitstreamFormatService.find(context, bitstreamFormatId);
if (StringUtils.isNotBlank(bitstreamFormatMimeType)) {
bitstreamFormat = bitstreamFormatService.findByMIMEType(context, bitstreamFormatMimeType);
}
bitstream.setFormat(context, bitstreamFormat);
String deletedString = request.getParameter("deleted");
Expand Down
Loading
Loading