title: How to restrict access by IP to specific dynamic URLs (only 1-2 pages) in tomcat or url-pattern format
body: <p>Please do not close this question as answered, because all links I found like <a href="https://stackoverflow.com/questions/4850112/restrict-access-to-specific-url-apache-tomcat/4850330">this</a> and they are about how to block single static URL, but not a dynamic.</p>
  
  <p>I have a Tomcat 7 and I have an application something like <a href="http://server/myapp/" rel="nofollow noreferrer">http://server/myapp/</a>.
  I need to restrict some pages inside this application for some IPs. for example, everything should work fine for all IPs, except these 2 pages</p>
  
  <p><a href="http://server/myapp/admin/appversion/index.jsp" rel="nofollow noreferrer">http://server/myapp/admin/appversion/index.jsp</a>
  <a href="http://server/myapp/admin/appversion/app_parameters.jsp" rel="nofollow noreferrer">http://server/myapp/admin/appversion/app_parameters.jsp</a></p>
  
  <p>for static URL's it works perfectly if I add the filter to server's web.xml (...\apache-tomcat-7\conf\web.xml) like this</p>
  
  <pre><code>&lt;filter&gt;
      &lt;filter-name&gt;IPFilter&lt;/filter-name&gt;
      &lt;filter-class&gt;org.apache.catalina.filters.RemoteAddrFilter&lt;/filter-class&gt;
      &lt;init-param&gt;
          &lt;param-name&gt;allow&lt;/param-name&gt;
          &lt;param-value&gt;127\.\d+\.\d+\.\d+&lt;/param-value&gt;
      &lt;/init-param&gt;
  &lt;/filter&gt;
  &lt;filter-mapping&gt;
      &lt;filter-name&gt;IPFilter&lt;/filter-name&gt;
      &lt;url-pattern&gt;/admin/appversion/index.jsp&lt;/url-pattern&gt;
      &lt;url-pattern&gt;/admin/appversion/app_parameters.jsp&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;
  </code></pre>
  
  <p>The problem comes when I need to do dynamic (or regexp) filtering. For example, every time I have a new version of application this part of URL (appversion) changes.</p>
  
  <p>/admin/<strong>appversion</strong>/app_parameters.jsp</p>
  
  <p>real url today looks like this /admin/1.0/app_parameters.jsp in 1 month it will be /admin/1.1/app_parameters.jsp etc. and I do not want to change it every time when I have an update. Also it might be different for dev, test and production environment and I do not want to support 3 different configurations and change for every update.</p>
  
  <p>If I try to do it like this</p>
  
  <pre><code>&lt;url-pattern&gt;/admin/*/app_parameters.jsp&lt;/url-pattern&gt;
  </code></pre>
  
  <p>then it does not work. and if I read <a href="http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#Remote_Address_Filter" rel="nofollow noreferrer">tomcat official documentation</a> there is no explanation how this  works. There are some examples like /*, but it works only for every page.</p>
  
  <p>My question:
  Is there any way how to configure tomcat in a standard way and restrict some pages dynamically? One of the solutions can be to find full syntax of url-pattern and check if proper regexp is supported. Maybe using subfilters/nested filters etc. Or there is only one solution to create my custom java filter based on org.apache.catalina.filters.RemoteAddrFilter where I can apply proper regular expression to the URL?</p>
  
  <p>P.S. one might think why I have admin pages inside the main application and I just should modify my app and move it to another app, but the problem is, that this application is a standard application from some vendor. I did not create this application by myself. If I change this application by my self, I will lose a support for it and I already checked, it is not easy to move this 2 pages. These 2 pages have a lot of dependencies from other parts of the application. Of course, I will create a ticket for this vendor separately, but it will be good to get an independent solution (Plan B) in case vendor cannot provide something.</p>
  
  <p>UPDATE 1</p>
  
  <p>I have checked tomcat source codes and looks like only 4 patterns are supported in  element. This is the code from org.apache.catalina.core.ApplicationFilterFactory</p>
  
  <pre><code>private boolean matchFiltersURL(String testPath, String requestPath) {
      if (testPath == null) {
          return false;
      }
      if (testPath.equals(requestPath)) {
          return true;
      }
  
      if (testPath.equals("/*"))
          return true;
      if (testPath.endsWith("/*")) {
          if (testPath.regionMatches(0, requestPath, 0, testPath.length() - 2)) {
              if (requestPath.length() == testPath.length() - 2)
                  return true;
              if ('/' == requestPath.charAt(testPath.length() - 2)) {
                  return true;
              }
          }
          return false;
      }
  
      if (testPath.startsWith("*.")) {
          int slash = requestPath.lastIndexOf('/');
          int period = requestPath.lastIndexOf('.');
          if ((slash &gt;= 0) &amp;&amp; (period &gt; slash) &amp;&amp; (period != requestPath.length() - 1) &amp;&amp; (requestPath.length() - period == testPath.length() - 1)) {
  
              return testPath.regionMatches(2, requestPath, period + 1, testPath.length() - 2);
          }
      }
  
      return false;
  }
  </code></pre>
  
  <p>briefly what is supported</p>
  
  <pre><code>  1. exact URL match
    2. &lt;url-pattern&gt;/*&lt;/url-pattern&gt; means match for all URLs.
    3. &lt;url-pattern&gt;/some/path/*&lt;/url-pattern&gt; means match for all URLs starting with  "/some/path". It support /* only at the end of the URL.
    4. &lt;url-pattern&gt;*.ext&lt;/url-pattern&gt; means match for any path but with specific extension.
    5. All others are not supported (examples what is not supported: /fld1/*/fld2, /fld1/*.jsp, etc
  </code></pre>
  
  <p>some examples which can help to understand it</p>
  
  <pre><code>matchFiltersURL("", "/fld1/fld2/mypage.jsp")
       (boolean) false
  
  matchFiltersURL("*", "/fld1/fld2/mypage.jsp")
       (boolean) false
  
  matchFiltersURL("/*", "/fld1/fld2/mypage.jsp")
       (boolean) true
  
  matchFiltersURL("/fld1/*", "/fld1/fld2/mypage.jsp")
       (boolean) true
  
  matchFiltersURL("/fld1*", "/fld1/fld2/mypage.jsp")
       (boolean) false
  
  matchFiltersURL("/fld1/fld2/*", "/fld1/fld2/mypage.jsp")
       (boolean) true
  
  matchFiltersURL("/fld1/*/mypage.jsp", "/fld1/fld2/mypage.jsp")
       (boolean) false
  
  matchFiltersURL("*./fld1/fld2/mypage.jsp", "/fld1/fld2/mypage.jsp")
       (boolean) false
  
  matchFiltersURL("*./fld1/fld2/mypagejs", "./fld1/fld2/mypagejsp")
  
  matchFiltersURL("*.jsp", "/.jsp");
       (boolean) true
  
  matchFiltersURL("*.xxxx", "/.xxxx");
       (boolean) true
  
  matchFiltersURL("*./fld1/xxxx", "/fld1/.xxxx");
       (boolean) false
  
  matchFiltersURL("*./fld1/.xxxx", "/fld1/.xxxx");
       (boolean) false
  
  matchFiltersURL("/fld1/fld2/*.jsp", "/fld1/fld2/mypage.jsp")
       (boolean) false
  
  matchFiltersURL("*./fld1/fld2/*", "/fld1/fld2/mypage.jsp")
       (boolean) false
  </code></pre>
  
  <p>As result of this, it is clearly not possible to use  for dynamic filtering. The only possibility I can see now is a custom filter or nested filters.</p>