mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 15:33:09 +00:00
[CST-5669] ORCID Authorizations (REST) .
This commit is contained in:
@@ -10,6 +10,7 @@ package org.dspace.app.orcid.service;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.dspace.app.orcid.model.OrcidTokenResponseDTO;
|
import org.dspace.app.orcid.model.OrcidTokenResponseDTO;
|
||||||
|
import org.dspace.app.profile.OrcidProfileDisconnectionMode;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
|
|
||||||
@@ -33,4 +34,20 @@ public interface OrcidSynchronizationService {
|
|||||||
*/
|
*/
|
||||||
public void linkProfile(Context context, Item profile, OrcidTokenResponseDTO token) throws SQLException;
|
public void linkProfile(Context context, Item profile, OrcidTokenResponseDTO token) throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect the given profile from ORCID.
|
||||||
|
*
|
||||||
|
* @param context the relevant DSpace Context.
|
||||||
|
* @param profile the profile to disconnect
|
||||||
|
* @throws SQLException if a SQL error occurs during the profile update
|
||||||
|
*/
|
||||||
|
public void unlinkProfile(Context context, Item profile) throws SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configuration ORCID profile's disconnection mode. If that mode is
|
||||||
|
* not configured or the configuration is wrong, the value DISABLED is returned.
|
||||||
|
*
|
||||||
|
* @return the disconnection mode
|
||||||
|
*/
|
||||||
|
OrcidProfileDisconnectionMode getDisconnectionMode();
|
||||||
}
|
}
|
||||||
|
@@ -16,6 +16,7 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import org.dspace.app.orcid.model.OrcidTokenResponseDTO;
|
import org.dspace.app.orcid.model.OrcidTokenResponseDTO;
|
||||||
import org.dspace.app.orcid.service.OrcidSynchronizationService;
|
import org.dspace.app.orcid.service.OrcidSynchronizationService;
|
||||||
|
import org.dspace.app.profile.OrcidProfileDisconnectionMode;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.MetadataValue;
|
import org.dspace.content.MetadataValue;
|
||||||
@@ -75,6 +76,27 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlinkProfile(Context context, Item profile) throws SQLException {
|
||||||
|
|
||||||
|
itemService.clearMetadata(context, profile, "person", "identifier", "orcid", Item.ANY);
|
||||||
|
itemService.clearMetadata(context, profile, "dspace", "orcid", "access-token", Item.ANY);
|
||||||
|
itemService.clearMetadata(context, profile, "dspace", "orcid", "refresh-token", Item.ANY);
|
||||||
|
itemService.clearMetadata(context, profile, "dspace", "orcid", "scope", Item.ANY);
|
||||||
|
itemService.clearMetadata(context, profile, "dspace", "orcid", "authenticated", Item.ANY);
|
||||||
|
updateItem(context, profile);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OrcidProfileDisconnectionMode getDisconnectionMode() {
|
||||||
|
String value = configurationService.getProperty("orcid.disconnection.allowed-users");
|
||||||
|
if (!OrcidProfileDisconnectionMode.isValid(value)) {
|
||||||
|
return OrcidProfileDisconnectionMode.DISABLED;
|
||||||
|
}
|
||||||
|
return OrcidProfileDisconnectionMode.fromString(value);
|
||||||
|
}
|
||||||
|
|
||||||
private Stream<MetadataValue> getMetadataValues(Item item, String metadataField) {
|
private Stream<MetadataValue> getMetadataValues(Item item, String metadataField) {
|
||||||
return item.getMetadata().stream()
|
return item.getMetadata().stream()
|
||||||
.filter(metadata -> metadataField.equals(metadata.getMetadataField().toString('.')));
|
.filter(metadata -> metadataField.equals(metadata.getMetadataField().toString('.')));
|
||||||
|
@@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.profile;
|
||||||
|
|
||||||
|
import static java.time.LocalDateTime.now;
|
||||||
|
import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
|
||||||
|
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
|
||||||
|
import static org.dspace.content.Item.ANY;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.dspace.app.profile.service.AfterResearcherProfileCreationAction;
|
||||||
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.content.MetadataFieldName;
|
||||||
|
import org.dspace.content.MetadataValue;
|
||||||
|
import org.dspace.content.service.ItemService;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.dspace.eperson.service.EPersonService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of {@link AfterResearcherProfileCreationAction} that copy the
|
||||||
|
* ORCID metadata, if any, from the owner to the researcher profile item.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
public class OrcidMetadataCopyingAction implements AfterResearcherProfileCreationAction {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ItemService itemService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EPersonService ePersonService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform(Context context, ResearcherProfile researcherProfile, EPerson owner) throws SQLException {
|
||||||
|
|
||||||
|
Item item = researcherProfile.getItem();
|
||||||
|
|
||||||
|
copyMetadataValues(context, owner, "eperson.orcid", item, "person.identifier.orcid");
|
||||||
|
copyMetadataValues(context, owner, "eperson.orcid.access-token", item, "dspace.orcid.access-token");
|
||||||
|
copyMetadataValues(context, owner, "eperson.orcid.refresh-token", item, "dspace.orcid.refresh-token");
|
||||||
|
copyMetadataValues(context, owner, "eperson.orcid.scope", item, "dspace.orcid.scope");
|
||||||
|
|
||||||
|
if (isLinkedToOrcid(owner)) {
|
||||||
|
String currentDate = ISO_DATE_TIME.format(now());
|
||||||
|
itemService.setMetadataSingleValue(context, item, "dspace", "orcid", "authenticated", null, currentDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyMetadataValues(Context context, EPerson ePerson, String ePersonMetadataField, Item item,
|
||||||
|
String itemMetadataField) throws SQLException {
|
||||||
|
|
||||||
|
List<String> values = getMetadataValues(ePerson, ePersonMetadataField);
|
||||||
|
if (CollectionUtils.isEmpty(values)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MetadataFieldName metadata = new MetadataFieldName(itemMetadataField);
|
||||||
|
itemService.clearMetadata(context, item, metadata.schema, metadata.element, metadata.qualifier, ANY);
|
||||||
|
itemService.addMetadata(context, item, metadata.schema, metadata.element, metadata.qualifier, null, values);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLinkedToOrcid(EPerson ePerson) {
|
||||||
|
return isNotEmpty(getMetadataValues(ePerson, "eperson.orcid"))
|
||||||
|
&& isNotEmpty(getMetadataValues(ePerson, "eperson.orcid.access-token"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getMetadataValues(EPerson ePerson, String metadataField) {
|
||||||
|
return ePersonService.getMetadataByMetadataString(ePerson, metadataField).stream()
|
||||||
|
.map(MetadataValue::getValue)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.profile;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.EnumUtils.isValidEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum that models all the available values of the property that which
|
||||||
|
* determines which users can disconnect a profile from an ORCID account.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum OrcidProfileDisconnectionMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The disconnection is disabled.
|
||||||
|
*/
|
||||||
|
DISABLED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only the profile's owner can disconnect that profile from ORCID.
|
||||||
|
*/
|
||||||
|
ONLY_OWNER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only the admins can disconnect profiles from ORCID.
|
||||||
|
*/
|
||||||
|
ONLY_ADMIN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only the admin or the profile's owner can disconnect that profile from ORCID.
|
||||||
|
*/
|
||||||
|
ADMIN_AND_OWNER;
|
||||||
|
|
||||||
|
public static boolean isValid(String mode) {
|
||||||
|
return mode != null ? isValidEnum(OrcidProfileDisconnectionMode.class, mode.toUpperCase()) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OrcidProfileDisconnectionMode fromString(String mode) {
|
||||||
|
return isValid(mode) ? OrcidProfileDisconnectionMode.valueOf(mode.toUpperCase()) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -15,14 +15,17 @@ import java.io.IOException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.dspace.app.exception.ResourceConflictException;
|
import org.dspace.app.exception.ResourceConflictException;
|
||||||
|
import org.dspace.app.profile.service.AfterResearcherProfileCreationAction;
|
||||||
import org.dspace.app.profile.service.ResearcherProfileService;
|
import org.dspace.app.profile.service.ResearcherProfileService;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
@@ -85,6 +88,18 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AuthorizeService authorizeService;
|
private AuthorizeService authorizeService;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private List<AfterResearcherProfileCreationAction> afterCreationActions;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void postConstruct() {
|
||||||
|
|
||||||
|
if (afterCreationActions == null) {
|
||||||
|
afterCreationActions = Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResearcherProfile findById(Context context, UUID id) throws SQLException, AuthorizeException {
|
public ResearcherProfile findById(Context context, UUID id) throws SQLException, AuthorizeException {
|
||||||
Assert.notNull(id, "An id must be provided to find a researcher profile");
|
Assert.notNull(id, "An id must be provided to find a researcher profile");
|
||||||
@@ -118,6 +133,10 @@ public class ResearcherProfileServiceImpl implements ResearcherProfileService {
|
|||||||
|
|
||||||
ResearcherProfile researcherProfile = new ResearcherProfile(item);
|
ResearcherProfile researcherProfile = new ResearcherProfile(item);
|
||||||
|
|
||||||
|
for (AfterResearcherProfileCreationAction afterCreationAction : afterCreationActions) {
|
||||||
|
afterCreationAction.perform(context, researcherProfile, ePerson);
|
||||||
|
}
|
||||||
|
|
||||||
return researcherProfile;
|
return researcherProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.profile.service;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.dspace.app.profile.ResearcherProfile;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to mark classes that allow to perform additional logic on created
|
||||||
|
* researcher profile.
|
||||||
|
*
|
||||||
|
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface AfterResearcherProfileCreationAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform some actions on the given researcher profile and returns the updated
|
||||||
|
* profile.
|
||||||
|
*
|
||||||
|
* @param context the DSpace context
|
||||||
|
* @param researcherProfile the created researcher profile
|
||||||
|
* @param owner the EPerson that is owner of the given profile
|
||||||
|
* @throws SQLException if a SQL error occurs
|
||||||
|
*/
|
||||||
|
void perform(Context context, ResearcherProfile researcherProfile, EPerson owner) throws SQLException;
|
||||||
|
}
|
@@ -129,6 +129,26 @@ public class EPersonBuilder extends AbstractDSpaceObjectBuilder<EPerson> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EPersonBuilder withOrcid(final String orcid) {
|
||||||
|
setMetadataSingleValue(ePerson, "eperson", "orcid", null, orcid);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EPersonBuilder withOrcidAccessToken(final String accessToken) {
|
||||||
|
setMetadataSingleValue(ePerson, "eperson", "orcid", "access-token", accessToken);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EPersonBuilder withOrcidRefreshToken(final String refreshToken) {
|
||||||
|
setMetadataSingleValue(ePerson, "eperson", "orcid", "refresh-token", refreshToken);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EPersonBuilder withOrcidScope(final String scope) {
|
||||||
|
addMetadataValue(ePerson, "eperson", "orcid", "scope", scope);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public static void deleteEPerson(UUID uuid) throws SQLException, IOException {
|
public static void deleteEPerson(UUID uuid) throws SQLException, IOException {
|
||||||
try (Context c = new Context()) {
|
try (Context c = new Context()) {
|
||||||
c.turnOffAuthorisationSystem();
|
c.turnOffAuthorisationSystem();
|
||||||
|
@@ -0,0 +1,106 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.repository.patch.operation;
|
||||||
|
|
||||||
|
import static org.dspace.app.profile.OrcidProfileDisconnectionMode.ADMIN_AND_OWNER;
|
||||||
|
import static org.dspace.app.profile.OrcidProfileDisconnectionMode.DISABLED;
|
||||||
|
import static org.dspace.app.profile.OrcidProfileDisconnectionMode.ONLY_ADMIN;
|
||||||
|
import static org.dspace.app.profile.OrcidProfileDisconnectionMode.ONLY_OWNER;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.dspace.app.orcid.service.OrcidSynchronizationService;
|
||||||
|
import org.dspace.app.profile.OrcidProfileDisconnectionMode;
|
||||||
|
import org.dspace.app.profile.ResearcherProfile;
|
||||||
|
import org.dspace.app.profile.service.ResearcherProfileService;
|
||||||
|
import org.dspace.app.rest.exception.RESTAuthorizationException;
|
||||||
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.authorize.service.AuthorizeService;
|
||||||
|
import org.dspace.core.Context;
|
||||||
|
import org.dspace.eperson.EPerson;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation for ResearcherProfile ORCID disconnection.
|
||||||
|
*
|
||||||
|
* Example: <code><br/>
|
||||||
|
* curl -X PATCH http://${dspace.server.url}/api/cris/profiles/<:id-eperson> -H "
|
||||||
|
* Content-Type: application/json" -d '[{ "op": "remove", "path": "/orcid" }]'
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ResearcherProfileRemoveOrcidOperation extends PatchOperation<ResearcherProfile> {
|
||||||
|
|
||||||
|
private static final String OPERATION_ORCID = "/orcid";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResearcherProfileService profileService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrcidSynchronizationService synchronizationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthorizeService authorizeService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResearcherProfile perform(Context context, ResearcherProfile profile, Operation operation)
|
||||||
|
throws SQLException {
|
||||||
|
|
||||||
|
checkProfileDisconnectionPermissions(context, profile);
|
||||||
|
|
||||||
|
synchronizationService.unlinkProfile(context, profile.getItem());
|
||||||
|
|
||||||
|
try {
|
||||||
|
return profileService.findById(context, profile.getId());
|
||||||
|
} catch (AuthorizeException e) {
|
||||||
|
throw new RESTAuthorizationException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkProfileDisconnectionPermissions(Context context, ResearcherProfile profile) throws SQLException {
|
||||||
|
|
||||||
|
OrcidProfileDisconnectionMode mode = synchronizationService.getDisconnectionMode();
|
||||||
|
|
||||||
|
if (mode == ADMIN_AND_OWNER) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == DISABLED) {
|
||||||
|
throw new RESTAuthorizationException("Profile disconnection from ORCID is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ONLY_OWNER && isNotOwner(context, profile)) {
|
||||||
|
throw new RESTAuthorizationException("Only the profile's owner can perform the ORCID disconnection");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == ONLY_ADMIN && isNotAdmin(context)) {
|
||||||
|
throw new RESTAuthorizationException("Only admins can perform the profile disconnection from ORCID");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNotAdmin(Context context) throws SQLException {
|
||||||
|
return !authorizeService.isAdmin(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNotOwner(Context context, ResearcherProfile profile) {
|
||||||
|
EPerson currentUser = context.getCurrentUser();
|
||||||
|
return currentUser == null || !currentUser.getID().equals(profile.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Object objectToMatch, Operation operation) {
|
||||||
|
return objectToMatch instanceof ResearcherProfile
|
||||||
|
&& operation.getOp().trim().equalsIgnoreCase(OPERATION_REMOVE)
|
||||||
|
&& operation.getPath().trim().toLowerCase().startsWith(OPERATION_ORCID);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -15,7 +15,10 @@ import static org.dspace.app.rest.matcher.HalMatcher.matchLinks;
|
|||||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
|
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
|
||||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataDoesNotExist;
|
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataDoesNotExist;
|
||||||
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataNotEmpty;
|
import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadataNotEmpty;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST;
|
import static org.springframework.data.rest.webmvc.RestMediaTypes.TEXT_URI_LIST;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||||
@@ -26,6 +29,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -34,6 +38,7 @@ import com.jayway.jsonpath.JsonPath;
|
|||||||
import org.dspace.app.rest.model.MetadataValueRest;
|
import org.dspace.app.rest.model.MetadataValueRest;
|
||||||
import org.dspace.app.rest.model.patch.AddOperation;
|
import org.dspace.app.rest.model.patch.AddOperation;
|
||||||
import org.dspace.app.rest.model.patch.Operation;
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
|
import org.dspace.app.rest.model.patch.RemoveOperation;
|
||||||
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
||||||
import org.dspace.app.rest.repository.ResearcherProfileRestRepository;
|
import org.dspace.app.rest.repository.ResearcherProfileRestRepository;
|
||||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||||
@@ -43,6 +48,8 @@ import org.dspace.builder.EPersonBuilder;
|
|||||||
import org.dspace.builder.ItemBuilder;
|
import org.dspace.builder.ItemBuilder;
|
||||||
import org.dspace.content.Collection;
|
import org.dspace.content.Collection;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
|
import org.dspace.content.MetadataValue;
|
||||||
|
import org.dspace.content.service.ItemService;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -61,6 +68,9 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ItemService itemService;
|
||||||
|
|
||||||
private EPerson user;
|
private EPerson user;
|
||||||
|
|
||||||
private EPerson anotherUser;
|
private EPerson anotherUser;
|
||||||
@@ -1035,15 +1045,525 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.andExpect(status().isConflict());
|
.andExpect(status().isConflict());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getItemIdByProfileId(String token, String id) throws Exception {
|
@Test
|
||||||
MvcResult result = getClient(token).perform(get("/api/eperson/profiles/{id}/item", id))
|
public void testOwnerPatchToDisconnectProfileFromOrcidWithDisabledConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "disabled");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(ePerson.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdminPatchToDisconnectProfileFromOrcidWithDisabledConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", null);
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(admin.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnotherUserPatchToDisconnectProfileFromOrcidWithDisabledConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
EPerson anotherUser = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withEmail("user@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Another", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(anotherUser.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwnerPatchToDisconnectProfileFromOrcidWithOnlyOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "only_owner");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(ePerson.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andReturn();
|
.andExpect(jsonPath("$.id", is(ePerson.getID().toString())))
|
||||||
|
.andExpect(jsonPath("$.visible", is(false)))
|
||||||
|
.andExpect(jsonPath("$.type", is("profile")))
|
||||||
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdminPatchToDisconnectProfileFromOrcidWithOnlyOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "only_owner");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(admin.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnotherUserPatchToDisconnectProfileFromOrcidWithOnlyOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "admin_and_owner");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(anotherUser.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwnerPatchToDisconnectProfileFromOrcidWithOnlyAdminConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "only_admin");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(ePerson.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdminPatchToDisconnectProfileFromOrcidWithOnlyAdminConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "only_admin");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(admin.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.id", is(ePerson.getID().toString())))
|
||||||
|
.andExpect(jsonPath("$.visible", is(false)))
|
||||||
|
.andExpect(jsonPath("$.type", is("profile")))
|
||||||
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnotherUserPatchToDisconnectProfileFromOrcidWithOnlyAdminConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "only_admin");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(anotherUser.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOwnerPatchToDisconnectProfileFromOrcidWithAdminAndOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "admin_and_owner");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(ePerson.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.id", is(ePerson.getID().toString())))
|
||||||
|
.andExpect(jsonPath("$.visible", is(false)))
|
||||||
|
.andExpect(jsonPath("$.type", is("profile")))
|
||||||
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAdminPatchToDisconnectProfileFromOrcidWithAdminAndOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "admin_and_owner");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(admin.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.id", is(ePerson.getID().toString())))
|
||||||
|
.andExpect(jsonPath("$.visible", is(false)))
|
||||||
|
.andExpect(jsonPath("$.type", is("profile")))
|
||||||
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), empty());
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAnotherUserPatchToDisconnectProfileFromOrcidWithAdminAndOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
|
configurationService.setProperty("orcid.disconnection.allowed-users", "admin_and_owner");
|
||||||
|
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
|
EPerson ePerson = EPersonBuilder.createEPerson(context)
|
||||||
|
.withCanLogin(true)
|
||||||
|
.withOrcid("0000-1111-2222-3333")
|
||||||
|
.withOrcidAccessToken("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4")
|
||||||
|
.withOrcidRefreshToken("6b29a03d-f494-4690-889f-2c0ddf26b82d")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
getClient(getAuthToken(anotherUser.getEmail(), password))
|
||||||
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.access-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.refresh-token"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Item createProfile(EPerson ePerson) throws Exception {
|
||||||
|
|
||||||
|
String authToken = getAuthToken(ePerson.getEmail(), password);
|
||||||
|
|
||||||
|
AtomicReference<UUID> ePersonIdRef = new AtomicReference<UUID>();
|
||||||
|
AtomicReference<UUID> itemIdRef = new AtomicReference<UUID>();
|
||||||
|
|
||||||
|
getClient(authToken).perform(post("/api/eperson/profiles/")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isCreated())
|
||||||
|
.andDo(result -> ePersonIdRef.set(fromString(read(result.getResponse().getContentAsString(),
|
||||||
|
"$.id"))));
|
||||||
|
|
||||||
|
getClient(authToken).perform(get("/api/eperson/profiles/{id}/item", ePersonIdRef.get())
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andDo(result -> itemIdRef.set(fromString(read(result.getResponse().getContentAsString(),
|
||||||
|
"$.id"))));
|
||||||
|
|
||||||
|
return itemService.find(context, itemIdRef.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getItemIdByProfileId(String token, String id) throws SQLException, Exception {
|
||||||
|
MvcResult result = getClient(token).perform(get("/api/eperson/profiles/{id}/item", id))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andReturn();
|
||||||
|
|
||||||
return readAttributeFromResponse(result, "$.id");
|
return readAttributeFromResponse(result, "$.id");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<MetadataValue> getMetadataValues(Item item, String metadataField) {
|
||||||
|
return itemService.getMetadataByMetadataString(item, metadataField);
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T readAttributeFromResponse(MvcResult result, String attribute) throws UnsupportedEncodingException {
|
private <T> T readAttributeFromResponse(MvcResult result, String attribute) throws UnsupportedEncodingException {
|
||||||
return JsonPath.read(result.getResponse().getContentAsString(), attribute);
|
return JsonPath.read(result.getResponse().getContentAsString(), attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1586,21 +1586,6 @@ request.item.helpdesk.override = false
|
|||||||
# ${dspace.dir}/config/ directory.
|
# ${dspace.dir}/config/ directory.
|
||||||
module_dir = modules
|
module_dir = modules
|
||||||
|
|
||||||
#------------------------------------------------------------------#
|
|
||||||
#--------------------ORCID CONFIGURATIONS--------------------------#
|
|
||||||
#------------------------------------------------------------------#
|
|
||||||
|
|
||||||
orcid.domain-url= https://sandbox.orcid.org
|
|
||||||
orcid.authorize-url = ${orcid.domain-url}/oauth/authorize
|
|
||||||
orcid.token-url = ${orcid.domain-url}/oauth/token
|
|
||||||
orcid.api-url = https://api.sandbox.orcid.org/v3.0
|
|
||||||
orcid.redirect-url = ${dspace.server.url}/api/authn/orcid
|
|
||||||
orcid.application-client-id =
|
|
||||||
orcid.application-client-secret =
|
|
||||||
orcid.scope = /authenticate
|
|
||||||
orcid.scope = /read-limited
|
|
||||||
orcid.scope = /activities/update
|
|
||||||
orcid.scope = /person/update
|
|
||||||
|
|
||||||
# Load default module configs
|
# Load default module configs
|
||||||
# ----------------------------
|
# ----------------------------
|
||||||
@@ -1644,4 +1629,5 @@ include = ${module_dir}/translator.cfg
|
|||||||
include = ${module_dir}/usage-statistics.cfg
|
include = ${module_dir}/usage-statistics.cfg
|
||||||
include = ${module_dir}/versioning.cfg
|
include = ${module_dir}/versioning.cfg
|
||||||
include = ${module_dir}/workflow.cfg
|
include = ${module_dir}/workflow.cfg
|
||||||
include = ${module_dir}/authority.cfg
|
include = ${module_dir}/authority.cfg
|
||||||
|
include = ${module_dir}/orcid.cfg
|
24
dspace/config/modules/orcid.cfg
Normal file
24
dspace/config/modules/orcid.cfg
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#------------------------------------------------------------------#
|
||||||
|
#--------------------ORCID GENERIC CONFIGURATIONS------------------#
|
||||||
|
#------------------------------------------------------------------#
|
||||||
|
|
||||||
|
#Allowed values are disabled, only_admin, only_owner or admin_and_owner
|
||||||
|
orcid.disconnection.allowed-users = admin_and_owner
|
||||||
|
|
||||||
|
#------------------------------------------------------------------#
|
||||||
|
#--------------------ORCID CLIENT CONFIGURATIONS-------------------#
|
||||||
|
#------------------------------------------------------------------#
|
||||||
|
|
||||||
|
orcid.domain-url= https://sandbox.orcid.org
|
||||||
|
orcid.authorize-url = ${orcid.domain-url}/oauth/authorize
|
||||||
|
orcid.token-url = ${orcid.domain-url}/oauth/token
|
||||||
|
orcid.api-url = https://api.sandbox.orcid.org/v3.0
|
||||||
|
orcid.public-url = https://pub.sandbox.orcid.org/v3.0
|
||||||
|
orcid.redirect-url = ${dspace.server.url}/api/authn/orcid
|
||||||
|
orcid.webhook-url = https://api.sandbox.orcid.org/
|
||||||
|
orcid.application-client-id =
|
||||||
|
orcid.application-client-secret =
|
||||||
|
orcid.scope = /authenticate
|
||||||
|
orcid.scope = /read-limited
|
||||||
|
orcid.scope = /activities/update
|
||||||
|
orcid.scope = /person/update
|
@@ -65,6 +65,8 @@
|
|||||||
|
|
||||||
<bean class="org.dspace.app.profile.ResearcherProfileServiceImpl"/>
|
<bean class="org.dspace.app.profile.ResearcherProfileServiceImpl"/>
|
||||||
|
|
||||||
|
<bean class="org.dspace.app.profile.OrcidMetadataCopyingAction"/>
|
||||||
|
|
||||||
<bean class='org.dspace.service.impl.HttpConnectionPoolService'
|
<bean class='org.dspace.service.impl.HttpConnectionPoolService'
|
||||||
id='solrHttpConnectionPoolService'
|
id='solrHttpConnectionPoolService'
|
||||||
scope='singleton'
|
scope='singleton'
|
||||||
|
Reference in New Issue
Block a user