Rename Office365AuthService to AzureActiveDirectoryService
* Running plugin init step will check for previously installed
Office365 oauth and if it is found it will ask the user y/n
based on the Office365 naming.
If no configuration for Office365 where found it will ask to install
Azure oauth instead.
* Added link-to-existing-office365-accounts to support automatic linking
of any old Office365 accounts.
Change-Id: I52e8834f5c9bac0c62f5f9b19523341f0e94c874
diff --git a/README.md b/README.md
index de036fb..3e70431 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
* [Google](https://developers.google.com/identity/protocols/OAuth2)
* [Keycloak](http://www.keycloak.org/)
* [LemonLDAP::NG](https://lemonldap-ng.org)
-* [Office365](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols)
+* [Azure (previously named Office365)](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols)
* [Phabricator](https://secure.phabricator.com/book/phabcontrib/article/using_oauthserver/)
See the [Wiki](https://github.com/davido/gerrit-oauth-provider/wiki) what it can do for you.
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/Office365OAuthService.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/AzureActiveDirectoryService.java
similarity index 87%
rename from src/main/java/com/googlesource/gerrit/plugins/oauth/Office365OAuthService.java
rename to src/main/java/com/googlesource/gerrit/plugins/oauth/AzureActiveDirectoryService.java
index bdafd92..81dc53f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/Office365OAuthService.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/AzureActiveDirectoryService.java
@@ -49,14 +49,16 @@
import org.slf4j.LoggerFactory;
@Singleton
-class Office365OAuthService implements OAuthServiceProvider {
- private static final Logger log = LoggerFactory.getLogger(Office365OAuthService.class);
- static final String CONFIG_SUFFIX = "-office365-oauth";
+class AzureActiveDirectoryService implements OAuthServiceProvider {
+ private static final Logger log = LoggerFactory.getLogger(AzureActiveDirectoryService.class);
+ static final String CONFIG_SUFFIX_LEGACY = "-office365-oauth";
+ static final String CONFIG_SUFFIX = "-azure-oauth";
+ private static final String AZURE_PROVIDER_PREFIX = "azure-oauth:";
private static final String OFFICE365_PROVIDER_PREFIX = "office365-oauth:";
private static final String PROTECTED_RESOURCE_URL = "https://graph.microsoft.com/v1.0/me";
private static final String SCOPE =
"openid offline_access https://graph.microsoft.com/user.readbasic.all";
- private static final String DEFAULT_TENANT = "organizations";
+ public static final String DEFAULT_TENANT = "organizations";
private static final ImmutableSet<String> TENANTS_WITHOUT_VALIDATION =
ImmutableSet.<String>builder().add(DEFAULT_TENANT).add("common").add("consumers").build();
private final OAuth20Service service;
@@ -65,13 +67,26 @@
private final boolean useEmailAsUsername;
private final String tenant;
private final String clientId;
+ private String providerPrefix;
+ private final boolean linkOffice365Id;
@Inject
- Office365OAuthService(
+ AzureActiveDirectoryService(
PluginConfigFactory cfgFactory,
@PluginName String pluginName,
@CanonicalWebUrl Provider<String> urlProvider) {
PluginConfig cfg = cfgFactory.getFromGerritConfig(pluginName + CONFIG_SUFFIX);
+ providerPrefix = AZURE_PROVIDER_PREFIX;
+
+ // ?: Did we find the client_id with the CONFIG_SUFFIX
+ if (cfg.getString(InitOAuth.CLIENT_ID) == null) {
+ // -> No, we did not find the client_id in the azure config so we should try the old legacy
+ // office365 section
+ cfg = cfgFactory.getFromGerritConfig(pluginName + CONFIG_SUFFIX_LEGACY);
+ // We must also use the new provider prefix
+ providerPrefix = OFFICE365_PROVIDER_PREFIX;
+ }
+ this.linkOffice365Id = cfg.getBoolean(InitOAuth.LINK_TO_EXISTING_OFFICE365_ACCOUNT, false);
this.canonicalWebUrl = CharMatcher.is('/').trimTrailingFrom(urlProvider.get()) + "/";
this.useEmailAsUsername = cfg.getBoolean(InitOAuth.USE_EMAIL_AS_USERNAME, false);
this.tenant = cfg.getString(InitOAuth.TENANT, DEFAULT_TENANT);
@@ -167,12 +182,13 @@
if (useEmailAsUsername && !email.isJsonNull()) {
login = email.getAsString().split("@")[0];
}
+
return new OAuthUserInfo(
- OFFICE365_PROVIDER_PREFIX + id.getAsString() /*externalId*/,
+ providerPrefix + id.getAsString() /*externalId*/,
login /*username*/,
email == null || email.isJsonNull() ? null : email.getAsString() /*email*/,
name == null || name.isJsonNull() ? null : name.getAsString() /*displayName*/,
- null);
+ linkOffice365Id ? OFFICE365_PROVIDER_PREFIX + id.getAsString() : null);
}
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException("Cannot retrieve user info resource", e);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/HttpModule.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/HttpModule.java
index 80bc605..b9517b2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/HttpModule.java
@@ -20,6 +20,7 @@
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.inject.Inject;
+import com.google.inject.ProvisionException;
import com.google.inject.servlet.ServletModule;
class HttpModule extends ServletModule {
@@ -99,11 +100,28 @@
.to(KeycloakOAuthService.class);
}
- cfg = cfgFactory.getFromGerritConfig(pluginName + Office365OAuthService.CONFIG_SUFFIX);
+ boolean office365LegacyProviderBound = false;
+ cfg =
+ cfgFactory.getFromGerritConfig(
+ pluginName + AzureActiveDirectoryService.CONFIG_SUFFIX_LEGACY);
if (cfg.getString(InitOAuth.CLIENT_ID) != null) {
+ office365LegacyProviderBound = true;
bind(OAuthServiceProvider.class)
- .annotatedWith(Exports.named(Office365OAuthService.CONFIG_SUFFIX))
- .to(Office365OAuthService.class);
+ .annotatedWith(Exports.named(AzureActiveDirectoryService.CONFIG_SUFFIX))
+ .to(AzureActiveDirectoryService.class);
+ }
+ cfg = cfgFactory.getFromGerritConfig(pluginName + AzureActiveDirectoryService.CONFIG_SUFFIX);
+ if (cfg.getString(InitOAuth.CLIENT_ID) != null) {
+ // ?: Check if the legacy Office365 is already bound, we can only have one of these bound at
+ // one time
+ if (office365LegacyProviderBound) {
+ // -> Yes, the legacy Office365 is already bound and we are trying to bind the
+ // AzureActiveDirectoryService.CONFIG_SUFFIX at the same time.
+ throw new ProvisionException("Legacy Office365 OAuth provider is already bound!");
+ }
+ bind(OAuthServiceProvider.class)
+ .annotatedWith(Exports.named(AzureActiveDirectoryService.CONFIG_SUFFIX))
+ .to(AzureActiveDirectoryService.class);
}
cfg = cfgFactory.getFromGerritConfig(pluginName + AirVantageOAuthService.CONFIG_SUFFIX);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
index 6f7ca01..3fbb2ca 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
@@ -35,6 +35,7 @@
static final String ROOT_URL = "root-url";
static final String REALM = "realm";
static final String TENANT = "tenant";
+ static final String LINK_TO_EXISTING_OFFICE365_ACCOUNT = "link-to-existing-office365-accounts";
static final String SERVICE_NAME = "service-name";
static String FIX_LEGACY_USER_ID_QUESTION = "Fix legacy user id, without oauth provider prefix?";
@@ -49,6 +50,7 @@
private final Section dexOAuthProviderSection;
private final Section keycloakOAuthProviderSection;
private final Section office365OAuthProviderSection;
+ private final Section azureActiveDirectoryAuthProviderSection;
private final Section airVantageOAuthProviderSection;
private final Section phabricatorOAuthProviderSection;
@@ -74,7 +76,9 @@
this.keycloakOAuthProviderSection =
sections.get(PLUGIN_SECTION, pluginName + KeycloakOAuthService.CONFIG_SUFFIX);
this.office365OAuthProviderSection =
- sections.get(PLUGIN_SECTION, pluginName + Office365OAuthService.CONFIG_SUFFIX);
+ sections.get(PLUGIN_SECTION, pluginName + AzureActiveDirectoryService.CONFIG_SUFFIX_LEGACY);
+ this.azureActiveDirectoryAuthProviderSection =
+ sections.get(PLUGIN_SECTION, pluginName + AzureActiveDirectoryService.CONFIG_SUFFIX);
this.airVantageOAuthProviderSection =
sections.get(PLUGIN_SECTION, pluginName + AirVantageOAuthService.CONFIG_SUFFIX);
this.phabricatorOAuthProviderSection =
@@ -159,12 +163,28 @@
keycloakOAuthProviderSection.string("Keycloak Realm", REALM, null);
}
- boolean configureOffice365OAuthProvider =
- ui.yesno(
- isConfigured(office365OAuthProviderSection),
- "Use Office365 OAuth provider for Gerrit login ?");
- if (configureOffice365OAuthProvider) {
- configureOAuth(office365OAuthProviderSection);
+ // ?: Are there legacy office365 already configured on the system?
+ if (isConfigured(office365OAuthProviderSection)) {
+ // -> Yes, this system has already configured the old legacy office365.
+ boolean configureOffice365OAuthProvider =
+ ui.yesno(
+ isConfigured(office365OAuthProviderSection),
+ "Use Office365 OAuth provider for Gerrit login ?");
+ if (configureOffice365OAuthProvider) {
+ configureOAuth(office365OAuthProviderSection);
+ }
+ }
+ // E-> No, we either are setting up on an new system or using the new azure config
+ else {
+ boolean configureAzureActiveDirectoryAuthProvider =
+ ui.yesno(
+ isConfigured(azureActiveDirectoryAuthProviderSection),
+ "Use Azure OAuth provider for Gerrit login ?");
+ if (configureAzureActiveDirectoryAuthProvider) {
+ configureOAuth(azureActiveDirectoryAuthProviderSection);
+ azureActiveDirectoryAuthProviderSection.string(
+ "Tenant", TENANT, AzureActiveDirectoryService.DEFAULT_TENANT);
+ }
}
boolean configureAirVantageOAuthProvider =
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index fec6ecb..78eb908 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -49,10 +49,18 @@
client-secret = "<client-secret>"
root-url = "<phabricator url>"
+ # The office365 has been renamed to azure and is deprecated.
[plugin "@PLUGIN@-office365-oauth"]
client-id = "<client-id>"
client-secret = "<client-secret>"
tenant = "<tenant (optional defaults to organizations if not set)>"
+
+ [plugin "@PLUGIN@-azure-oauth"]
+ client-id = "<client-id>"
+ client-secret = "<client-secret>"
+ tenant = "<tenant (optional defaults to organizations if not set)>"
+ link-to-existing-office365-accounts = true #Optional, if set will try to link old account with the @PLUGIN@-office365-oauth naming
+
```
When one from the sections above is omitted, OAuth SSO is used.
@@ -228,26 +236,41 @@
Client application.
See [Using the Phabricator OAuth Server](https://secure.phabricator.com/book/phabcontrib/article/using_oauthserver/).
-### Office365
-The client-id and client-secret for Office365/Azure can be obtained by registering a new application,
+### Azure (previously named Office365)
+Were previously named Office365 but both `plugin.gerrit-oauth-provider-azure-oauth` and
+`plugin.gerrit-oauth-provider-office365-oauth` is supported by the Azure OAuth.
+When running *java gerrit.war init* it will check the existing config to see if it finds the old
+naming and use that during the init run, if it does not find the `office365-oauth` it will
+use the new `azure-oauth` naming.
+
+The client-id and client-secret for Azure can be obtained by registering a new application,
see [OAuth 2.0 and OpenID Connect protocols on Microsoft identity platform](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols).
####Username
-By default Office365 OAuth will not set a username (used for ssh) and the user can choose one from the web ui
-(needed before using ssh). To automatically set the user part from the email the option *use-email-as-username*
+By default, Azure OAuth will not set a username (used for ssh) and the user can choose one from the web ui
can be used.
```
-plugin.gerrit-oauth-provider-office365-oauth.use-email-as-username = true
+plugin.gerrit-oauth-provider-azure-oauth.use-email-as-username = true
```
####Tenant
-The Gerrit OAuth plugin is default set to use the tenant `organizations` but a specific tenant can be used by
+The Azure OAuth is default set to use the tenant `organizations` but a specific tenant can be used by
the option `tenant`. If a tenant other than `common`, `organizations` or `consumers` is used then the tokens will be
validated that they are originating from the same tenant that is configured in the Gerrit OAuth plugin.
-See [https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#fetch-the-openid-connect-metadata-document](Microsoft identity platform and OpenID Connect protocol)
+See [Microsoft identity platform and OpenID Connect protocol](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#fetch-the-openid-connect-metadata-document)
```
-plugin.gerrit-oauth-provider-office365-oauth.tenant = <tenant to use>
+plugin.gerrit-oauth-provider-azure-oauth.tenant = <tenant to use>
```
Regardless of tenant all tokens will be checked that they contain the client_id set
-in the Gerrit OAuth plugin.
+in the Azure OAuth.
+
+####Migrating from Office365 naming
+If this where previously installed with the `office365-oauth` you can migrate to `azure-oauth` by setting the
+flag.
+```
+plugin.gerrit-oauth-provider-azure-oauth.link-to-existing-office365-accounts = true
+```
+This will try to link the old `office365-oauth` external id to the new `azure-oauth` external id automatically.
+Another option is to migrate these manually offline, see [External IDs](https://gerrit-review.googlesource.com/Documentation/config-accounts.html#external-ids)
+for more information.
diff --git a/src/test/java/com/googlesource/gerrit/plugins/oauth/Office365ApiTest.java b/src/test/java/com/googlesource/gerrit/plugins/oauth/MicrosoftAzureActiveDirectory20ApiTest.java
similarity index 95%
rename from src/test/java/com/googlesource/gerrit/plugins/oauth/Office365ApiTest.java
rename to src/test/java/com/googlesource/gerrit/plugins/oauth/MicrosoftAzureActiveDirectory20ApiTest.java
index a725167..a98348e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/oauth/Office365ApiTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/oauth/MicrosoftAzureActiveDirectory20ApiTest.java
@@ -21,7 +21,7 @@
import org.junit.Before;
import org.junit.Test;
-public class Office365ApiTest {
+public class MicrosoftAzureActiveDirectory20ApiTest {
private MicrosoftAzureActiveDirectory20Api api;
@Before