Allow automatic canonical web URL detection

Do not rely anymore on a statically defined canonicalWebUrl and instead
resolve it dynamically at runtime from the incoming request.

Enable the use of the GitHub OAuth plugin in a multi-tenant environment
where the same Gerrit Server can serve multiple domains at once,
by automatically getting the server name and path from the incoming
request.

Change-Id: Ia744273cbb8a4367cd37a8966ba546ce1a8e2aae
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
index 88c8b18..1625b81 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubLogin.java
@@ -110,7 +110,7 @@
       Set<String> configuredScopesProfiles = config.scopes.keySet();
       String scopeRequested = getScopesKey(request, response);
       if (Strings.isNullOrEmpty(scopeRequested) && configuredScopesProfiles.size() > 1) {
-        response.sendRedirect(config.scopeSelectionUrl);
+        response.sendRedirect(config.getScopeSelectionUrl(request));
       } else {
         this.loginScopes = getScopes(MoreObjects.firstNonNull(scopeRequested, "scopes"), scopes);
         log.debug("Login-PHASE1 " + this);
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java
index 03fabc6..319a850 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/GitHubOAuthConfig.java
@@ -19,8 +19,8 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
 import com.google.gerrit.extensions.client.AuthType;
+import com.google.gerrit.httpd.CanonicalWebUrl;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
@@ -31,11 +31,15 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
 import lombok.Getter;
 import org.eclipse.jgit.lib.Config;
 
 @Singleton
 public class GitHubOAuthConfig {
+  private final Config config;
+  private final CanonicalWebUrl canonicalWebUrl;
+
   public static final String CONF_SECTION = "github";
   public static final String GITHUB_OAUTH_AUTHORIZE = "/login/oauth/authorize";
   public static final String GITHUB_OAUTH_ACCESS_TOKEN = "/login/oauth/access_token";
@@ -54,7 +58,6 @@
   public final String logoutRedirectUrl;
   public final String httpHeader;
   public final String gitHubOAuthUrl;
-  public final String oAuthFinalRedirectUrl;
   public final String gitHubOAuthAccessTokenUrl;
   public final boolean enabled;
 
@@ -64,15 +67,15 @@
   public final int fileUpdateMaxRetryIntervalMsec;
   public final String oauthHttpHeader;
 
-  @Getter public final String scopeSelectionUrl;
   public final long httpConnectionTimeout;
   public final long httpReadTimeout;
 
   @Inject
   protected GitHubOAuthConfig(
-      @GerritServerConfig Config config,
-      @CanonicalWebUrl String canonicalWebUrl,
-      AuthConfig authConfig) {
+      @GerritServerConfig Config config, CanonicalWebUrl canonicalWebUrl, AuthConfig authConfig) {
+    this.config = config;
+    this.canonicalWebUrl = canonicalWebUrl;
+
     httpHeader =
         Preconditions.checkNotNull(
             config.getString("auth", null, "httpHeader"),
@@ -97,12 +100,6 @@
     gitHubOAuthUrl = gitHubUrl + GITHUB_OAUTH_AUTHORIZE;
     gitHubOAuthAccessTokenUrl = gitHubUrl + GITHUB_OAUTH_ACCESS_TOKEN;
     logoutRedirectUrl = config.getString(CONF_SECTION, null, "logoutRedirectUrl");
-    oAuthFinalRedirectUrl = trimTrailingSlash(canonicalWebUrl) + GERRIT_OAUTH_FINAL;
-    scopeSelectionUrl =
-        trimTrailingSlash(canonicalWebUrl)
-            + MoreObjects.firstNonNull(
-                config.getString(CONF_SECTION, null, "scopeSelectionUrl"),
-                GITHUB_PLUGIN_OAUTH_SCOPE);
 
     enabled = config.getString("auth", null, "type").equalsIgnoreCase(AuthType.HTTP.toString());
     scopes = getScopes(config);
@@ -124,6 +121,19 @@
             TimeUnit.SECONDS);
   }
 
+  public String getOAuthFinalRedirectUrl(HttpServletRequest req) {
+    return req == null
+        ? GERRIT_OAUTH_FINAL
+        : trimTrailingSlash(canonicalWebUrl.get(req)) + GERRIT_OAUTH_FINAL;
+  }
+
+  public String getScopeSelectionUrl(HttpServletRequest req) {
+    String canonicalUrl = req == null ? "" : trimTrailingSlash(canonicalWebUrl.get(req));
+    return canonicalUrl
+        + MoreObjects.firstNonNull(
+            config.getString(CONF_SECTION, null, "scopeSelectionUrl"), GITHUB_PLUGIN_OAUTH_SCOPE);
+  }
+
   private Map<String, List<Scope>> getScopes(Config config) {
     Map<String, List<Scope>> result = Maps.newHashMap();
     Set<String> configKeys = config.getNames(CONF_SECTION, true);
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java
index a60ee05..ddbbec9 100644
--- a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java
+++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/oauth/OAuthProtocol.java
@@ -248,12 +248,12 @@
     }
   }
 
-  public String getAuthorizationUrl(String scopesString, String state) {
+  public String getAuthorizationUrl(String scopesString, String state, HttpServletRequest req) {
     return config.gitHubOAuthUrl
         + "?client_id="
         + config.gitHubClientId
         + getURLEncodedParameter("&scope=", scopesString)
-        + getURLEncodedParameter("&redirect_uri=", config.oAuthFinalRedirectUrl)
+        + getURLEncodedParameter("&redirect_uri=", config.getOAuthFinalRedirectUrl(req))
         + getURLEncodedParameter("&state=", state);
   }
 
@@ -272,7 +272,7 @@
             + config.gitHubClientId
             + " Scopes="
             + scopesString);
-    response.sendRedirect(getAuthorizationUrl(scopesString, state));
+    response.sendRedirect(getAuthorizationUrl(scopesString, state, request));
     return state;
   }
 
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
index 1a6d7fe..a6646b1 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubConfig.java
@@ -15,9 +15,9 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Maps;
+import com.google.gerrit.httpd.CanonicalWebUrl;
 import com.google.gerrit.server.config.AllProjectsNameProvider;
 import com.google.gerrit.server.config.AuthConfig;
-import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
@@ -72,7 +72,7 @@
       @GerritServerConfig Config config,
       final SitePaths site,
       AllProjectsNameProvider allProjectsNameProvider,
-      @CanonicalWebUrl String canonicalWebUrl,
+      CanonicalWebUrl canonicalWebUrl,
       AuthConfig authConfig)
       throws MalformedURLException {
     super(config, canonicalWebUrl, authConfig);
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubOAuthServiceProvider.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubOAuthServiceProvider.java
index 7ee4dbf..6c2cb84 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubOAuthServiceProvider.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubOAuthServiceProvider.java
@@ -45,7 +45,7 @@
   @Override
   public String getAuthorizationUrl() {
     return oauth.getAuthorizationUrl(
-        oauth.getScope(Sets.newHashSet(config.getDefaultScopes())), null);
+        oauth.getScope(Sets.newHashSet(config.getDefaultScopes())), null, null);
   }
 
   @Override
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java
index 860a13a..5ff5363 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GitHubTopMenu.java
@@ -47,7 +47,7 @@
             new MenuEntry(
                 "GitHub",
                 Arrays.asList(
-                    getItem("Scope", ghConfig.scopeSelectionUrl),
+                    getItem("Scope", ghConfig.getScopeSelectionUrl(null)),
                     getItem("Profile", baseUrl + "/static/account.html"),
                     getItem("Repositories", baseUrl + "/static/repositories.html"),
                     getItem("Pull Requests", baseUrl + "/static/pullrequests.html"))));