Restrict access to java-melody monitoring url
Asked Answered
N

4

7

Is there a way I can restrict access to /monitoring url generated by Java-Melody plugin in Grails using Shiro roles?

Update: a little bit more details. It's no problem so secure most Grails ressources with shiro. But in case of the java melody plugin, it seems that the melody filter is executed before the shiro filter gets executed. This renders shiro useless.

There are some solutions which say that this might be fixed through a change in the web.xml, but this is not a quick hit and I (rdmueller) didn't manage to make it work yet. The web.xml plugin also seems to promise some help, but I don't want to add another plugin just to secure one plugin.

Some older statements found on the web state that this problem should be already solved through the usage of the loadAfter list in this file: https://github.com/javamelody/grails-melody-plugin/blob/master/GrailsMelodyGrailsPlugin.groovy - but it seems that this only worked for older versions of Grails.

Update2: In order to make it easier to propose a solution, I've create a Grails 2.2.4 sample: https://github.com/rdmueller/SO30739581

just clone the project, do a grailsw run-app and navigate to

http://localhost:8080/SO30739581/dbdoc

and you'll get a login screen via shiro. Navigate to

http://localhost:8080/SO30739581/monitoring

and you'll get the melody screen without being logged in :-(

Nonego answered 9/6, 2015 at 18:5 Comment(1)
PS: the :shiro-protect-any:0.1.0-plugin seems to work, but it seems to be to be a bit too complicated and the plugin is "not fully tested". A simpler solution would be great.Zollie
N
5

I ended up doing so by making changes to web.xml for HTTP authentication. Add this to you web.config file.

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Monitoring</realm-name>
</login-config>
<security-role>
    <role-name>monitoring</role-name>
</security-role>
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Monitoring</web-resource-name>
        <url-pattern>/monitoring</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>monitoring</role-name>
    </auth-constraint>
</security-constraint>

Then add a user and role to your tomcat-users.xml

<user username="yourusername" password="yourpassword" roles="monitoring"/>
Nonego answered 19/7, 2015 at 0:56 Comment(3)
great - this solution works. But I will still investigate some more since this solution a) does not make use of shiro b) uses basic auth which implies that https is used - otherwise it will not be secure enough. Nevertheless it's a great workaround!Zollie
btw: I did a grails installTemplates and then added your section to the web.xml file. Seems to work quite well. Thanx!Zollie
I give the bounty to this answer since it works. It does not make use of shiro, but it works :-) Thanx for sharing...Zollie
E
3

I assume you're using Grails 2.x, you could hardcode it this way :

<!-- language: java-->
// grails-app/conf/MonitoringFilters.groovy
import org.apache.shiro.SecurityUtils
class MonitoringFilters {

    def dependsOn = [ShiroSecurityFilters]

    def filters = {
        myMonitoringArea(uri: "/monitoring") {
           before = {      
              SecurityUtils.subject.hasRole('ADMIN')             
           }
        }       
    }
}
Enormous answered 15/7, 2015 at 15:1 Comment(6)
OK. with starting the bounty, I should have explained the problem a little bit more in detail: it seems that the melody filter is configured before the shiro filter which renders the shiro filter useless. Nevertheless, I will give your solution a try and see if it is somehow different from my solution.Zollie
You could define filter dependency, like this : <pre> class MonitoringFilters { ... def dependsOn = [ShiroSecurityFilters] } </pre>Enormous
I ended up implementing access control using web.xml. I'll give your solution a try and comment again. Thanks.Nonego
@AverageJoe: can you explain how you did it?Zollie
@Zollie I posted my solution as an update to the question.Nonego
@AverageJoe: Post it as an answer and you might get the bounty if the solution works for me too!Zollie
Y
1

This is not a "quick hit", but the following approach should work with Shiro or whatever security framework your Grails app uses.

In web.xml, add the following elements above any existing <filter> elements:

<filter>
  <filter-name>melodyFilter</filter-name>
  <filter-class>com.your.package.MelodyFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>melodyFilter</filter-name>
  <url-pattern>/monitoring/*</url-pattern>
</filter-mapping>

This will call com.your.package.MelodyFilter any time the /monitoring/* url pattern is invoked.

Next, you'll need to create a MelodyFilter Java class in /src/java/com/your/package/MelodyFilter.java.

In the body of the doFilter method, you may call a Grails service method to perform any desired security checks, as follows:

package com.your.package;

import com.my.grails.app.MyService;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class MelodyFilter implements Filter {

    @Override
    public void destroy() { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        String uri = ((HttpServletRequest)request).getRequestURI();
        HttpSession session = ((HttpServletRequest)request).getSession(false);
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(session.getServletContext());
        // replace MyService with your actual service
        MyService myService = (MyService)ctx.getBean("myService");
        // replace isUserAuthorized with your actual service method;
        // session and uri params included to demonstrate how to pass them
        // your argument list can be whatever your service method requires
        boolean authorized = myService.isUserAuthorized(session, uri);
        if (authorized) { chain.doFilter(request,response); }
        else {
            request.setAttribute("error", "User is not authorized to access " + uri); 
            request.getRequestDispatcher("/someController/someAction").forward(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException { }
}

Then simply implement myService.isUserAuthorized() to perform whatever security checks you desire.

I have verified this technique works in Grails-2.3.6 with grails-melody:1.59.0

Yon answered 11/4, 2017 at 21:58 Comment(0)
Z
0

Just to list all available options:

the shiro-protect-any - plugin seems to work, but IMHO, it seems to be to be a bit too complicated and the plugin is "not fully tested" (says the author)...

Zollie answered 19/7, 2015 at 17:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.