diff --git a/doc/Architecture/update-user-account-info.png b/doc/Architecture/update-user-account-info.png
index a372104438c..aa7d5f881f1 100644
Binary files a/doc/Architecture/update-user-account-info.png and b/doc/Architecture/update-user-account-info.png differ
diff --git a/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/microsoft.json b/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/microsoft.json
new file mode 100644
index 00000000000..8c555735577
--- /dev/null
+++ b/doc/sphinx-guides/source/_static/installation/files/root/auth-providers/microsoft.json
@@ -0,0 +1,8 @@
+{
+ "id":"microsoft",
+ "factoryAlias":"oauth2",
+ "title":"Microsoft",
+ "subtitle":"",
+ "factoryData":"type: microsoft | userEndpoint: NONE | clientId: FIXME | clientSecret: FIXME",
+ "enabled":true
+}
diff --git a/doc/sphinx-guides/source/installation/oauth2.rst b/doc/sphinx-guides/source/installation/oauth2.rst
index d77a320446b..14483d655c3 100644
--- a/doc/sphinx-guides/source/installation/oauth2.rst
+++ b/doc/sphinx-guides/source/installation/oauth2.rst
@@ -1,5 +1,5 @@
-OAuth Login: ORCID, GitHub, Google
-==================================
+OAuth Login Options
+===================
.. contents:: |toctitle|
:local:
@@ -11,7 +11,7 @@ As explained under "Auth Modes" in the :doc:`config` section, OAuth2 is one of t
`OAuth2 `_ is an authentication protocol that allows systems to share user data, while letting the users control what data is being shared. When you see buttons stating "login with Google" or "login through Facebook", OAuth2 is probably involved. For the purposes of this section, we will shorten "OAuth2" to just "OAuth." OAuth can be compared and contrasted with :doc:`shibboleth`.
-Dataverse supports three OAuth providers: `ORCID `_, `GitHub `_, and `Google `_.
+Dataverse supports four OAuth providers: `ORCID `_, `Microsoft Azure Active Directory (AD) `_, `GitHub `_, and `Google `_.
Setup
-----
@@ -24,18 +24,19 @@ Identity Provider Side
Obtain Client ID and Client Secret
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Before OAuth providers will release information about their users (first name, last name, etc.) to your Dataverse installation, you must request a "Client ID" and "Client Secret" from them. In the case of GitHub and Google, this is as simple as clicking a few buttons and there is no cost associated with using their authentication service. ORCID, on the other hand, does not have an automated system for requesting these credentials, and it is not free to use the ORCID authentication service.
+Before OAuth providers will release information about their users (first name, last name, etc.) to your Dataverse installation, you must request a "Client ID" and "Client Secret" from them. In the case of GitHub and Google, this is as simple as clicking a few buttons and there is no cost associated with using their authentication service. ORCID and Microsoft, on the other hand, do not have an automated system for requesting these credentials, and it is not free to use these authentication services.
-URLs to help you request a Client ID and Client Secret from the providers supported by Dataverse are provided below. For all of these providers, it's a good idea to request the Client ID and Client secret using a generic account, perhaps the one that's associated with the ``:SystemEmail`` you've configured for Dataverse, rather than your own personal ORCID, GitHub, or Google account:
+URLs to help you request a Client ID and Client Secret from the providers supported by Dataverse are provided below. For all of these providers, it's a good idea to request the Client ID and Client secret using a generic account, perhaps the one that's associated with the ``:SystemEmail`` you've configured for Dataverse, rather than your own personal Microsoft Azure AD, ORCID, GitHub, or Google account:
- ORCID: https://orcid.org/content/register-client-application-production-trusted-party
+- Microsoft: https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code
- GitHub: https://github.com/settings/applications/new via https://developer.github.com/v3/oauth/
- Google: https://console.developers.google.com/projectselector/apis/credentials via https://developers.google.com/identity/protocols/OAuth2WebServer (pick "OAuth client ID")
Each of these providers will require the following information from you:
- Basic information about your Dataverse installation such as a name, description, URL, logo, privacy policy, etc.
-- OAuth2 Redirect URI (ORCID) or Authorization Callback URL (GitHub) or Authorized Redirect URIs (Google): This is the URL on the Dataverse side to which the user will be sent after successfully authenticating with the identity provider. This should be the advertised URL of your Dataverse installation (the protocol, fully qualified domain name, and optional port configured via the ``dataverse.siteUrl`` JVM option mentioned in the :doc:`config` section) appended with ``/oauth2/callback.xhtml`` such as ``https://dataverse.example.edu/oauth2/callback.xhtml``.
+- OAuth2 Redirect URI (ORCID) or Redirect URI (Microsoft Azure AD) or Authorization Callback URL (GitHub) or Authorized Redirect URIs (Google): This is the URL on the Dataverse side to which the user will be sent after successfully authenticating with the identity provider. This should be the advertised URL of your Dataverse installation (the protocol, fully qualified domain name, and optional port configured via the ``dataverse.siteUrl`` JVM option mentioned in the :doc:`config` section) appended with ``/oauth2/callback.xhtml`` such as ``https://dataverse.example.edu/oauth2/callback.xhtml``.
When you are finished you should have a Client ID and Client Secret from the provider. Keep them safe and secret.
@@ -51,6 +52,7 @@ We will ``POST`` a JSON file containing the Client ID and Client Secret to this
- :download:`orcid.json <../_static/installation/files/root/auth-providers/orcid.json>`
- :download:`github.json <../_static/installation/files/root/auth-providers/github.json>`
- :download:`google.json <../_static/installation/files/root/auth-providers/google.json>`
+- :download:`microsoft.json <../_static/installation/files/root/auth-providers/microsoft.json>`
Here's how the JSON template for GitHub looks, for example:
diff --git a/doc/sphinx-guides/source/user/account.rst b/doc/sphinx-guides/source/user/account.rst
index f9180a530c3..cd08fe3dbbc 100755
--- a/doc/sphinx-guides/source/user/account.rst
+++ b/doc/sphinx-guides/source/user/account.rst
@@ -22,12 +22,13 @@ Dataverse has been configured for one or more of the following log in options:
- Username/Email and Password
- Institutional Log In
- ORCID
+- Microsoft Azure AD
- GitHub
- Google
Please note that once you create your Dataverse account, it will be associated with only one of the log in options above.
-The Institutional Log In, ORCID, GitHub, and Google options are described in more detail below under "Remote Authentication."
+The Institutional Log In, ORCID, Microsoft, GitHub, and Google options are described in more detail below under "Remote Authentication."
Create Account
~~~~~~~~~~~~~~
@@ -134,10 +135,10 @@ Convert your Dataverse account away from ORCID for log in
If you don't want to log in to Dataverse using ORCID any more, you will want to convert your Dataverse account to the Dataverse Username/Email log in option. To do this, you will need to contact support for the Dataverse installation you are using. On your account page, there is a link that will open a popup form to contact support for assistance.
-GitHub and Google Log In
-~~~~~~~~~~~~~~~~~~~~~~~~~
+Microsoft Azure AD, GitHub, and Google Log In
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You can also convert your Dataverse account to use authentication provided by GitHub or Google. These options may be found in the "Other options" section of the log in page, and function similarly to how ORCID is outlined above. If you would like to convert your account away from using one of these services for log in, then you can follow the same steps as listed above for converting away from the ORCID log in.
+You can also convert your Dataverse account to use authentication provided by GitHub, Microsoft, or Google. These options may be found in the "Other options" section of the log in page, and function similarly to how ORCID is outlined above. If you would like to convert your account away from using one of these services for log in, then you can follow the same steps as listed above for converting away from the ORCID log in.
My Data
-------
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 70e8c092df3..65bf466e3ef 100644
--- a/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java
+++ b/src/main/java/edu/harvard/iq/dataverse/authorization/AuthenticationServiceBean.java
@@ -20,6 +20,7 @@
import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GitHubOAuth2AP;
import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GoogleOAuth2AP;
import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.OrcidOAuth2AP;
+import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.MicrosoftOAuth2AP;
import edu.harvard.iq.dataverse.authorization.providers.shib.ShibAuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.providers.shib.ShibAuthenticationProviderFactory;
import edu.harvard.iq.dataverse.authorization.users.ApiToken;
@@ -880,13 +881,15 @@ public AuthenticatedUser canLogInAsBuiltinUser(String username, String password)
public List getAuthenticationProviderIdsSorted() {
GitHubOAuth2AP github = new GitHubOAuth2AP(null, null);
GoogleOAuth2AP google = new GoogleOAuth2AP(null, null);
+ MicrosoftOAuth2AP microsoft = new MicrosoftOAuth2AP(null, null);
return Arrays.asList(
BuiltinAuthenticationProvider.PROVIDER_ID,
ShibAuthenticationProvider.PROVIDER_ID,
OrcidOAuth2AP.PROVIDER_ID_PRODUCTION,
OrcidOAuth2AP.PROVIDER_ID_SANDBOX,
github.getId(),
- google.getId()
+ google.getId(),
+ microsoft.getId()
);
}
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 d26a87cf020..700bd17a176 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
@@ -127,7 +127,7 @@ public OAuth2UserRecord getUserRecord(String code, @NotNull OAuth20Service servi
throws IOException, OAuth2Exception, InterruptedException, ExecutionException {
OAuth2AccessToken accessToken = service.getAccessToken(code);
-
+ //final String userEndpoint = getUserEndpoint(accessToken);
// We need to check if scope is null first: GitHub is used without scope, so the responses scope is null.
// Checking scopes via Stream to be independent from order.
if ( ( accessToken.getScope() != null && ! getScope().stream().allMatch(accessToken.getScope()::contains) ) ||
@@ -135,11 +135,12 @@ public OAuth2UserRecord getUserRecord(String code, @NotNull OAuth20Service servi
// We did not get the permissions on the scope(s) we need. Abort and inform the user.
throw new OAuth2Exception(200, BundleUtil.getStringFromBundle("auth.providers.insufficientScope", Arrays.asList(this.getTitle())), "");
}
-
OAuthRequest request = new OAuthRequest(Verb.GET, getUserEndpoint(accessToken));
request.setCharset("UTF-8");
+ if (id.equals("microsoft")) {
+ request.addHeader("Accept", "application/json");
+ }
service.signRequest(accessToken, request);
-
Response response = service.execute(request);
int responseCode = response.getCode();
String body = response.getBody();
diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2AuthenticationProviderFactory.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2AuthenticationProviderFactory.java
index eebe87dea97..594ee6f718d 100644
--- a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2AuthenticationProviderFactory.java
+++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/OAuth2AuthenticationProviderFactory.java
@@ -7,6 +7,7 @@
import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GitHubOAuth2AP;
import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.GoogleOAuth2AP;
import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.OrcidOAuth2AP;
+import edu.harvard.iq.dataverse.authorization.providers.oauth2.impl.MicrosoftOAuth2AP;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -31,6 +32,7 @@ public OAuth2AuthenticationProviderFactory() {
builders.put("github", (row, data) -> readRow(row, new GitHubOAuth2AP(data.get("clientId"), data.get("clientSecret"))));
builders.put("google", (row, data) -> readRow(row, new GoogleOAuth2AP(data.get("clientId"), data.get("clientSecret"))));
builders.put("orcid", (row, data) -> readRow(row, new OrcidOAuth2AP(data.get("clientId"), data.get("clientSecret"), data.get("userEndpoint"))));
+ builders.put("microsoft", (row, data) -> readRow(row, new MicrosoftOAuth2AP(data.get("clientId"), data.get("clientSecret"))));
}
@Override
diff --git a/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/MicrosoftOAuth2AP.java b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/MicrosoftOAuth2AP.java
new file mode 100644
index 00000000000..da260a9fb0e
--- /dev/null
+++ b/src/main/java/edu/harvard/iq/dataverse/authorization/providers/oauth2/impl/MicrosoftOAuth2AP.java
@@ -0,0 +1,60 @@
+package edu.harvard.iq.dataverse.authorization.providers.oauth2.impl;
+
+import com.github.scribejava.apis.MicrosoftAzureActiveDirectory20Api;
+import com.github.scribejava.core.builder.api.DefaultApi20;
+import edu.harvard.iq.dataverse.authorization.providers.oauth2.AbstractOAuth2AuthenticationProvider;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.logging.Logger;
+import java.io.StringReader;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import edu.harvard.iq.dataverse.authorization.AuthenticatedUserDisplayInfo;
+
+/**
+ *
+ * @author
+ */
+public class MicrosoftOAuth2AP extends AbstractOAuth2AuthenticationProvider{
+
+ private static final Logger logger = Logger.getLogger(MicrosoftOAuth2AP.class.getCanonicalName());
+
+ public MicrosoftOAuth2AP(String aClientId, String aClientSecret){
+ this.id = "microsoft";
+ this.title = "Microsoft";
+ this.clientId = aClientId;
+ this.clientSecret = aClientSecret;
+ this.scope = Arrays.asList("User.Read");
+ this.baseUserEndpoint = "https://graph.microsoft.com/v1.0/me";
+ }
+
+ @Override
+ public DefaultApi20 getApiInstance(){
+ return MicrosoftAzureActiveDirectory20Api.instance();
+ }
+
+ @Override
+ protected ParsedUserResponse parseUserResponse(final String responseBody) {
+ try ( StringReader rdr = new StringReader(responseBody);
+ JsonReader jrdr = Json.createReader(rdr) ) {
+ JsonObject response = jrdr.readObject();
+ AuthenticatedUserDisplayInfo displayInfo = new AuthenticatedUserDisplayInfo(
+ response.getString("givenName", ""),
+ response.getString("surname", ""),
+ response.getString("userPrincipalName", ""),
+ "", "");
+ String persistentUserId = response.getString("id");
+ String username = response.getString("userPrincipalName");
+ return new ParsedUserResponse(displayInfo, persistentUserId, username,
+ (displayInfo.getEmailAddress().length() > 0 ? Collections.singletonList(displayInfo.getEmailAddress()) : Collections.emptyList() )
+ );
+ }
+ }
+
+ public boolean isDisplayIdentifier()
+ {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/propertyFiles/Bundle.properties b/src/main/java/propertyFiles/Bundle.properties
index 5014d2b3b26..ddbea69e1d2 100755
--- a/src/main/java/propertyFiles/Bundle.properties
+++ b/src/main/java/propertyFiles/Bundle.properties
@@ -393,7 +393,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 about the information being requested, see the User Guide.
+oauth2.callback.message=Authentication Error - Dataverse could not authenticate your login with the provider that you selected. Please make sure you authorize your 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