我的自定义 tomcat 阀未被拦截
My custom tomcat valve is not being intercepted
这是我编写的自定义阀 class。它所做的只是在登录以访问日志文件之前屏蔽密码 ...
package com.test;
import org.apache.catalina.valves.AccessLogValve;
public class FilteredAccessLogValve extends AccessLogValve {
public void log(String message) {
message = message.replaceAll("password=[^&]*", "password=***");
super.log(message);
}
}
我将其构建为值-lib.jar 并复制到 $TOMCAT_HOME/lib 文件夹。
然后我在 server.xml 中自定义登录条目,如下在条目 localhost
下
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="com.test.FilteredAccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern=" com.test.FilteredAccessLogValve %{X-Forwarded-For}i %h %l %S %u %t '%r' %s %b %D"/>
<!-- pattern="%h %l %u %t "%r" %s %b" /-->
</Host>
现在,我所有的日志请求都像这样正确记录在 localhost_access_log.2018-02-12.txt 文件中
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:13:49 +0530] 'GET / HTTP/1.1' 200 11452 362
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:13:56 +0530] 'GET /manager/html HTTP/1.1' 401 2536 45
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:14:11 +0530] 'GET /host-manager/html HTTP/1.1' 401 2098 16
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:22:21 +0530] 'GET /host-manager/html HTTP/1.1' 401 2098 132
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:22:22 +0530] 'GET /favicon.ico HTTP/1.1' 200 21630 9
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:24:53 +0530] 'GET / HTTP/1.1' 200 11452 212
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:25:04 +0530] 'GET /?password=123 HTTP/1.1' 200 11452 10
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:46:53 +0530] 'GET /ROOT/ HTTP/1.1' 404 1075 52
我面临的问题是当我将 password=123 之类的参数传递给 URL 时,例如 http://localhost:8080?password=123.
我希望记录为
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:11:01:02 +0530] 'GET /?password=*** HTTP/1.1' 200 11452 14
现在记录为
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:11:01:02 +0530] 'GET /?password=123 HTTP/1.1' 200 11452 14
密码值没有屏蔽。我试图通过远程 Java 应用程序在 jar 的 eclipse 中放置一个调试器,Tomcat 在 "jpda start" 模式下启动.
我根本看不到控制权转移到这个 class..
所以,我对它的工作原理有点困惑,因为它从我添加到 server.xml 的 XML 配置中获取日志格式,但在相同的 XML 配置中我将 class 名称提到为 "com.test.FilteredAccessLogValve" 但未被选中
最后我找到了解决方案。问题是我在开发中使用 tomcat 7 jar 并在 tomcat 8.5 实现中测试解决方案..
Tomcat 在这两个版本之间更改了 "AccessLogValve" class 中 log() 调用的方法签名。之前是
public void log(String message);
现已修改为
public void log(CharArrayWriter message);
因此我的自定义实现已更改为
package com.test;
import org.apache.catalina.valves.AccessLogValve;
public class FilteredAccessLogValve extends AccessLogValve {
public void log(CharArrayWriter message) {
String mymessage = message.toString();
if(mymessage.toLowerCase().contains("password=")) {
mymessage = mymessage.replaceAll("password=[^&]*", "password=***");
CharArrayWriter maskedMessage = new CharArrayWriter(1024);
try {
maskedMessage.write(mymessage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.log(maskedMessage);
} else {
super.log(message);
}
}
}
由于我覆盖了正确的方法,现在此 http://localhost:8080/manager/html/list?password=123 调用的日志被正确屏蔽,如下所示
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - C71654B9F585F83AAF6E9A4233BD7D8B tomcat [12/Feb/2018:13:01:06 +0530] 'GET /manager/html/list?password=***
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - C71654B9F585F83AAF6E9A4233BD7D8B tomcat [12/Feb/2018:13:01:11 +0530] 'GET /manager/html/list?password=***
这是我编写的自定义阀 class。它所做的只是在登录以访问日志文件之前屏蔽密码 ...
package com.test;
import org.apache.catalina.valves.AccessLogValve;
public class FilteredAccessLogValve extends AccessLogValve {
public void log(String message) {
message = message.replaceAll("password=[^&]*", "password=***");
super.log(message);
}
}
我将其构建为值-lib.jar 并复制到 $TOMCAT_HOME/lib 文件夹。
然后我在 server.xml 中自定义登录条目,如下在条目 localhost
下 <Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="com.test.FilteredAccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern=" com.test.FilteredAccessLogValve %{X-Forwarded-For}i %h %l %S %u %t '%r' %s %b %D"/>
<!-- pattern="%h %l %u %t "%r" %s %b" /-->
</Host>
现在,我所有的日志请求都像这样正确记录在 localhost_access_log.2018-02-12.txt 文件中
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:13:49 +0530] 'GET / HTTP/1.1' 200 11452 362
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:13:56 +0530] 'GET /manager/html HTTP/1.1' 401 2536 45
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:14:11 +0530] 'GET /host-manager/html HTTP/1.1' 401 2098 16
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:22:21 +0530] 'GET /host-manager/html HTTP/1.1' 401 2098 132
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:22:22 +0530] 'GET /favicon.ico HTTP/1.1' 200 21630 9
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:24:53 +0530] 'GET / HTTP/1.1' 200 11452 212
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:25:04 +0530] 'GET /?password=123 HTTP/1.1' 200 11452 10
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:10:46:53 +0530] 'GET /ROOT/ HTTP/1.1' 404 1075 52
我面临的问题是当我将 password=123 之类的参数传递给 URL 时,例如 http://localhost:8080?password=123.
我希望记录为
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:11:01:02 +0530] 'GET /?password=*** HTTP/1.1' 200 11452 14
现在记录为
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - - - [12/Feb/2018:11:01:02 +0530] 'GET /?password=123 HTTP/1.1' 200 11452 14
密码值没有屏蔽。我试图通过远程 Java 应用程序在 jar 的 eclipse 中放置一个调试器,Tomcat 在 "jpda start" 模式下启动.
我根本看不到控制权转移到这个 class..
所以,我对它的工作原理有点困惑,因为它从我添加到 server.xml 的 XML 配置中获取日志格式,但在相同的 XML 配置中我将 class 名称提到为 "com.test.FilteredAccessLogValve" 但未被选中
最后我找到了解决方案。问题是我在开发中使用 tomcat 7 jar 并在 tomcat 8.5 实现中测试解决方案..
Tomcat 在这两个版本之间更改了 "AccessLogValve" class 中 log() 调用的方法签名。之前是
public void log(String message);
现已修改为
public void log(CharArrayWriter message);
因此我的自定义实现已更改为
package com.test;
import org.apache.catalina.valves.AccessLogValve;
public class FilteredAccessLogValve extends AccessLogValve {
public void log(CharArrayWriter message) {
String mymessage = message.toString();
if(mymessage.toLowerCase().contains("password=")) {
mymessage = mymessage.replaceAll("password=[^&]*", "password=***");
CharArrayWriter maskedMessage = new CharArrayWriter(1024);
try {
maskedMessage.write(mymessage);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.log(maskedMessage);
} else {
super.log(message);
}
}
}
由于我覆盖了正确的方法,现在此 http://localhost:8080/manager/html/list?password=123 调用的日志被正确屏蔽,如下所示
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - C71654B9F585F83AAF6E9A4233BD7D8B tomcat [12/Feb/2018:13:01:06 +0530] 'GET /manager/html/list?password=***
com.test.FilteredAccessLogValve - 0:0:0:0:0:0:0:1 - C71654B9F585F83AAF6E9A4233BD7D8B tomcat [12/Feb/2018:13:01:11 +0530] 'GET /manager/html/list?password=***