0

I've recently added Java Melody to a grails application. So I wanted to restrict the IP addresses that can access the monitoring endpoint, and also add basic auth for it so that not anyone can access the monitoring endpoint once the application is released for public use.

I've added filters to my web.xml, according to their documentation (https://github.com/javamelody/javamelody/wiki/UserGuide#16-security).

They look like this:

<filter>
    <filter-name>javamelody</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <init-param>
        <param-name>authorized-users</param-name>
        <param-value>user1:pwd1</param-value>
    </init-param>
    <init-param>
        <param-name>allowed-addr-pattern</param-name>
        <param-value>192\.168\.1\.*</param-value>
    </init-param>
</filter>

<filter-mapping>
        <filter-name>javamelody</filter-name>
        <url-pattern>/monitoring</url-pattern>
</filter-mapping>

I've verified that it works when I run the application using grails run-app. If i try to access the monitoring endpoint, I am prompted for a username and password.

However, when I create a war file and deploy it to run on a jetty instance, the security filters don't work anymore. I can access the monitoring endpoint without providing a username and password.

Can anyone help me? I'm new to this and I really don't know how to proceed with this problem. I searched around for answers but nothing really fits the bill. I'm not sure if the issue is with Java Melody or with Jetty.

Appreciate all the help I can get. Thanks!

EDIT:

My whole web.xml used in grails prod run-app:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
     metadata-complete="true"
     xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

<display-name>/@grails.project.key@</display-name>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>@grails.project.key@</param-value>
</context-param>

<filter>
    <filter-name>charEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>characterEncodingFilter</param-value>
    </init-param>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter>
    <filter-name>javamelody</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <init-param>
        <param-name>authorized-users</param-name>
        <param-value>user1:pwd1</param-value>
    </init-param>
    <init-param>
        <param-name>allowed-addr-pattern</param-name>
        <param-value>192\.168\.1\.*</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>charEncodingFilter</filter-name>
    <url-pattern>/ *</url-pattern>
</filter-mapping>


<filter-mapping>
    <filter-name>javamelody</filter-name>
    <url-pattern>/monitoring</url-pattern>
</filter-mapping>


<listener>
    <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
</listener>

<!-- Grails dispatcher servlet -->
<servlet>
    <servlet-name>grails</servlet-name>
    <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
    <init-param>
        <param-name>dispatchOptionsRequest</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

<!-- The Groovy Server Pages servlet -->
<servlet>
    <servlet-name>gsp</servlet-name>
    <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>gsp</servlet-name>
    <url-pattern>*.gsp</url-pattern>
</servlet-mapping>

<session-config>
    <!-- 30 minutes -->
    <session-timeout>30</session-timeout>
</session-config>

<welcome-file-list>
    <!--
    The order of the welcome pages is important.  JBoss deployment will
    break if index.gsp is first in the list.
    -->
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.gsp</welcome-file>
</welcome-file-list>

Web.xml of my WAR file:

<web-app xmlns="http://java.sun.com/xml/ns/javaee" metadata-complete="true" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<display-name>/radius-api-production-0.1</display-name>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<context-param>
    <param-name>webAppRootKey</param-name>
    <param-value>radius-api-production-0.1</param-value>
</context-param>
<context-param>
    <param-name>sample</param-name>
    <param-value>Sample Value</param-value>
</context-param>
<context-param>
    <param-name>javamelody.displayed-counters</param-name>
    <param-value>http,sql,error,log,spring,jsp</param-value>
</context-param>
<filter>
    <filter-name>monitoring</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter>
    <filter-name>charEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>characterEncodingFilter</param-value>
    </init-param>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter>
    <filter-name>AssetPipelineFilter</filter-name>
    <filter-class>asset.pipeline.AssetPipelineFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter>
    <filter-name>javamelody</filter-name>
    <filter-class>net.bull.javamelody.MonitoringFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
        <param-name>authorized-users</param-name>
        <param-value>user1:pwd1</param-value>
    </init-param>
</filter>
<filter>
    <filter-name>urlMapping</filter-name>
    <filter-class>org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter>
    <filter-name>hiddenHttpMethod</filter-name>
    <filter-class>org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter>
    <filter-name>grailsWebRequest</filter-name>
    <filter-class>org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter>
    <filter-name>grailsCacheFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>charEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>hiddenHttpMethod</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
    <filter-name>javamelody</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>AssetPipelineFilter</filter-name>
    <url-pattern>/assets/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
    <filter-name>grailsWebRequest</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
<filter-mapping>
    <filter-name>monitoring</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>urlMapping</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
    <filter-name>grailsCacheFilter</filter-name>
    <url-pattern>*.dispatch</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<listener>
    <listener-class>net.bull.javamelody.SessionListener</listener-class>
</listener>
<listener>
    <listener-class>org.codehaus.groovy.grails.plugins.log4j.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
    <listener-class>org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener</listener-class>
</listener>
<servlet>
    <servlet-name>grails</servlet-name>
    <servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
    <init-param>
        <param-name>dispatchOptionsRequest</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>
<servlet>
    <servlet-name>gsp</servlet-name>
    <servlet-class>org.codehaus.groovy.grails.web.pages.GroovyPagesServlet</servlet-class>
</servlet>
<servlet>
    <servlet-name>grails-errorhandler</servlet-name>
    <servlet-class>org.codehaus.groovy.grails.web.servlet.ErrorHandlingServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>gsp</servlet-name>
    <url-pattern>*.gsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>grails-errorhandler</servlet-name>
    <url-pattern>/grails-errorhandler</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>grails</servlet-name>
    <url-pattern>*.dispatch</url-pattern>
</servlet-mapping>
<session-config>
    <session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.gsp</welcome-file>
</welcome-file-list>
<error-page>
    <error-code>500</error-code>
    <location>/grails-errorhandler</location>
</error-page>

Alron
  • 1
  • 2

1 Answers1

0
  1. you can turn on debug logging to see if the monitorFilter is started. I've found this in melody's source. LOG.debug("JavaMelody filter init started");
  2. you can extend the monitorFilter, override the init method and add logging of the init-params. like: public void init(FilterConfig config) throws ServletException { //log the init-params here //blabla super.init(config); }

Your problem looks like caused by web.xml conflit, providing the whole web.xml file and versions info would be better.

PaniniGelato
  • 565
  • 1
  • 5
  • 13
  • I've updated my post to include both the web.xml used in `grails prod run-app` and the web.xml included in the generated war file run on jetty. I've tried your suggestion (somewhat, not exactly) and found that my melody filters were being logged when doing `grails prod run-app` but not when on jetty. Could it be possible that the generation of the web.xml file for my WAR caused it to not work properly? @PaniniGelato – Alron Nov 06 '15 at 09:38
  • I can see 2 MonitoringFilter in your jetty-web.xml. One named 'monitoring' without init-params, the other named 'javamelody' with params. Could u try remove one of them? – PaniniGelato Nov 09 '15 at 04:18