mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 15:03:18 +00:00
[CST-14905] Orcid revoke token feature
This commit is contained in:
@@ -10,6 +10,7 @@ package org.dspace.orcid.client;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.dspace.orcid.OrcidToken;
|
||||||
import org.dspace.orcid.exception.OrcidClientException;
|
import org.dspace.orcid.exception.OrcidClientException;
|
||||||
import org.dspace.orcid.model.OrcidTokenResponseDTO;
|
import org.dspace.orcid.model.OrcidTokenResponseDTO;
|
||||||
import org.orcid.jaxb.model.v3.release.record.Person;
|
import org.orcid.jaxb.model.v3.release.record.Person;
|
||||||
@@ -161,4 +162,11 @@ public interface OrcidClient {
|
|||||||
*/
|
*/
|
||||||
OrcidResponse deleteByPutCode(String accessToken, String orcid, String putCode, String path);
|
OrcidResponse deleteByPutCode(String accessToken, String orcid, String putCode, String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revokes the given {@param accessToken} with a POST method.
|
||||||
|
* @param orcidToken the access token to revoke
|
||||||
|
* @throws OrcidClientException if some error occurs during the search
|
||||||
|
*/
|
||||||
|
void revokeToken(OrcidToken orcidToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,7 @@ import org.apache.http.client.methods.RequestBuilder;
|
|||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.apache.http.impl.client.HttpClientBuilder;
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
|
import org.dspace.orcid.OrcidToken;
|
||||||
import org.dspace.orcid.exception.OrcidClientException;
|
import org.dspace.orcid.exception.OrcidClientException;
|
||||||
import org.dspace.orcid.model.OrcidEntityType;
|
import org.dspace.orcid.model.OrcidEntityType;
|
||||||
import org.dspace.orcid.model.OrcidProfileSectionType;
|
import org.dspace.orcid.model.OrcidProfileSectionType;
|
||||||
@@ -178,6 +179,16 @@ public class OrcidClientImpl implements OrcidClient {
|
|||||||
return execute(buildDeleteUriRequest(accessToken, "/" + orcid + path + "/" + putCode), true);
|
return execute(buildDeleteUriRequest(accessToken, "/" + orcid + path + "/" + putCode), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revokeToken(OrcidToken orcidToken) {
|
||||||
|
List<NameValuePair> params = new ArrayList<>();
|
||||||
|
params.add(new BasicNameValuePair("client_id", orcidConfiguration.getClientId()));
|
||||||
|
params.add(new BasicNameValuePair("client_secret", orcidConfiguration.getClientSecret()));
|
||||||
|
params.add(new BasicNameValuePair("token", orcidToken.getAccessToken()));
|
||||||
|
|
||||||
|
executeSuccessful(buildPostForRevokeToken(new UrlEncodedFormEntity(params, Charset.defaultCharset())));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OrcidTokenResponseDTO getReadPublicAccessToken() {
|
public OrcidTokenResponseDTO getReadPublicAccessToken() {
|
||||||
return getClientCredentialsAccessToken("/read-public");
|
return getClientCredentialsAccessToken("/read-public");
|
||||||
@@ -220,6 +231,14 @@ public class OrcidClientImpl implements OrcidClient {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HttpUriRequest buildPostForRevokeToken(HttpEntity entity) {
|
||||||
|
return post(orcidConfiguration.getRevokeUrl())
|
||||||
|
.addHeader("Accept", "application/json")
|
||||||
|
.addHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.setEntity(entity)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
private HttpUriRequest buildPutUriRequest(String accessToken, String relativePath, Object object) {
|
private HttpUriRequest buildPutUriRequest(String accessToken, String relativePath, Object object) {
|
||||||
return put(orcidConfiguration.getApiUrl() + relativePath.trim())
|
return put(orcidConfiguration.getApiUrl() + relativePath.trim())
|
||||||
.addHeader("Content-Type", "application/vnd.orcid+xml")
|
.addHeader("Content-Type", "application/vnd.orcid+xml")
|
||||||
@@ -234,6 +253,24 @@ public class OrcidClientImpl implements OrcidClient {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void executeSuccessful(HttpUriRequest httpUriRequest) {
|
||||||
|
try {
|
||||||
|
HttpClient client = HttpClientBuilder.create().build();
|
||||||
|
HttpResponse response = client.execute(httpUriRequest);
|
||||||
|
|
||||||
|
if (isNotSuccessfull(response)) {
|
||||||
|
throw new OrcidClientException(
|
||||||
|
getStatusCode(response),
|
||||||
|
"Operation " + httpUriRequest.getMethod() + " for the resource " + httpUriRequest.getURI() +
|
||||||
|
" was not successful: " + new String(response.getEntity().getContent().readAllBytes(),
|
||||||
|
StandardCharsets.UTF_8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T executeAndParseJson(HttpUriRequest httpUriRequest, Class<T> clazz) {
|
private <T> T executeAndParseJson(HttpUriRequest httpUriRequest, Class<T> clazz) {
|
||||||
|
|
||||||
HttpClient client = HttpClientBuilder.create().build();
|
HttpClient client = HttpClientBuilder.create().build();
|
||||||
|
@@ -35,6 +35,8 @@ public final class OrcidConfiguration {
|
|||||||
|
|
||||||
private String scopes;
|
private String scopes;
|
||||||
|
|
||||||
|
private String revokeUrl;
|
||||||
|
|
||||||
public String getApiUrl() {
|
public String getApiUrl() {
|
||||||
return apiUrl;
|
return apiUrl;
|
||||||
}
|
}
|
||||||
@@ -111,4 +113,11 @@ public final class OrcidConfiguration {
|
|||||||
return !StringUtils.isAnyBlank(clientId, clientSecret);
|
return !StringUtils.isAnyBlank(clientId, clientSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRevokeUrl() {
|
||||||
|
return revokeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRevokeUrl(String revokeUrl) {
|
||||||
|
this.revokeUrl = revokeUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,6 +37,7 @@ import org.dspace.discovery.indexobject.IndexableItem;
|
|||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.service.EPersonService;
|
import org.dspace.eperson.service.EPersonService;
|
||||||
import org.dspace.orcid.OrcidToken;
|
import org.dspace.orcid.OrcidToken;
|
||||||
|
import org.dspace.orcid.client.OrcidClient;
|
||||||
import org.dspace.orcid.model.OrcidEntityType;
|
import org.dspace.orcid.model.OrcidEntityType;
|
||||||
import org.dspace.orcid.model.OrcidTokenResponseDTO;
|
import org.dspace.orcid.model.OrcidTokenResponseDTO;
|
||||||
import org.dspace.orcid.service.OrcidSynchronizationService;
|
import org.dspace.orcid.service.OrcidSynchronizationService;
|
||||||
@@ -47,6 +48,8 @@ import org.dspace.profile.OrcidProfileSyncPreference;
|
|||||||
import org.dspace.profile.OrcidSynchronizationMode;
|
import org.dspace.profile.OrcidSynchronizationMode;
|
||||||
import org.dspace.profile.service.ResearcherProfileService;
|
import org.dspace.profile.service.ResearcherProfileService;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,6 +60,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
*/
|
*/
|
||||||
public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationService {
|
public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(OrcidSynchronizationServiceImpl.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
private ItemService itemService;
|
private ItemService itemService;
|
||||||
|
|
||||||
@@ -75,6 +79,9 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ResearcherProfileService researcherProfileService;
|
private ResearcherProfileService researcherProfileService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrcidClient orcidClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void linkProfile(Context context, Item profile, OrcidTokenResponseDTO token) throws SQLException {
|
public void linkProfile(Context context, Item profile, OrcidTokenResponseDTO token) throws SQLException {
|
||||||
|
|
||||||
@@ -118,7 +125,14 @@ public class OrcidSynchronizationServiceImpl implements OrcidSynchronizationServ
|
|||||||
itemService.clearMetadata(context, profile, "dspace", "orcid", "scope", Item.ANY);
|
itemService.clearMetadata(context, profile, "dspace", "orcid", "scope", Item.ANY);
|
||||||
itemService.clearMetadata(context, profile, "dspace", "orcid", "authenticated", Item.ANY);
|
itemService.clearMetadata(context, profile, "dspace", "orcid", "authenticated", Item.ANY);
|
||||||
|
|
||||||
|
OrcidToken profileToken = orcidTokenService.findByProfileItem(context, profile);
|
||||||
|
if (profileToken == null) {
|
||||||
|
log.warn("Cannot find any token related to the user profile: {}", profile.getID());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
orcidTokenService.deleteByProfileItem(context, profile);
|
orcidTokenService.deleteByProfileItem(context, profile);
|
||||||
|
orcidClient.revokeToken(profileToken);
|
||||||
|
|
||||||
updateItem(context, profile);
|
updateItem(context, profile);
|
||||||
|
|
||||||
|
@@ -30,7 +30,10 @@ import static org.hamcrest.Matchers.not;
|
|||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -44,6 +47,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.lang.reflect.Field;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -79,11 +83,13 @@ import org.dspace.orcid.client.OrcidClient;
|
|||||||
import org.dspace.orcid.exception.OrcidClientException;
|
import org.dspace.orcid.exception.OrcidClientException;
|
||||||
import org.dspace.orcid.model.OrcidTokenResponseDTO;
|
import org.dspace.orcid.model.OrcidTokenResponseDTO;
|
||||||
import org.dspace.orcid.service.OrcidQueueService;
|
import org.dspace.orcid.service.OrcidQueueService;
|
||||||
|
import org.dspace.orcid.service.OrcidSynchronizationService;
|
||||||
import org.dspace.orcid.service.OrcidTokenService;
|
import org.dspace.orcid.service.OrcidTokenService;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.util.UUIDUtils;
|
import org.dspace.util.UUIDUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mock;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
@@ -114,7 +120,11 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
@Autowired
|
@Autowired
|
||||||
private OrcidClient orcidClient;
|
private OrcidClient orcidClient;
|
||||||
|
|
||||||
private OrcidClient orcidClientMock = mock(OrcidClient.class);
|
@Mock
|
||||||
|
private OrcidClient orcidClientMock;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrcidSynchronizationService orcidSynchronizationService;
|
||||||
|
|
||||||
private EPerson user;
|
private EPerson user;
|
||||||
|
|
||||||
@@ -158,16 +168,36 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
researcherProfileAddOrcidOperation.setOrcidClient(orcidClientMock);
|
useInstanceForBean(orcidSynchronizationService, orcidClientMock);
|
||||||
|
useInstanceForBean(researcherProfileAddOrcidOperation, orcidClientMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
orcidTokenService.deleteAll(context);
|
orcidTokenService.deleteAll(context);
|
||||||
researcherProfileAddOrcidOperation.setOrcidClient(orcidClient);
|
useInstanceForBean(orcidSynchronizationService, orcidClient);
|
||||||
|
useInstanceForBean(researcherProfileAddOrcidOperation, orcidClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <B, I> void useInstanceForBean(B bean, I instance) {
|
||||||
|
Field[] fields = bean.getClass().getDeclaredFields();
|
||||||
|
|
||||||
|
for (Field field : fields) {
|
||||||
|
if (field.getType().isAssignableFrom(instance.getClass())) {
|
||||||
|
boolean accessible = field.isAccessible();
|
||||||
|
try {
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(bean, instance);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
field.setAccessible(accessible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that the findById endpoint returns the own profile.
|
* Verify that the findById endpoint returns the own profile.
|
||||||
*
|
*
|
||||||
@@ -608,30 +638,38 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.withOrcidAuthenticated("authenticated")
|
.withOrcidAuthenticated("authenticated")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
String id = user.getID().toString();
|
|
||||||
String authToken = getAuthToken(user.getEmail(), password);
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}", id))
|
String id = user.getID().toString();
|
||||||
|
String authToken = getAuthToken(user.getEmail(), password);
|
||||||
|
OrcidToken orcidToken = orcidTokenService.findByProfileItem(context, profileItem);
|
||||||
|
|
||||||
|
getClient(authToken)
|
||||||
|
.perform(get("/api/eperson/profiles/{id}", id))
|
||||||
.andExpect(status().isOk());
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
assertThat(profileItem.getMetadata(), hasItem(with("person.identifier.orcid", "0000-1111-2222-3333")));
|
assertThat(profileItem.getMetadata(), hasItem(with("person.identifier.orcid", "0000-1111-2222-3333")));
|
||||||
assertThat(profileItem.getMetadata(), hasItem(with("dspace.orcid.authenticated", "authenticated")));
|
assertThat(profileItem.getMetadata(), hasItem(with("dspace.orcid.authenticated", "authenticated")));
|
||||||
assertThat(getOrcidAccessToken(profileItem), notNullValue());
|
assertThat(orcidToken.getAccessToken(), notNullValue());
|
||||||
|
|
||||||
getClient(authToken).perform(get("/api/eperson/profiles/{id}/item", id))
|
getClient(authToken).perform(get("/api/eperson/profiles/{id}/item", id))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$", hasJsonPath("$.metadata", matchMetadataNotEmpty("dspace.object.owner"))));
|
.andExpect(jsonPath("$", hasJsonPath("$.metadata", matchMetadataNotEmpty("dspace.object.owner"))));
|
||||||
|
|
||||||
|
|
||||||
getClient(authToken).perform(delete("/api/eperson/profiles/{id}", id))
|
getClient(authToken).perform(delete("/api/eperson/profiles/{id}", id))
|
||||||
.andExpect(status().isNoContent());
|
.andExpect(status().isNoContent());
|
||||||
|
|
||||||
|
verify(orcidClientMock, times(1)).revokeToken(matchesToken(orcidToken));
|
||||||
|
verifyNoMoreInteractions(orcidClientMock);
|
||||||
|
|
||||||
profileItem = context.reloadEntity(profileItem);
|
profileItem = context.reloadEntity(profileItem);
|
||||||
|
|
||||||
|
orcidToken = orcidTokenService.findByProfileItem(context, profileItem);
|
||||||
|
|
||||||
assertThat(profileItem.getMetadata(), not(hasItem(with("person.identifier.orcid", "0000-1111-2222-3333"))));
|
assertThat(profileItem.getMetadata(), not(hasItem(with("person.identifier.orcid", "0000-1111-2222-3333"))));
|
||||||
assertThat(profileItem.getMetadata(), not(hasItem(with("dspace.orcid.authenticated", "authenticated"))));
|
assertThat(profileItem.getMetadata(), not(hasItem(with("dspace.orcid.authenticated", "authenticated"))));
|
||||||
assertThat(getOrcidAccessToken(profileItem), nullValue());
|
assertThat(orcidToken, nullValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1850,7 +1888,8 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.withNameInMetadata("Test", "User")
|
.withNameInMetadata("Test", "User")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
OrcidToken orcidToken =
|
||||||
|
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
||||||
|
|
||||||
Item profile = createProfile(ePerson);
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
@@ -1872,6 +1911,9 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.andExpect(jsonPath("$.orcid").doesNotExist())
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
verify(orcidClientMock, times(1)).revokeToken(matchesToken(orcidToken));
|
||||||
|
verifyNoMoreInteractions(orcidClientMock);
|
||||||
|
|
||||||
profile = context.reloadEntity(profile);
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
@@ -1880,6 +1922,54 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
assertThat(getOrcidAccessToken(profile), nullValue());
|
assertThat(getOrcidAccessToken(profile), nullValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatchToDisconnectProfileFromOrcidDoesntRevokeOrcidToken() 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")
|
||||||
|
.withOrcidScope("/read")
|
||||||
|
.withOrcidScope("/write")
|
||||||
|
.withEmail("test@email.it")
|
||||||
|
.withPassword(password)
|
||||||
|
.withNameInMetadata("Test", "User")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
OrcidToken orcidToken =
|
||||||
|
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
||||||
|
|
||||||
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
assertThat(getOrcidAccessToken(profile), is("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4"));
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
doThrow(new OrcidClientException(403, "")).when(orcidClientMock).revokeToken(any(OrcidToken.class));
|
||||||
|
|
||||||
|
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().isInternalServerError());
|
||||||
|
|
||||||
|
verify(orcidClientMock, times(1)).revokeToken(matchesToken(orcidToken));
|
||||||
|
verifyNoMoreInteractions(orcidClientMock);
|
||||||
|
|
||||||
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
|
assertThat(getOrcidAccessToken(profile), is("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAdminPatchToDisconnectProfileFromOrcidWithOnlyOwnerConfiguration() throws Exception {
|
public void testAdminPatchToDisconnectProfileFromOrcidWithOnlyOwnerConfiguration() throws Exception {
|
||||||
|
|
||||||
@@ -2023,7 +2113,8 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.withNameInMetadata("Test", "User")
|
.withNameInMetadata("Test", "User")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
OrcidToken orcidToken =
|
||||||
|
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
||||||
|
|
||||||
Item profile = createProfile(ePerson);
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
@@ -2034,6 +2125,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
|
||||||
getClient(getAuthToken(admin.getEmail(), password))
|
getClient(getAuthToken(admin.getEmail(), password))
|
||||||
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
@@ -2045,6 +2137,9 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.andExpect(jsonPath("$.orcid").doesNotExist())
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
verify(orcidClientMock, times(1)).revokeToken(matchesToken(orcidToken));
|
||||||
|
verifyNoMoreInteractions(orcidClientMock);
|
||||||
|
|
||||||
profile = context.reloadEntity(profile);
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
@@ -2111,17 +2206,18 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.withPassword(password)
|
.withPassword(password)
|
||||||
.withNameInMetadata("Test", "User")
|
.withNameInMetadata("Test", "User")
|
||||||
.build();
|
.build();
|
||||||
|
OrcidToken orcidToken =
|
||||||
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
||||||
|
|
||||||
Item profile = createProfile(ePerson);
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), not(empty()));
|
||||||
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
assertThat(getMetadataValues(profile, "dspace.orcid.scope"), not(empty()));
|
||||||
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
assertThat(getMetadataValues(profile, "dspace.orcid.authenticated"), not(empty()));
|
||||||
assertThat(getOrcidAccessToken(profile), is("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4"));
|
assertThat(getOrcidAccessToken(profile), is("3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4"));
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
|
|
||||||
getClient(getAuthToken(ePerson.getEmail(), password))
|
getClient(getAuthToken(ePerson.getEmail(), password))
|
||||||
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
@@ -2134,6 +2230,9 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.andExpect(jsonPath("$.orcid").doesNotExist())
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
verify(orcidClientMock, times(1)).revokeToken(matchesToken(orcidToken));
|
||||||
|
verifyNoMoreInteractions(orcidClientMock);
|
||||||
|
|
||||||
profile = context.reloadEntity(profile);
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
@@ -2159,7 +2258,8 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.withNameInMetadata("Test", "User")
|
.withNameInMetadata("Test", "User")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
OrcidToken orcidToken =
|
||||||
|
OrcidTokenBuilder.create(context, ePerson, "3de2e370-8aa9-4bbe-8d7e-f5b1577bdad4").build();
|
||||||
|
|
||||||
Item profile = createProfile(ePerson);
|
Item profile = createProfile(ePerson);
|
||||||
|
|
||||||
@@ -2170,6 +2270,7 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
|
|
||||||
getClient(getAuthToken(admin.getEmail(), password))
|
getClient(getAuthToken(admin.getEmail(), password))
|
||||||
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
.perform(patch("/api/eperson/profiles/{id}", ePerson.getID().toString())
|
||||||
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
.content(getPatchContent(asList(new RemoveOperation("/orcid"))))
|
||||||
@@ -2181,6 +2282,10 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
.andExpect(jsonPath("$.orcid").doesNotExist())
|
.andExpect(jsonPath("$.orcid").doesNotExist())
|
||||||
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
.andExpect(jsonPath("$.orcidSynchronization").doesNotExist());
|
||||||
|
|
||||||
|
|
||||||
|
verify(orcidClientMock, times(1)).revokeToken(matchesToken(orcidToken));
|
||||||
|
verifyNoMoreInteractions(orcidClientMock);
|
||||||
|
|
||||||
profile = context.reloadEntity(profile);
|
profile = context.reloadEntity(profile);
|
||||||
|
|
||||||
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
assertThat(getMetadataValues(profile, "person.identifier.orcid"), empty());
|
||||||
@@ -2627,4 +2732,13 @@ public class ResearcherProfileRestRepositoryIT extends AbstractControllerIntegra
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static OrcidToken matchesToken(OrcidToken orcidToken) {
|
||||||
|
return argThat(
|
||||||
|
token ->
|
||||||
|
token != null &&
|
||||||
|
orcidToken.getAccessToken().equals(token.getAccessToken()) &&
|
||||||
|
orcidToken.getID().equals(token.getID())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ orcid.disconnection.allowed-users = admin_and_owner
|
|||||||
# ORCID API (https://github.com/ORCID/ORCID-Source/tree/master/orcid-api-web#endpoints)
|
# ORCID API (https://github.com/ORCID/ORCID-Source/tree/master/orcid-api-web#endpoints)
|
||||||
orcid.domain-url= https://sandbox.orcid.org
|
orcid.domain-url= https://sandbox.orcid.org
|
||||||
orcid.authorize-url = ${orcid.domain-url}/oauth/authorize
|
orcid.authorize-url = ${orcid.domain-url}/oauth/authorize
|
||||||
|
orcid.revoke-url = ${orcid.domain-url}/oauth/revoke
|
||||||
orcid.token-url = ${orcid.domain-url}/oauth/token
|
orcid.token-url = ${orcid.domain-url}/oauth/token
|
||||||
orcid.api-url = https://api.sandbox.orcid.org/v3.0
|
orcid.api-url = https://api.sandbox.orcid.org/v3.0
|
||||||
orcid.public-url = https://pub.sandbox.orcid.org/v3.0
|
orcid.public-url = https://pub.sandbox.orcid.org/v3.0
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
<property name="tokenEndpointUrl" value="${orcid.token-url}" />
|
<property name="tokenEndpointUrl" value="${orcid.token-url}" />
|
||||||
<property name="authorizeEndpointUrl" value="${orcid.authorize-url}" />
|
<property name="authorizeEndpointUrl" value="${orcid.authorize-url}" />
|
||||||
<property name="scopes" value="${orcid.scope}" />
|
<property name="scopes" value="${orcid.scope}" />
|
||||||
|
<property name="revokeUrl" value="${orcid.revoke-url}" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<bean class="org.dspace.orcid.client.OrcidClientImpl" />
|
<bean class="org.dspace.orcid.client.OrcidClientImpl" />
|
||||||
|
Reference in New Issue
Block a user