/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package nl.nn.adapterframework.webcontrol;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import nl.nn.adapterframework.util.LogUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
/**
* ParamWrapperFilter.
*
* @author Alvaro Munoz, HP Fortify Team
* @author Rene Gielen, Apache Struts Team
*/
public class ParamWrapperFilter implements Filter {
private static final Log LOG = LogFactory.getLog(ParamWrapperFilter.class);
protected Logger iaflog = LogUtil.getLogger(this);
private static final String DEFAULT_BLACKLIST_PATTERN = "(.*\\.|^|.*|\\[('|\"))(c|C)lass(\\.|('|\")]|\\[).*";
private static final String INIT_PARAM_NAME = "excludeParams";
private Pattern pattern;
public void init(FilterConfig filterConfig) throws ServletException {
final String toCompile;
final String initParameter = filterConfig
.getInitParameter(INIT_PARAM_NAME);
if (initParameter != null && initParameter.trim().length() > 0) {
toCompile = initParameter;
} else {
toCompile = DEFAULT_BLACKLIST_PATTERN;
}
iaflog.info("INFO Message: Struts1 'do'-Filter active");
this.pattern = Pattern.compile(toCompile, Pattern.DOTALL);
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// to prevent NPE (????)
request.getParameterMap();
ParamFilteredRequest wrapper = null;
if (request instanceof HttpServletRequest)
wrapper = new ParamFilteredRequest(request, pattern);
if (wrapper != null)
chain.doFilter(wrapper, response);
else
chain.doFilter(request, response);
}
public void destroy() {
}
static class ParamFilteredRequest extends HttpServletRequestWrapper {
private static final int BUFFER_SIZE = 128;
private static final String CONTENT_LENGTH_PATTERN = "(?i)content-length";
private final String body;
private final Pattern pattern;
private final Pattern content_length_pattern;
private boolean read_stream = false;
public ParamFilteredRequest(ServletRequest request, Pattern pattern) {
super((HttpServletRequest) request);
this.pattern = pattern;
this.content_length_pattern = Pattern.compile(
CONTENT_LENGTH_PATTERN, Pattern.DOTALL);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
String characterEncoding = this.getCharacterEncoding();
if (characterEncoding == null) {
bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
} else {
bufferedReader = new BufferedReader(
new InputStreamReader(inputStream,
characterEncoding));
}
char[] charBuffer = new char[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
logCatchedException(ex);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
logCatchedException(ex);
}
}
}
body = stringBuilder.toString();
}
@Override
public Enumeration getParameterNames() {
List finalParameterNames = new ArrayList();
List parameterNames = Collections.list((Enumeration) super
.getParameterNames());
final Iterator iterator = parameterNames.iterator();
while (iterator.hasNext()) {
String parameterName = (String) iterator.next();
if (!pattern.matcher(parameterName).matches()) {
finalParameterNames.add(parameterName);
}
}
return Collections.enumeration(finalParameterNames);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (LOG.isTraceEnabled()) {
LOG.trace(body);
}
final ByteArrayInputStream byteArrayInputStream;
if (pattern.matcher(body).matches()) {
if (LOG.isWarnEnabled()) {
LOG.warn("[getInputStream]: found body to match blacklisted parameter pattern");
}
byteArrayInputStream = new ByteArrayInputStream("".getBytes());
} else if (read_stream) {
byteArrayInputStream = new ByteArrayInputStream("".getBytes());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("[getInputStream]: OK - body does not match blacklisted parameter pattern");
}
byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
read_stream = true;
}
return new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
@Override
public String getHeader(String name) {
if (pattern.matcher(body).matches()
&& content_length_pattern.matcher(name).matches()) {
return "0";
}
return super.getHeader(name);
}
@Override
public int getContentLength() {
if (pattern.matcher(body).matches()) {
return 0;
}
return super.getContentLength();
}
private void logCatchedException(IOException ex) {
LOG.error("[ParamFilteredRequest]: Exception catched: ", ex);
}
}
}