Cq5.5 applying a servlet filter to a specific path
Asked Answered
M

2

7

I'm working on a custom form handler in cq5.5 and everything is going great. I'm now working on locking down some of the security and one of my tasks is to implement a request throttling filter to the form handlers path.

Currently I have something like

@Component(immediate = true, metatype = true)

@Service(javax.servlet.Filter.class)

@Properties({
  @Property(name="service.pid", value="com.xxxxxx.cq.core.filter.FormFilter",propertyPrivate=false),
  @Property(name="service.description",value="FormFilter", propertyPrivate=false),
  @Property(name="service.vendor",value="xxxxxx - Microsites", propertyPrivate=false),
  @Property(name = "filter.scope", value = "request"),
  @Property(name = "sling.filter.scope", value = "request"),
  @Property(name = "service.ranking", intValue = 100001)
})

public class FormFilter implements javax.servlet.Filter {
  private Logger LOGGER = LoggerFactory.getLogger(TrackingFilter.class.getName());
  private static final Object lock = new Object();

  @Override
  public void doFilter(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {
      //my filter stuff
  }
}

This works fine but I'd like to lock it down to only run at a specific path.

thanks for any insights.

----EDIT----- After doing more research I found a few posts stating that there is no way to register a filter to a specified path for the default ServletFilter handler. Basically the two solutions to this issue I've found were either create a new OSGI bundle for the filter and register it using the ExtHTTPService or Whiteboard:

http://felix.apache.org/documentation/subprojects/apache-felix-http-service.html

OR

Filter out the url within the filter itself. So basically add a check for the specified path in my filter.

i.e:

  @Override
  public void doFilter(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain) throws IOException, ServletException {

      String path = pRequest.getContextPath();

      if (path.contains("my/matching/path")
      {
        //my filter stuff
      }
  }

I would love to see if there are additional solutions to this issue, but wanted to share what I've been able to find so far, in hopes that this will either help spur more ideas or even just help someone with the same issue save some time on google searching.

thank you, Brodie

Mahone answered 31/12, 2013 at 19:23 Comment(0)
E
4
  1. Your insight is correct: there is no way to bind the filter to the path. You should check it manually (don't forget to call chain.doFilter()).

  2. Alternative option is the OptingServlet. It is an interface providing one method: accepts(SlingHttpServletRequest request). Implementing this interface in your Sling[Safe|All]MethodsServlet allows you to define what kind of requests you are interested in.

  3. Another option is to use selector instead of a path fragment. Eg. servlet with following annotation will be invoked for all requests with a selector (like /content/geometrixx/en.my-selector.html):

    @SlingServlet(selectors = "my-selector", resourceTypes="sling/servlet/default")
    

Sidenote: you may want to use this nice annotation to declare a filter:

@SlingFilter(scope = SlingFilterScope.REQUEST, order = 100001)

It will add @Component and @Service declarations automatically.

Escarole answered 1/1, 2014 at 10:19 Comment(4)
I think these comments in combination w/ the solution i went with (checking paths in the filter itself) are a good coverage of possible options. Thanks for the additional tips, #3 is especially interesting, and I think I might actually have further usecases for that in the future.Mahone
Just to provide some clarity, from my understanding, option 2 & 3, are nice ways to indicate a servlet that matches the request but they don't act as a filter.Chest
Yep, Brodie asked about some additional solutions so I described how servlet could be used instead of the filter.Outweigh
You can bind a filter to Path. see my answer below.Shelve
S
9

@Tomek Rękawek::: This is not True.... You can map a Filter to a path. I have done it using the following way please See code below.

@SlingFilter(order=1)
@Properties({
    @Property(name="service.pid", value="com.videojet.hiresite.filters.AddNewUserFilter",propertyPrivate=false),
    @Property(name="service.description",value="Authentication Filter", propertyPrivate=false),
    @Property(name="service.vendor",value="Zensar Tech", propertyPrivate=false),
    @Property(name="pattern",value="/services/videojet/v1/AddNewUserController/view", propertyPrivate=false)    
})
public class AddNewUserFilter implements javax.servlet.Filter{

    private final Logger log = LoggerFactory.getLogger(this.getClass());
    public void destroy() {
        // TODO Auto-generated method stub

    }
......

The Property "pattern" Maps the Filter to the URL. And Don't forget to use @SlingFilter

In the pattern property you could ofcourse also use a regx "/.*" whetever it may be . This is tried and Tested code.

Also there is no need to register it in bundle activator or ExtHttpSevice.

Shelve answered 29/5, 2014 at 7:33 Comment(4)
@zacheusz :: I work in CQ5.5. I don't have an Idea about AEM 6. But the question asked by the user is in CQ5.5 environment and it sure does work in CQ5.5 Environment. As I mentioned this is a tried and a tested code.Shelve
In addition to AEM 6, it seems that this also doesn't work in 5.6.1.Rainger
According to the sling docs... "Restrict the filter to paths that match the supplied regular expression. Requires Sling Engine 2.4.0 ".... sling.apache.org/documentation/the-sling-engine/filters.htmlSmallwood
I've tried this for robots.txt recently in AEM 6.2 and it works fine. #46931962Shelve
E
4
  1. Your insight is correct: there is no way to bind the filter to the path. You should check it manually (don't forget to call chain.doFilter()).

  2. Alternative option is the OptingServlet. It is an interface providing one method: accepts(SlingHttpServletRequest request). Implementing this interface in your Sling[Safe|All]MethodsServlet allows you to define what kind of requests you are interested in.

  3. Another option is to use selector instead of a path fragment. Eg. servlet with following annotation will be invoked for all requests with a selector (like /content/geometrixx/en.my-selector.html):

    @SlingServlet(selectors = "my-selector", resourceTypes="sling/servlet/default")
    

Sidenote: you may want to use this nice annotation to declare a filter:

@SlingFilter(scope = SlingFilterScope.REQUEST, order = 100001)

It will add @Component and @Service declarations automatically.

Escarole answered 1/1, 2014 at 10:19 Comment(4)
I think these comments in combination w/ the solution i went with (checking paths in the filter itself) are a good coverage of possible options. Thanks for the additional tips, #3 is especially interesting, and I think I might actually have further usecases for that in the future.Mahone
Just to provide some clarity, from my understanding, option 2 & 3, are nice ways to indicate a servlet that matches the request but they don't act as a filter.Chest
Yep, Brodie asked about some additional solutions so I described how servlet could be used instead of the filter.Outweigh
You can bind a filter to Path. see my answer below.Shelve

© 2022 - 2024 — McMap. All rights reserved.