Merge branch 'stable-2.14' into stable-2.15

* stable-2.14:
  Update bazlets to latest stable-2.14 to build with 2.14.14 API
  Update bazlets to latest stable-2.14 to build with 2.14.13 API
  Update bazlets to latest stable-2.14 to use 2.14.12 API
  Allow access using Basic Authentication prefix
  Update javamelody-core to 1.74.0
  Prefer Javamelody's own configuration constants
  Allow access to metrics from Prometheus
  Migrate `tools/bazel.rc` to `.bazelrc`
  Delegate canMonitor() check to the MonitorFilter
  Update javamelody-core to 1.73.1

Change-Id: I0d954515d2043a03ca4560b2d494b38867419b59
diff --git a/tools/bazel.rc b/.bazelrc
similarity index 100%
rename from tools/bazel.rc
rename to .bazelrc
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 28ca83b..895cfc5 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -3,8 +3,8 @@
 def external_plugin_deps():
   maven_jar(
     name = 'javamelody-core',
-    artifact = 'net.bull.javamelody:javamelody-core:1.72.0',
-    sha1 = '199beaab8db0abb45b9c3bad58bf2659d2f96499',
+    artifact = 'net.bull.javamelody:javamelody-core:1.74.0',
+    sha1 = '208ab93932b32be209d264502ed153f18034500f',
   )
 
   maven_jar(
diff --git a/src/main/java/com/googlesource/gerrit/plugins/javamelody/GerritMonitoringFilter.java b/src/main/java/com/googlesource/gerrit/plugins/javamelody/GerritMonitoringFilter.java
index c23044f..488fe94 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/javamelody/GerritMonitoringFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/javamelody/GerritMonitoringFilter.java
@@ -36,6 +36,9 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import net.bull.javamelody.MonitoringFilter;
+import net.bull.javamelody.Parameter;
+import net.bull.javamelody.internal.common.HttpParameter;
+import net.bull.javamelody.internal.common.Parameters;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,12 +46,10 @@
 class GerritMonitoringFilter extends AllRequestFilter {
   private static final Logger log = LoggerFactory.getLogger(GerritMonitoringFilter.class);
   private final JavamelodyFilter monitoring;
-  private final CapabilityChecker capabilityChecker;
 
   @Inject
-  GerritMonitoringFilter(JavamelodyFilter monitoring, CapabilityChecker capabilityChecker) {
+  GerritMonitoringFilter(JavamelodyFilter monitoring) {
     this.monitoring = monitoring;
-    this.capabilityChecker = capabilityChecker;
   }
 
   @Override
@@ -62,7 +63,7 @@
     HttpServletResponse httpResponse = (HttpServletResponse) response;
     HttpServletRequest httpRequest = (HttpServletRequest) request;
 
-    if (canMonitor(httpRequest)) {
+    if (monitoring.canMonitor(httpRequest)) {
       monitoring.doFilter(request, response, chain);
     } else {
       httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access");
@@ -79,21 +80,19 @@
     monitoring.destroy();
   }
 
-  private boolean canMonitor(HttpServletRequest httpRequest) {
-    if (httpRequest.getRequestURI().equals(monitoring.getJavamelodyUrl(httpRequest))) {
-      return capabilityChecker.canMonitor();
-    }
-    return true;
-  }
-
   static class JavamelodyFilter extends MonitoringFilter {
     private static final String JAVAMELODY_PREFIX = "javamelody";
-    private static final String HTTP_TRANSFORM_PATTERN = "http-transform-pattern";
+    private static final String HTTP_TRANSFORM_PATTERN = Parameter.HTTP_TRANSFORM_PATTERN.getCode();
     private static final String GLOBAL_HTTP_TRANSFORM_PATTERN =
         String.format("%s.%s", JAVAMELODY_PREFIX, HTTP_TRANSFORM_PATTERN);
-    private static final String STORAGE_DIR = "storage-directory";
+    private static final String STORAGE_DIR = Parameter.STORAGE_DIRECTORY.getCode();
     private static final String GLOBAL_STORAGE_DIR =
         String.format("%s.%s", JAVAMELODY_PREFIX, STORAGE_DIR);
+    private static final String PROMETHEUS_BEARER_TOKEN = "prometheusBearerToken";
+    private static final String FORMAT_PROMETHEUS = "prometheus";
+    private static final String AUTHORIZATION_HEADER = "Authorization";
+    private final CapabilityChecker capabilityChecker;
+    private final boolean useBearerTokenForPrometheus;
 
     static final String GERRIT_GROUPING =
         new StringJoiner("|")
@@ -111,14 +110,18 @@
 
     private final PluginConfig cfg;
     private final Path defaultDataDir;
+    private String authenticatedMonitoringUrl;
 
     @Inject
     JavamelodyFilter(
         PluginConfigFactory cfgFactory,
         @PluginName String pluginName,
-        @PluginData Path defaultDataDir) {
+        @PluginData Path defaultDataDir,
+        CapabilityChecker capabilityChecker) {
       this.defaultDataDir = defaultDataDir;
       this.cfg = cfgFactory.getFromGerritConfig(pluginName);
+      this.capabilityChecker = capabilityChecker;
+      this.useBearerTokenForPrometheus = isPropertyInPluginConfig(PROMETHEUS_BEARER_TOKEN);
     }
 
     @Override
@@ -140,6 +143,20 @@
       return getMonitoringUrl(httpRequest);
     }
 
+    @Override
+    protected String getMonitoringUrl(HttpServletRequest httpRequest) {
+      if (authenticatedMonitoringUrl == null) {
+        authenticatedMonitoringUrl =
+            httpRequest.getContextPath() + "/a" + Parameters.getMonitoringPath();
+      }
+
+      if (httpRequest.getRequestURI().equals(authenticatedMonitoringUrl)) {
+        return authenticatedMonitoringUrl;
+      }
+
+      return super.getMonitoringUrl(httpRequest);
+    }
+
     private String getTransformPattern() {
       return cfg.getString(HTTP_TRANSFORM_PATTERN, GERRIT_GROUPING);
     }
@@ -176,5 +193,28 @@
           && config.getServletContext().getInitParameter(globalName) == null
           && config.getInitParameter(name) == null;
     }
+
+    boolean canMonitor(HttpServletRequest httpRequest) {
+      if (httpRequest.getRequestURI().equals(getJavamelodyUrl(httpRequest))) {
+        /* Exception when access to metrics for Prometheus using Bearer Token
+         * without going through any Gerrit Authentication step.
+         * Enable to access the Prometheus metrics ONLY and nothing else, skipping
+         * any authentication and ACL check.
+         */
+        if (useBearerTokenForPrometheus
+            && httpRequest.getHeader(AUTHORIZATION_HEADER) != null
+            && FORMAT_PROMETHEUS.equals(HttpParameter.FORMAT.getParameterFrom(httpRequest))) {
+          return canMonitorFromPrometheusUsingBearerToken(httpRequest);
+        }
+        return capabilityChecker.canMonitor();
+      }
+      return true;
+    }
+
+    private boolean canMonitorFromPrometheusUsingBearerToken(HttpServletRequest httpRequest) {
+      return httpRequest
+          .getHeader(AUTHORIZATION_HEADER)
+          .equals("Bearer " + cfg.getString(PROMETHEUS_BEARER_TOKEN));
+    }
   }
 }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index dd74e42..4eaa5ba 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -23,6 +23,20 @@
 : Whether it is allowed to show top menu in Gerrit UI.
   By default true.
 
+<a id="prometheusBearerToken">
+`plugin.@PLUGIN@.prometheusBearerToken`
+: Bearer token for allowing Prometheus to query JavaMelody data
+  through its scraper.
+  When defined, access to the /monitoring?format=prometheus URL
+  does not require any authentication and do not check any ACL related
+  to the ViewMetrics global capability. Any access to the other monitoring
+  screen and URLs will still require standard authentication and authorization checks.
+  See <a href="https://github.com/javamelody/javamelody/wiki/UserGuideAdvanced#exposing-metrics-to-prometheus">JavaMelody-Prometheus</a>
+  configuration for more details and
+  <a href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/">Prometheus documentation</a>
+  for how to configure the integration with Prometheus.
+  By default undefined.
+
 <a id="storage-directory">
 `plugin.@PLUGIN@.storage-directory`
 : The directory in which to store data files. Javamelody, by default,