Skip to content

Commit

Permalink
IQSS#5991. Refactor ORCID provider to use current ScribeJava lib. Ref…
Browse files Browse the repository at this point in the history
…actor base class to avoid code duplication when generating the user record.
  • Loading branch information
poikilotherm committed Jul 5, 2019
1 parent 1a4e449 commit 26af35e
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo;
import edu.harvard.iq.dataverse.authorization.AuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.AuthenticationProviderDisplayInfo;
import edu.harvard.iq.dataverse.util.BundleUtil;

import javax.validation.constraints.NotNull;
import java.io.IOException;
Expand Down Expand Up @@ -127,28 +128,47 @@ public OAuth2UserRecord getUserRecord(String code, @NotNull OAuth20Service servi
throws IOException, OAuth2Exception, InterruptedException, ExecutionException {

OAuth2AccessToken accessToken = service.getAccessToken(code);
String userEndpoint = getUserEndpoint(accessToken);

if ( ! accessToken.getScope().contains(scope) ) {
// We did not get the permissions on the scope we need. Abort and inform the user.
throw new OAuth2Exception(200, BundleUtil.getStringFromBundle("auth.providers.orcid.insufficientScope"), "");
}

OAuthRequest request = new OAuthRequest(Verb.GET, userEndpoint);
OAuthRequest request = new OAuthRequest(Verb.GET, getUserEndpoint(accessToken));
request.setCharset("UTF-8");
service.signRequest(accessToken, request);

Response response = service.execute(request);
int responseCode = response.getCode();
String body = response.getBody();
logger.log(Level.FINE, "In getUserRecord. Body: {0}", body);

if ( responseCode == 200 ) {
final ParsedUserResponse parsed = parseUserResponse(body);
return new OAuth2UserRecord(getId(), parsed.userIdInProvider,
parsed.username,
OAuth2TokenData.from(accessToken),
parsed.displayInfo,
parsed.emails);
logger.log(Level.FINE, "In requestUserRecord. Body: {0}", body);
if ( responseCode == 200 && body != null ) {
return getUserRecord(body, accessToken, service);
} else {
throw new OAuth2Exception(responseCode, body, "Error getting the user info record.");
}
}

/**
* Get the user record from the response body.
* Might be overriden by subclasses to add information from the access token response not included
* within the request response body.
* @param accessToken Access token used to create the request
* @param responseBody The response body = message from provider
* @param service Not used in base class, but may be used in overrides to lookup more data
* @return A complete record to be forwarded to user handling logic
* @throws OAuth2Exception When some lookup fails in overrides
*/
protected OAuth2UserRecord getUserRecord(@NotNull String responseBody, @NotNull OAuth2AccessToken accessToken, @NotNull OAuth20Service service)
throws OAuth2Exception {

final ParsedUserResponse parsed = parseUserResponse(responseBody);
return new OAuth2UserRecord(getId(), parsed.userIdInProvider,
parsed.username,
OAuth2TokenData.from(accessToken),
parsed.displayInfo,
parsed.emails);
}

@Override
public boolean isUserInfoUpdateAllowed() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@
import edu.harvard.iq.dataverse.util.BundleUtil;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
Expand All @@ -29,6 +26,7 @@
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.validation.constraints.NotNull;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
Expand Down Expand Up @@ -78,42 +76,31 @@ public DefaultApi20 getApiInstance() {
}

@Override
public OAuth2UserRecord getUserRecord(String code, String state, String redirectUrl) throws IOException, OAuth2Exception {
OAuth20Service service = getService(state, redirectUrl);
OAuth2AccessToken accessToken = service.getAccessToken(code);
final protected OAuth2UserRecord getUserRecord(@NotNull String responseBody, @NotNull OAuth2AccessToken accessToken, @NotNull OAuth20Service service)
throws OAuth2Exception {

if ( ! accessToken.getScope().contains(scope) ) {
// We did not get the permissions on the scope we need. Abort and inform the user.
throw new OAuth2Exception(200, BundleUtil.getStringFromBundle("auth.providers.orcid.insufficientScope"), "");
// parse the main response
final ParsedUserResponse parsed = parseUserResponse(responseBody);

// mixin org data, but optional
try {
Optional<AuthenticatedUserDisplayInfo> orgData = getOrganizationalData(accessToken, service);
if (orgData.isPresent()) {
parsed.displayInfo.setAffiliation(orgData.get().getAffiliation());
parsed.displayInfo.setPosition(orgData.get().getPosition());
}
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not get affiliation data from ORCiD due to an IO problem: {0}", ex.getLocalizedMessage());
}

// mixin ORCiD not present in main response
String orcidNumber = extractOrcidNumber(accessToken.getRawResponse());

final String userEndpoint = getUserEndpoint(accessToken);

final OAuthRequest request = new OAuthRequest(Verb.GET, userEndpoint, service);
request.addHeader("Authorization", "Bearer " + accessToken.getAccessToken());
request.setCharset("UTF-8");

final Response response = request.send();
int responseCode = response.getCode();
final String body = response.getBody();
logger.log(Level.FINE, "In getUserRecord. Body: {0}", body);

if ( responseCode == 200 ) {
final ParsedUserResponse parsed = parseUserResponse(body);
AuthenticatedUserDisplayInfo orgData = getOrganizationalData(userEndpoint, accessToken.getAccessToken(), service);
parsed.displayInfo.setAffiliation(orgData.getAffiliation());
parsed.displayInfo.setPosition(orgData.getPosition());

return new OAuth2UserRecord(getId(), orcidNumber,
parsed.username,
OAuth2TokenData.from(accessToken),
parsed.displayInfo,
parsed.emails);
} else {
throw new OAuth2Exception(responseCode, body, "Error getting the user info record.");
}

return new OAuth2UserRecord(getId(), orcidNumber,
parsed.username,
OAuth2TokenData.from(accessToken),
parsed.displayInfo,
parsed.emails);
}

@Override
Expand Down Expand Up @@ -280,23 +267,29 @@ protected String extractOrcidNumber( String rawResponse ) throws OAuth2Exception
}
}

protected AuthenticatedUserDisplayInfo getOrganizationalData(String userEndpoint, String accessToken, OAuth20Service service) throws IOException {
final OAuthRequest request = new OAuthRequest(Verb.GET, userEndpoint.replace("/person", "/employments"), service);
request.addHeader("Authorization", "Bearer " + accessToken);
request.setCharset("UTF-8");
protected Optional<AuthenticatedUserDisplayInfo> getOrganizationalData(OAuth2AccessToken accessToken, OAuth20Service service) throws IOException {

final Response response = request.send();
int responseCode = response.getCode();
final String responseBody = response.getBody();
OAuthRequest request = new OAuthRequest(Verb.GET, getUserEndpoint(accessToken).replace("/person", "/employments"));
request.setCharset("UTF-8");
service.signRequest(accessToken, request);

if ( responseCode != 200 ) {
// This is bad, but not bad enough to stop a signup/in process.
logger.log(Level.WARNING, "Cannot get affiliation data from ORCiD. Response code: {0} body:\n{1}\n/body",
new Object[]{responseCode, responseBody});
return null;

} else {
return parseActivitiesResponse(responseBody);
try {
Response response = service.execute(request);
int responseCode = response.getCode();
String responseBody = response.getBody();

if (responseCode != 200 && responseBody != null) {
// This is bad, but not bad enough to stop a signup/in process.
logger.log(Level.WARNING, "Cannot get affiliation data from ORCiD. Response code: {0} body:\n{1}\n/body",
new Object[]{responseCode, responseBody});
return Optional.empty();

} else {
return Optional.of(parseActivitiesResponse(responseBody));
}
} catch (InterruptedException | ExecutionException ex) {
logger.log(Level.WARNING, "Could not get affiliation data from ORCiD due to threading problems.");
return Optional.empty();
}
}

Expand Down

0 comments on commit 26af35e

Please sign in to comment.