My last article for Tomcat Expert described various aspects of the Valve construct of Apache Tomcat: some basics about how to implement and configure a valve and an example of where things could go wrong if you were unaware of the operational details. For those of you who don’t remember (or didn’t read the article in the first place), the key takeaway was that because Tomcat valves are maintained as a chain, the order in which the valves are added to the configuration (typically in conf/server.xml) is significant, and the code that implements the filter must conclude with a call to invoke the next filter in the chain.
This time we’re going to lighten things up a bit with a general survey of what valves are available and how one might put them to use. Given the imminent arrival of the winter holiday season, one might think of it as the Apache Tomcat Valve Gift Catalog. Peruse it and find just the right gift for your favorite Tomcat administrator.
For each valve, I’ll describe its functionality, the most important configuration parameters, and point out any configuration subtleties that might not be apparent from the stock documentation. that can be found at http://tomcat.apache.org/tomcat-7.0-doc/config/valve.html. If there are any less well-known attributes or “secret” parameters associated with the valve, I’ll describe them.
The AccessLogValve can be configured at the context, host, or engine level and will log requests made to that container to a file. Attributes of AccessLogValve control the directory, the filename, and the format of the data to be written, including the ability to write information about headers (incoming and outgoing), cookies, and session or request attributes.
While the documentation says “The files produces by this Valve are rolled over nightly at midnight”, the frequency of rotation can be controlled by the fileDateFormat attribute. Unfortunately, there is no built-in way to specify rotation based on log file size. However, on Unix-type systems (including Linux) there is an attribute checkExists. When checkExists is true the valve will check for the existence of the logfile before every attempt to log and if the file does not exist it will be created. This allows the use of an external program to monitor and rotate the log files. When using this functionality you should disable the rotating functionality of AccessLogValve by setting rotatable to false.
AccessLogValve interacts with the RemoteIPValve via the requestAttributesEnabled attribute. If this is set to true, then the request attributes set by RemoteIPValve will be logged. (This is used for instance, to log the true originating IP address of a request rather than that of an intervening proxy).
Note that if you’re migrating an installation from Tomcat 6 to Tomcat 7, the resolveHosts attribute is no longer supported; you need to use the enableLookups attribute of the particular connector in order to log the hostname of the requestor rather than its IP address.
ExtendedAccessLogValve is a variant of the AccessLogValve that supports the Extended Log File Format defined by the W3C. It differs from AccessLogValve in the supported log pattern values.
RemoteAddressFilter is a subclass of the abstract class RequestFilterValve that filters requests based on the originating address of the request. The attributes allow and deny are regular expressions ala java.util.regex. The requestor’s address is initially compared to the deny expression. If it matches, the request is rejected, otherwise (and including the case where no deny expression is specified) the address is next compared to the allow expression. If one is specified, then the address must match or the request is rejected.
So a key element here is that the valve first compares the address with the deny attribute, so if the set of strings matching deny are not mutually exclusive with those matching allow, requests from addresses present in both sets will be denied.
There is an attribute, denyStatus, that allows you to change the HTTP response code returned for rejected requests.
In order to filter on the true originating IP address, rather than that of an intervening proxy, one should configure the RemoteIPValve in the filter chain prior to RemoteAddressFilter.
Finally, don’t be fooled by the unfortunate name of this valve. While the documentation and other texts refer to it as the Remote Address Filter, the className attribute you specify when configuring it is org.apache.catalina.valves.RemoteAddrValve.
RemoteHostFilter provides essentially the same functionality as RemoteAddressFilter except that it compares the hostname instead of the IP address. It too is subclassed from RequestFilterValve, so the only real difference from RemoteAddressFilter is the request property that gets compared to the allow and deny regular expressions.
The caveat regarding RemoteIPValve discussed above for RemoteAddressFilter also applies here.
RemoteIPValve is used in conjunction with the preceding valves to provide those valves with the true originating IP address, hostname, and protocol of the request being processed. This is crucial when requests pass through a proxy or other intermediary system that might mask the true originating system and protocol.
When using this valve, it is vital that it appear in the configuration prior to any valve that is relying on its behavior. Remember the lesson we learned in my last article: the valve pipeline is ordered and behavior can change based upon the order the valves are specified in the configuration file.
In all but the most rare cases, one should let the requestAttributeEnabled attribute remain its default value, which is true.
This has been a short summary of the Apache Tomcat valves that are available to log requests and the valves that are available to control access to the configured context (based on hostname or IP address). Future articles will cover further categories of valves.