From 7a1bc4373cccb8004d2160045974662378fd834f Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Thu, 19 Oct 2017 18:17:12 -0400 Subject: [PATCH 01/38] put existing response text into files to allow validation --- .../oauth2/impl/OrcidOAuth2APTest.java | 51 ++++++++++++++-- .../xml/oauth2/orcid/v12_no_email.xml | 28 +++++++++ .../xml/oauth2/orcid/v12_no_email_has_aff.xml | 59 +++++++++++++++++++ .../xml/oauth2/orcid/v12_response.xml | 32 ++++++++++ 4 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/xml/oauth2/orcid/v12_no_email.xml create mode 100644 src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml create mode 100644 src/test/resources/xml/oauth2/orcid/v12_response.xml diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index 80a94f16a75..622e7a7afdd 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -5,14 +5,18 @@ import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import org.junit.Test; +import org.junit.Before; /** * * @author michael */ public class OrcidOAuth2APTest extends OrcidOAuth2AP { - + private final String response_file="src/test/resources/xml/oauth2/orcid/v12_response.xml"; + private static String RESPONSE = null; + /* private static final String RESPONSE = "\n" + "\n" @@ -46,7 +50,10 @@ public class OrcidOAuth2APTest extends OrcidOAuth2AP { + " \n" + " \n" + ""; - + */ + private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml"; + private static String NO_EMAIL_HAS_AFFILIATION = null; + /* private final String NO_EMAIL_HAS_AFFILIATION = "\n" + "\n" + " 1.2\n" @@ -106,14 +113,47 @@ public class OrcidOAuth2APTest extends OrcidOAuth2AP { + " \n" + " \n" + ""; + */ + private final String no_email_file="src/test/resources/xml/oauth2/orcid/v12_no_email.xml"; + private static String NO_EMAIL = null; public OrcidOAuth2APTest() { super("", "", ""); } + + + @Before + public void setUp() + { + RESPONSE = loadResponseXML( response_file ); + NO_EMAIL_HAS_AFFILIATION = loadResponseXML( no_email_has_affiliation_file ); + NO_EMAIL = loadResponseXML( no_email_file ); + } + /** + * load XML responses from filesystem (resources). + * Why? To allow validating against the XSD prior to 1.2 -> 2.0 upgrade + */ + private static String loadResponseXML(String fname) + { + String txt = null; + try + { + java.io.File inp = new java.io.File( fname ); + //java.io.InputStream inp = new java.io.FileInputStream( new java.io.File( fname ) ); + txt = org.apache.commons.io.FileUtils.readFileToString( inp ); + } + catch( java.io.IOException ie ) + { + // no-op; assert that the needed strings are not null in tests + } + return txt; + } + @Test public void testParseUserResponse() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); + assertNotNull( RESPONSE ); System.out.println("withEmailResponse = " + RESPONSE); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(RESPONSE); @@ -131,6 +171,7 @@ public void testParseUserResponse() { @Test public void testParseUserResponseNoEmailHasAffiliation() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); + assertNotNull( NO_EMAIL_HAS_AFFILIATION ); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL_HAS_AFFILIATION); assertEquals("0000-0002-3283-0661", actual.userIdInProvider); @@ -148,9 +189,9 @@ public void testParseUserResponseNoEmailHasAffiliation() { @Test public void testParseUserResponse_noEmails() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); - String noEmailResponse = RESPONSE.replaceAll(".*", ""); - System.out.println("noEmailResponse = " + noEmailResponse); - final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(noEmailResponse); + assertNotNull( NO_EMAIL ); + System.out.println("noEmailResponse = " + NO_EMAIL ); + final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL); assertEquals("0000-0002-3283-0661", actual.userIdInProvider); assertEquals("Pete.Dataversky", actual.username); diff --git a/src/test/resources/xml/oauth2/orcid/v12_no_email.xml b/src/test/resources/xml/oauth2/orcid/v12_no_email.xml new file mode 100644 index 00000000000..0a82ccda355 --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v12_no_email.xml @@ -0,0 +1,28 @@ + + + 1.2 + + + http://sandbox.orcid.org/0000-0002-3283-0661 + 0000-0002-3283-0661 + sandbox.orcid.org + + + en + + + Member-referred + 2016-10-12T21:59:25.760Z + 2016-10-16T21:11:33.032Z + true + false + false + + + + Pete K. + Dataversky + + + + diff --git a/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml b/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml new file mode 100644 index 00000000000..a852aa3acab --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml @@ -0,0 +1,59 @@ + + + 1.2 + + + http://orcid.org/0000-0002-3283-0661 + 0000-0002-3283-0661 + orcid.org + + + en + + + Direct + 2015-11-30T23:14:04.260Z + 2016-12-13T19:45:57.958Z + true + true + true + + + + Pete K. + Dataversky + + + + + + employment + BCMP + + Harvard Medical School +
+ Boston + MA + US +
+ + 1811 + RINGGOLD + +
+ + + http://orcid.org/0000-0002-3283-0661 + 0000-0002-3283-0661 + orcid.org + + Pete K. Dataversky + 2015-11-30T23:18:22.764Z + + 2015-11-30T23:18:22.764Z + 2016-05-07T02:26:10.970Z +
+
+
+
+
diff --git a/src/test/resources/xml/oauth2/orcid/v12_response.xml b/src/test/resources/xml/oauth2/orcid/v12_response.xml new file mode 100644 index 00000000000..e94f8921fcb --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v12_response.xml @@ -0,0 +1,32 @@ + + + 1.2 + + + http://sandbox.orcid.org/0000-0002-3283-0661 + 0000-0002-3283-0661 + sandbox.orcid.org + + + en + + + Member-referred + 2016-10-12T21:59:25.760Z + 2016-10-16T21:11:33.032Z + true + false + false + + + + Pete K. + Dataversky + + + pete2@mailinator.com + pete@mailinator.com + " + + + From 64f2e7289ad379cf9309ccd96ffd098bcf243dce Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Thu, 19 Oct 2017 18:48:41 -0400 Subject: [PATCH 02/38] fix typo so response text validates vs orcid-messages-1.2.xsd --- src/test/resources/xml/oauth2/orcid/v12_response.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/xml/oauth2/orcid/v12_response.xml b/src/test/resources/xml/oauth2/orcid/v12_response.xml index e94f8921fcb..c030a6062f7 100644 --- a/src/test/resources/xml/oauth2/orcid/v12_response.xml +++ b/src/test/resources/xml/oauth2/orcid/v12_response.xml @@ -26,7 +26,7 @@ pete2@mailinator.com pete@mailinator.com - " + From 0ed400ae89bf2e5d20da817adfed30081704537c Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:28:23 -0400 Subject: [PATCH 03/38] temporarilly checking v1.2 vs v2.0 API responses --- src/test/resources/xml/oauth2/orcid/v12_3.xml | 61 ++++++++++++++ src/test/resources/xml/oauth2/orcid/v20_3.xml | 83 +++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 src/test/resources/xml/oauth2/orcid/v12_3.xml create mode 100644 src/test/resources/xml/oauth2/orcid/v20_3.xml diff --git a/src/test/resources/xml/oauth2/orcid/v12_3.xml b/src/test/resources/xml/oauth2/orcid/v12_3.xml new file mode 100644 index 00000000000..cb901fa3267 --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v12_3.xml @@ -0,0 +1,61 @@ + + + 1.2 + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + + en + + + Direct + 2017-08-08T16:49:27.162Z + 2017-10-20T16:22:41.922Z + true + true + true + + + + Bob + Doc + + + bdoc@mailinator.com + + + + + + employment + + 2017 + 10 + 31 + + + Miskatonic University +
+ Arkham + US +
+
+ + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + Bob Doc + 2017-10-20T16:20:46.204Z + + 2017-10-20T16:20:46.204Z + 2017-10-20T16:20:46.204Z +
+
+
+
+
diff --git a/src/test/resources/xml/oauth2/orcid/v20_3.xml b/src/test/resources/xml/oauth2/orcid/v20_3.xml new file mode 100644 index 00000000000..3ea15c62b77 --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v20_3.xml @@ -0,0 +1,83 @@ + + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + + en + + + Direct + 2017-08-08T16:49:27.162Z + 2017-10-20T16:22:41.922Z + true + true + true + + + 2017-08-08T16:50:43.585Z + + 2017-08-08T16:49:27.162Z + 2017-08-08T16:49:27.421Z + Bob + Doc + + + + + 2017-08-08T16:50:43.585Z + + 2017-08-08T16:49:27.420Z + 2017-08-08T16:50:43.585Z + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + Bob Doc + + bdoc@mailinator.com + + + + + + + + 2017-10-20T16:20:46.204Z + + + 2017-10-20T16:20:46.204Z + + 2017-10-20T16:20:46.204Z + 2017-10-20T16:20:46.204Z + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + Bob Doc + + + 2017 + 10 + 31 + + + Miskatonic University + + Arkham + US + + + + + + + + + From 63f97dd2d300a234d1f4023a4d3d49be29acc5e7 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:38:58 -0400 Subject: [PATCH 04/38] remove commented-out strings (in files now) --- .../oauth2/impl/OrcidOAuth2APTest.java | 97 ------------------- .../xml/oauth2/orcid/v20_response.xml | 62 ++++++++++++ 2 files changed, 62 insertions(+), 97 deletions(-) create mode 100644 src/test/resources/xml/oauth2/orcid/v20_response.xml diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index 622e7a7afdd..2fd3b795f59 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -16,105 +16,8 @@ public class OrcidOAuth2APTest extends OrcidOAuth2AP { private final String response_file="src/test/resources/xml/oauth2/orcid/v12_response.xml"; private static String RESPONSE = null; - /* - private static final String RESPONSE - = "\n" - + "\n" - + " 1.2\n" - + " \n" - + " \n" - + " http://sandbox.orcid.org/0000-0002-3283-0661\n" - + " 0000-0002-3283-0661\n" - + " sandbox.orcid.org\n" - + " \n" - + " \n" - + " en\n" - + " \n" - + " \n" - + " Member-referred\n" - + " 2016-10-12T21:59:25.760Z\n" - + " 2016-10-16T21:11:33.032Z\n" - + " true\n" - + " false\n" - + " false\n" - + " \n" - + " \n" - + " \n" - + " Pete K.\n" - + " Dataversky\n" - + " \n" - + " " - + " pete2@mailinator.com" - + " pete@mailinator.com" - + " " - + " \n" - + " \n" - + ""; - */ private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml"; private static String NO_EMAIL_HAS_AFFILIATION = null; - /* - private final String NO_EMAIL_HAS_AFFILIATION = "\n" - + "\n" - + " 1.2\n" - + " \n" - + " \n" - + " http://orcid.org/0000-0002-3283-0661\n" - + " 0000-0002-3283-0661\n" - + " orcid.org\n" - + " \n" - + " \n" - + " en\n" - + " \n" - + " \n" - + " Direct\n" - + " 2015-11-30T23:14:04.260Z\n" - + " 2016-12-13T19:45:57.958Z\n" - + " true\n" - + " true\n" - + " true\n" - + " \n" - + " \n" - + " \n" - + " Pete K.\n" - + " Dataversky\n" - + " \n" - + " \n" - + " \n" - + " \n" - + " \n" - + " employment\n" - + " BCMP\n" - + " \n" - + " Harvard Medical School\n" - + "
\n" - + " Boston\n" - + " MA\n" - + " US\n" - + "
\n" - + " \n" - + " 1811\n" - + " RINGGOLD\n" - + " \n" - + "
\n" - + " \n" - + " \n" - + " http://orcid.org/0000-0002-3283-0661\n" - + " 0000-0002-3283-0661\n" - + " orcid.org\n" - + " \n" - + " Pete K. Dataversky\n" - + " 2015-11-30T23:18:22.764Z\n" - + " \n" - + " 2015-11-30T23:18:22.764Z\n" - + " 2016-05-07T02:26:10.970Z\n" - + "
\n" - + "
\n" - + "
\n" - + "
\n" - + "
"; - */ - private final String no_email_file="src/test/resources/xml/oauth2/orcid/v12_no_email.xml"; private static String NO_EMAIL = null; public OrcidOAuth2APTest() { diff --git a/src/test/resources/xml/oauth2/orcid/v20_response.xml b/src/test/resources/xml/oauth2/orcid/v20_response.xml new file mode 100644 index 00000000000..0e8741aeabf --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v20_response.xml @@ -0,0 +1,62 @@ + + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + + en + + + Direct + 2017-08-08T16:49:27.162Z + 2017-10-20T16:22:41.922Z + true + true + true + + + 2017-08-08T16:50:43.585Z + + 2017-08-08T16:49:27.162Z + 2017-08-08T16:49:27.421Z + Bob T. + Doc + + + + + 2017-08-08T16:50:43.585Z + + 2017-08-08T16:49:27.420Z + 2017-08-08T16:50:43.585Z + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + Bob T. Doc + + bdoc@mailinator.com + + + 2017-08-08T16:49:27.420Z + 2017-08-08T16:50:43.585Z + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + Bob T. Doc + + bdoc2@mailinator.com + + + + + + + From f62bf06cd66b657df8f25e10f20c60e8f56d6965 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:39:21 -0400 Subject: [PATCH 05/38] remove commented-out strings (in files now) --- src/test/resources/xml/oauth2/orcid/v12_response.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/resources/xml/oauth2/orcid/v12_response.xml b/src/test/resources/xml/oauth2/orcid/v12_response.xml index c030a6062f7..0971b5f10d7 100644 --- a/src/test/resources/xml/oauth2/orcid/v12_response.xml +++ b/src/test/resources/xml/oauth2/orcid/v12_response.xml @@ -3,8 +3,8 @@ 1.2 - http://sandbox.orcid.org/0000-0002-3283-0661 - 0000-0002-3283-0661 + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 sandbox.orcid.org @@ -20,12 +20,12 @@ - Pete K. - Dataversky + Bob T. + Doc - pete2@mailinator.com - pete@mailinator.com + bdoc2@mailinator.com + bdoc@mailinator.com From 2d450b9760f0a868c88bd990e68e407b11ed74d3 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:45:20 -0400 Subject: [PATCH 06/38] update first test --- .../providers/oauth2/impl/OrcidOAuth2APTest.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index 2fd3b795f59..4d4ec80a0c5 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -60,14 +60,15 @@ public void testParseUserResponse() { System.out.println("withEmailResponse = " + RESPONSE); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(RESPONSE); - assertEquals("0000-0002-3283-0661", actual.userIdInProvider); - assertEquals("pete", actual.username); - assertEquals("Pete K.", actual.displayInfo.getFirstName()); - assertEquals("Dataversky", actual.displayInfo.getLastName()); - assertEquals("pete@mailinator.com", actual.displayInfo.getEmailAddress()); + assertEquals("0000-0003-2591-1698", actual.userIdInProvider); + //assertEquals("bob", actual.username); + assertEquals("bdoc", actual.username); + assertEquals("Bob T.", actual.displayInfo.getFirstName()); + assertEquals("Doc", actual.displayInfo.getLastName()); + assertEquals("bdoc@mailinator.com", actual.displayInfo.getEmailAddress()); assertEquals("", actual.displayInfo.getAffiliation()); assertEquals("", actual.displayInfo.getPosition()); - assertEquals(Arrays.asList("pete@mailinator.com", "pete2@mailinator.com"), actual.emails); + assertEquals(Arrays.asList("bdoc@mailinator.com", "bdoc2@mailinator.com"), actual.emails); } From c877b500ffd3fcf9d705cd14539be5b14060ea84 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:50:52 -0400 Subject: [PATCH 07/38] update second test --- .../oauth2/impl/OrcidOAuth2APTest.java | 10 ++++---- .../xml/oauth2/orcid/v12_no_email_has_aff.xml | 23 ++++++++----------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index 4d4ec80a0c5..167a44a3e2f 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -78,15 +78,15 @@ public void testParseUserResponseNoEmailHasAffiliation() { assertNotNull( NO_EMAIL_HAS_AFFILIATION ); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL_HAS_AFFILIATION); - assertEquals("0000-0002-3283-0661", actual.userIdInProvider); - assertEquals("Pete K.", actual.displayInfo.getFirstName()); - assertEquals("Dataversky", actual.displayInfo.getLastName()); + assertEquals("0000-0003-2591-1698", actual.userIdInProvider); + assertEquals("Bob T.", actual.displayInfo.getFirstName()); + assertEquals("Doc", actual.displayInfo.getLastName()); assertEquals("", actual.displayInfo.getEmailAddress()); - assertEquals("Harvard Medical School", actual.displayInfo.getAffiliation()); + assertEquals("Miskatonic University", actual.displayInfo.getAffiliation()); assertEquals("", actual.displayInfo.getPosition()); List emptyList = new ArrayList<>(); assertEquals(emptyList, actual.emails); - assertEquals("Pete.Dataversky", actual.username); + assertEquals("Bob.Doc", actual.username); } diff --git a/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml b/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml index a852aa3acab..e6924b97235 100644 --- a/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml +++ b/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml @@ -3,8 +3,8 @@ 1.2 - http://orcid.org/0000-0002-3283-0661 - 0000-0002-3283-0661 + http://orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 orcid.org @@ -20,34 +20,29 @@ - Pete K. - Dataversky + Bob T. + Doc employment - BCMP - Harvard Medical School + Miskatonic University
- Boston + Arkham MA US
- - 1811 - RINGGOLD -
- http://orcid.org/0000-0002-3283-0661 - 0000-0002-3283-0661 + http://orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 orcid.org - Pete K. Dataversky + Bob T. Doc 2015-11-30T23:18:22.764Z 2015-11-30T23:18:22.764Z From 8249e38bb74d45dc8d00b30b468a7c952f152127 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:53:43 -0400 Subject: [PATCH 08/38] update third test (ready for 1.2->2.0 switch) --- .../providers/oauth2/impl/OrcidOAuth2APTest.java | 8 ++++---- src/test/resources/xml/oauth2/orcid/v12_no_email.xml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index 167a44a3e2f..0966474b17b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -97,10 +97,10 @@ public void testParseUserResponse_noEmails() { System.out.println("noEmailResponse = " + NO_EMAIL ); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL); - assertEquals("0000-0002-3283-0661", actual.userIdInProvider); - assertEquals("Pete.Dataversky", actual.username); - assertEquals("Pete K.", actual.displayInfo.getFirstName()); - assertEquals("Dataversky", actual.displayInfo.getLastName()); + assertEquals("0000-0003-2591-1698", actual.userIdInProvider); + assertEquals("Bob.Doc", actual.username); + assertEquals("Bob T.", actual.displayInfo.getFirstName()); + assertEquals("Doc", actual.displayInfo.getLastName()); assertEquals("", actual.displayInfo.getEmailAddress()); assertEquals("", actual.displayInfo.getAffiliation()); assertEquals("", actual.displayInfo.getPosition()); diff --git a/src/test/resources/xml/oauth2/orcid/v12_no_email.xml b/src/test/resources/xml/oauth2/orcid/v12_no_email.xml index 0a82ccda355..2b4f42901ea 100644 --- a/src/test/resources/xml/oauth2/orcid/v12_no_email.xml +++ b/src/test/resources/xml/oauth2/orcid/v12_no_email.xml @@ -3,8 +3,8 @@ 1.2 - http://sandbox.orcid.org/0000-0002-3283-0661 - 0000-0002-3283-0661 + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 sandbox.orcid.org @@ -20,8 +20,8 @@ - Pete K. - Dataversky + Bob T. + Doc From 37a6d1b56f8a18d4e78c130f7edf32754bc1a3f1 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 12:59:14 -0400 Subject: [PATCH 09/38] data for no email test --- .../xml/oauth2/orcid/v20_no_email.xml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/resources/xml/oauth2/orcid/v20_no_email.xml diff --git a/src/test/resources/xml/oauth2/orcid/v20_no_email.xml b/src/test/resources/xml/oauth2/orcid/v20_no_email.xml new file mode 100644 index 00000000000..76137f3bffd --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v20_no_email.xml @@ -0,0 +1,34 @@ + + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + + en + + + Direct + 2017-08-08T16:49:27.162Z + 2017-10-20T16:22:41.922Z + true + true + true + + + 2017-08-08T16:50:43.585Z + + 2017-08-08T16:49:27.162Z + 2017-08-08T16:49:27.421Z + Bob + Doc + + + + + + + + + From 6cc56c49a26db5c912359f6e3e0e1037398d5e20 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 13:00:52 -0400 Subject: [PATCH 10/38] last v2 test file (first was previously added with incorrect commit message) --- .../xml/oauth2/orcid/v20_no_email_has_aff.xml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml diff --git a/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml b/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml new file mode 100644 index 00000000000..eb22b201f80 --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml @@ -0,0 +1,68 @@ + + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + + en + + + Direct + 2017-08-08T16:49:27.162Z + 2017-10-20T16:22:41.922Z + true + true + true + + + 2017-08-08T16:50:43.585Z + + 2017-08-08T16:49:27.162Z + 2017-08-08T16:49:27.421Z + Bob + Doc + + + + + + + + + + 2017-10-20T16:20:46.204Z + + + 2017-10-20T16:20:46.204Z + + 2017-10-20T16:20:46.204Z + 2017-10-20T16:20:46.204Z + + + http://sandbox.orcid.org/0000-0003-2591-1698 + 0000-0003-2591-1698 + sandbox.orcid.org + + Bob Doc + + + 2017 + 10 + 31 + + + Miskatonic University + + Arkham + US + + + + + + + + + From 34164a93797e07826296e7714df913f61b1a4236 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 14:24:54 -0400 Subject: [PATCH 11/38] update test data (forgot middle initial for user) --- src/test/resources/xml/oauth2/orcid/v20_no_email.xml | 2 +- src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/xml/oauth2/orcid/v20_no_email.xml b/src/test/resources/xml/oauth2/orcid/v20_no_email.xml index 76137f3bffd..4df340ca5ea 100644 --- a/src/test/resources/xml/oauth2/orcid/v20_no_email.xml +++ b/src/test/resources/xml/oauth2/orcid/v20_no_email.xml @@ -21,7 +21,7 @@ 2017-08-08T16:49:27.162Z 2017-08-08T16:49:27.421Z - Bob + Bob T. Doc diff --git a/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml b/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml index eb22b201f80..fc09dfcf8f7 100644 --- a/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml +++ b/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml @@ -21,7 +21,7 @@ 2017-08-08T16:49:27.162Z 2017-08-08T16:49:27.421Z - Bob + Bob T. Doc From f50580f45db772aa441ea279f63e285f0a4a3513 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 14:25:46 -0400 Subject: [PATCH 12/38] start switch --- .../providers/oauth2/impl/OrcidOAuth2AP.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index c56fe77bcf0..b69b8f5f570 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -68,18 +68,22 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { try ( StringReader reader = new StringReader(responseBody)) { DocumentBuilder db = dbFact.newDocumentBuilder(); Document doc = db.parse( new InputSource(reader) ); - List orcidIdNodeList = getNodes(doc, "orcid-message", "orcid-profile","orcid-identifier","path"); + //List orcidIdNodeList = getNodes(doc, "orcid-message", "orcid-profile","orcid-identifier","path"); + List orcidIdNodeList = getNodes(doc, "record:record", "common:orcid-identifier","common:path"); if ( orcidIdNodeList.size() != 1 ) { throw new OAuth2Exception(0, responseBody, "Cannot find ORCiD id in response."); } String orcidId = orcidIdNodeList.get(0).getTextContent().trim(); - String firstName = getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio", "personal-details", "given-names" ) + //String firstName = getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio", "personal-details", "given-names" ) + String firstName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:given-names" ) .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - String familyName = getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio", "personal-details", "family-name" ) + //String familyName = getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio", "personal-details", "family-name" ) + String familyName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:family-name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - String affiliation = getNodes(doc, "orcid-message", "orcid-profile", "orcid-activities", "affiliations", "affiliation", "organization", "name" ) + //String affiliation = getNodes(doc, "orcid-message", "orcid-profile", "orcid-activities", "affiliations", "affiliation", "organization", "name" ) + String affiliation = getNodes(doc, "record:record", "activities:activities-summary", "activities:employments", "employment:employment-summary", "employment:organization", "common:name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); List emails = new ArrayList<>(); From 29507f600d51838243ff201da648b87d6ffe1f02 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 14:52:26 -0400 Subject: [PATCH 13/38] initial switch of test to 2.0 --- .../providers/oauth2/impl/OrcidOAuth2APTest.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index 0966474b17b..589c844f913 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -14,11 +14,14 @@ * @author michael */ public class OrcidOAuth2APTest extends OrcidOAuth2AP { - private final String response_file="src/test/resources/xml/oauth2/orcid/v12_response.xml"; + //private final String response_file="src/test/resources/xml/oauth2/orcid/v12_response.xml"; + private final String response_file="src/test/resources/xml/oauth2/orcid/v20_response.xml"; private static String RESPONSE = null; - private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml"; + //private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml"; + private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml"; private static String NO_EMAIL_HAS_AFFILIATION = null; - private final String no_email_file="src/test/resources/xml/oauth2/orcid/v12_no_email.xml"; + //private final String no_email_file="src/test/resources/xml/oauth2/orcid/v12_no_email.xml"; + private final String no_email_file="src/test/resources/xml/oauth2/orcid/v20_no_email.xml"; private static String NO_EMAIL = null; public OrcidOAuth2APTest() { super("", "", ""); @@ -62,13 +65,14 @@ public void testParseUserResponse() { assertEquals("0000-0003-2591-1698", actual.userIdInProvider); //assertEquals("bob", actual.username); - assertEquals("bdoc", actual.username); + //assertEquals("bdoc", actual.username); + assertEquals("Bob.Doc", actual.username); assertEquals("Bob T.", actual.displayInfo.getFirstName()); assertEquals("Doc", actual.displayInfo.getLastName()); - assertEquals("bdoc@mailinator.com", actual.displayInfo.getEmailAddress()); + assertEquals("bdoc@mailinator.com", actual.displayInfo.getEmailAddress());//FIXME - failing assertEquals("", actual.displayInfo.getAffiliation()); assertEquals("", actual.displayInfo.getPosition()); - assertEquals(Arrays.asList("bdoc@mailinator.com", "bdoc2@mailinator.com"), actual.emails); + assertEquals(Arrays.asList("bdoc@mailinator.com", "bdoc2@mailinator.com"), actual.emails); //FIXME - failing } From e6c56537854f6d5e33ad97d7ee3124a44f80960a Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 15:11:52 -0400 Subject: [PATCH 14/38] primary email only --- .../providers/oauth2/impl/OrcidOAuth2AP.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index b69b8f5f570..0a226c35c74 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -28,6 +28,11 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import javax.xml.xpath.XPathFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; /** * OAuth2 identity provider for ORCiD. Note that ORCiD has two systems: sandbox @@ -87,6 +92,7 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); List emails = new ArrayList<>(); + /* getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio","contact-details","email").forEach( n ->{ String email = n.getTextContent().trim(); Node primaryAtt = n.getAttributes().getNamedItem("primary"); @@ -100,6 +106,12 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { } }); String primaryEmail = (emails.size()>1) ? emails.get(0) : ""; + */ + String primaryEmail = getPrimaryEmail(doc); + if ( "" != primaryEmail ) + { + emails.add( primaryEmail ); + } // make the username up String username; @@ -149,6 +161,32 @@ private List getNodes( Node node, List path ) { .orElse( Collections.emptyList() ); } + } + // xmlstarlet sel -t -c "/record:record/person:person/email:emails/email:email[@primary='true']/email:email" + /** + * retrieve email from ORCID 2.0 response document, or empty string if no primary email is present + */ + private String getPrimaryEmail(Document doc) + { + String xp_pattern = "/record/person/emails/email[@primary='true']/email/text()"; + String primary_email = ""; + XPathFactory xpf = XPathFactory.newInstance(); + XPath xp = xpf.newXPath(); + try + { + XPathExpression srch = xp.compile( xp_pattern ); + NodeList emails = (NodeList) srch.evaluate(doc, XPathConstants.NODESET); + if ( 1 == emails.getLength() ) + { + primary_email = emails.item(0).getTextContent(); + } + // if there are no (or somehow more than 1) primary email(s), then we've already at failure value + } + catch( javax.xml.xpath.XPathExpressionException xpe ) + { + //no-op; already at failure value (and this shouldn't happen with hard-coded xpath expression anyway) + } + return primary_email; } @Override From 1f2220e82f5d06d26e7da7bfc0cfac39638e5abd Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 15:28:01 -0400 Subject: [PATCH 15/38] retrieve multiple emails back again --- .../providers/oauth2/impl/OrcidOAuth2AP.java | 46 ++++++++++++++----- .../oauth2/impl/OrcidOAuth2APTest.java | 8 ++-- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index 0a226c35c74..5c64115852d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -91,7 +91,8 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { String affiliation = getNodes(doc, "record:record", "activities:activities-summary", "activities:employments", "employment:employment-summary", "employment:organization", "common:name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - List emails = new ArrayList<>(); + //List emails = new ArrayList<>(); + List emails = getAllEmails(doc); /* getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio","contact-details","email").forEach( n ->{ String email = n.getTextContent().trim(); @@ -108,10 +109,12 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { String primaryEmail = (emails.size()>1) ? emails.get(0) : ""; */ String primaryEmail = getPrimaryEmail(doc); + /* if ( "" != primaryEmail ) { emails.add( primaryEmail ); } + */ // make the username up String username; @@ -168,25 +171,46 @@ private List getNodes( Node node, List path ) { */ private String getPrimaryEmail(Document doc) { - String xp_pattern = "/record/person/emails/email[@primary='true']/email/text()"; + String p = "/record/person/emails/email[@primary='true']/email/text()"; + NodeList emails = xpath_matches( doc, p ); String primary_email = ""; + if ( 1 == emails.getLength() ) + { + primary_email = emails.item(0).getTextContent(); + } + // if there are no (or somehow more than 1) primary email(s), then we've already at failure value + return primary_email; + } + private List getAllEmails(Document doc) + { + String p = "/record/person/emails/email/email/text()"; + NodeList emails = xpath_matches( doc, p ); + List rs = new ArrayList(); + for(int i=0;i Date: Fri, 20 Oct 2017 15:33:37 -0400 Subject: [PATCH 16/38] clean up --- .../providers/oauth2/impl/OrcidOAuth2AP.java | 35 ++++--------------- .../oauth2/impl/OrcidOAuth2APTest.java | 7 +--- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index 5c64115852d..f50db1e759c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -38,6 +38,7 @@ * OAuth2 identity provider for ORCiD. Note that ORCiD has two systems: sandbox * and production. Hence having the user endpoint as a parameter. * @author michael + * But don't blame michael for pameyer's later changes */ public class OrcidOAuth2AP extends AbstractOAuth2AuthenticationProvider { @@ -73,48 +74,23 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { try ( StringReader reader = new StringReader(responseBody)) { DocumentBuilder db = dbFact.newDocumentBuilder(); Document doc = db.parse( new InputSource(reader) ); - //List orcidIdNodeList = getNodes(doc, "orcid-message", "orcid-profile","orcid-identifier","path"); List orcidIdNodeList = getNodes(doc, "record:record", "common:orcid-identifier","common:path"); if ( orcidIdNodeList.size() != 1 ) { throw new OAuth2Exception(0, responseBody, "Cannot find ORCiD id in response."); } String orcidId = orcidIdNodeList.get(0).getTextContent().trim(); - //String firstName = getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio", "personal-details", "given-names" ) String firstName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:given-names" ) .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - //String familyName = getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio", "personal-details", "family-name" ) String familyName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:family-name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - //String affiliation = getNodes(doc, "orcid-message", "orcid-profile", "orcid-activities", "affiliations", "affiliation", "organization", "name" ) String affiliation = getNodes(doc, "record:record", "activities:activities-summary", "activities:employments", "employment:employment-summary", "employment:organization", "common:name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - //List emails = new ArrayList<>(); - List emails = getAllEmails(doc); - /* - getNodes(doc, "orcid-message", "orcid-profile", "orcid-bio","contact-details","email").forEach( n ->{ - String email = n.getTextContent().trim(); - Node primaryAtt = n.getAttributes().getNamedItem("primary"); - boolean isPrimary = (primaryAtt!=null) && - (primaryAtt.getTextContent()!=null) && - (primaryAtt.getTextContent().trim().toLowerCase().equals("true")); - if ( isPrimary ) { - emails.add(0, email); - } else { - emails.add(email); - } - }); - String primaryEmail = (emails.size()>1) ? emails.get(0) : ""; - */ + //switch to XPath based methods here for (debatable) clarity, and structural changes with email on 1.2 orcid message -> 2.0 orcid response. String primaryEmail = getPrimaryEmail(doc); - /* - if ( "" != primaryEmail ) - { - emails.add( primaryEmail ); - } - */ + List emails = getAllEmails(doc); // make the username up String username; @@ -165,12 +141,12 @@ private List getNodes( Node node, List path ) { } } - // xmlstarlet sel -t -c "/record:record/person:person/email:emails/email:email[@primary='true']/email:email" /** * retrieve email from ORCID 2.0 response document, or empty string if no primary email is present */ private String getPrimaryEmail(Document doc) { + // `xmlstarlet sel -t -c "/record:record/person:person/email:emails/email:email[@primary='true']/email:email"`, if you're curious String p = "/record/person/emails/email[@primary='true']/email/text()"; NodeList emails = xpath_matches( doc, p ); String primary_email = ""; @@ -181,6 +157,9 @@ private String getPrimaryEmail(Document doc) // if there are no (or somehow more than 1) primary email(s), then we've already at failure value return primary_email; } + /** + * retrieve all emails (including primary) from ORCID 2.0 response document + */ private List getAllEmails(Document doc) { String p = "/record/person/emails/email/email/text()"; diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index f87a2eeda21..e134e14065b 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -12,15 +12,13 @@ /** * * @author michael + * later changes by pameyer */ public class OrcidOAuth2APTest extends OrcidOAuth2AP { - //private final String response_file="src/test/resources/xml/oauth2/orcid/v12_response.xml"; private final String response_file="src/test/resources/xml/oauth2/orcid/v20_response.xml"; private static String RESPONSE = null; - //private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml"; private final String no_email_has_affiliation_file="src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml"; private static String NO_EMAIL_HAS_AFFILIATION = null; - //private final String no_email_file="src/test/resources/xml/oauth2/orcid/v12_no_email.xml"; private final String no_email_file="src/test/resources/xml/oauth2/orcid/v20_no_email.xml"; private static String NO_EMAIL = null; public OrcidOAuth2APTest() { @@ -46,7 +44,6 @@ private static String loadResponseXML(String fname) try { java.io.File inp = new java.io.File( fname ); - //java.io.InputStream inp = new java.io.FileInputStream( new java.io.File( fname ) ); txt = org.apache.commons.io.FileUtils.readFileToString( inp ); } catch( java.io.IOException ie ) @@ -64,9 +61,7 @@ public void testParseUserResponse() { final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(RESPONSE); assertEquals("0000-0003-2591-1698", actual.userIdInProvider); - //assertEquals("bob", actual.username); assertEquals("bdoc", actual.username); - //assertEquals("Bob.Doc", actual.username); assertEquals("Bob T.", actual.displayInfo.getFirstName()); assertEquals("Doc", actual.displayInfo.getLastName()); assertEquals("bdoc@mailinator.com", actual.displayInfo.getEmailAddress()); From 4194ad004403fd3e41e97d01e830ae4204b72289 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Fri, 20 Oct 2017 15:59:21 -0400 Subject: [PATCH 17/38] initial (aka - not yet tested) configuration files for ORCID 1.2 -> 2.0 --- .../installation/files/root/auth-providers/orcid-sandbox.json | 2 +- .../_static/installation/files/root/auth-providers/orcid.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid-sandbox.json b/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid-sandbox.json index 61bf7b79c82..79363f4d42f 100644 --- a/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid-sandbox.json +++ b/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid-sandbox.json @@ -3,6 +3,6 @@ "factoryAlias":"oauth2", "title":"ORCID", "subtitle":"", - "factoryData":"type: orcid | userEndpoint: https://api.sandbox.orcid.org/v1.2/{ORCID}/orcid-profile | clientId: FIXME | clientSecret: FIXME", + "factoryData":"type: orcid | userEndpoint: https://api.sandbox.orcid.org/v2.0/{ORCID}/record | clientId: FIXME | clientSecret: FIXME", "enabled":true } diff --git a/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid.json b/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid.json index 0615bacb056..249c4226f25 100644 --- a/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid.json +++ b/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/orcid.json @@ -3,6 +3,6 @@ "factoryAlias":"oauth2", "title":"ORCID", "subtitle":"", - "factoryData":"type: orcid | userEndpoint: https://api.orcid.org/v1.2/{ORCID}/orcid-profile | clientId: FIXME | clientSecret: FIXME", + "factoryData":"type: orcid | userEndpoint: https://api.orcid.org/v2.0/{ORCID}/record | clientId: FIXME | clientSecret: FIXME", "enabled":true } From 6c6d35c5aadedb9803b2ecf81208366ff90568ac Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Mon, 23 Oct 2017 10:42:40 -0400 Subject: [PATCH 18/38] remove template test xml --- src/test/resources/xml/oauth2/orcid/v12_3.xml | 61 -------------- src/test/resources/xml/oauth2/orcid/v20_3.xml | 83 ------------------- 2 files changed, 144 deletions(-) delete mode 100644 src/test/resources/xml/oauth2/orcid/v12_3.xml delete mode 100644 src/test/resources/xml/oauth2/orcid/v20_3.xml diff --git a/src/test/resources/xml/oauth2/orcid/v12_3.xml b/src/test/resources/xml/oauth2/orcid/v12_3.xml deleted file mode 100644 index cb901fa3267..00000000000 --- a/src/test/resources/xml/oauth2/orcid/v12_3.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - 1.2 - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - - en - - - Direct - 2017-08-08T16:49:27.162Z - 2017-10-20T16:22:41.922Z - true - true - true - - - - Bob - Doc - - - bdoc@mailinator.com - - - - - - employment - - 2017 - 10 - 31 - - - Miskatonic University -
- Arkham - US -
-
- - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - Bob Doc - 2017-10-20T16:20:46.204Z - - 2017-10-20T16:20:46.204Z - 2017-10-20T16:20:46.204Z -
-
-
-
-
diff --git a/src/test/resources/xml/oauth2/orcid/v20_3.xml b/src/test/resources/xml/oauth2/orcid/v20_3.xml deleted file mode 100644 index 3ea15c62b77..00000000000 --- a/src/test/resources/xml/oauth2/orcid/v20_3.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - - en - - - Direct - 2017-08-08T16:49:27.162Z - 2017-10-20T16:22:41.922Z - true - true - true - - - 2017-08-08T16:50:43.585Z - - 2017-08-08T16:49:27.162Z - 2017-08-08T16:49:27.421Z - Bob - Doc - - - - - 2017-08-08T16:50:43.585Z - - 2017-08-08T16:49:27.420Z - 2017-08-08T16:50:43.585Z - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - Bob Doc - - bdoc@mailinator.com - - - - - - - - 2017-10-20T16:20:46.204Z - - - 2017-10-20T16:20:46.204Z - - 2017-10-20T16:20:46.204Z - 2017-10-20T16:20:46.204Z - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - Bob Doc - - - 2017 - 10 - 31 - - - Miskatonic University - - Arkham - US - - - - - - - - - From 6efe65176427ceb314732e3a6b267428560b01ff Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Thu, 9 Nov 2017 15:59:56 -0500 Subject: [PATCH 19/38] #4251 - Fix Request Access on File Page --- src/main/java/edu/harvard/iq/dataverse/FilePage.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/edu/harvard/iq/dataverse/FilePage.java b/src/main/java/edu/harvard/iq/dataverse/FilePage.java index 6b156725b90..cc874a6e4a6 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FilePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/FilePage.java @@ -760,5 +760,13 @@ public String getPublicDownloadUrl() { return FileUtil.getPublicDownloadUrl(systemConfig.getDataverseSiteUrl(), fileId); } + + public FileDownloadHelper getFileDownloadHelper() { + return fileDownloadHelper; + } + + public void setFileDownloadHelper(FileDownloadHelper fileDownloadHelper) { + this.fileDownloadHelper = fileDownloadHelper; + } } From 2cb0134f425d1386260aa5184ba4641581cf9be5 Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Thu, 9 Nov 2017 23:37:18 +0200 Subject: [PATCH 20/38] Updates ORCiD sandbox to v2 --- .../{echo.json => base-oauth.json} | 0 .../api/data/authentication-providers/base-oauth2.json | 8 -------- .../api/data/authentication-providers/orcid-sandbox.json | 6 +++--- 3 files changed, 3 insertions(+), 11 deletions(-) rename scripts/api/data/authentication-providers/{echo.json => base-oauth.json} (100%) delete mode 100644 scripts/api/data/authentication-providers/base-oauth2.json diff --git a/scripts/api/data/authentication-providers/echo.json b/scripts/api/data/authentication-providers/base-oauth.json similarity index 100% rename from scripts/api/data/authentication-providers/echo.json rename to scripts/api/data/authentication-providers/base-oauth.json diff --git a/scripts/api/data/authentication-providers/base-oauth2.json b/scripts/api/data/authentication-providers/base-oauth2.json deleted file mode 100644 index 177fd12a023..00000000000 --- a/scripts/api/data/authentication-providers/base-oauth2.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "id":"echo-dignified", - "factoryAlias":"Echo", - "title":"Dignified Echo provider", - "subtitle":"Approves everyone, based on their credentials, and adds some flair", - "factoryData":"Sir,Esq.", - "enabled":true -} diff --git a/scripts/api/data/authentication-providers/orcid-sandbox.json b/scripts/api/data/authentication-providers/orcid-sandbox.json index 7f017add1e6..3a1c311fff4 100644 --- a/scripts/api/data/authentication-providers/orcid-sandbox.json +++ b/scripts/api/data/authentication-providers/orcid-sandbox.json @@ -1,8 +1,8 @@ { - "id":"orcid-sandbox", + "id":"orcid-v2-sandbox", "factoryAlias":"oauth2", "title":"ORCID Sandbox", - "subtitle":"ORCiD - sandbox", - "factoryData":"type: orcid | userEndpoint: https://api.sandbox.orcid.org/v1.2/{ORCID}/orcid-profile | clientId: APP-HIV99BRM37FSWPH6 | clientSecret: ee844b70-f223-4f15-9b6f-4991bf8ed7f0", + "subtitle":"ORCiD - sandbox (v2)", + "factoryData":"type: orcid | userEndpoint: https://api.sandbox.orcid.org/v2.0/{ORCID}/person | clientId: APP-HIV99BRM37FSWPH6 | clientSecret: ee844b70-f223-4f15-9b6f-4991bf8ed7f0", "enabled":true } From 7a2b203cc525ba4aca97f78f20b62ae098c030d8 Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Fri, 10 Nov 2017 10:09:44 +0200 Subject: [PATCH 21/38] Support ORCiD authentication flow ORCiD passes the orcid number at the access token response and not at the user info (which makes sense in the ORCiD context). For Dataverse, though, we need to support this as a special case --- .../edu/harvard/iq/dataverse/LoginPage.java | 2 +- .../AuthenticationServiceBean.java | 38 ++-- .../AbstractOAuth2AuthenticationProvider.java | 6 +- .../oauth2/OAuth2FirstLoginPage.java | 31 ++- .../oauth2/OAuth2LoginBackingBean.java | 3 +- .../providers/oauth2/impl/OrcidApi.java | 2 +- .../providers/oauth2/impl/OrcidOAuth2AP.java | 65 ++++-- .../oauth2/impl/OrcidOAuth2APTest.java | 29 ++- .../xml/oauth2/orcid/v20_response.xml | 196 ++++++++++++------ 9 files changed, 254 insertions(+), 118 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/LoginPage.java b/src/main/java/edu/harvard/iq/dataverse/LoginPage.java index 1f5328f9b35..050044c2e8c 100644 --- a/src/main/java/edu/harvard/iq/dataverse/LoginPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/LoginPage.java @@ -168,7 +168,7 @@ public String login() { } authReq.setIpAddress( dvRequestService.getDataverseRequest().getSourceAddress() ); try { - AuthenticatedUser r = authSvc.authenticate(credentialsAuthProviderId, authReq); + AuthenticatedUser r = authSvc.getCreateAuthenticatedUser(credentialsAuthProviderId, authReq); logger.log(Level.FINE, "User authenticated: {0}", r.getEmail()); session.setUser(r); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java index 401a5d0a932..83f3b0ce09e 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java @@ -317,7 +317,19 @@ public AuthenticatedUser getAuthenticatedUserByEmail( String email ) { } } - public AuthenticatedUser authenticate( String authenticationProviderId, AuthenticationRequest req ) throws AuthenticationFailedException { + /** + * Returns an {@link AuthenticatedUser} matching the passed provider id and the authentication request. If + * no such user exist, it is created and then returned. + * + * Invariant: upon successful return from this call, an {@link AuthenticatedUser} record + * matching the request and provider exists in the database. + * + * @param authenticationProviderId + * @param req + * @return The authenticated user for the passed provider id and authentication request. + * @throws AuthenticationFailedException + */ + public AuthenticatedUser getCreateAuthenticatedUser( String authenticationProviderId, AuthenticationRequest req ) throws AuthenticationFailedException { AuthenticationProvider prv = getAuthenticationProvider(authenticationProviderId); if ( prv == null ) throw new IllegalArgumentException("No authentication provider listed under id " + authenticationProviderId ); if ( ! (prv instanceof CredentialsAuthenticationProvider) ) { @@ -333,18 +345,16 @@ public AuthenticatedUser authenticate( String authenticationProviderId, Authenti user = userService.updateLastLogin(user); } - /** - * @todo Why does a method called "authenticate" have the potential - * to call "createAuthenticatedUser"? Isn't the creation of a user a - * different action than authenticating? - * - * @todo Wouldn't this be more readable with if/else rather than - * ternary? (please) - */ - return ( user == null ) ? - AuthenticationServiceBean.this.createAuthenticatedUser( - new UserRecordIdentifier(authenticationProviderId, resp.getUserId()), resp.getUserId(), resp.getUserDisplayInfo(), true ) - : (BuiltinAuthenticationProvider.PROVIDER_ID.equals(user.getAuthenticatedUserLookup().getAuthenticationProviderId())) ? user : updateAuthenticatedUser(user, resp.getUserDisplayInfo()); + if ( user == null ) { + return createAuthenticatedUser( + new UserRecordIdentifier(authenticationProviderId, resp.getUserId()), resp.getUserId(), resp.getUserDisplayInfo(), true ); + } else { + if (BuiltinAuthenticationProvider.PROVIDER_ID.equals(user.getAuthenticatedUserLookup().getAuthenticationProviderId())) { + return user; + } else { + return updateAuthenticatedUser(user, resp.getUserDisplayInfo()); + } + } } else { throw new AuthenticationFailedException(resp, "Authentication Failed: " + resp.getMessage()); } @@ -778,7 +788,7 @@ public AuthenticatedUser canLogInAsBuiltinUser(String username, String password) String credentialsAuthProviderId = BuiltinAuthenticationProvider.PROVIDER_ID; try { - AuthenticatedUser au = authenticate(credentialsAuthProviderId, authReq); + AuthenticatedUser au = getCreateAuthenticatedUser(credentialsAuthProviderId, authReq); logger.fine("User authenticated:" + au.getEmail()); return au; } catch (AuthenticationFailedException ex) { diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java index 5e89df5118e..354578ca91d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -90,8 +91,6 @@ public String toString() { protected String redirectUrl; protected String scope; - public AbstractOAuth2AuthenticationProvider(){} - public abstract BaseApi getApiInstance(); protected abstract ParsedUserResponse parseUserResponse( String responseBody ); @@ -111,6 +110,7 @@ public OAuth20Service getService(String state, String redirectUrl) { public OAuth2UserRecord getUserRecord(String code, String state, String redirectUrl) throws IOException, OAuth2Exception { OAuth20Service service = getService(state, redirectUrl); OAuth2AccessToken accessToken = service.getAccessToken(code); + final String userEndpoint = getUserEndpoint(accessToken); final OAuthRequest request = new OAuthRequest(Verb.GET, userEndpoint, service); @@ -120,7 +120,7 @@ public OAuth2UserRecord getUserRecord(String code, String state, String redirect final Response response = request.send(); int responseCode = response.getCode(); final String body = response.getBody(); - logger.fine("In getUserRecord. Body: " + body); + logger.log(Level.FINE, "In getUserRecord. Body: {0}", body); if ( responseCode == 200 ) { final ParsedUserResponse parsed = parseUserResponse(body); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java index 9c29b4319b2..4cb87c1f133 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java @@ -99,7 +99,7 @@ public void init() throws IOException { logger.fine("init called"); AbstractOAuth2AuthenticationProvider.DevOAuthAccountType devMode = systemConfig.getDevOAuthAccountType(); - logger.fine("devMode: " + devMode); + logger.log(Level.FINE, "devMode: {0}", devMode); if (!AbstractOAuth2AuthenticationProvider.DevOAuthAccountType.PRODUCTION.equals(devMode)) { if (devMode.toString().startsWith("RANDOM")) { Map randomUser = authTestDataSvc.getRandomUser(); @@ -185,7 +185,9 @@ public String createNewAccount() { userNotificationService.sendNotification(user, new Timestamp(new Date().getTime()), UserNotification.Type.CREATEACC, null); - + + // TODO ORCIDv2 store the raw access token + return "/dataverse.xhtml?faces-redirect=true"; } @@ -196,13 +198,13 @@ public String convertExistingAccount() { auReq.putCredential(creds.get(0).getTitle(), getUsername()); auReq.putCredential(creds.get(1).getTitle(), getPassword()); try { - AuthenticatedUser existingUser = authenticationSvc.authenticate(BuiltinAuthenticationProvider.PROVIDER_ID, auReq); + AuthenticatedUser existingUser = authenticationSvc.getCreateAuthenticatedUser(BuiltinAuthenticationProvider.PROVIDER_ID, auReq); authenticationSvc.updateProvider(existingUser, newUser.getServiceId(), newUser.getIdInService()); builtinUserSvc.removeUser(existingUser.getUserIdentifier()); session.setUser(existingUser); - AuthenticationProvider authProvider = authenticationSvc.getAuthenticationProvider(newUser.getServiceId()); - JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("oauth2.convertAccount.success", Arrays.asList(authProvider.getInfo().getTitle()))); + AuthenticationProvider newUserAuthProvider = authenticationSvc.getAuthenticationProvider(newUser.getServiceId()); + JsfHelper.addSuccessMessage(BundleUtil.getStringFromBundle("oauth2.convertAccount.success", Arrays.asList(newUserAuthProvider.getInfo().getTitle()))); return "/dataverse.xhtml?faces-redirect=true"; @@ -212,22 +214,17 @@ public String convertExistingAccount() { } } - public String testAction() { - Logger.getLogger(OAuth2FirstLoginPage.class.getName()).log(Level.INFO, "testAction"); - return "dataverse.xhtml"; - } - public boolean isEmailAvailable() { return authenticationSvc.isEmailAddressAvailable(getSelectedEmail()); } - /** + /* * @todo This was copied from DataverseUserPage and modified so consider * consolidating common code (DRY). */ public void validateUserName(FacesContext context, UIComponent toValidate, Object value) { String userName = (String) value; - logger.fine("Validating username: " + userName); + logger.log(Level.FINE, "Validating username: {0}", userName); boolean userNameFound = authenticationSvc.identifierExists(userName); if (userNameFound) { ((UIInput) toValidate).setValid(false); @@ -236,7 +233,7 @@ public void validateUserName(FacesContext context, UIComponent toValidate, Objec } } - /** + /* * @todo This was copied from DataverseUserPage and modified so consider * consolidating common code (DRY). */ @@ -336,11 +333,7 @@ public String getCreateFromWhereTip() { public boolean isConvertFromBuiltinIsPossible() { AuthenticationProvider builtinAuthProvider = authenticationSvc.getAuthenticationProvider(BuiltinAuthenticationProvider.PROVIDER_ID); - if (builtinAuthProvider != null) { - return true; - } else { - return false; - } + return builtinAuthProvider != null; } public String getSuggestConvertInsteadOfCreate() { @@ -371,7 +364,7 @@ public List getEmailsToPickFrom() { } } } - logger.fine(emailsToPickFrom.size() + " emails to pick from: " + emailsToPickFrom); + logger.log(Level.FINE, "{0} emails to pick from: {1}", new Object[]{emailsToPickFrom.size(), emailsToPickFrom}); return emailsToPickFrom; } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java index 600e97b00bd..5280a3392f4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java @@ -91,7 +91,7 @@ public void exchangeCodeForToken() throws IOException { oauthUser = idp.getUserRecord(code, state, getCallbackUrl()); UserRecordIdentifier idtf = oauthUser.getUserRecordIdentifier(); AuthenticatedUser dvUser = authenticationSvc.lookupUser(idtf); - + if (dvUser == null) { // need to create the user newAccountPage.setNewUser(oauthUser); @@ -100,6 +100,7 @@ public void exchangeCodeForToken() throws IOException { } else { // login the user and redirect to HOME of intended page (if any). session.setUser(dvUser); + // TODO ORCIDv2 store the raw access token String destination = redirectPage.orElse("/"); HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse(); String prettyUrl = response.encodeRedirectURL(destination); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidApi.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidApi.java index 9fffe2171bc..d5f32e67bc0 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidApi.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidApi.java @@ -12,7 +12,7 @@ public class OrcidApi extends DefaultApi20 { /** - * The instance holder pattern allows for lazy creation of the intance. + * The instance holder pattern allows for lazy creation of the instance. */ private static class SandboxInstanceHolder { private static final OrcidApi INSTANCE = diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index f50db1e759c..649930e8bd3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -2,10 +2,15 @@ import com.github.scribejava.core.builder.api.BaseApi; import com.github.scribejava.core.model.OAuth2AccessToken; +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.model.Verb; +import com.github.scribejava.core.oauth.OAuth20Service; import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.AuthenticationProviderDisplayInfo; import edu.harvard.iq.dataverse.authorization.providers.oauth2.AbstractOAuth2AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2Exception; +import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2UserRecord; import edu.harvard.iq.dataverse.util.BundleUtil; import java.io.IOException; import java.io.StringReader; @@ -19,6 +24,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; import javax.json.Json; +import javax.json.JsonObject; import javax.json.JsonReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -32,7 +38,6 @@ import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; /** * OAuth2 identity provider for ORCiD. Note that ORCiD has two systems: sandbox @@ -67,18 +72,44 @@ public String getUserEndpoint( OAuth2AccessToken token ) { public BaseApi getApiInstance() { return OrcidApi.instance( ! baseUserEndpoint.contains("sandbox") ); } + + @Override + public OAuth2UserRecord getUserRecord(String code, String state, String redirectUrl) throws IOException, OAuth2Exception { + OAuth20Service service = getService(state, redirectUrl); + OAuth2AccessToken accessToken = service.getAccessToken(code); + + 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); + return new OAuth2UserRecord(getId(), orcidNumber, + parsed.username, + accessToken.getAccessToken(), + parsed.displayInfo, + parsed.emails); + } else { + throw new OAuth2Exception(responseCode, body, "Error getting the user info record."); + } + } + @Override protected ParsedUserResponse parseUserResponse(String responseBody) { DocumentBuilderFactory dbFact = DocumentBuilderFactory.newInstance(); try ( StringReader reader = new StringReader(responseBody)) { DocumentBuilder db = dbFact.newDocumentBuilder(); Document doc = db.parse( new InputSource(reader) ); - List orcidIdNodeList = getNodes(doc, "record:record", "common:orcid-identifier","common:path"); - if ( orcidIdNodeList.size() != 1 ) { - throw new OAuth2Exception(0, responseBody, "Cannot find ORCiD id in response."); - } - String orcidId = orcidIdNodeList.get(0).getTextContent().trim(); + String firstName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:given-names" ) .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); @@ -88,8 +119,8 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { String affiliation = getNodes(doc, "record:record", "activities:activities-summary", "activities:employments", "employment:employment-summary", "employment:organization", "common:name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - //switch to XPath based methods here for (debatable) clarity, and structural changes with email on 1.2 orcid message -> 2.0 orcid response. - String primaryEmail = getPrimaryEmail(doc); + //switch to XPath based methods here for (debatable) clarity, and structural changes with email on 1.2 orcid message -> 2.0 orcid response. + String primaryEmail = getPrimaryEmail(doc); List emails = getAllEmails(doc); // make the username up @@ -100,8 +131,10 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { username = firstName.split(" ")[0] + "." + familyName; } + // returning the parsed user. The user-id-in-provider will be added by the caller, since ORCiD passes it + // on the access token response. final ParsedUserResponse userResponse = new ParsedUserResponse( - new AuthenticatedUserDisplayInfo(firstName, familyName, primaryEmail, affiliation, ""), orcidId, username); + new AuthenticatedUserDisplayInfo(firstName, familyName, primaryEmail, affiliation, ""), null, username); userResponse.emails.addAll(emails); return userResponse; @@ -112,8 +145,6 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { logger.log(Level.SEVERE, "I/O error parsing response body from ORCiD: " + ex.getMessage(), ex); } catch (ParserConfigurationException ex) { logger.log(Level.SEVERE, "While parsing the ORCiD response: Bad parse configuration. " + ex.getMessage(), ex); - } catch (OAuth2Exception ex) { - logger.log(Level.SEVERE, "Semantic error parsing response body from ORCiD: " + ex.getMessage(), ex); } return null; @@ -164,7 +195,7 @@ private List getAllEmails(Document doc) { String p = "/record/person/emails/email/email/text()"; NodeList emails = xpath_matches( doc, p ); - List rs = new ArrayList(); + List rs = new ArrayList<>(); for(int i=0;i - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - - en - - - Direct - 2017-08-08T16:49:27.162Z - 2017-10-20T16:22:41.922Z - true - true - true - - - 2017-08-08T16:50:43.585Z - - 2017-08-08T16:49:27.162Z - 2017-08-08T16:49:27.421Z - Bob T. - Doc - - - - - 2017-08-08T16:50:43.585Z - - 2017-08-08T16:49:27.420Z - 2017-08-08T16:50:43.585Z - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - Bob T. Doc - - bdoc@mailinator.com - - - 2017-08-08T16:49:27.420Z - 2017-08-08T16:50:43.585Z - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - Bob T. Doc - - bdoc2@mailinator.com - - - - - - - + + + 2016-04-14T20:56:22.279Z + + 2016-04-14T20:56:22.279Z + 2016-04-14T20:56:22.279Z + Bob T. + Doc + Bob the Doc + + + 2001-12-31T12:00:00 + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + other-name-1 + + + + 2016-04-14T20:56:22.279Z + 2016-04-14T20:56:22.279Z + biography + + + 2001-12-31T12:00:00 + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + url-name-1 + http://url.com/ + + + + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + bdoc@mailinator.com + + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + bdoc2@mailinator.com + + + + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + US + + + + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + keyword1 + + + + + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + type-1 + value-1 + http://url.com/1 + + + \ No newline at end of file From 3f77c0686aada6f8d6403f9a157bbd4783bdfef0 Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Fri, 10 Nov 2017 17:02:04 +0200 Subject: [PATCH 22/38] Add parsing of the organizational position data --- .../AuthenticatedUserDisplayInfo.java | 2 +- .../providers/oauth2/impl/OrcidOAuth2AP.java | 113 +++++++++++++----- .../oauth2/impl/OrcidOAuth2APTest.java | 84 ++++++++----- .../xml/oauth2/orcid/v20_activities.xml | 53 ++++++++ .../xml/oauth2/orcid/v20_response.xml | 34 +++--- 5 files changed, 212 insertions(+), 74 deletions(-) create mode 100644 src/test/resources/xml/oauth2/orcid/v20_activities.xml diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java index 739c0c915bf..909e124e5bd 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticatedUserDisplayInfo.java @@ -15,7 +15,7 @@ public class AuthenticatedUserDisplayInfo extends RoleAssigneeDisplayInfo { private String firstName; private String position; - /** + /* * @todo Shouldn't we persist the displayName too? It still exists on the * authenticateduser table. */ diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index 649930e8bd3..bcb40192356 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -18,9 +18,11 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import static java.util.stream.Collectors.joining; import java.util.stream.IntStream; import java.util.stream.Stream; import javax.json.Json; @@ -93,6 +95,10 @@ public OAuth2UserRecord getUserRecord(String code, String state, String redirect 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, accessToken.getAccessToken(), @@ -110,16 +116,20 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { DocumentBuilder db = dbFact.newDocumentBuilder(); Document doc = db.parse( new InputSource(reader) ); - String firstName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:given-names" ) + String firstName = getNodes(doc, "person:person", "person:name", "personal-details:given-names" ) .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - String familyName = getNodes(doc, "record:record", "person:person", "person:name", "personal-details:family-name") + String familyName = getNodes(doc, "person:person", "person:name", "personal-details:family-name") .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - String affiliation = getNodes(doc, "record:record", "activities:activities-summary", "activities:employments", "employment:employment-summary", "employment:organization", "common:name") + + // fallback - try to use the credit-name + if ( (firstName + familyName).equals("") ) { + firstName = getNodes(doc, "person:person", "person:name", "personal-details:credit-name" ) .stream().findFirst().map( Node::getTextContent ) .map( String::trim ).orElse(""); - //switch to XPath based methods here for (debatable) clarity, and structural changes with email on 1.2 orcid message -> 2.0 orcid response. + } + String primaryEmail = getPrimaryEmail(doc); List emails = getAllEmails(doc); @@ -130,11 +140,13 @@ protected ParsedUserResponse parseUserResponse(String responseBody) { } else { username = firstName.split(" ")[0] + "." + familyName; } + username = username.replaceAll("[^a-zA-Z0-9.]",""); // returning the parsed user. The user-id-in-provider will be added by the caller, since ORCiD passes it // on the access token response. + // Affilifation added after a later call. final ParsedUserResponse userResponse = new ParsedUserResponse( - new AuthenticatedUserDisplayInfo(firstName, familyName, primaryEmail, affiliation, ""), null, username); + new AuthenticatedUserDisplayInfo(firstName, familyName, primaryEmail, "", ""), null, username); userResponse.emails.addAll(emails); return userResponse; @@ -172,52 +184,48 @@ private List getNodes( Node node, List path ) { } } + /** * retrieve email from ORCID 2.0 response document, or empty string if no primary email is present */ - private String getPrimaryEmail(Document doc) - { + private String getPrimaryEmail(Document doc) { // `xmlstarlet sel -t -c "/record:record/person:person/email:emails/email:email[@primary='true']/email:email"`, if you're curious - String p = "/record/person/emails/email[@primary='true']/email/text()"; - NodeList emails = xpath_matches( doc, p ); - String primary_email = ""; - if ( 1 == emails.getLength() ) - { - primary_email = emails.item(0).getTextContent(); + String p = "/person/emails/email[@primary='true']/email/text()"; + NodeList emails = xpathMatches( doc, p ); + String primaryEmail = ""; + if ( 1 == emails.getLength() ) { + primaryEmail = emails.item(0).getTextContent(); } // if there are no (or somehow more than 1) primary email(s), then we've already at failure value - return primary_email; + return primaryEmail; } + /** * retrieve all emails (including primary) from ORCID 2.0 response document */ - private List getAllEmails(Document doc) - { - String p = "/record/person/emails/email/email/text()"; - NodeList emails = xpath_matches( doc, p ); + private List getAllEmails(Document doc) { + String p = "/person/emails/email/email/text()"; + NodeList emails = xpathMatches( doc, p ); List rs = new ArrayList<>(); - for(int i=0;i 2.0 upgrade */ - private static String loadResponseXML(String fname) - { + private static String loadResponseXML(String fname) { String txt = null; - try - { + try { java.io.File inp = new java.io.File( fname ); txt = org.apache.commons.io.FileUtils.readFileToString( inp ); - } - catch( java.io.IOException ie ) - { + } catch( java.io.IOException ie ) { // no-op; assert that the needed strings are not null in tests } return txt; @@ -57,11 +54,9 @@ private static String loadResponseXML(String fname) @Test public void testParseUserResponse() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); - assertNotNull( RESPONSE ); - System.out.println("withEmailResponse = " + RESPONSE); + assertNotNull( RESPONSE ); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(RESPONSE); - assertEquals("8888-8888-8888-8880", actual.userIdInProvider); assertEquals("bdoc", actual.username); assertEquals("Bob T.", actual.displayInfo.getFirstName()); assertEquals("Doc", actual.displayInfo.getLastName()); @@ -69,16 +64,14 @@ public void testParseUserResponse() { assertEquals("", actual.displayInfo.getAffiliation()); assertEquals("", actual.displayInfo.getPosition()); assertEquals(Arrays.asList("bdoc@mailinator.com", "bdoc2@mailinator.com"), actual.emails); - } @Test public void testParseUserResponseNoEmailHasAffiliation() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); - assertNotNull( NO_EMAIL_HAS_AFFILIATION ); + assertNotNull( NO_EMAIL_HAS_AFFILIATION ); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL_HAS_AFFILIATION); - assertEquals("0000-0003-2591-1698", actual.userIdInProvider); assertEquals("Bob T.", actual.displayInfo.getFirstName()); assertEquals("Doc", actual.displayInfo.getLastName()); assertEquals("", actual.displayInfo.getEmailAddress()); @@ -97,7 +90,6 @@ public void testParseUserResponse_noEmails() { System.out.println("noEmailResponse = " + NO_EMAIL ); final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL); - assertEquals("0000-0003-2591-1698", actual.userIdInProvider); assertEquals("Bob.Doc", actual.username); assertEquals("Bob T.", actual.displayInfo.getFirstName()); assertEquals("Doc", actual.displayInfo.getLastName()); @@ -105,7 +97,6 @@ public void testParseUserResponse_noEmails() { assertEquals("", actual.displayInfo.getAffiliation()); assertEquals("", actual.displayInfo.getPosition()); assertEquals(Arrays.asList("").toString(), actual.emails.toString()); - } @Test @@ -128,4 +119,39 @@ public void testExtractOrcidBad() throws OAuth2Exception { sut.extractOrcidNumber(response); } + @Test + public void testParseActivitiesResponse() { + OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); + assertNotNull( ACTIVITIES ); + final AuthenticatedUserDisplayInfo actual = sut.parseActivitiesResponse(ACTIVITIES); + + assertEquals("My Organization Name", actual.getAffiliation()); + assertEquals("role, department", actual.getPosition()); + } + + @Test + public void testParseActivitiesResponseNoOrgName() { + OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); + assertNotNull( ACTIVITIES ); + + String responseWithNoOrg = ACTIVITIES.replaceAll("\n","").replaceAll(".*", ""); + + final AuthenticatedUserDisplayInfo actual = sut.parseActivitiesResponse(responseWithNoOrg); + + assertEquals(null, actual.getAffiliation()); + assertEquals("role, department", actual.getPosition()); + } + + @Test + public void testParseActivitiesResponseNoRole() { + OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); + assertNotNull( ACTIVITIES ); + + String responseWithNoOrg = ACTIVITIES.replaceAll("\n","").replaceAll(".*", ""); + + final AuthenticatedUserDisplayInfo actual = sut.parseActivitiesResponse(responseWithNoOrg); + + assertEquals("My Organization Name", actual.getAffiliation()); + assertEquals("department", actual.getPosition()); + } } diff --git a/src/test/resources/xml/oauth2/orcid/v20_activities.xml b/src/test/resources/xml/oauth2/orcid/v20_activities.xml new file mode 100644 index 00000000000..6fb414f922f --- /dev/null +++ b/src/test/resources/xml/oauth2/orcid/v20_activities.xml @@ -0,0 +1,53 @@ + + + 2017-01-18T13:32:45.500-06:00 + + 2017-01-18T13:32:45.500-06:00 + 2017-01-18T13:32:45.500-06:00 + + + http://orcid.org/8888-8888-8888-8888 + 8888-8888-8888-8888 + orcid.org + + User One Credit name + + department + role + + My Organization Name + + x + AS + + + + + 2017-01-18T13:32:45.500-06:00 + 2017-01-18T13:32:45.500-06:00 + + + http://orcid.org/8888-8888-8888-8888 + 8888-8888-8888-8888 + orcid.org + + User One Credit name + + employment + + employment + + x + AS + + + + \ No newline at end of file diff --git a/src/test/resources/xml/oauth2/orcid/v20_response.xml b/src/test/resources/xml/oauth2/orcid/v20_response.xml index f0f63315fa9..785e3f91cd9 100644 --- a/src/test/resources/xml/oauth2/orcid/v20_response.xml +++ b/src/test/resources/xml/oauth2/orcid/v20_response.xml @@ -12,13 +12,13 @@ 2016-04-14T20:56:22.279Z 2016-04-14T20:56:22.279Z - 2016-04-14T20:56:22.279Z - Bob T. - Doc + 2016-04-14T20:56:22.279Z + Bob T. + Doc Bob the Doc - 2001-12-31T12:00:00 + 2001-12-31T12:00:00 2001-12-31T12:00:00 2001-12-31T12:00:00 @@ -35,7 +35,7 @@ 2016-04-14T20:56:22.279Z - 2016-04-14T20:56:22.279Z + 2016-04-14T20:56:22.279Z biography @@ -101,18 +101,18 @@ - 2001-12-31T12:00:00 - 2001-12-31T12:00:00 - - - http://orcid.org/8888-8888-8888-8880 - 8888-8888-8888-8880 - orcid.org - - - - keyword1 - + 2001-12-31T12:00:00 + 2001-12-31T12:00:00 + + + http://orcid.org/8888-8888-8888-8880 + 8888-8888-8888-8880 + orcid.org + + + + keyword1 + From 00c028f685e23954c56a0394432442a718d19a9f Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Sat, 11 Nov 2017 21:48:48 +0200 Subject: [PATCH 23/38] Parse v2.0 XMLs --- .../oauth2/impl/OrcidOAuth2APTest.java | 41 ++--------- .../xml/oauth2/orcid/v12_no_email_has_aff.xml | 54 --------------- .../xml/oauth2/orcid/v20_no_email.xml | 34 ---------- .../xml/oauth2/orcid/v20_no_email_has_aff.xml | 68 ------------------- .../{v20_response.xml => v20_person.xml} | 2 +- 5 files changed, 8 insertions(+), 191 deletions(-) delete mode 100644 src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml delete mode 100644 src/test/resources/xml/oauth2/orcid/v20_no_email.xml delete mode 100644 src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml rename src/test/resources/xml/oauth2/orcid/{v20_response.xml => v20_person.xml} (99%) diff --git a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java index b8c3d6d06b9..0009820ee41 100644 --- a/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2APTest.java @@ -3,13 +3,10 @@ import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo; import edu.harvard.iq.dataverse.authorization.providers.oauth2.AbstractOAuth2AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2Exception; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Test; -import org.junit.Before; /** * @@ -17,13 +14,9 @@ * @author pameyer */ public class OrcidOAuth2APTest extends OrcidOAuth2AP { - private static final String RESPONSE_FILE="src/test/resources/xml/oauth2/orcid/v20_response.xml"; - private static final String NO_EMAIL_HAS_AFFILIATION_FILE="src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml"; - private static final String NO_EMAIL_FILE="src/test/resources/xml/oauth2/orcid/v20_no_email.xml"; + private static final String PERSON_FILE="src/test/resources/xml/oauth2/orcid/v20_person.xml"; private static final String ACTIVITIES_FILE="src/test/resources/xml/oauth2/orcid/v20_activities.xml"; - private static final String RESPONSE; - private static final String NO_EMAIL_HAS_AFFILIATION; - private static final String NO_EMAIL; + private static final String PERSON; private static final String ACTIVITIES; public OrcidOAuth2APTest() { @@ -31,9 +24,7 @@ public OrcidOAuth2APTest() { } static { - RESPONSE = loadResponseXML( RESPONSE_FILE ); - NO_EMAIL_HAS_AFFILIATION = loadResponseXML( NO_EMAIL_HAS_AFFILIATION_FILE ); - NO_EMAIL = loadResponseXML( NO_EMAIL_FILE ); + PERSON = loadResponseXML( PERSON_FILE ); ACTIVITIES = loadResponseXML( ACTIVITIES_FILE ); } /** @@ -54,8 +45,8 @@ private static String loadResponseXML(String fname) { @Test public void testParseUserResponse() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); - assertNotNull( RESPONSE ); - final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(RESPONSE); + assertNotNull( PERSON ); + final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(PERSON); assertEquals("bdoc", actual.username); assertEquals("Bob T.", actual.displayInfo.getFirstName()); @@ -66,29 +57,11 @@ public void testParseUserResponse() { assertEquals(Arrays.asList("bdoc@mailinator.com", "bdoc2@mailinator.com"), actual.emails); } - @Test - public void testParseUserResponseNoEmailHasAffiliation() { - OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); - assertNotNull( NO_EMAIL_HAS_AFFILIATION ); - final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL_HAS_AFFILIATION); - - assertEquals("Bob T.", actual.displayInfo.getFirstName()); - assertEquals("Doc", actual.displayInfo.getLastName()); - assertEquals("", actual.displayInfo.getEmailAddress()); - assertEquals("Miskatonic University", actual.displayInfo.getAffiliation()); - assertEquals("", actual.displayInfo.getPosition()); - List emptyList = new ArrayList<>(); - assertEquals(emptyList, actual.emails); - assertEquals("Bob.Doc", actual.username); - - } - @Test public void testParseUserResponse_noEmails() { OrcidOAuth2AP sut = new OrcidOAuth2AP("clientId", "clientSecret", "userEndpoint"); - assertNotNull( NO_EMAIL ); - System.out.println("noEmailResponse = " + NO_EMAIL ); - final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(NO_EMAIL); + String noEmail = PERSON.replaceAll("\n", " ").replaceAll(".*", ""); + final AbstractOAuth2AuthenticationProvider.ParsedUserResponse actual = sut.parseUserResponse(noEmail); assertEquals("Bob.Doc", actual.username); assertEquals("Bob T.", actual.displayInfo.getFirstName()); diff --git a/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml b/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml deleted file mode 100644 index e6924b97235..00000000000 --- a/src/test/resources/xml/oauth2/orcid/v12_no_email_has_aff.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - 1.2 - - - http://orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - orcid.org - - - en - - - Direct - 2015-11-30T23:14:04.260Z - 2016-12-13T19:45:57.958Z - true - true - true - - - - Bob T. - Doc - - - - - - employment - - Miskatonic University -
- Arkham - MA - US -
-
- - - http://orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - orcid.org - - Bob T. Doc - 2015-11-30T23:18:22.764Z - - 2015-11-30T23:18:22.764Z - 2016-05-07T02:26:10.970Z -
-
-
-
-
diff --git a/src/test/resources/xml/oauth2/orcid/v20_no_email.xml b/src/test/resources/xml/oauth2/orcid/v20_no_email.xml deleted file mode 100644 index 4df340ca5ea..00000000000 --- a/src/test/resources/xml/oauth2/orcid/v20_no_email.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - - en - - - Direct - 2017-08-08T16:49:27.162Z - 2017-10-20T16:22:41.922Z - true - true - true - - - 2017-08-08T16:50:43.585Z - - 2017-08-08T16:49:27.162Z - 2017-08-08T16:49:27.421Z - Bob T. - Doc - - - - - - - - - diff --git a/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml b/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml deleted file mode 100644 index fc09dfcf8f7..00000000000 --- a/src/test/resources/xml/oauth2/orcid/v20_no_email_has_aff.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - - en - - - Direct - 2017-08-08T16:49:27.162Z - 2017-10-20T16:22:41.922Z - true - true - true - - - 2017-08-08T16:50:43.585Z - - 2017-08-08T16:49:27.162Z - 2017-08-08T16:49:27.421Z - Bob T. - Doc - - - - - - - - - - 2017-10-20T16:20:46.204Z - - - 2017-10-20T16:20:46.204Z - - 2017-10-20T16:20:46.204Z - 2017-10-20T16:20:46.204Z - - - http://sandbox.orcid.org/0000-0003-2591-1698 - 0000-0003-2591-1698 - sandbox.orcid.org - - Bob Doc - - - 2017 - 10 - 31 - - - Miskatonic University - - Arkham - US - - - - - - - - - diff --git a/src/test/resources/xml/oauth2/orcid/v20_response.xml b/src/test/resources/xml/oauth2/orcid/v20_person.xml similarity index 99% rename from src/test/resources/xml/oauth2/orcid/v20_response.xml rename to src/test/resources/xml/oauth2/orcid/v20_person.xml index 785e3f91cd9..1d8a1c27069 100644 --- a/src/test/resources/xml/oauth2/orcid/v20_response.xml +++ b/src/test/resources/xml/oauth2/orcid/v20_person.xml @@ -57,7 +57,7 @@
- + 2001-12-31T12:00:00 2001-12-31T12:00:00 From 848d24e78c9217114abef7a5b404d2672f906a3f Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Sun, 12 Nov 2017 01:29:48 +0200 Subject: [PATCH 24/38] Add OAuth token storage --- src/main/java/Bundle.properties | 1 + .../AbstractOAuth2AuthenticationProvider.java | 2 +- .../providers/oauth2/OAuth2FirstLoginPage.java | 11 +++++++++-- .../providers/oauth2/OAuth2LoginBackingBean.java | 13 +++++++++---- .../providers/oauth2/OAuth2UserRecord.java | 16 ++++++++-------- .../providers/oauth2/impl/OrcidOAuth2AP.java | 11 +++++++++-- src/main/webapp/loginpage.xhtml | 3 ++- 7 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index de637c3c455..0820161176c 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -259,6 +259,7 @@ auth.providers.persistentUserIdName.orcid=ORCID iD auth.providers.persistentUserIdName.github=ID auth.providers.persistentUserIdTooltip.orcid=ORCID provides a persistent digital identifier that distinguishes you from other researchers. auth.providers.persistentUserIdTooltip.github=GitHub assigns a unique number to every user. +auth.providers.orcid.insufficientScope=Dataverse was not granted the permission to read user data from ORCiD. # Friendly AuthenticationProvider names authenticationProvider.name.builtin=Dataverse authenticationProvider.name.null=(provider is unknown) diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java index 354578ca91d..8cfb84e7ce3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/AbstractOAuth2AuthenticationProvider.java @@ -126,7 +126,7 @@ public OAuth2UserRecord getUserRecord(String code, String state, String redirect final ParsedUserResponse parsed = parseUserResponse(body); return new OAuth2UserRecord(getId(), parsed.userIdInProvider, parsed.username, - accessToken.getAccessToken(), + OAuth2TokenData.from(accessToken), parsed.displayInfo, parsed.emails); } else { diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java index 4cb87c1f133..9ca92466465 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2FirstLoginPage.java @@ -66,6 +66,9 @@ public class OAuth2FirstLoginPage implements java.io.Serializable { @EJB AuthTestDataServiceBean authTestDataSvc; + @EJB + OAuth2TokenDataServiceBean oauth2Tokens; + @Inject DataverseSession session; @@ -136,7 +139,8 @@ public void init() throws IOException { } String randomUsername = randomUser.get("username"); String eppn = randomUser.get("eppn"); - String accessToken = "qwe-addssd-iiiiie"; + OAuth2TokenData accessToken = new OAuth2TokenData(); + accessToken.setAccessToken("qwe-addssd-iiiiie"); setNewUser(new OAuth2UserRecord(authProviderId, eppn, randomUsername, accessToken, new AuthenticatedUserDisplayInfo(firstName, lastName, email, "myAffiliation", "myPosition"), extraEmails)); @@ -186,7 +190,10 @@ public String createNewAccount() { new Timestamp(new Date().getTime()), UserNotification.Type.CREATEACC, null); - // TODO ORCIDv2 store the raw access token + final OAuth2TokenData tokenData = newUser.getTokenData(); + tokenData.setUser(user); + tokenData.setOauthProviderId(newUser.getServiceId()); + oauth2Tokens.store(tokenData); return "/dataverse.xhtml?faces-redirect=true"; } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java index 5280a3392f4..6fdc33b48b3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2LoginBackingBean.java @@ -4,7 +4,6 @@ import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; import edu.harvard.iq.dataverse.authorization.UserRecordIdentifier; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; -import edu.harvard.iq.dataverse.settings.SettingsServiceBean; import edu.harvard.iq.dataverse.util.StringUtil; import java.io.BufferedReader; import java.io.IOException; @@ -26,8 +25,8 @@ import edu.harvard.iq.dataverse.util.SystemConfig; /** - * Backing bean of the oauth2 login process. Used from the login page and the - * callback page. + * Backing bean of the oauth2 login process. Used from the login and the + * callback pages. * * @author michael */ @@ -45,6 +44,9 @@ public class OAuth2LoginBackingBean implements Serializable { @EJB AuthenticationServiceBean authenticationSvc; + + @EJB + OAuth2TokenDataServiceBean oauth2Tokens; @EJB SystemConfig systemConfig; @@ -100,7 +102,10 @@ public void exchangeCodeForToken() throws IOException { } else { // login the user and redirect to HOME of intended page (if any). session.setUser(dvUser); - // TODO ORCIDv2 store the raw access token + final OAuth2TokenData tokenData = oauthUser.getTokenData(); + tokenData.setUser(dvUser); + tokenData.setOauthProviderId(idp.getId()); + oauth2Tokens.store(tokenData); String destination = redirectPage.orElse("/"); HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse(); String prettyUrl = response.encodeRedirectURL(destination); diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2UserRecord.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2UserRecord.java index eca69a3697f..234c2828ab5 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2UserRecord.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2UserRecord.java @@ -20,19 +20,19 @@ public class OAuth2UserRecord implements java.io.Serializable { /** A potentially mutable String that is easier on the eye than a number. */ private final String username; - private final String accessToken; - private final AuthenticatedUserDisplayInfo displayInfo; private final List availableEmailAddresses; + private final OAuth2TokenData tokenData; + public OAuth2UserRecord(String aServiceId, String anIdInService, String aUsername, - String anAccessToken, AuthenticatedUserDisplayInfo aDisplayInfo, + OAuth2TokenData someTokenData, AuthenticatedUserDisplayInfo aDisplayInfo, List someAvailableEmailAddresses) { serviceId = aServiceId; idInService = anIdInService; username = aUsername; - accessToken = anAccessToken; + tokenData = someTokenData; displayInfo = aDisplayInfo; availableEmailAddresses = someAvailableEmailAddresses; } @@ -49,10 +49,6 @@ public String getUsername() { return username; } - public String getAccessToken() { - return accessToken; - } - public List getAvailableEmailAddresses() { return availableEmailAddresses; } @@ -61,6 +57,10 @@ public AuthenticatedUserDisplayInfo getDisplayInfo() { return displayInfo; } + public OAuth2TokenData getTokenData() { + return tokenData; + } + @Override public String toString() { return "OAuth2UserRecord{" + "serviceId=" + serviceId + ", idInService=" + idInService + '}'; diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java index bcb40192356..030680f29c4 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/OrcidOAuth2AP.java @@ -10,6 +10,7 @@ import edu.harvard.iq.dataverse.authorization.AuthenticationProviderDisplayInfo; import edu.harvard.iq.dataverse.authorization.providers.oauth2.AbstractOAuth2AuthenticationProvider; import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2Exception; +import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2TokenData; import edu.harvard.iq.dataverse.authorization.providers.oauth2.OAuth2UserRecord; import edu.harvard.iq.dataverse.util.BundleUtil; import java.io.IOException; @@ -44,8 +45,9 @@ /** * OAuth2 identity provider for ORCiD. Note that ORCiD has two systems: sandbox * and production. Hence having the user endpoint as a parameter. + * * @author michael - * But don't blame michael for pameyer's later changes + * @author pameyer */ public class OrcidOAuth2AP extends AbstractOAuth2AuthenticationProvider { @@ -80,6 +82,11 @@ public OAuth2UserRecord getUserRecord(String code, String state, String redirect OAuth20Service service = getService(state, redirectUrl); OAuth2AccessToken accessToken = service.getAccessToken(code); + 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"), ""); + } + String orcidNumber = extractOrcidNumber(accessToken.getRawResponse()); final String userEndpoint = getUserEndpoint(accessToken); @@ -101,7 +108,7 @@ public OAuth2UserRecord getUserRecord(String code, String state, String redirect return new OAuth2UserRecord(getId(), orcidNumber, parsed.username, - accessToken.getAccessToken(), + OAuth2TokenData.from(accessToken), parsed.displayInfo, parsed.emails); } else { diff --git a/src/main/webapp/loginpage.xhtml b/src/main/webapp/loginpage.xhtml index 6ded99c5eb6..135aeb366f2 100644 --- a/src/main/webapp/loginpage.xhtml +++ b/src/main/webapp/loginpage.xhtml @@ -5,6 +5,7 @@ xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:o="http://omnifaces.org/ui" xmlns:p="http://primefaces.org/ui" + xmlns:fn="http://java.sun.com/jsp/jstl/functions" xmlns:jsf="http://xmlns.jcp.org/jsf"> @@ -187,7 +188,7 @@
- + From 0890091c3a67e1282f0690cf9145a391f4d2dd1b Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Sun, 12 Nov 2017 08:15:38 +0200 Subject: [PATCH 25/38] Added required classes --- .../providers/oauth2/OAuth2TokenData.java | 179 ++++++++++++++++++ .../oauth2/OAuth2TokenDataServiceBean.java | 45 +++++ 2 files changed, 224 insertions(+) create mode 100644 src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenData.java create mode 100644 src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenData.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenData.java new file mode 100644 index 00000000000..c6ecf1fc008 --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenData.java @@ -0,0 +1,179 @@ +package edu.harvard.iq.dataverse.authorization.providers.oauth2; + +import com.github.scribejava.core.model.OAuth2AccessToken; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import java.io.Serializable; +import java.sql.Timestamp; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +/** + * Token data for a given user, received from an OAuth2 system. Contains the + * user's access token for the remote system, as well as additional data, + * such as refresh token and expiry date. + * + * @author michael + */ +@NamedQueries({ + @NamedQuery( name="OAuth2TokenData.findByUserIdAndProviderId", + query = "SELECT d FROM OAuth2TokenData d WHERE d.user.id=:userId AND d.oauthProviderId=:providerId" ), + @NamedQuery( name="OAuth2TokenData.deleteByUserIdAndProviderId", + query = "DELETE FROM OAuth2TokenData d WHERE d.user.id=:userId AND d.oauthProviderId=:providerId" ) + +}) +@Entity +public class OAuth2TokenData implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + private AuthenticatedUser user; + + private String oauthProviderId; + + private Timestamp expiryDate; + + @Column(length = 64) + private String accessToken; + + @Column(length = 64) + private String refreshToken; + + @Column(length = 64) + private String scope; + + @Column(length = 32) + private String tokenType; + + @Column(columnDefinition = "TEXT") + private String rawResponse; + + + /** + * Creates a new {@link OAuth2TokenData} instance, based on the data in + * the passed {@link OAuth2AccessToken}. + * @param accessTokenResponse The token parsed by the ScribeJava library. + * @return A new, pre-populated {@link OAuth2TokenData}. + */ + public static OAuth2TokenData from( OAuth2AccessToken accessTokenResponse ) { + OAuth2TokenData retVal = new OAuth2TokenData(); + retVal.setAccessToken(accessTokenResponse.getAccessToken()); + retVal.setRefreshToken( accessTokenResponse.getRefreshToken() ); + retVal.setScope( accessTokenResponse.getScope() ); + retVal.setTokenType( accessTokenResponse.getTokenType() ); + if ( accessTokenResponse.getExpiresIn() != null ) { + retVal.setExpiryDate( new Timestamp( System.currentTimeMillis() + accessTokenResponse.getExpiresIn())); + } + retVal.setRawResponse( accessTokenResponse.getRawResponse() ); + + return retVal; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public AuthenticatedUser getUser() { + return user; + } + + public void setUser(AuthenticatedUser user) { + this.user = user; + } + + public String getOauthProviderId() { + return oauthProviderId; + } + + public void setOauthProviderId(String oauthProviderId) { + this.oauthProviderId = oauthProviderId; + } + + public Timestamp getExpiryDate() { + return expiryDate; + } + + public void setExpiryDate(Timestamp expiryDate) { + this.expiryDate = expiryDate; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getTokenType() { + return tokenType; + } + + public void setTokenType(String tokenType) { + this.tokenType = tokenType; + } + + public String getRawResponse() { + return rawResponse; + } + + public void setRawResponse(String rawResponse) { + this.rawResponse = rawResponse; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 71 * hash + (int) (this.id ^ (this.id >>> 32)); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final OAuth2TokenData other = (OAuth2TokenData) obj; + if (this.id != other.id) { + return false; + } + return true; + } + + + +} diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java new file mode 100644 index 00000000000..f4ed1d9b93a --- /dev/null +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java @@ -0,0 +1,45 @@ +package edu.harvard.iq.dataverse.authorization.providers.oauth2; + +import java.util.List; +import java.util.Optional; +import javax.ejb.Stateless; +import javax.inject.Named; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +/** + * CRUD for {@link OAuth2TokenData}. + * + * @author michael + */ +@Named +@Stateless +public class OAuth2TokenDataServiceBean { + + @PersistenceContext + private EntityManager em; + + public void store( OAuth2TokenData tokenData ) { + if ( tokenData.getId() != null ) { + // token exists, this is an update + em.merge(tokenData); + + } else { + // ensure there's only one token for each user/service pair. + em.createNamedQuery("OAuth2TokenData.deleteByUserIdAndProviderId") + .setParameter("userId", tokenData.getUser().getId() ) + .setParameter("providerId", tokenData.getOauthProviderId() ) + .executeUpdate(); + em.persist( tokenData ); + } + } + + public Optional get( long authenticatedUserId, String serviceId ) { + final List tokens = em.createNamedQuery("OAuth2TokenData.findByUserIdAndProviderId", OAuth2TokenData.class) + .setParameter("userId", authenticatedUserId ) + .setParameter("providerId", serviceId ) + .getResultList(); + return Optional.ofNullable( tokens.isEmpty() ? null : tokens.get(0) ); + } + +} From 6673e5a60d4e62487342f4feccf278351d95ba54 Mon Sep 17 00:00:00 2001 From: Michael Bar-Sinai Date: Sun, 12 Nov 2017 09:38:06 +0200 Subject: [PATCH 26/38] Add conditional footer note about ORCiD --- src/main/java/Bundle.properties | 5 +++++ src/main/java/edu/harvard/iq/dataverse/api/Admin.java | 8 ++++++-- .../authorization/AuthenticationServiceBean.java | 9 ++++++++- .../providers/oauth2/OAuth2TokenDataServiceBean.java | 1 - src/main/webapp/dataverse_footer.xhtml | 10 +++++++++- src/main/webapp/loginpage.xhtml | 2 +- src/main/webapp/resources/css/structure.css | 1 + 7 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 0820161176c..9175ca2d031 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -1698,3 +1698,8 @@ ingest.csv.invalidHeader=Invalid header row. One of the cells is empty. ingest.csv.lineMismatch=Mismatch between line counts in first and final passes!, {0} found on first pass, but {1} found on second. ingest.csv.recordMismatch=Reading mismatch, line {0} of the Data file: {1} delimited values expected, {2} found. ingest.csv.nullStream=Stream can't be null. + +# ORCiD branding for the footer +orcid.poweredby=Logins also by +orcid.poweredby.title=Get or create your ORCiD at orcid.org +orcid.poweredby.imagealt=ORCiD logo \ No newline at end of file diff --git a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java index 92086575199..6865ef9af2d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/api/Admin.java +++ b/src/main/java/edu/harvard/iq/dataverse/api/Admin.java @@ -63,8 +63,6 @@ import edu.harvard.iq.dataverse.ingest.IngestServiceBean; import edu.harvard.iq.dataverse.userdata.UserListMaker; import edu.harvard.iq.dataverse.userdata.UserListResult; -import edu.harvard.iq.dataverse.util.StringUtil; -import java.math.BigDecimal; import java.util.Date; import java.util.ResourceBundle; import javax.inject.Inject; @@ -1002,4 +1000,10 @@ public Response validatePassword(String password) { .add("errors", errorArray) ); } + + @GET + @Path("/isOrcid") + public Response isOrcidEnabled() { + return authSvc.isOrcidEnabled() ? ok("Orcid is enabled") : ok("no orcid for you."); + } } diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java index 83f3b0ce09e..f4a5249c263 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java @@ -47,6 +47,7 @@ import javax.ejb.EJB; import javax.ejb.EJBException; import javax.ejb.Singleton; +import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; @@ -63,6 +64,7 @@ * * Register the providers in the {@link #startup()} method. */ +@Named @Singleton public class AuthenticationServiceBean { private static final Logger logger = Logger.getLogger(AuthenticationServiceBean.class.getName()); @@ -233,7 +235,12 @@ public void removeApiToken(AuthenticatedUser user){ em.remove(apiToken); } } - } + } + + public boolean isOrcidEnabled() { + return oAuth2authenticationProviders.values().stream().anyMatch( s -> s.getId().toLowerCase().contains("orcid") ); + } + /** * Use with care! This method was written primarily for developers * interested in API testing who want to: diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java index f4ed1d9b93a..d8f1fa7600b 100644 --- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java +++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2TokenDataServiceBean.java @@ -12,7 +12,6 @@ * * @author michael */ -@Named @Stateless public class OAuth2TokenDataServiceBean { diff --git a/src/main/webapp/dataverse_footer.xhtml b/src/main/webapp/dataverse_footer.xhtml index b39d3717756..55ee05aea66 100644 --- a/src/main/webapp/dataverse_footer.xhtml +++ b/src/main/webapp/dataverse_footer.xhtml @@ -34,8 +34,16 @@
diff --git a/src/main/webapp/loginpage.xhtml b/src/main/webapp/loginpage.xhtml index 135aeb366f2..af0ebb0e0f6 100644 --- a/src/main/webapp/loginpage.xhtml +++ b/src/main/webapp/loginpage.xhtml @@ -191,7 +191,7 @@ - +

ORCID is an open, non-profit, community-based effort to provide a registry of unique researcher identifiers and a transparent method of linking research activities and outputs to these identifiers. ORCID is unique in diff --git a/src/main/webapp/resources/css/structure.css b/src/main/webapp/resources/css/structure.css index 12b0c889a4c..fd4eab647c1 100644 --- a/src/main/webapp/resources/css/structure.css +++ b/src/main/webapp/resources/css/structure.css @@ -42,6 +42,7 @@ body .ui-widget {font-size: inherit;} #footer.widget-view {position:fixed; left:0px; bottom:0px; margin:0; padding:4px 0 0 0; min-height:44px; width:100%; background:#fff;} #footer .poweredbylogo {text-align:right;} #footer .poweredbylogo span {font-size:.85em;margin-right:.3em;} + #footer .version {vertical-align:bottom;white-space:nowrap;} #footer.widget-view .widgetBrandMsg {line-height:42px;} From 383c13e8ed7feb17cb8613567a0626313d315301 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Mon, 13 Nov 2017 13:51:37 -0500 Subject: [PATCH 27/38] move Workflows content to Big Data Support in dev guide #4167 --- .../source/developers/big-data-support.rst | 98 ++++++++++++++++++- doc/sphinx-guides/source/index.rst | 1 - doc/sphinx-guides/source/workflows.rst | 92 ----------------- 3 files changed, 97 insertions(+), 94 deletions(-) delete mode 100644 doc/sphinx-guides/source/workflows.rst diff --git a/doc/sphinx-guides/source/developers/big-data-support.rst b/doc/sphinx-guides/source/developers/big-data-support.rst index 5136a1707df..fa37176e6c3 100644 --- a/doc/sphinx-guides/source/developers/big-data-support.rst +++ b/doc/sphinx-guides/source/developers/big-data-support.rst @@ -112,7 +112,7 @@ Configuring the RSAL Mock Info for configuring the RSAL Mock: https://github.com/sbgrid/rsal/tree/master/mocks -Also, to configure Dataverse to use the new workflow you must do the following: +Also, to configure Dataverse to use the new workflow you must do the following (see also the section below on workflows): 1. Configure the RSAL URL: @@ -160,3 +160,99 @@ To specify replication sites that appear in rsync URLs: In the GUI, this is called "Local Access". It's where you can compute on files on your cluster. ``curl http://localhost:8080/api/admin/settings/:LocalDataAccessPath -X PUT -d "/programs/datagrid"`` + +Workflows +--------- + +Dataverse can perform two sequences of actions when datasets are published: one prior to publishing (marked by a ``PrePublishDataset`` trigger), and one after the publication has succeeded (``PostPublishDataset``). The pre-publish workflow is useful for having an external system prepare a dataset for being publicly accessed (a possibly lengthy activity that requires moving files around, uploading videos to a streaming server, etc.), or to start an approval process. A post-publish workflow might be used for sending notifications about the newly published dataset. + +Workflow steps are created using *step providers*. Dataverse ships with an internal step provider that offers some basic functionality, and with the ability to load 3rd party step providers. This allows installations to implement functionality they need without changing the Dataverse source code. + +Steps can be internal (say, writing some data to the log) or external. External steps involve Dataverse sending a request to an external system, and waiting for the system to reply. The wait period is arbitrary, and so allows the external system unbounded operation time. This is useful, e.g., for steps that require human intervension, such as manual approval of a dataset publication. + +The external system reports the step result back to dataverse, by sending a HTTP ``POST`` command to ``api/workflows/{invocation-id}``. The body of the request is passed to the paused step for further processing. + +If a step in a workflow fails, Dataverse make an effort to roll back all the steps that preceeded it. Some actions, such as writing to the log, cannot be rolled back. If such an action has a public external effect (e.g. send an EMail to a mailing list) it is advisable to put it in the post-release workflow. + +.. tip:: + For invoking external systems using a REST api, Dataverse's internal step + provider offers a step for sending and receiving customizable HTTP requests. + It's called *http/sr*, and is detailed below. + +Administration +~~~~~~~~~~~~~~ + +A Dataverse instance stores a set of workflows in its database. Workflows can be managed using the ``api/admin/workflows/`` endpoints of the :doc:`/api/native-api`. Sample workflow files are available in ``scripts/api/data/workflows``. + +At the moment, defining a workflow for each trigger is done for the entire instance, using the endpoint ``api/admin/workflows/default/«trigger type»``. + +In order to prevent unauthorized resuming of workflows, Dataverse maintains a "white list" of IP addresses from which resume requests are honored. This list is maintained using the ``/api/admin/workflows/ip-whitelist`` endpoint of the :doc:`/api/native-api`. By default, Dataverse honors resume requests from localhost only (``127.0.0.1;::1``), so set-ups that use a single server work with no additional configuration. + + +Available Steps +~~~~~~~~~~~~~~~ + +Dataverse has an internal step provider, whose id is ``:internal``. It offers the following steps: + +log ++++ + +A step that writes data about the current workflow invocation to the instance log. It also writes the messages in its ``parameters`` map. + +.. code:: json + + { + "provider":":internal", + "stepType":"log", + "parameters": { + "aMessage": "message content", + "anotherMessage": "message content, too" + } + } + + +pause ++++++ + +A step that pauses the workflow. The workflow is paused until a POST request is sent to ``/api/workflows/{invocation-id}``. + +.. code:: json + + { + "provider":":internal", + "stepType":"pause" + } + + +http/sr ++++++++ + +A step that sends a HTTP request to an external system, and then waits for a response. The response has to match a regular expression specified in the step parameters. The url, content type, and message body can use data from the workflow context, using a simple markup language. This step has specific parameters for rollback. + +.. code:: json + + { + "provider":":internal", + "stepType":"http/sr", + "parameters": { + "url":"http://localhost:5050/dump/${invocationId}", + "method":"POST", + "contentType":"text/plain", + "body":"START RELEASE ${dataset.id} as ${dataset.displayName}", + "expectedResponse":"OK.*", + "rollbackUrl":"http://localhost:5050/dump/${invocationId}", + "rollbackMethod":"DELETE ${dataset.id}" + } + } + +Available variables are: + +* ``invocationId`` +* ``dataset.id`` +* ``dataset.identifier`` +* ``dataset.globalId`` +* ``dataset.displayName`` +* ``dataset.citation`` +* ``minorVersion`` +* ``majorVersion`` +* ``releaseStatus`` diff --git a/doc/sphinx-guides/source/index.rst b/doc/sphinx-guides/source/index.rst index afb73458bc8..a3229ebd32c 100755 --- a/doc/sphinx-guides/source/index.rst +++ b/doc/sphinx-guides/source/index.rst @@ -19,7 +19,6 @@ These guides are for the most recent version of Dataverse. For the guides for ** developers/index style/index admin/index - workflows How the Guides Are Organized ============================= diff --git a/doc/sphinx-guides/source/workflows.rst b/doc/sphinx-guides/source/workflows.rst deleted file mode 100644 index 477530ef7d1..00000000000 --- a/doc/sphinx-guides/source/workflows.rst +++ /dev/null @@ -1,92 +0,0 @@ -Workflows -========== - -Dataverse can perform two sequences of actions when datasets are published: one prior to publishing (marked by a ``PrePublishDataset`` trigger), and one after the publication has succeeded (``PostPublishDataset``). The pre-publish workflow is useful for having an external system prepare a dataset for being publicly accessed (a possibly lengthy activity that requires moving files around, uploading videos to a streaming server, etc.), or to start an approval process. A post-publish workflow might be used for sending notifications about the newly published dataset. - -Workflow steps are created using *step providers*. Dataverse ships with an internal step provider that offers some basic functionality, and with the ability to load 3rd party step providers. This allows installations to implement functionality they need without changing the Dataverse source code. - -Steps can be internal (say, writing some data to the log) or external. External steps involve Dataverse sending a request to an external system, and waiting for the system to reply. The wait period is arbitrary, and so allows the external system unbounded operation time. This is useful, e.g., for steps that require human intervension, such as manual approval of a dataset publication. - -The external system reports the step result back to dataverse, by sending a HTTP ``POST`` command to ``api/workflows/{invocation-id}``. The body of the request is passed to the paused step for further processing. - -If a step in a workflow fails, Dataverse make an effort to roll back all the steps that preceeded it. Some actions, such as writing to the log, cannot be rolled back. If such an action has a public external effect (e.g. send an EMail to a mailing list) it is advisable to put it in the post-release workflow. - -.. tip:: - For invoking external systems using a REST api, Dataverse's internal step - provider offers a step for sending and receiving customizable HTTP requests. - It's called *http/sr*, and is detailed below. - -Administration --------------- - -A Dataverse instance stores a set of workflows in its database. Workflows can be managed using the ``api/admin/workflows/`` endpoints of the :doc:`api/native-api`. Sample workflow files are available in ``scripts/api/data/workflows``. - -At the moment, defining a workflow for each trigger is done for the entire instance, using the endpoint ``api/admin/workflows/default/«trigger type»``. - -In order to prevent unauthorized resuming of workflows, Dataverse maintains a "white list" of IP addresses from which resume requests are honored. This list is maintained using the ``/api/admin/workflows/ip-whitelist`` endpoint of the :doc:`api/native-api`. By default, Dataverse honors resume requests from localhost only (``127.0.0.1;::1``), so set-ups that use a single server work with no additional configuration. - - -Available Steps ---------------- - -Dataverse has an internal step provider, whose id is ``:internal``. It offers the following steps: - -log -~~~~~~~~ -A step that writes data about the current workflow invocation to the instance log. It also writes the messages in its ``parameters`` map. - -.. code:: json - - { - "provider":":internal", - "stepType":"log", - "parameters": { - "aMessage": "message content", - "anotherMessage": "message content, too" - } - } - - -pause -~~~~~~~~ -A step that pauses the workflow. The workflow is paused until a POST request is sent to ``/api/workflows/{invocation-id}``. - -.. code:: json - - { - "provider":":internal", - "stepType":"pause" - } - - -http/sr -~~~~~~~~~ -A step that sends a HTTP request to an external system, and then waits for a response. The response has to match a regular expression specified in the step parameters. The url, content type, and message body can use data from the workflow context, using a simple markup language. This step has specific parameters for rollback. - -.. code:: json - - { - "provider":":internal", - "stepType":"http/sr", - "parameters": { - "url":"http://localhost:5050/dump/${invocationId}", - "method":"POST", - "contentType":"text/plain", - "body":"START RELEASE ${dataset.id} as ${dataset.displayName}", - "expectedResponse":"OK.*", - "rollbackUrl":"http://localhost:5050/dump/${invocationId}", - "rollbackMethod":"DELETE ${dataset.id}" - } - } - -Available variables are: - -* ``invocationId`` -* ``dataset.id`` -* ``dataset.identifier`` -* ``dataset.globalId`` -* ``dataset.displayName`` -* ``dataset.citation`` -* ``minorVersion`` -* ``majorVersion`` -* ``releaseStatus`` From 45dab479fb202dc3d9cbefe9d82de63212546137 Mon Sep 17 00:00:00 2001 From: Philip Durbin Date: Mon, 13 Nov 2017 13:53:19 -0500 Subject: [PATCH 28/38] order guides by number of readers expected #4167 --- doc/sphinx-guides/source/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/sphinx-guides/source/index.rst b/doc/sphinx-guides/source/index.rst index a3229ebd32c..8ced980c842 100755 --- a/doc/sphinx-guides/source/index.rst +++ b/doc/sphinx-guides/source/index.rst @@ -14,11 +14,11 @@ These guides are for the most recent version of Dataverse. For the guides for ** :maxdepth: 2 user/index - installation/index api/index + installation/index + admin/index developers/index style/index - admin/index How the Guides Are Organized ============================= From c4425ebdcac919904486d0a3a2c38010c12d5375 Mon Sep 17 00:00:00 2001 From: Stephen Kraffmiller Date: Mon, 13 Nov 2017 15:53:15 -0500 Subject: [PATCH 29/38] #4251 Cleanup params for request access popup --- src/main/java/edu/harvard/iq/dataverse/FilePage.java | 8 -------- src/main/webapp/file.xhtml | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/FilePage.java b/src/main/java/edu/harvard/iq/dataverse/FilePage.java index cc874a6e4a6..6b156725b90 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FilePage.java +++ b/src/main/java/edu/harvard/iq/dataverse/FilePage.java @@ -760,13 +760,5 @@ public String getPublicDownloadUrl() { return FileUtil.getPublicDownloadUrl(systemConfig.getDataverseSiteUrl(), fileId); } - - public FileDownloadHelper getFileDownloadHelper() { - return fileDownloadHelper; - } - - public void setFileDownloadHelper(FileDownloadHelper fileDownloadHelper) { - this.fileDownloadHelper = fileDownloadHelper; - } } diff --git a/src/main/webapp/file.xhtml b/src/main/webapp/file.xhtml index ee0c674948e..6241a3b4aab 100644 --- a/src/main/webapp/file.xhtml +++ b/src/main/webapp/file.xhtml @@ -532,8 +532,7 @@ - - + From aa355b2c5e66c8b39df9da8af05273329d25bb67 Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Mon, 13 Nov 2017 18:26:07 -0500 Subject: [PATCH 30/38] include all drivers in dvinstall.zip #4278 --- scripts/installer/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/installer/Makefile b/scripts/installer/Makefile index df29cda93a5..046e6cb73cd 100644 --- a/scripts/installer/Makefile +++ b/scripts/installer/Makefile @@ -45,10 +45,10 @@ ${GLASSFISH_SETUP_SCRIPT}: glassfish-setup.sh /bin/cp glassfish-setup.sh ${INSTALLER_ZIP_DIR} -${POSTGRES_DRIVERS}: pgdriver/postgresql-8.4-703.jdbc4.jar pgdriver/postgresql-9.0-802.jdbc4.jar pgdriver/postgresql-9.1-902.jdbc4.jar +${POSTGRES_DRIVERS}: pgdriver/postgresql-8.4-703.jdbc4.jar pgdriver/postgresql-9.0-802.jdbc4.jar pgdriver/postgresql-9.1-902.jdbc4.jar pgdriver/postgresql-9.2-1004.jdbc4.jar pgdriver/postgresql-9.3-1104.jdbc4.jar pgdriver/postgresql-9.4.1212.jar pgdriver/postgresql-42.1.4.jar @echo copying postgres drviers @mkdir -p ${POSTGRES_DRIVERS} - /bin/cp pgdriver/postgresql-8.4-703.jdbc4.jar pgdriver/postgresql-9.0-802.jdbc4.jar pgdriver/postgresql-9.1-902.jdbc4.jar ${INSTALLER_ZIP_DIR}/pgdriver + /bin/cp pgdriver/postgresql-8.4-703.jdbc4.jar pgdriver/postgresql-9.0-802.jdbc4.jar pgdriver/postgresql-9.1-902.jdbc4.jar pgdriver/postgresql-9.2-1004.jdbc4.jar pgdriver/postgresql-9.3-1104.jdbc4.jar pgdriver/postgresql-9.4.1212.jar pgdriver/postgresql-42.1.4.jar ${INSTALLER_ZIP_DIR}/pgdriver ${API_SCRIPTS}: ../api/setup-datasetfields.sh ../api/setup-users.sh ../api/setup-dvs.sh ../api/setup-identity-providers.sh ../api/setup-all.sh ../api/post-install-api-block.sh ../api/setup-builtin-roles.sh ../api/data @echo copying api scripts From b5bbc404513c2a80598fdc8619e614b16a9c4ea5 Mon Sep 17 00:00:00 2001 From: Derek Murphy Date: Tue, 14 Nov 2017 13:09:14 -0500 Subject: [PATCH 31/38] Oauth2 error msg revision [#4218] Edited error message in bundle, also edited callback.xhtml to get link to the user guide working. --- src/main/java/Bundle.properties | 2 +- src/main/webapp/oauth2/callback.xhtml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index 9175ca2d031..2a5bb57589f 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -332,7 +332,7 @@ oauth2.convertAccount.success=Your Dataverse account is now associated with your # oauth2/callback.xhtml oauth2.callback.page.title=OAuth Callback -oauth2.callback.message=OAuth2 Error - Sorry, the identification process did not succeed. +oauth2.callback.message=Authentication Error - Dataverse could not authenticate your ORCID login. Please make sure you authorize your ORCID account to connect with Dataverse. For more details, see the User Guide. # tab on dataverseuser.xhtml apitoken.title=API Token diff --git a/src/main/webapp/oauth2/callback.xhtml b/src/main/webapp/oauth2/callback.xhtml index 80c02e26819..9ccef3ddb2a 100644 --- a/src/main/webapp/oauth2/callback.xhtml +++ b/src/main/webapp/oauth2/callback.xhtml @@ -21,7 +21,10 @@

diff --git a/src/main/webapp/resources/css/structure.css b/src/main/webapp/resources/css/structure.css index fd4eab647c1..12b0c889a4c 100644 --- a/src/main/webapp/resources/css/structure.css +++ b/src/main/webapp/resources/css/structure.css @@ -42,7 +42,6 @@ body .ui-widget {font-size: inherit;} #footer.widget-view {position:fixed; left:0px; bottom:0px; margin:0; padding:4px 0 0 0; min-height:44px; width:100%; background:#fff;} #footer .poweredbylogo {text-align:right;} #footer .poweredbylogo span {font-size:.85em;margin-right:.3em;} - #footer .version {vertical-align:bottom;white-space:nowrap;} #footer.widget-view .widgetBrandMsg {line-height:42px;} From 11d4f0dd95d539889e125af2ea614c5282c53deb Mon Sep 17 00:00:00 2001 From: Pete Meyer Date: Thu, 16 Nov 2017 11:40:35 -0500 Subject: [PATCH 35/38] incorporate wording / button text changes --- src/main/java/Bundle.properties | 5 +++-- src/main/webapp/loginpage.xhtml | 8 ++++++-- src/main/webapp/oauth2/callback.xhtml | 11 ++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/Bundle.properties b/src/main/java/Bundle.properties index e5404ade66f..654f7f6a747 100755 --- a/src/main/java/Bundle.properties +++ b/src/main/java/Bundle.properties @@ -246,6 +246,7 @@ login.error=Error validating the username, email address, or password. Please tr user.error.cannotChangePassword=Sorry, your password cannot be changed. Please contact your system administrator. user.error.wrongPassword=Sorry, wrong password. login.button=Log In with {0} +login.button.orcid=Create or Connect your ORCID # authentication providers auth.providers.title=Other options auth.providers.tip=You can convert a Dataverse account to use one of the options above. Learn more. @@ -332,7 +333,7 @@ oauth2.convertAccount.success=Your Dataverse account is now associated with your # oauth2/callback.xhtml oauth2.callback.page.title=OAuth Callback -oauth2.callback.message=Authentication Error - Dataverse could not authenticate your ORCID login. Please make sure you authorize your ORCID account to connect with Dataverse. For more details, see the User Guide. +oauth2.callback.message=Authentication Error - Dataverse could not authenticate your ORCID login. Please make sure you authorize your ORCID account to connect with Dataverse. For more details about the information being requested, see the User Guide. # tab on dataverseuser.xhtml apitoken.title=API Token @@ -1701,4 +1702,4 @@ authenticationProvider.name.shib=Shibboleth ingest.csv.invalidHeader=Invalid header row. One of the cells is empty. ingest.csv.lineMismatch=Mismatch between line counts in first and final passes!, {0} found on first pass, but {1} found on second. ingest.csv.recordMismatch=Reading mismatch, line {0} of the Data file: {1} delimited values expected, {2} found. -ingest.csv.nullStream=Stream can't be null. \ No newline at end of file +ingest.csv.nullStream=Stream can't be null. diff --git a/src/main/webapp/loginpage.xhtml b/src/main/webapp/loginpage.xhtml index af0ebb0e0f6..229da67e691 100644 --- a/src/main/webapp/loginpage.xhtml +++ b/src/main/webapp/loginpage.xhtml @@ -189,7 +189,7 @@
- +

@@ -197,7 +197,11 @@ and a transparent method of linking research activities and outputs to these identifiers. ORCID is unique in its ability to reach across disciplines, research sectors, and national boundaries and its cooperation with other identifier systems. Find out more at orcid.org/about. -

+

+

+ This repository uses your ORCID for authentication (so you don't need another username/password combination). + Having your ORCID associated with your datasets also makes it easier for people to find the datasets you have published. +

diff --git a/src/main/webapp/oauth2/callback.xhtml b/src/main/webapp/oauth2/callback.xhtml index 9ccef3ddb2a..6ae50318e6c 100644 --- a/src/main/webapp/oauth2/callback.xhtml +++ b/src/main/webapp/oauth2/callback.xhtml @@ -20,11 +20,16 @@ -