[CST-10704][CST-14902] Adds ORCID login flow with private email

This commit is contained in:
Vincenzo Mecca
2023-10-04 09:52:13 +02:00
parent fc16a5f39f
commit c04aba89f0
44 changed files with 3402 additions and 233 deletions

View File

@@ -29,7 +29,10 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.RegistrationData;
import org.dspace.eperson.RegistrationTypeEnum;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.RegistrationDataService;
import org.dspace.orcid.OrcidToken;
import org.dspace.orcid.client.OrcidClient;
import org.dspace.orcid.client.OrcidConfiguration;
@@ -47,11 +50,15 @@ import org.springframework.beans.factory.annotation.Autowired;
* ORCID authentication for DSpace.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class OrcidAuthenticationBean implements AuthenticationMethod {
public static final String ORCID_DEFAULT_FIRSTNAME = "Unnamed";
public static final String ORCID_DEFAULT_LASTNAME = ORCID_DEFAULT_FIRSTNAME;
public static final String ORCID_AUTH_ATTRIBUTE = "orcid-authentication";
public static final String ORCID_REGISTRATION_TOKEN = "orcid-registration-token";
public static final String ORCID_DEFAULT_REGISTRATION_URL = "/external-login/{0}";
private final static Logger LOGGER = LogManager.getLogger();
@@ -78,6 +85,9 @@ public class OrcidAuthenticationBean implements AuthenticationMethod {
@Autowired
private OrcidTokenService orcidTokenService;
@Autowired
private RegistrationDataService registrationDataService;
@Override
public int authenticate(Context context, String username, String password, String realm, HttpServletRequest request)
throws SQLException {
@@ -183,7 +193,7 @@ public class OrcidAuthenticationBean implements AuthenticationMethod {
return ePerson.canLogIn() ? logInEPerson(context, token, ePerson) : BAD_ARGS;
}
return canSelfRegister() ? registerNewEPerson(context, person, token) : NO_SUCH_USER;
return canSelfRegister() ? createRegistrationData(context, request, person, token) : NO_SUCH_USER;
}
@@ -211,48 +221,59 @@ public class OrcidAuthenticationBean implements AuthenticationMethod {
}
}
private int registerNewEPerson(Context context, Person person, OrcidTokenResponseDTO token) throws SQLException {
private int createRegistrationData(
Context context, HttpServletRequest request, Person person, OrcidTokenResponseDTO token
) throws SQLException {
try {
context.turnOffAuthorisationSystem();
String email = getEmail(person)
.orElseThrow(() -> new IllegalStateException("The email is configured private on orcid"));
RegistrationData registrationData =
this.registrationDataService.create(context, token.getOrcid(), RegistrationTypeEnum.ORCID);
String orcid = token.getOrcid();
registrationData.setEmail(getEmail(person).orElse(null));
setOrcidMetadataOnRegistration(context, registrationData, person, token);
EPerson eperson = ePersonService.create(context);
registrationDataService.update(context, registrationData);
eperson.setNetid(orcid);
eperson.setEmail(email);
Optional<String> firstName = getFirstName(person);
if (firstName.isPresent()) {
eperson.setFirstName(context, firstName.get());
}
Optional<String> lastName = getLastName(person);
if (lastName.isPresent()) {
eperson.setLastName(context, lastName.get());
}
eperson.setCanLogIn(true);
eperson.setSelfRegistered(true);
setOrcidMetadataOnEPerson(context, eperson, token);
ePersonService.update(context, eperson);
context.setCurrentUser(eperson);
request.setAttribute(ORCID_REGISTRATION_TOKEN, registrationData.getToken());
context.commit();
context.dispatchEvents();
return SUCCESS;
} catch (Exception ex) {
LOGGER.error("An error occurs registering a new EPerson from ORCID", ex);
context.rollback();
return NO_SUCH_USER;
} finally {
context.restoreAuthSystemState();
return NO_SUCH_USER;
}
}
private void setOrcidMetadataOnRegistration(
Context context, RegistrationData registration, Person person, OrcidTokenResponseDTO token
) throws SQLException, AuthorizeException {
String orcid = token.getOrcid();
setRegistrationMetadata(context, registration, "eperson.firstname", getFirstName(person));
setRegistrationMetadata(context, registration, "eperson.lastname", getLastName(person));
registrationDataService.setRegistrationMetadataValue(context, registration, "eperson", "orcid", null, orcid);
for (String scope : token.getScopeAsArray()) {
registrationDataService.addMetadata(context, registration, "eperson", "orcid", "scope", scope);
}
}
private void setRegistrationMetadata(
Context context, RegistrationData registration, String metadataString, String value) {
String[] split = metadataString.split("\\.");
String qualifier = split.length > 2 ? split[2] : null;
try {
registrationDataService.setRegistrationMetadataValue(
context, registration, split[0], split[1], qualifier, value
);
} catch (SQLException | AuthorizeException ex) {
LOGGER.error("An error occurs setting metadata", ex);
throw new RuntimeException(ex);
}
}
@@ -296,16 +317,20 @@ public class OrcidAuthenticationBean implements AuthenticationMethod {
return Optional.ofNullable(emails.get(0).getEmail());
}
private Optional<String> getFirstName(Person person) {
private String getFirstName(Person person) {
return Optional.ofNullable(person.getName())
.map(name -> name.getGivenNames())
.map(givenNames -> givenNames.getContent());
.map(name -> name.getGivenNames())
.map(givenNames -> givenNames.getContent())
.filter(StringUtils::isNotBlank)
.orElse(ORCID_DEFAULT_FIRSTNAME);
}
private Optional<String> getLastName(Person person) {
private String getLastName(Person person) {
return Optional.ofNullable(person.getName())
.map(name -> name.getFamilyName())
.map(givenNames -> givenNames.getContent());
.map(name -> name.getFamilyName())
.map(givenNames -> givenNames.getContent())
.filter(StringUtils::isNotBlank)
.orElse(ORCID_DEFAULT_LASTNAME);
}
private boolean canSelfRegister() {