Javamelody: Protect monitoring url based on pugin own capability Change-Id: I12c7efd287a9a6c73ad38d9ec31e527b9201977b
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 8139caf..4bbdedb 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/javamelody/GerritMonitoringFilter.java +++ b/src/main/java/com/googlesource/gerrit/plugins/javamelody/GerritMonitoringFilter.java
@@ -21,26 +21,52 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import net.bull.javamelody.MonitoringFilter; +import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.httpd.AllRequestFilter; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.account.CapabilityControl; import com.google.inject.Inject; +import com.google.inject.Provider; import com.google.inject.Singleton; @Singleton class GerritMonitoringFilter extends AllRequestFilter { - private final MonitoringFilter monitoring; + private final JavamelodyFilter monitoring; + private final Provider<CurrentUser> userProvider; + private final String pluginName; @Inject - GerritMonitoringFilter(MonitoringFilter monitoring) { + GerritMonitoringFilter(JavamelodyFilter monitoring, + Provider<CurrentUser> userProvider, + @PluginName String pluginName) { this.monitoring = monitoring; + this.userProvider = userProvider; + this.pluginName = pluginName; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - monitoring.doFilter(request, response, chain); + if (!(request instanceof HttpServletRequest) + || !(response instanceof HttpServletResponse)) { + chain.doFilter(request, response); + return; + } + + HttpServletResponse httpResponse = (HttpServletResponse) response; + HttpServletRequest httpRequest = (HttpServletRequest) request; + + if (canMonitor(httpRequest)) { + monitoring.doFilter(request, response, chain); + } else { + httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, + "Forbidden access"); + } } @Override @@ -52,4 +78,24 @@ public void destroy() { monitoring.destroy(); } + + private boolean canMonitor(HttpServletRequest httpRequest) { + if (httpRequest.getRequestURI().equals(monitoring + .getJavamelodyUrl(httpRequest))) { + if (userProvider.get().isIdentifiedUser()) { + CapabilityControl ctl = userProvider.get().getCapabilities(); + return ctl.canAdministrateServer() + || ctl.canPerform(String.format("%s-%s", + pluginName, MonitoringCapability.ID)); + } + return false; + } + return true; + } + + static class JavamelodyFilter extends MonitoringFilter { + public String getJavamelodyUrl(HttpServletRequest httpRequest) { + return getMonitoringUrl(httpRequest); + } + } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/javamelody/Module.java b/src/main/java/com/googlesource/gerrit/plugins/javamelody/Module.java index f6b6026..e300143 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/javamelody/Module.java +++ b/src/main/java/com/googlesource/gerrit/plugins/javamelody/Module.java
@@ -14,6 +14,8 @@ package com.googlesource.gerrit.plugins.javamelody; +import com.google.gerrit.extensions.annotations.Exports; +import com.google.gerrit.extensions.config.CapabilityDefinition; import com.google.gerrit.extensions.registration.DynamicSet; import com.google.gerrit.extensions.webui.TopMenu; import com.google.inject.AbstractModule; @@ -22,7 +24,10 @@ @Override protected void configure() { + bind(CapabilityDefinition.class) + .annotatedWith(Exports.named(MonitoringCapability.ID)) + .to(MonitoringCapability.class); DynamicSet.bind(binder(), TopMenu.class) - .to(MonitoringTopMenu.class); + .to(MonitoringTopMenu.class); } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringCapability.java b/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringCapability.java new file mode 100644 index 0000000..98c32f0 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringCapability.java
@@ -0,0 +1,26 @@ +// Copyright (C) 2014 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.javamelody; + +import com.google.gerrit.extensions.config.CapabilityDefinition; + +public class MonitoringCapability extends CapabilityDefinition { + static final String ID = "monitoring"; + + @Override + public String getDescription() { + return "Javamelody Monitoring"; + } +}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringTopMenu.java b/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringTopMenu.java index abad806..59510d7 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringTopMenu.java +++ b/src/main/java/com/googlesource/gerrit/plugins/javamelody/MonitoringTopMenu.java
@@ -1,4 +1,4 @@ -// Copyright (C) 2013 The Android Open Source Project +// Copyright (C) 2014 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. @@ -18,18 +18,25 @@ import java.util.List; import com.google.common.collect.Lists; +import com.google.gerrit.extensions.annotations.PluginName; import com.google.gerrit.extensions.webui.TopMenu; import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.account.CapabilityControl; import com.google.inject.Inject; import com.google.inject.Provider; public class MonitoringTopMenu implements TopMenu { private final List<MenuEntry> menuEntries; + private final Provider<CurrentUser> userProvider; + private final String pluginName; @Inject - public MonitoringTopMenu(Provider<CurrentUser> u) { + public MonitoringTopMenu(Provider<CurrentUser> userProvider, + @PluginName String pluginName) { + this.userProvider = userProvider; + this.pluginName = pluginName; menuEntries = Lists.newArrayList(); - if (u.get().getCapabilities().canAdministrateServer()) { + if (canMonitor()) { menuEntries.add(new MenuEntry("Monitoring", Collections .singletonList(new MenuItem("JavaMelody", "monitoring")))); } @@ -39,4 +46,14 @@ public List<MenuEntry> getEntries() { return menuEntries; } + + private boolean canMonitor() { + if (userProvider.get().isIdentifiedUser()) { + CapabilityControl ctl = userProvider.get().getCapabilities(); + return ctl.canAdministrateServer() + || ctl.canPerform(String.format("%s-%s", + pluginName, MonitoringCapability.ID)); + } + return false; + } }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md index d242c6a..f7326e9 100644 --- a/src/main/resources/Documentation/about.md +++ b/src/main/resources/Documentation/about.md
@@ -3,5 +3,8 @@ This plugin integrates [JavaMelody](https://code.google.com/p/javamelody) in Gerrit in order to retrieve live instrumentation data from Gerrit. -It adds top menu item "Monitoring" that is only accessible to administratos -to access java melody page. +To access the monitoring URL a user must be a member of a group that is +granted the 'Javamelody Monitoring' capability (provided by this plugin) +or the 'Administrate Server' capability. + +It adds top menu item "Monitoring" to access java melody page.