VIVO-769 Merge branch 'feature/orcid' into develop
This commit is contained in:
parent
73fbe66534
commit
939950dcd4
25 changed files with 1551 additions and 1 deletions
107
src/edu/cornell/mannlib/vivo/orcid/OrcidContextSetup.java
Normal file
107
src/edu/cornell/mannlib/vivo/orcid/OrcidContextSetup.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid;
|
||||
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.AUTHORIZED_API_BASE_URL;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.CALLBACK_PATH;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.CLIENT_ID;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.CLIENT_SECRET;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.MESSAGE_VERSION;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.OAUTH_AUTHORIZE_URL;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.OAUTH_TOKEN_URL;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.PUBLIC_API_BASE_URL;
|
||||
import static edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting.WEBAPP_BASE_URL;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.DEFAULT_EXTERNAL_ID_COMMON_NAME;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.PROPERTY_EXTERNAL_ID_COMMON_NAME;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
import edu.cornell.mannlib.orcidclient.context.OrcidClientContext;
|
||||
import edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting;
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
|
||||
|
||||
/**
|
||||
* Setup for the ORCID interface.
|
||||
*
|
||||
* Note that the property for CLIENT_SECRET is "orcid.clientPassword". Since it
|
||||
* ends in "password", it will not be displayed on the ShowConfiguration page.
|
||||
*
|
||||
* The CALLBACK_PATH is hardcoded. It is relative to the WEBAPP_BASE_URL, so it
|
||||
* won't change.
|
||||
*/
|
||||
public class OrcidContextSetup implements ServletContextListener {
|
||||
private static final Log log = LogFactory.getLog(OrcidContextSetup.class);
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
ConfigurationProperties props = ConfigurationProperties.getBean(ctx);
|
||||
StartupStatus ss = StartupStatus.getBean(ctx);
|
||||
|
||||
if (props.getProperty("orcid.clientId", "").isEmpty()) {
|
||||
ss.info(this, "ORCID Integration is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
initializeOrcidClientContext(props, ss);
|
||||
|
||||
checkForCommonNameProperty(props, ss);
|
||||
}
|
||||
|
||||
private void initializeOrcidClientContext(ConfigurationProperties props,
|
||||
StartupStatus ss) {
|
||||
try {
|
||||
Map<Setting, String> settings = new EnumMap<>(Setting.class);
|
||||
settings.put(CLIENT_ID, props.getProperty("orcid.clientId"));
|
||||
settings.put(CLIENT_SECRET,
|
||||
props.getProperty("orcid.clientPassword"));
|
||||
settings.put(PUBLIC_API_BASE_URL,
|
||||
props.getProperty("orcid.publicApiBaseUrl"));
|
||||
settings.put(AUTHORIZED_API_BASE_URL,
|
||||
props.getProperty("orcid.authorizedApiBaseUrl"));
|
||||
settings.put(OAUTH_AUTHORIZE_URL,
|
||||
props.getProperty("orcid.oauthAuthorizeUrl"));
|
||||
settings.put(OAUTH_TOKEN_URL,
|
||||
props.getProperty("orcid.oauthTokenUrl"));
|
||||
settings.put(MESSAGE_VERSION,
|
||||
props.getProperty("orcid.messageVersion"));
|
||||
settings.put(WEBAPP_BASE_URL,
|
||||
props.getProperty("orcid.webappBaseUrl"));
|
||||
settings.put(CALLBACK_PATH, "orcid/callback");
|
||||
|
||||
OrcidClientContext.initialize(settings);
|
||||
ss.info(this, "Context is: " + OrcidClientContext.getInstance());
|
||||
|
||||
} catch (OrcidClientException e) {
|
||||
ss.warning(this, "Failed to initialize OrcidClientContent", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkForCommonNameProperty(ConfigurationProperties props,
|
||||
StartupStatus ss) {
|
||||
if (StringUtils.isBlank(props
|
||||
.getProperty(PROPERTY_EXTERNAL_ID_COMMON_NAME))) {
|
||||
ss.warning(this, "'" + PROPERTY_EXTERNAL_ID_COMMON_NAME
|
||||
+ "' is not set. " + "Using default value of '"
|
||||
+ DEFAULT_EXTERNAL_ID_COMMON_NAME + "'");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
// Nothing to tear down.
|
||||
}
|
||||
|
||||
}
|
217
src/edu/cornell/mannlib/vivo/orcid/OrcidIdDataGetter.java
Normal file
217
src/edu/cornell/mannlib/vivo/orcid/OrcidIdDataGetter.java
Normal file
|
@ -0,0 +1,217 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.query.QuerySolution;
|
||||
import com.hp.hpl.jena.query.ResultSet;
|
||||
import com.hp.hpl.jena.rdf.model.RDFNode;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasAssociatedIndividual;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasProfile;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasProxyEditingRights;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsRootUser;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryRunner;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.SparqlQueryRunner.QueryParser;
|
||||
import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
|
||||
import edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController;
|
||||
|
||||
/**
|
||||
* This data getter should be assigned to the template that renders the list
|
||||
* view for ORCID IDs.
|
||||
*
|
||||
* Find out whether the user is authorized to confirm the ORCID IDs on this
|
||||
* page. Find the list of ORCID IDs, and whether each has already been
|
||||
* confirmed.
|
||||
*
|
||||
* The information is stored in the values map like this:
|
||||
*
|
||||
* <pre>
|
||||
* orcidInfo = map {
|
||||
* authorizedToConfirm: boolean
|
||||
* orcids: map of String to boolean [
|
||||
* orcid: String
|
||||
* confirm: boolean
|
||||
* ]
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class OrcidIdDataGetter implements DataGetter {
|
||||
private static final Log log = LogFactory.getLog(OrcidIdDataGetter.class);
|
||||
|
||||
private static final Map<String, Object> EMPTY_RESULT = Collections
|
||||
.emptyMap();
|
||||
public static final String ORCID_ID = "http://vivoweb.org/ontology/core#orcidId";
|
||||
public static final String ORCID_IS_CONFIRMED = "http://vivoweb.org/ontology/core#confirmedOrcidId";
|
||||
private static final String QUERY_TEMPLATE = "SELECT ?orcid ?confirmed \n"
|
||||
+ "WHERE { \n" //
|
||||
+ " <%s> <%s> ?orcid . \n" //
|
||||
+ " OPTIONAL { \n" //
|
||||
+ " ?orcid <%s> ?confirmed . \n" //
|
||||
+ " } \n" //
|
||||
+ "}\n";
|
||||
|
||||
private final VitroRequest vreq;
|
||||
|
||||
public OrcidIdDataGetter(VitroRequest vreq) {
|
||||
this.vreq = vreq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getData(Map<String, Object> valueMap) {
|
||||
try {
|
||||
String individualUri = findIndividualUri(valueMap);
|
||||
if (individualUri == null) {
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
|
||||
boolean isAuthorizedToConfirm = figureIsAuthorizedtoConfirm(individualUri);
|
||||
List<OrcidInfo> orcids = runSparqlQuery(individualUri);
|
||||
return buildMap(isAuthorizedToConfirm, orcids, individualUri);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to get orcID information", e);
|
||||
return EMPTY_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
private String findIndividualUri(Map<String, Object> valueMap) {
|
||||
try {
|
||||
String uri = (String) valueMap.get("individualURI");
|
||||
|
||||
if (uri == null) {
|
||||
log.warn("valueMap has no individualURI. Keys are: "
|
||||
+ valueMap.keySet());
|
||||
return null;
|
||||
} else {
|
||||
return uri;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("has a problem finding the individualURI", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* You are authorized to confirm an orcId only if you are a self-editor or
|
||||
* root.
|
||||
*/
|
||||
private boolean figureIsAuthorizedtoConfirm(String individualUri) {
|
||||
IdentifierBundle ids = RequestIdentifiers.getIdBundleForRequest(vreq);
|
||||
boolean isSelfEditor = HasProfile.getProfileUris(ids).contains(
|
||||
individualUri);
|
||||
boolean isProxyEditor = HasProxyEditingRights.getProxiedPageUris(ids)
|
||||
.contains(individualUri);
|
||||
boolean isRoot = IsRootUser.isRootUser(ids);
|
||||
return isRoot || isProxyEditor || isSelfEditor;
|
||||
}
|
||||
|
||||
private List<OrcidInfo> runSparqlQuery(String individualUri) {
|
||||
String queryStr = String.format(QUERY_TEMPLATE, individualUri,
|
||||
ORCID_ID, ORCID_IS_CONFIRMED);
|
||||
SparqlQueryRunner runner = new SparqlQueryRunner(vreq.getJenaOntModel());
|
||||
return runner.executeSelect(new OrcidResultParser(), queryStr);
|
||||
}
|
||||
|
||||
private Map<String, Object> buildMap(boolean isAuthorizedToConfirm,
|
||||
List<OrcidInfo> orcids, String individualUri) {
|
||||
Map<String, Boolean> confirmationMap = new HashMap<>();
|
||||
for (OrcidInfo oInfo : orcids) {
|
||||
confirmationMap.put(oInfo.getOrcid(), oInfo.isConfirmed());
|
||||
}
|
||||
|
||||
Map<String, Object> orcidInfoMap = new HashMap<>();
|
||||
orcidInfoMap.put("authorizedToConfirm", isAuthorizedToConfirm);
|
||||
orcidInfoMap.put("orcidUrl", UrlBuilder.getUrl(
|
||||
OrcidIntegrationController.PATH_DEFAULT, "individualUri",
|
||||
individualUri));
|
||||
orcidInfoMap.put("orcids", confirmationMap);
|
||||
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("orcidInfo", orcidInfoMap);
|
||||
|
||||
log.debug("Returning these values:" + map);
|
||||
return map;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Helper classes
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse the results of the SPARQL query.
|
||||
*/
|
||||
private static class OrcidResultParser extends QueryParser<List<OrcidInfo>> {
|
||||
@Override
|
||||
protected List<OrcidInfo> defaultValue() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<OrcidInfo> parseResults(String queryStr,
|
||||
ResultSet results) {
|
||||
List<OrcidInfo> orcids = new ArrayList<>();
|
||||
|
||||
while (results.hasNext()) {
|
||||
try {
|
||||
QuerySolution solution = results.next();
|
||||
Resource orcid = solution.getResource("orcid");
|
||||
RDFNode cNode = solution.get("confirmed");
|
||||
log.debug("Result is orcid=" + orcid + ", confirmed="
|
||||
+ cNode);
|
||||
|
||||
if (orcid != null && orcid.isURIResource()) {
|
||||
boolean confirmed = (cNode != null);
|
||||
orcids.add(new OrcidInfo(orcid.getURI(), confirmed));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to parse the query result: " + queryStr, e);
|
||||
}
|
||||
}
|
||||
|
||||
return orcids;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A bean to hold info for each ORCID.
|
||||
*/
|
||||
static class OrcidInfo {
|
||||
private final String orcid;
|
||||
private final boolean confirmed;
|
||||
|
||||
public OrcidInfo(String orcid, boolean confirmed) {
|
||||
this.orcid = orcid;
|
||||
this.confirmed = confirmed;
|
||||
}
|
||||
|
||||
public String getOrcid() {
|
||||
return orcid;
|
||||
}
|
||||
|
||||
public boolean isConfirmed() {
|
||||
return confirmed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OrcidInfo[orcid=" + orcid + ", confirmed=" + confirmed
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary.OWL_THING;
|
||||
import static edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary.RDF_TYPE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.OrcidIdDataGetter.ORCID_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.OrcidIdDataGetter.ORCID_IS_CONFIRMED;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.TEMPLATE_CONFIRM;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationManager;
|
||||
import edu.cornell.mannlib.orcidclient.context.OrcidClientContext;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidMessage;
|
||||
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyStatementDao;
|
||||
import edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress;
|
||||
|
||||
/**
|
||||
* Some utility methods for the handlers.
|
||||
*/
|
||||
public abstract class OrcidAbstractHandler {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidAbstractHandler.class);
|
||||
|
||||
protected final VitroRequest vreq;
|
||||
protected final OrcidClientContext occ;
|
||||
protected final AuthorizationManager auth;
|
||||
protected final OrcidConfirmationState state;
|
||||
protected final UserAccount currentUser;
|
||||
|
||||
protected OrcidAbstractHandler(VitroRequest vreq) {
|
||||
this.vreq = vreq;
|
||||
this.occ = OrcidClientContext.getInstance();
|
||||
this.auth = this.occ.getAuthorizationManager(vreq);
|
||||
this.state = OrcidConfirmationState.fetch(vreq);
|
||||
this.currentUser = LoginStatusBean.getCurrentUser(vreq);
|
||||
}
|
||||
|
||||
protected Individual findIndividual() {
|
||||
String uri = state.getIndividualUri();
|
||||
try {
|
||||
IndividualDao iDao = vreq.getWebappDaoFactory().getIndividualDao();
|
||||
Individual individual = iDao.getIndividualByURI(uri);
|
||||
if (individual == null) {
|
||||
throw new IllegalStateException("Individual URI not valid: '"
|
||||
+ uri + "'");
|
||||
}
|
||||
return individual;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Individual URI not valid: '" + uri
|
||||
+ "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected void recordConfirmation() {
|
||||
String individualUri = state.getIndividualUri();
|
||||
String orcidUri = state.getOrcidUri();
|
||||
log.debug("Recording confirmation of ORCID '" + orcidUri + "' on '"
|
||||
+ individualUri + "'");
|
||||
ObjectPropertyStatement ops1 = new ObjectPropertyStatementImpl(
|
||||
individualUri, ORCID_ID, orcidUri);
|
||||
ObjectPropertyStatement ops2 = new ObjectPropertyStatementImpl(
|
||||
orcidUri, RDF_TYPE, OWL_THING);
|
||||
ObjectPropertyStatement ops3 = new ObjectPropertyStatementImpl(
|
||||
orcidUri, ORCID_IS_CONFIRMED, individualUri);
|
||||
|
||||
ObjectPropertyStatementDao opsd = vreq.getWebappDaoFactory()
|
||||
.getObjectPropertyStatementDao();
|
||||
opsd.insertNewObjectPropertyStatement(ops1);
|
||||
opsd.insertNewObjectPropertyStatement(ops2);
|
||||
opsd.insertNewObjectPropertyStatement(ops3);
|
||||
}
|
||||
|
||||
protected String cornellNetId() {
|
||||
if (currentUser == null) {
|
||||
return null;
|
||||
}
|
||||
String externalId = currentUser.getExternalAuthId();
|
||||
if (externalId == null) {
|
||||
return null;
|
||||
}
|
||||
if (externalId.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return externalId;
|
||||
}
|
||||
|
||||
protected ResponseValues show500InternalServerError(String message) {
|
||||
log.error("Problem with ORCID request: " + message);
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("title", "500 Internal Server Error");
|
||||
map.put("errorMessage", message);
|
||||
return new TemplateResponseValues("error-titled.ftl", map,
|
||||
SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
protected ResponseValues showConfirmationPage(Progress p,
|
||||
OrcidMessage... messages) {
|
||||
state.progress(p, messages);
|
||||
return showConfirmationPage();
|
||||
}
|
||||
|
||||
protected ResponseValues showConfirmationPage() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("orcidInfo", state.toMap());
|
||||
return new TemplateResponseValues(TEMPLATE_CONFIRM, map);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.orcidclient.actions.ApiAction.ADD_EXTERNAL_ID;
|
||||
import static edu.cornell.mannlib.orcidclient.orcidmessage.Visibility.PUBLIC;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.ADDED_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.DENIED_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.FAILED_ID;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
import edu.cornell.mannlib.orcidclient.actions.AddExternalIdAction;
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationStatus;
|
||||
import edu.cornell.mannlib.orcidclient.beans.ExternalId;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidMessage;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
|
||||
/**
|
||||
* We should now be logged in to ORCID and authorized to add an external ID.
|
||||
*/
|
||||
public class OrcidAddExternalIdHandler extends OrcidAbstractHandler {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidAddExternalIdHandler.class);
|
||||
|
||||
private AuthorizationStatus status;
|
||||
private OrcidMessage profile;
|
||||
|
||||
protected OrcidAddExternalIdHandler(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
public ResponseValues exec() throws OrcidClientException {
|
||||
status = auth.getAuthorizationStatus(ADD_EXTERNAL_ID);
|
||||
if (status.isSuccess()) {
|
||||
addVivoId();
|
||||
return showConfirmationPage(ADDED_ID, profile);
|
||||
} else if (status.isDenied()) {
|
||||
return showConfirmationPage(DENIED_ID);
|
||||
} else {
|
||||
return showConfirmationPage(FAILED_ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void addVivoId() throws OrcidClientException {
|
||||
Individual individual = findIndividual();
|
||||
ExternalId externalId = new ExternalId().setCommonName("VIVO Cornell")
|
||||
.setReference(individual.getLocalName())
|
||||
.setUrl(individual.getURI()).setVisibility(PUBLIC);
|
||||
|
||||
log.debug("Adding external VIVO ID");
|
||||
profile = new AddExternalIdAction().execute(externalId,
|
||||
status.getAccessToken());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.orcidclient.actions.ApiAction.AUTHENTICATE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.DENIED_AUTHENTICATE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.FAILED_AUTHENTICATE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.PATH_READ_PROFILE;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
|
||||
/**
|
||||
* We offered the confirmation screen, and they decided to go ahead. Get
|
||||
* authorization to authenticate them.
|
||||
*
|
||||
* We can't assume that they haven't been here before, so they might already
|
||||
* have authorized, or denied authorization.
|
||||
*/
|
||||
public class OrcidAuthAuthenticateHandler extends OrcidAbstractHandler {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidAuthAuthenticateHandler.class);
|
||||
|
||||
private AuthorizationStatus status;
|
||||
|
||||
public OrcidAuthAuthenticateHandler(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
public ResponseValues exec() throws URISyntaxException,
|
||||
OrcidClientException {
|
||||
status = auth.getAuthorizationStatus(AUTHENTICATE);
|
||||
if (status.isNone()) {
|
||||
return seekAuthorizationForAuthenticate();
|
||||
} else if (status.isSuccess()) {
|
||||
return redirectToReadProfile();
|
||||
} else if (status.isDenied()) {
|
||||
return showConfirmationPage(DENIED_AUTHENTICATE);
|
||||
} else {
|
||||
return showConfirmationPage(FAILED_AUTHENTICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private ResponseValues seekAuthorizationForAuthenticate()
|
||||
throws OrcidClientException, URISyntaxException {
|
||||
log.debug("Seeking authorization to authenticate.");
|
||||
String returnUrl = occ.resolvePathWithWebapp(PATH_READ_PROFILE);
|
||||
String seekUrl = auth.seekAuthorization(AUTHENTICATE, returnUrl);
|
||||
return new RedirectResponseValues(seekUrl);
|
||||
}
|
||||
|
||||
private ResponseValues redirectToReadProfile() throws URISyntaxException {
|
||||
log.debug("Already authorized to authenticate.");
|
||||
return new RedirectResponseValues(
|
||||
occ.resolvePathWithWebapp(PATH_READ_PROFILE));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.orcidclient.actions.ApiAction.ADD_EXTERNAL_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.DENIED_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.FAILED_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.PATH_ADD_EXTERNAL_ID;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationStatus;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
|
||||
/**
|
||||
* We offered to add external IDs and they decided to go ahead. Get
|
||||
* authorization.
|
||||
*
|
||||
* We can't assume that they haven't been here before, so they might already
|
||||
* have authorized, or denied authorization.
|
||||
*/
|
||||
public class OrcidAuthExternalIdsHandler extends OrcidAbstractHandler {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidAuthExternalIdsHandler.class);
|
||||
|
||||
private AuthorizationStatus status;
|
||||
|
||||
public OrcidAuthExternalIdsHandler(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
public ResponseValues exec() throws URISyntaxException,
|
||||
OrcidClientException {
|
||||
status = auth.getAuthorizationStatus(ADD_EXTERNAL_ID);
|
||||
if (status.isNone()) {
|
||||
return seekAuthorizationForExternalId();
|
||||
} else if (status.isSuccess()) {
|
||||
return redirectToAddExternalId();
|
||||
} else if (status.isDenied()) {
|
||||
return showConfirmationPage(DENIED_ID);
|
||||
} else {
|
||||
return showConfirmationPage(FAILED_ID);
|
||||
}
|
||||
}
|
||||
|
||||
private ResponseValues seekAuthorizationForExternalId()
|
||||
throws OrcidClientException, URISyntaxException {
|
||||
log.debug("Seeking authorization to add external ID");
|
||||
String returnUrl = occ.resolvePathWithWebapp(PATH_ADD_EXTERNAL_ID);
|
||||
String seekUrl = auth.seekAuthorization(ADD_EXTERNAL_ID, returnUrl);
|
||||
return new RedirectResponseValues(seekUrl);
|
||||
}
|
||||
|
||||
private ResponseValues redirectToAddExternalId() throws URISyntaxException {
|
||||
log.debug("Already authorized to add external ID.");
|
||||
return new RedirectResponseValues(
|
||||
occ.resolvePathWithWebapp(PATH_ADD_EXTERNAL_ID));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationManager;
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationStatus;
|
||||
import edu.cornell.mannlib.orcidclient.context.OrcidClientContext;
|
||||
|
||||
/**
|
||||
* Handle the callbacks during the OAuth dance.
|
||||
*
|
||||
* This is not like other handlers. It is created and invoked from doGet(), not
|
||||
* from processRequest().
|
||||
*/
|
||||
public class OrcidCallbackHandler {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidCallbackHandler.class);
|
||||
|
||||
private final HttpServletRequest req;
|
||||
private final HttpServletResponse resp;
|
||||
|
||||
public OrcidCallbackHandler(HttpServletRequest req, HttpServletResponse resp) {
|
||||
this.req = req;
|
||||
this.resp = resp;
|
||||
}
|
||||
|
||||
public void exec() throws IOException {
|
||||
OrcidClientContext occ = OrcidClientContext.getInstance();
|
||||
AuthorizationManager authManager = occ.getAuthorizationManager(req);
|
||||
try {
|
||||
AuthorizationStatus auth = authManager
|
||||
.processAuthorizationResponse();
|
||||
if (auth.isSuccess()) {
|
||||
resp.sendRedirect(auth.getSuccessUrl());
|
||||
} else {
|
||||
resp.sendRedirect(auth.getFailureUrl());
|
||||
}
|
||||
} catch (OrcidClientException e) {
|
||||
log.error("Invalid authorization response", e);
|
||||
resp.sendError(SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.START;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.PATH_AUTH_EXTERNAL_ID;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidIntegrationController.PATH_AUTH_AUTHENTICATE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.ExternalIdentifier;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.ExternalIdentifiers;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidBio;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidId;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidMessage;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidProfile;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
|
||||
/**
|
||||
* Keep track of where we are in the Orcid confirmation process; what has been
|
||||
* requested, and what has been returned.
|
||||
*/
|
||||
class OrcidConfirmationState {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidConfirmationState.class);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The factory
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
private static final String ATTRIBUTE_NAME = OrcidConfirmationState.class
|
||||
.getName();
|
||||
|
||||
static OrcidConfirmationState fetch(HttpServletRequest req) {
|
||||
HttpSession session = req.getSession();
|
||||
Object o = session.getAttribute(ATTRIBUTE_NAME);
|
||||
if (o instanceof OrcidConfirmationState) {
|
||||
return (OrcidConfirmationState) o;
|
||||
} else {
|
||||
OrcidConfirmationState ocs = new OrcidConfirmationState();
|
||||
session.setAttribute(ATTRIBUTE_NAME, ocs);
|
||||
return ocs;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The instance
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public enum Progress {
|
||||
START, DENIED_AUTHENTICATE, FAILED_AUTHENTICATE, GOT_PROFILE, ID_ALREADY_PRESENT, DENIED_ID, FAILED_ID, ADDED_ID
|
||||
}
|
||||
|
||||
private static final Set<Progress> requiresMessage = EnumSet.of(
|
||||
Progress.GOT_PROFILE, Progress.ADDED_ID);
|
||||
|
||||
private Progress progress;
|
||||
private String individualUri;
|
||||
private Set<String> existingOrcids;
|
||||
private OrcidMessage profile;
|
||||
private String profilePageUrl;
|
||||
|
||||
public void reset(String uri, String profileUrl) {
|
||||
progress = START;
|
||||
individualUri = uri;
|
||||
existingOrcids = Collections.emptySet();
|
||||
profile = null;
|
||||
profilePageUrl = profileUrl;
|
||||
}
|
||||
|
||||
public void setExistingOrcids(Set<String> existing) {
|
||||
existingOrcids = new HashSet<>(existing);
|
||||
}
|
||||
|
||||
public void progress(Progress p, OrcidMessage... messages) {
|
||||
progress = p;
|
||||
|
||||
if (requiresMessage.contains(p)) {
|
||||
if (messages.length != 1) {
|
||||
throw new IllegalStateException("Progress to " + p
|
||||
+ " requires an OrcidMessage");
|
||||
}
|
||||
profile = messages[0];
|
||||
} else {
|
||||
if (messages.length != 0) {
|
||||
throw new IllegalStateException("Progress to " + p
|
||||
+ " does not accept an OrcidMessage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Convenience methods for extracting information from the profile.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public String getProgress() {
|
||||
return progress.toString();
|
||||
}
|
||||
|
||||
public String getProgressUrl() {
|
||||
switch (progress) {
|
||||
case START:
|
||||
return UrlBuilder.getUrl(PATH_AUTH_AUTHENTICATE);
|
||||
case GOT_PROFILE:
|
||||
return UrlBuilder.getUrl(PATH_AUTH_EXTERNAL_ID);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getIndividualUri() {
|
||||
return individualUri;
|
||||
}
|
||||
|
||||
public String getProfilePageUrl() {
|
||||
return profilePageUrl;
|
||||
}
|
||||
|
||||
public String getOrcid() {
|
||||
return getElementFromOrcidIdentifier("path");
|
||||
|
||||
}
|
||||
|
||||
public String getOrcidUri() {
|
||||
return getElementFromOrcidIdentifier("uri");
|
||||
}
|
||||
|
||||
public ExternalIdentifier getVivoId() {
|
||||
for (ExternalIdentifier id : getExternalIds()) {
|
||||
if (individualUri.equals(id.getExternalIdUrl().getValue())) {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ExternalIdentifier> getExternalIds() {
|
||||
OrcidProfile orcidProfile = getOrcidProfile();
|
||||
if (orcidProfile == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
OrcidBio bio = orcidProfile.getOrcidBio();
|
||||
if (bio == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ExternalIdentifiers identifiers = bio.getExternalIdentifiers();
|
||||
if (identifiers == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ExternalIdentifier> list = identifiers.getExternalIdentifier();
|
||||
if (list == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private String getElementFromOrcidIdentifier(String elementName) {
|
||||
OrcidProfile orcidProfile = getOrcidProfile();
|
||||
if (orcidProfile == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
OrcidId id = orcidProfile.getOrcidIdentifier();
|
||||
if (id == null) {
|
||||
log.warn("There is no ORCID Identifier in the profile.");
|
||||
return "";
|
||||
}
|
||||
|
||||
List<JAXBElement<String>> idElements = id.getContent();
|
||||
if (idElements != null) {
|
||||
for (JAXBElement<String> idElement : idElements) {
|
||||
QName name = idElement.getName();
|
||||
if (name != null && elementName.equals(name.getLocalPart())) {
|
||||
String value = idElement.getValue();
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log.warn("Didn't find the element '' in the ORCID Identifier: " + idElements);
|
||||
return "";
|
||||
}
|
||||
|
||||
private OrcidProfile getOrcidProfile() {
|
||||
if (profile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OrcidProfile orcidProfile = profile.getOrcidProfile();
|
||||
if (orcidProfile == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return orcidProfile;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMap() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("progress", progress.toString());
|
||||
map.put("individualUri", individualUri);
|
||||
map.put("profilePage", profilePageUrl);
|
||||
map.put("orcid", getOrcid());
|
||||
map.put("orcidUri", getOrcidUri());
|
||||
map.put("hasVivoId", getVivoId() == null);
|
||||
map.put("externalIds", formatExternalIds());
|
||||
map.put("existingOrcids", existingOrcids);
|
||||
|
||||
String progressUrl = getProgressUrl();
|
||||
if (progressUrl == null) {
|
||||
map.put("progressUrl", "");
|
||||
} else {
|
||||
map.put("progressUrl", progressUrl);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private List<Map<String, String>> formatExternalIds() {
|
||||
List<Map<String, String>> list = new ArrayList<>();
|
||||
for (ExternalIdentifier id : getExternalIds()) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("commonName", id.getExternalIdCommonName().getContent());
|
||||
map.put("reference", id.getExternalIdReference().getContent());
|
||||
map.put("uri", id.getExternalIdUrl().getValue());
|
||||
list.add(map);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.orcidclient.actions.ApiAction.ADD_EXTERNAL_ID;
|
||||
import static edu.cornell.mannlib.orcidclient.actions.ApiAction.READ_PROFILE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.OrcidIdDataGetter.ORCID_ID;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.RequestIdentifiers;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.HasProfile;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.NotAuthorizedResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
|
||||
|
||||
/**
|
||||
* A request came from the "Confirm" button on the individual profile. Get a
|
||||
* fresh state object, clear the AuthorizationCache and show the confirmation
|
||||
* page.
|
||||
*/
|
||||
public class OrcidDefaultHandler extends OrcidAbstractHandler {
|
||||
private static final Log log = LogFactory.getLog(OrcidDefaultHandler.class);
|
||||
|
||||
private Individual individual;
|
||||
private final Set<String> existingOrcids = new HashSet<>();
|
||||
|
||||
public OrcidDefaultHandler(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
public ResponseValues exec() {
|
||||
try {
|
||||
initializeState();
|
||||
initializeAuthorizationCache();
|
||||
} catch (Exception e) {
|
||||
log.error("No proper individual URI on the request", e);
|
||||
return show400BadRequest(e);
|
||||
}
|
||||
|
||||
if (!isAuthorized()) {
|
||||
return showNotAuthorized();
|
||||
}
|
||||
|
||||
return showConfirmationPage();
|
||||
}
|
||||
|
||||
private void initializeState() {
|
||||
String uri = vreq.getParameter("individualUri");
|
||||
if (uri == null) {
|
||||
throw new IllegalStateException(
|
||||
"No 'individualUri' parameter on request.");
|
||||
}
|
||||
|
||||
String profilePage = UrlBuilder.getIndividualProfileUrl(uri, vreq);
|
||||
state.reset(uri, profilePage);
|
||||
|
||||
individual = findIndividual();
|
||||
locateExistingOrcids();
|
||||
state.setExistingOrcids(existingOrcids);
|
||||
}
|
||||
|
||||
private void locateExistingOrcids() {
|
||||
if (individual == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ObjectPropertyStatement> opss = individual
|
||||
.getObjectPropertyStatements(ORCID_ID);
|
||||
if (opss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ObjectPropertyStatement ops : opss) {
|
||||
existingOrcids.add(ops.getObjectURI());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initializeAuthorizationCache() {
|
||||
auth.clearStatus(READ_PROFILE);
|
||||
auth.clearStatus(ADD_EXTERNAL_ID);
|
||||
}
|
||||
|
||||
private ResponseValues show400BadRequest(Exception e) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("title", "400 Bad Request");
|
||||
map.put("errorMessage", e.getMessage());
|
||||
return new TemplateResponseValues("error-titled.ftl", map,
|
||||
SC_BAD_REQUEST);
|
||||
}
|
||||
|
||||
private boolean isAuthorized() {
|
||||
// Only a self-editor is authorized.
|
||||
IdentifierBundle ids = RequestIdentifiers.getIdBundleForRequest(vreq);
|
||||
Collection<String> profileUris = HasProfile.getProfileUris(ids);
|
||||
log.debug("Authorized? individualUri=" + state.getIndividualUri()
|
||||
+ ", profileUris=" + profileUris);
|
||||
return profileUris.contains(state.getIndividualUri());
|
||||
}
|
||||
|
||||
private ResponseValues showNotAuthorized() {
|
||||
UserAccount user = LoginStatusBean.getCurrentUser(vreq);
|
||||
String userName = (user == null) ? "ANONYMOUS" : user.getEmailAddress();
|
||||
return new NotAuthorizedResponseValues(userName
|
||||
+ "is not authorized for ORCID operations on '" + individual
|
||||
+ "'");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
|
||||
/**
|
||||
* The OrcidConfirmationState is not as we expected. Probably deserves a 500
|
||||
* error.
|
||||
*/
|
||||
public class OrcidIllegalStateException extends OrcidClientException {
|
||||
public OrcidIllegalStateException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public OrcidIllegalStateException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.context.OrcidClientContext;
|
||||
import edu.cornell.mannlib.orcidclient.context.OrcidClientContext.Setting;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.AuthorizationRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LogoutRedirector;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ExceptionResponseValues;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
|
||||
/**
|
||||
* New workflow:
|
||||
*
|
||||
* <pre>
|
||||
* Default: clear status for both readProfile and addExternalIDs
|
||||
* show intro screen orcidOffer.ftl
|
||||
* The click "do it", goes to /getProfileAuth
|
||||
* Or "return to profile"
|
||||
* /getProfileAuth: If already authorized, redirect to /readProfile
|
||||
* Else, do the dance, ending with /readProfile callback
|
||||
* Denied? show orcidDenied.ftl
|
||||
* Failed? show orcidFailed.ftl
|
||||
* /readProfile: read the profile, store in status
|
||||
* figure external ID options, show orcidOfferIds.ftl
|
||||
* If they click "do it", goes /authExternalIds
|
||||
* If they click "nah", return to profile
|
||||
* /authExternalIds: if already authorized, redirect to /addExternalIds
|
||||
* Else, do the dance, ending with /addExternalIds callback
|
||||
* /addExternalIds add one or both IDs, store new profile in status
|
||||
* show orcidSuccess.ftl with "return to profile" and "view profile" links.
|
||||
* </pre>
|
||||
*/
|
||||
public class OrcidIntegrationController extends FreemarkerHttpServlet {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidIntegrationController.class);
|
||||
|
||||
private final static String PATHINFO_CALLBACK = "/callback";
|
||||
private final static String PATHINFO_AUTH_AUTHENTICATE = "/getAuthticateAuth";
|
||||
private final static String PATHINFO_READ_PROFILE = "/readProfile";
|
||||
private final static String PATHINFO_AUTH_EXTERNAL_ID = "/authExternalId";
|
||||
private final static String PATHINFO_ADD_EXTERNAL_ID = "/addExternalId";
|
||||
|
||||
public final static String PATH_DEFAULT = "orcid";
|
||||
|
||||
final static String PATH_AUTH_AUTHENTICATE = path(PATHINFO_AUTH_AUTHENTICATE);
|
||||
final static String PATH_READ_PROFILE = path(PATHINFO_READ_PROFILE);
|
||||
final static String PATH_AUTH_EXTERNAL_ID = path(PATHINFO_AUTH_EXTERNAL_ID);
|
||||
final static String PATH_ADD_EXTERNAL_ID = path(PATHINFO_ADD_EXTERNAL_ID);
|
||||
|
||||
static String path(String pathInfo) {
|
||||
return PATH_DEFAULT + pathInfo;
|
||||
}
|
||||
|
||||
final static String TEMPLATE_CONFIRM = "orcidConfirm.ftl";
|
||||
|
||||
public static final String PROPERTY_EXTERNAL_ID_COMMON_NAME = "orcid.externalIdCommonName";
|
||||
public static final String DEFAULT_EXTERNAL_ID_COMMON_NAME = "VIVO Identifier";
|
||||
|
||||
/**
|
||||
* Get in before FreemarkerHttpServlet for special handling.
|
||||
*/
|
||||
@Override
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws IOException, ServletException {
|
||||
if (!isOrcidConfigured()) {
|
||||
show404NotFound(resp);
|
||||
}
|
||||
if (PATHINFO_CALLBACK.equals(req.getPathInfo())) {
|
||||
new OrcidCallbackHandler(req, resp).exec();
|
||||
} else {
|
||||
super.doGet(req, resp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We return AUTHORIZED here, but we want the LogoutRedirector to know that
|
||||
* the user should not remain on this page after logging out.
|
||||
*/
|
||||
@Override
|
||||
protected AuthorizationRequest requiredActions(VitroRequest vreq) {
|
||||
LogoutRedirector.recordRestrictedPageUri(vreq);
|
||||
return AuthorizationRequest.AUTHORIZED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the path info and delegate to a handler.
|
||||
*/
|
||||
@Override
|
||||
protected ResponseValues processRequest(VitroRequest vreq) throws Exception {
|
||||
try {
|
||||
String pathInfo = vreq.getPathInfo();
|
||||
log.debug("Path info: " + pathInfo);
|
||||
if (PATHINFO_AUTH_AUTHENTICATE.equals(pathInfo)) {
|
||||
return new OrcidAuthAuthenticateHandler(vreq).exec();
|
||||
} else if (PATHINFO_READ_PROFILE.equals(pathInfo)) {
|
||||
return new OrcidReadProfileHandler(vreq).exec();
|
||||
} else if (PATHINFO_AUTH_EXTERNAL_ID.equals(pathInfo)) {
|
||||
return new OrcidAuthExternalIdsHandler(vreq).exec();
|
||||
} else if (PATHINFO_ADD_EXTERNAL_ID.equals(pathInfo)) {
|
||||
return new OrcidAddExternalIdHandler(vreq).exec();
|
||||
} else {
|
||||
return new OrcidDefaultHandler(vreq).exec();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return new ExceptionResponseValues(e, SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the ORCID interface is configured, it should not throw an exception
|
||||
* when asked for the value of a setting.
|
||||
*/
|
||||
private boolean isOrcidConfigured() {
|
||||
try {
|
||||
OrcidClientContext.getInstance().getSetting(Setting.CLIENT_ID);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void show404NotFound(HttpServletResponse resp) throws IOException {
|
||||
resp.sendError(SC_NOT_FOUND);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vivo.orcid.controller;
|
||||
|
||||
import static edu.cornell.mannlib.orcidclient.actions.ApiAction.AUTHENTICATE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.DENIED_AUTHENTICATE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.FAILED_AUTHENTICATE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.GOT_PROFILE;
|
||||
import static edu.cornell.mannlib.vivo.orcid.controller.OrcidConfirmationState.Progress.ID_ALREADY_PRESENT;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import edu.cornell.mannlib.orcidclient.OrcidClientException;
|
||||
import edu.cornell.mannlib.orcidclient.actions.ReadPublicBioAction;
|
||||
import edu.cornell.mannlib.orcidclient.auth.AuthorizationStatus;
|
||||
import edu.cornell.mannlib.orcidclient.orcidmessage.OrcidMessage;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
|
||||
|
||||
/**
|
||||
* We should now know the user's ORCID, so read the user's public ORCID profile.
|
||||
*/
|
||||
public class OrcidReadProfileHandler extends OrcidAbstractHandler {
|
||||
private static final Log log = LogFactory
|
||||
.getLog(OrcidReadProfileHandler.class);
|
||||
|
||||
private AuthorizationStatus status;
|
||||
private OrcidMessage profile;
|
||||
|
||||
protected OrcidReadProfileHandler(VitroRequest vreq) {
|
||||
super(vreq);
|
||||
}
|
||||
|
||||
public ResponseValues exec() throws OrcidClientException {
|
||||
status = auth.getAuthorizationStatus(AUTHENTICATE);
|
||||
if (status.isSuccess()) {
|
||||
readProfile();
|
||||
state.progress(GOT_PROFILE, profile);
|
||||
|
||||
recordConfirmation();
|
||||
|
||||
if (state.getVivoId() != null) {
|
||||
state.progress(ID_ALREADY_PRESENT);
|
||||
}
|
||||
|
||||
return showConfirmationPage();
|
||||
} else if (status.isDenied()) {
|
||||
return showConfirmationPage(DENIED_AUTHENTICATE);
|
||||
} else {
|
||||
return showConfirmationPage(FAILED_AUTHENTICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void readProfile() throws OrcidClientException {
|
||||
profile = new ReadPublicBioAction().execute(status.getAccessToken()
|
||||
.getOrcid());
|
||||
log.debug("Read profile");
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue