Is it possible to configure AccessLogValve to hide/replace passwords before they are written to the log file? I am not familiar with valves, perhaps there is a way to insert a custom filter/valve?
3 Answers
Solution with custom AccessLogValve class
Create a separate maven project:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>filtered-access-log-valve</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>7.0.70</version> </dependency> </dependencies> </project>
FilteredAccessLogValve.java
package test; import org.apache.catalina.valves.AccessLogValve; public class FilteredAccessLogValve extends AccessLogValve { @Override public void log(String message) { super.log(message.replaceAll("password=[^&]*", "password=***")); } }
Build jar artifact from the project and copy it to tomcat/lib/
In tomcat/conf/server.xml change access log valve class
<Valve className="test.FilteredAccessLogValve" ...>
Another solution using servlet filter
Finally I came to this solution as it requires minimal tomcat configuration.
- In tomcat/conf/context.xml turn off the default access log valve by commenting the
<Valve>
tag. Create AdvancedAccessLogFilter class:
package your.package; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class AdvancedAccessLogFilter implements Filter { private static final String PASSWORD_REGEX = "password=[^&]+"; private static final String PASSWORD_MASK = "password=***"; private FilterConfig filterConfig = null; public void destroy() { this.filterConfig = null; } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { if (filterConfig == null) { return; } HttpServletRequest request = (HttpServletRequest) servletRequest; String maskedPath = request.getRequestURI() + (request.getQueryString() == null ? "" : request.getQueryString().replaceAll(PASSWORD_REGEX, PASSWORD_MASK)) + " " + request.getProtocol(); request.setAttribute("maskedPath", maskedPath); chain.doFilter(request, servletResponse); } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } }
Register the servlet filter in your project's web.xml:
<filter> <filter-name>AdvancedAccessLogFilter</filter-name> <filter-class>your.package.AdvancedAccessLogFilter</filter-class> </filter> <filter-mapping> <filter-name>AdvancedAccessLogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Create src/main/webapp/META-INF/context.xml with modified access log valve pattern:
<?xml version='1.0' encoding='utf-8'?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Valve className='org.apache.catalina.valves.AccessLogValve' directory='logs' prefix='localhost_access_log.' suffix='.txt' pattern='%h %t %m "%{maskedPath}r" %s %b %D' /> </Context>
If you want to autowire some beans from the Spring context, add SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
to the filter's init()
method.

- 5,751
- 4
- 46
- 54
Simple answer is to extend the AccessLogValve class and override the log method, using String#replaceAll to replace all occurrences of the password with "*".

- 1,550
- 3
- 15
- 25
-
How should I distinguish between passwords and not passwords? – Michael May 27 '13 at 03:57
-
@Michael in the examples, the password is coming after a query parameter. If you don't know how to find the password in the logged data, then you're not going to be able to filter them out. – vipw Nov 04 '19 at 09:03
Encountered the same problem in one of the SAP/Hybris Project which uses an embedded tomcat server. Where User and OAuth client's confidential information getting logged in the access logs in below format, whenever an oauth/token call is being made with password grant type.
0:0:0:0:0:0:0:1 - - [31/Mar/2021:21:19:38 +0530] "POST /authorizationserver/oauth/token?client_id=trusted_client&client_secret=secret&grant_type=password&username=admin&password=nimda HTTP/1.1" 200 334 "-" "PostmanRuntime/7.24.1"
**Solved Using Custom AccessLogValve class **
Create one standalone maven project.
Update Pom.xml as below
4.0.0 FilteredAccessLogValve filtered-access-log-valve 0.0.1-SNAPSHOT Filtered Access Log valve Filtered Access Log valve For customizing Log Values org.apache.tomcat tomcat-catalina 8.5.57 maven-compiler-plugin 3.5.1 1.8 1.8 org.apache.maven.plugins maven-jar-plugin package jar
Create a class in src/main/java as FilteredAccessLogValve which extends AccessLogValve from org.apache.catalina.valves Package. The class looks like as below.
package org.apache.catalina.valves;
import java.io.CharArrayWriter; import java.io.IOException;
public class FilteredAccessLogValve extends AccessLogValve {
@Override
public void log(CharArrayWriter message) {
CharArrayWriter caw = new CharArrayWriter();
try {
caw.write(message.toString().replaceAll("password=[^&^ ]*", "password=***").replaceAll("client_secret=[^&^ ]*",
"client_secret=***"));
super.log(caw);
} catch (IOException e) {
e.printStackTrace();
} finally {
caw.close();
}
}
}
Build Jar using mvn clean -> mvn compile -> mvn install. Copy the filtered-access-log-valve-0.0.1-SNAPSHOT jar from /target folder and place it in the hybris/config/customize/platform/tomcat/lib folder.
look for all the server.xml hybris/config/tcServer/conf and hybris/config/tomcat/conf files and inside this replace all the valve class definition to new FilteredAccessLogValve class as below
Before:
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="${HYBRIS_LOG_DIR}/tomcat"
prefix="access."
suffix=".log"
pattern="combined"
/>
After:
<Valve className="org.apache.catalina.valves.FilteredAccessLogValve"
directory="${HYBRIS_LOG_DIR}/tomcat"
prefix="access."
suffix=".log"
pattern="combined"
/>
Run ant customize in the platform and then build and start the server.
Now the log will look like something as below
0:0:0:0:0:0:0:1 - - [31/Mar/2021:21:19:38 +0530] "POST /authorizationserver/oauth/token?client_id=trusted_client&client_secret=&grant_type=password&username=admin&password= HTTP/1.1" 200 334 "-" "PostmanRuntime/7.24.1"

- 171
- 1
- 6