Remove deprecated legacy naming of Azure AD (Office365)

This change removes support for the legacy "office365" OAuth provider
naming and configuration, which has been deprecated in 2021: I52e8834f5c
in favor of the canonical "azure" provider.

The OAuth plugin now only exposes the Azure AD provider under the
"azure" name. Configuration using the legacy "office365" provider name
is no longer recognized.

For backward compatibility, linking of existing user identities is still
supported: when enabled, existing Gerrit accounts that were previously
created using the "office365" external ID scheme can be linked to the
new "azure" external ID scheme during authentication. No new accounts
are created using the deprecated scheme.

Administrators of sites that previously relied on the legacy Office365
naming should have had sufficient time to migrate their configuration to
the "azure" provider and, if necessary, enable identity linking to
preserve existing user accounts.

Change-Id: Ibf29c03f312bc2a3f978c824b8c79cbc81b84c65
diff --git a/src/main/java/com/googlesource/gerrit/plugins/oauth/AzureOAuthServiceModule.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/AzureOAuthServiceModule.java
deleted file mode 100644
index 95563bf..0000000
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/AzureOAuthServiceModule.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) 2025 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.oauth;
-
-import com.google.gerrit.extensions.annotations.Exports;
-import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
-import com.google.gerrit.server.config.PluginConfig;
-import com.google.inject.AbstractModule;
-import com.google.inject.Inject;
-import com.google.inject.ProvisionException;
-import com.googlesource.gerrit.plugins.oauth.azure.AzureActiveDirectoryService;
-
-public class AzureOAuthServiceModule extends AbstractModule {
-  private final OAuthPluginConfigFactory cfgFactory;
-
-  @Inject
-  public AzureOAuthServiceModule(OAuthPluginConfigFactory cfgFactory) {
-    this.cfgFactory = cfgFactory;
-  }
-
-  @Override
-  public void configure() {
-    boolean office365LegacyProviderBound = false;
-    PluginConfig cfg = cfgFactory.create(AzureActiveDirectoryService.LEGACY_PROVIDER_NAME);
-    if (cfg.getString(InitOAuth.CLIENT_ID) != null) {
-      office365LegacyProviderBound = true;
-      bindOAuthServiceProvider(AzureActiveDirectoryService.LEGACY_PROVIDER_NAME);
-    }
-    cfg = cfgFactory.create(AzureActiveDirectoryService.PROVIDER_NAME);
-    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!");
-      }
-      bindOAuthServiceProvider(AzureActiveDirectoryService.PROVIDER_NAME);
-    }
-  }
-
-  protected void bindOAuthServiceProvider(String serviceProviderName) {
-    String extIdScheme = OAuthServiceProviderExternalIdScheme.create(serviceProviderName);
-    bind(OAuthServiceProvider.class)
-        .annotatedWith(Exports.named(extIdScheme))
-        .to(AzureActiveDirectoryService.class);
-  }
-}
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 a3494c2..6ba00aa 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/HttpModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/HttpModule.java
@@ -19,6 +19,7 @@
 import com.googlesource.gerrit.plugins.oauth.airvantage.AirVantageOAuthService;
 import com.googlesource.gerrit.plugins.oauth.auth0.Auth0OAuthService;
 import com.googlesource.gerrit.plugins.oauth.authentik.AuthentikOAuthService;
+import com.googlesource.gerrit.plugins.oauth.azure.AzureActiveDirectoryService;
 import com.googlesource.gerrit.plugins.oauth.bitbucket.BitbucketOAuthService;
 import com.googlesource.gerrit.plugins.oauth.cas.CasOAuthService;
 import com.googlesource.gerrit.plugins.oauth.cognito.CognitoOAuthService;
@@ -46,7 +47,7 @@
     install(new OAuthServiceModule(cfgFactory, AirVantageOAuthService.class));
     install(new OAuthServiceModule(cfgFactory, Auth0OAuthService.class));
     install(new OAuthServiceModule(cfgFactory, AuthentikOAuthService.class));
-    install(new AzureOAuthServiceModule(cfgFactory));
+    install(new OAuthServiceModule(cfgFactory, AzureActiveDirectoryService.class));
     install(new OAuthServiceModule(cfgFactory, BitbucketOAuthService.class));
     install(new OAuthServiceModule(cfgFactory, CasOAuthService.class));
     install(new OAuthServiceModule(cfgFactory, CognitoOAuthService.class));
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 4be60e3..dbd8cd5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/InitOAuth.java
@@ -74,7 +74,6 @@
   private final Section lemonldapOAuthProviderSection;
   private final Section dexOAuthProviderSection;
   private final Section keycloakOAuthProviderSection;
-  private final Section office365OAuthProviderSection;
   private final Section azureActiveDirectoryAuthProviderSection;
   private final Section airVantageOAuthProviderSection;
   private final Section phabricatorOAuthProviderSection;
@@ -99,8 +98,6 @@
     this.keycloakOAuthProviderSection = getConfigSection(KeycloakOAuthService.class);
     this.azureActiveDirectoryAuthProviderSection =
         getConfigSection(AzureActiveDirectoryService.class);
-    this.office365OAuthProviderSection =
-        getConfigSection(AzureActiveDirectoryService.LEGACY_PROVIDER_NAME);
     this.airVantageOAuthProviderSection = getConfigSection(AirVantageOAuthService.class);
     this.phabricatorOAuthProviderSection = getConfigSection(PhabricatorOAuthService.class);
     this.tuleapOAuthProviderSection = getConfigSection(TuleapOAuthService.class);
@@ -195,28 +192,14 @@
       keycloakOAuthProviderSection.string("Keycloak Realm", REALM, null);
     }
 
-    // ?: 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 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/java/com/googlesource/gerrit/plugins/oauth/azure/AzureActiveDirectoryService.java b/src/main/java/com/googlesource/gerrit/plugins/oauth/azure/AzureActiveDirectoryService.java
index 41e8107..79edfda 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/oauth/azure/AzureActiveDirectoryService.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/oauth/azure/AzureActiveDirectoryService.java
@@ -55,9 +55,10 @@
 @OAuthServiceProviderConfig(name = AzureActiveDirectoryService.PROVIDER_NAME)
 public class AzureActiveDirectoryService implements OAuthServiceProvider {
   private static final Logger log = LoggerFactory.getLogger(AzureActiveDirectoryService.class);
-  private static final String OFFICE365_PROVIDER_PREFIX = "office365-oauth:";
+  // Canonical provider name (Azure AD)
   public static final String PROVIDER_NAME = "azure";
-  public static final String LEGACY_PROVIDER_NAME = "office365";
+  // Deprecated provider name kept for backward compatibility
+  private static final String PROVIDER_DEPRECATED_NAME = "office365";
   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";
@@ -72,17 +73,17 @@
   private final String clientId;
   private final boolean linkOffice365Id;
   private final String extIdScheme;
+  // The deprecated Office365 external ID is used for linking
+  // existing accounts from previous Gerrit installations.
+  private final String extIdDeprecatedScheme;
 
   @Inject
   AzureActiveDirectoryService(
       OAuthPluginConfigFactory cfgFactory, @CanonicalWebUrl Provider<String> urlProvider) {
     PluginConfig cfg = cfgFactory.create(PROVIDER_NAME);
-    if (cfg.getString(InitOAuth.CLIENT_ID) == null) {
-      cfg = cfgFactory.create(LEGACY_PROVIDER_NAME);
-      extIdScheme = OAuthServiceProviderExternalIdScheme.create(LEGACY_PROVIDER_NAME);
-    } else {
-      extIdScheme = OAuthServiceProviderExternalIdScheme.create(PROVIDER_NAME);
-    }
+    this.extIdScheme = OAuthServiceProviderExternalIdScheme.create(PROVIDER_NAME);
+    this.extIdDeprecatedScheme =
+        OAuthServiceProviderExternalIdScheme.create(PROVIDER_DEPRECATED_NAME);
     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);
@@ -185,7 +186,7 @@
             login,
             asString(email),
             asString(name),
-            linkOffice365Id ? OFFICE365_PROVIDER_PREFIX + id.getAsString() : null);
+            linkOffice365Id ? extIdDeprecatedScheme + ":" + id.getAsString() : null);
       }
     } catch (ExecutionException | InterruptedException e) {
       throw new RuntimeException("Cannot retrieve user info resource", e);
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 3ce8f25..a1c214a 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -50,12 +50,6 @@
     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>"