This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
/*
* 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 org.apache.catalina.valves;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import org.junit.Assert;
import org.junit.Test;
public class TestAccessLogValve {
// Note that there is a similar test:
// org.apache.juli.TestDateFormatCache.testBug54044()
@Test
public void testBug54044() throws Exception {
final int cacheSize = 10;
SimpleDateFormat sdf =
new SimpleDateFormat("[dd/MMM/yyyy:HH:mm:ss Z]", Locale.US);
sdf.setTimeZone(TimeZone.getDefault());
AccessLogValve.DateFormatCache dfc =
new AccessLogValve.DateFormatCache(
cacheSize, Locale.US, null);
// Create an array to hold the expected values
String[] expected = new String[cacheSize];
// Fill the cache & populate the expected values
for (int secs = 0; secs < (cacheSize); secs++) {
dfc.getFormat(secs * 1000);
expected[secs] = generateExpected(sdf, secs);
}
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
// Cause the cache to roll-around by one and then confirm
dfc.getFormat(cacheSize * 1000);
expected[0] = generateExpected(sdf, cacheSize);
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
// Jump 2 ahead and then confirm (skipped value should be null)
dfc.getFormat((cacheSize + 2)* 1000);
expected[1] = null;
expected[2] = generateExpected(sdf, cacheSize + 2);
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
// Back 1 to fill in the gap
dfc.getFormat((cacheSize + 1)* 1000);
expected[1] = generateExpected(sdf, cacheSize + 1);
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
// Return to 1 and confirm skipped value is null
dfc.getFormat(1 * 1000);
expected[1] = generateExpected(sdf, 1);
expected[2] = null;
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
// Go back one further
dfc.getFormat(0);
expected[0] = generateExpected(sdf, 0);
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
// Jump ahead far enough that the entire cache will need to be cleared
dfc.getFormat(42 * 1000);
for (int i = 0; i < cacheSize; i++) {
expected[i] = null;
}
expected[0] = generateExpected(sdf, 42);
Assert.assertArrayEquals(expected, dfc.cLFCache.cache);
}
private String generateExpected(SimpleDateFormat sdf, long secs) {
return sdf.format(new Date(secs * 1000));
}
}

View File

@@ -0,0 +1,213 @@
/*
* 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 org.apache.catalina.valves;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingListener;
import org.hamcrest.CoreMatchers;
import org.hamcrest.MatcherAssert;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.Host;
import org.apache.catalina.Manager;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.session.StandardSession;
import org.easymock.EasyMock;
import org.easymock.IExpectationSetters;
public class TestCrawlerSessionManagerValve {
private static final Manager TEST_MANAGER;
static {
TEST_MANAGER = new StandardManager();
TEST_MANAGER.setContext(new StandardContext());
}
@Test
public void testCrawlerIpsPositive() throws Exception {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerIps("216\\.58\\.206\\.174");
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setNext(EasyMock.createMock(Valve.class));
HttpSession session = createSessionExpectations(valve, true);
Request request = createRequestExpectations("216.58.206.174", session, true);
EasyMock.replay(request, session);
valve.invoke(request, EasyMock.createMock(Response.class));
EasyMock.verify(request, session);
}
@Test
public void testCrawlerIpsNegative() throws Exception {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerIps("216\\.58\\.206\\.174");
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setNext(EasyMock.createMock(Valve.class));
HttpSession session = createSessionExpectations(valve, false);
Request request = createRequestExpectations("127.0.0.1", session, false);
EasyMock.replay(request, session);
valve.invoke(request, EasyMock.createMock(Response.class));
EasyMock.verify(request, session);
}
@Test
public void testCrawlerMultipleHostsHostAware() throws Exception {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setHostAware(true);
valve.setContextAware(true);
valve.setNext(EasyMock.createMock(Valve.class));
verifyCrawlingLocalhost(valve, "localhost");
verifyCrawlingLocalhost(valve, "example.invalid");
}
@Test
public void testCrawlerMultipleContextsContextAware() throws Exception {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setHostAware(true);
valve.setContextAware(true);
valve.setNext(EasyMock.createMock(Valve.class));
verifyCrawlingContext(valve, "/examples");
verifyCrawlingContext(valve, null);
}
@Test
public void testCrawlersSessionIdIsRemovedAfterSessionExpiry() throws IOException, ServletException {
CrawlerSessionManagerValve valve = new CrawlerSessionManagerValve();
valve.setCrawlerIps("216\\.58\\.206\\.174");
valve.setCrawlerUserAgents(valve.getCrawlerUserAgents());
valve.setNext(EasyMock.createMock(Valve.class));
valve.setSessionInactiveInterval(0);
StandardSession session = new StandardSession(TEST_MANAGER);
session.setId("id");
session.setValid(true);
Request request = createRequestExpectations("216.58.206.174", session, true);
EasyMock.replay(request);
valve.invoke(request, EasyMock.createMock(Response.class));
EasyMock.verify(request);
MatcherAssert.assertThat(valve.getClientIpSessionId().values(), CoreMatchers.hasItem("id"));
session.expire();
Assert.assertEquals(0, valve.getClientIpSessionId().values().size());
}
private void verifyCrawlingLocalhost(CrawlerSessionManagerValve valve, String hostname)
throws IOException, ServletException {
HttpSession session = createSessionExpectations(valve, true);
Request request = createRequestExpectations("127.0.0.1", session, true, hostname, "/examples", "tomcatBot 1.0");
EasyMock.replay(request, session);
valve.invoke(request, EasyMock.createMock(Response.class));
EasyMock.verify(request, session);
}
private void verifyCrawlingContext(CrawlerSessionManagerValve valve, String contextPath)
throws IOException, ServletException {
HttpSession session = createSessionExpectations(valve, true);
Request request = createRequestExpectations("127.0.0.1", session, true, "localhost", contextPath, "tomcatBot 1.0");
EasyMock.replay(request, session);
valve.invoke(request, EasyMock.createMock(Response.class));
EasyMock.verify(request, session);
}
private HttpSession createSessionExpectations(CrawlerSessionManagerValve valve, boolean isBot) {
HttpSession session = EasyMock.createMock(HttpSession.class);
if (isBot) {
EasyMock.expect(session.getId()).andReturn("id").times(2);
session.setAttribute(EasyMock.eq(valve.getClass().getName()), EasyMock.anyObject(HttpSessionBindingListener.class));
EasyMock.expectLastCall();
session.setMaxInactiveInterval(60);
EasyMock.expectLastCall();
}
return session;
}
private Request createRequestExpectations(String ip, HttpSession session, boolean isBot) {
return createRequestExpectations(ip, session, isBot, "localhost", "/examples", "something 1.0");
}
private Request createRequestExpectations(String ip, HttpSession session, boolean isBot, String hostname,
String contextPath, String userAgent) {
Request request = EasyMock.createMock(Request.class);
EasyMock.expect(request.getRemoteAddr()).andReturn(ip);
EasyMock.expect(request.getHost()).andReturn(simpleHostWithName(hostname));
EasyMock.expect(request.getContext()).andReturn(simpleContextWithName(contextPath));
IExpectationSetters<HttpSession> setter = EasyMock.expect(request.getSession(false))
.andReturn(null);
if (isBot) {
setter.andReturn(session);
}
EasyMock.expect(request.getHeaders("user-agent")).andReturn(Collections.enumeration(Arrays.asList(userAgent)));
return request;
}
private Host simpleHostWithName(String hostname) {
Host host = EasyMock.createMock(Host.class);
EasyMock.expect(host.getName()).andReturn(hostname);
EasyMock.replay(host);
return host;
}
private Context simpleContextWithName(String contextPath) {
if (contextPath == null) {
return null;
}
Context context = EasyMock.createMock(Context.class);
EasyMock.expect(context.getName()).andReturn(contextPath);
EasyMock.replay(context);
return context;
}
}

View File

@@ -0,0 +1,214 @@
/*
* 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 org.apache.catalina.valves;
import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.buf.ByteChunk;
public class TestErrorReportValve extends TomcatBaseTest {
@Test
public void testBug53071() throws Exception {
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
Tomcat.addServlet(ctx, "errorServlet", new ErrorServlet());
ctx.addServletMappingDecoded("/", "errorServlet");
tomcat.start();
ByteChunk res = getUrl("http://localhost:" + getPort());
Assert.assertTrue(res.toString().contains("<p><b>Message</b> " +
ErrorServlet.ERROR_TEXT + "</p>"));
}
private static final class ErrorServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String ERROR_TEXT = "The wheels fell off.";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.setAttribute(RequestDispatcher.ERROR_EXCEPTION,
new Throwable(ERROR_TEXT));
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
@Test
public void testBug54220DoNotSetNotFound() throws Exception {
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
Tomcat.addServlet(ctx, "bug54220", new Bug54220Servlet(false));
ctx.addServletMappingDecoded("/", "bug54220");
tomcat.start();
ByteChunk res = new ByteChunk();
int rc = getUrl("http://localhost:" + getPort(), res, null);
Assert.assertNull(res.toString());
Assert.assertEquals(HttpServletResponse.SC_OK, rc);
}
@Test
public void testBug54220SetNotFound() throws Exception {
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
Tomcat.addServlet(ctx, "bug54220", new Bug54220Servlet(true));
ctx.addServletMappingDecoded("/", "bug54220");
tomcat.start();
ByteChunk res = new ByteChunk();
int rc = getUrl("http://localhost:" + getPort(), res, null);
Assert.assertNull(res.toString());
Assert.assertEquals(HttpServletResponse.SC_NOT_FOUND, rc);
}
private static final class Bug54220Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private boolean setNotFound;
private Bug54220Servlet(boolean setNotFound) {
this.setNotFound = setNotFound;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (setNotFound) {
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
}
}
/*
* Custom error/status codes should not result in a blank response.
*/
@Test
public void testBug54536() throws Exception {
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
Tomcat.addServlet(ctx, "bug54536", new Bug54536Servlet());
ctx.addServletMappingDecoded("/", "bug54536");
tomcat.start();
ByteChunk res = new ByteChunk();
int rc = getUrl("http://localhost:" + getPort(), res, null);
Assert.assertEquals(Bug54536Servlet.ERROR_STATUS, rc);
String body = res.toString();
Assert.assertNotNull(body);
Assert.assertTrue(body, body.contains(Bug54536Servlet.ERROR_MESSAGE));
}
private static final class Bug54536Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final int ERROR_STATUS = 999;
private static final String ERROR_MESSAGE = "The sky is falling";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.sendError(ERROR_STATUS, ERROR_MESSAGE);
}
}
@Test
public void testBug56042() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
// No file system docBase required
Context ctx = tomcat.addContext("", null);
Bug56042Servlet bug56042Servlet = new Bug56042Servlet();
Wrapper wrapper =
Tomcat.addServlet(ctx, "bug56042Servlet", bug56042Servlet);
wrapper.setAsyncSupported(true);
ctx.addServletMappingDecoded("/bug56042Servlet", "bug56042Servlet");
tomcat.start();
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("/bug56042Servlet");
ByteChunk res = new ByteChunk();
int rc = getUrl(url.toString(), res, null);
Assert.assertEquals(HttpServletResponse.SC_BAD_REQUEST, rc);
}
private static class Bug56042Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Only set the status on the first call (the dispatch will trigger
// another call to this Servlet)
if (resp.getStatus() != HttpServletResponse.SC_BAD_REQUEST) {
resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
AsyncContext ac = req.startAsync();
ac.dispatch();
}
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* 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 org.apache.catalina.valves;
import org.junit.Assert;
import org.junit.Test;
public class TestExtendedAccessLogValve {
@Test
public void alpha() {
Assert.assertEquals("\"foo\"", ExtendedAccessLogValve.wrap("foo"));
}
@Test
public void testNull() {
Assert.assertEquals("-", ExtendedAccessLogValve.wrap(null));
}
@Test
public void empty() {
Assert.assertEquals("\"\"", ExtendedAccessLogValve.wrap(""));
}
@Test
public void singleQuoteMiddle() {
Assert.assertEquals("\"foo'bar\"", ExtendedAccessLogValve.wrap("foo'bar"));
}
@Test
public void doubleQuoteMiddle() {
Assert.assertEquals("\"foo\"\"bar\"", ExtendedAccessLogValve.wrap("foo\"bar"));
}
@Test
public void doubleQuoteStart() {
Assert.assertEquals("\"\"\"foobar\"", ExtendedAccessLogValve.wrap("\"foobar"));
}
@Test
public void doubleQuoteEnd() {
Assert.assertEquals("\"foobar\"\"\"", ExtendedAccessLogValve.wrap("foobar\""));
}
@Test
public void doubleQuote() {
Assert.assertEquals("\"\"\"\"", ExtendedAccessLogValve.wrap("\""));
}
}

View File

@@ -0,0 +1,275 @@
/* 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 org.apache.catalina.valves;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.SessionCookieConfig;
import javax.servlet.http.Cookie;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardPipeline;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
public class TestLoadBalancerDrainingValve {
static class MockResponse extends Response {
private List<Cookie> cookies;
@Override
public boolean isCommitted() {
return false;
}
@Override
public void addCookie(Cookie cookie)
{
if(null == cookies)
cookies = new ArrayList<>(1);
cookies.add(cookie);
}
@Override
public List<Cookie> getCookies() {
return cookies;
}
}
static class CookieConfig implements SessionCookieConfig {
private String name;
private String domain;
private String path;
private String comment;
private boolean httpOnly;
private boolean secure;
private int maxAge;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getDomain() {
return domain;
}
@Override
public void setDomain(String domain) {
this.domain = domain;
}
@Override
public String getPath() {
return path;
}
@Override
public void setPath(String path) {
this.path = path;
}
@Override
public String getComment() {
return comment;
}
@Override
public void setComment(String comment) {
this.comment = comment;
}
@Override
public boolean isHttpOnly() {
return httpOnly;
}
@Override
public void setHttpOnly(boolean httpOnly) {
this.httpOnly = httpOnly;
}
@Override
public boolean isSecure() {
return secure;
}
@Override
public void setSecure(boolean secure) {
this.secure = secure;
}
@Override
public int getMaxAge() {
return maxAge;
}
@Override
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
}
// A Cookie subclass that knows how to compare itself to other Cookie objects
static class MyCookie extends Cookie {
private static final long serialVersionUID = 1L;
public MyCookie(String name, String value) { super(name, value); }
@Override
public boolean equals(Object o) {
if(!(o instanceof MyCookie)) {
return false;
}
MyCookie mc = (MyCookie)o;
return mc.getName().equals(this.getName())
&& mc.getPath().equals(this.getPath())
&& mc.getValue().equals(this.getValue())
&& mc.getMaxAge() == this.getMaxAge();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getMaxAge();
result = prime * result + ((getName() == null) ? 0 : getName().hashCode());
result = prime * result + ((getPath() == null) ? 0 : getPath().hashCode());
result = prime * result + ((getValue() == null) ? 0 : getValue().hashCode());
return result;
}
@Override
public String toString() {
return "Cookie { name=" + getName() + ", value=" + getValue() + ", path=" + getPath() + ", maxAge=" + getMaxAge() + " }";
}
}
@Test
public void testNormalRequest() throws Exception {
runValve("ACT", true, true, false, null);
}
@Test
public void testDisabledValidSession() throws Exception {
runValve("DIS", true, true, false, null);
}
@Test
public void testDisabledInvalidSession() throws Exception {
runValve("DIS", false, false, false, "foo=bar");
}
@Test
public void testDisabledInvalidSessionWithIgnore() throws Exception {
runValve("DIS", false, true, true, "foo=bar");
}
private void runValve(String jkActivation,
boolean validSessionId,
boolean expectInvokeNext,
boolean enableIgnore,
String queryString) throws Exception {
IMocksControl control = EasyMock.createControl();
ServletContext servletContext = control.createMock(ServletContext.class);
Context ctx = control.createMock(Context.class);
Request request = control.createMock(Request.class);
Response response = control.createMock(Response.class);
String sessionCookieName = "JSESSIONID";
String sessionId = "cafebabe";
String requestURI = "/test/path";
SessionCookieConfig cookieConfig = new CookieConfig();
cookieConfig.setDomain("example.com");
cookieConfig.setName(sessionCookieName);
cookieConfig.setPath("/");
// Valve.init requires all of this stuff
EasyMock.expect(ctx.getMBeanKeyProperties()).andStubReturn("");
EasyMock.expect(ctx.getName()).andStubReturn("");
EasyMock.expect(ctx.getPipeline()).andStubReturn(new StandardPipeline());
EasyMock.expect(ctx.getDomain()).andStubReturn("foo");
EasyMock.expect(ctx.getLogger()).andStubReturn(org.apache.juli.logging.LogFactory.getLog(LoadBalancerDrainingValve.class));
EasyMock.expect(ctx.getServletContext()).andStubReturn(servletContext);
// Set up the actual test
EasyMock.expect(request.getAttribute(LoadBalancerDrainingValve.ATTRIBUTE_KEY_JK_LB_ACTIVATION)).andStubReturn(jkActivation);
EasyMock.expect(Boolean.valueOf(request.isRequestedSessionIdValid())).andStubReturn(Boolean.valueOf(validSessionId));
ArrayList<Cookie> cookies = new ArrayList<>();
if(enableIgnore) {
cookies.add(new Cookie("ignore", "true"));
}
if(!validSessionId) {
MyCookie cookie = new MyCookie(cookieConfig.getName(), sessionId);
cookie.setPath(cookieConfig.getPath());
cookie.setValue(sessionId);
cookies.add(cookie);
EasyMock.expect(request.getRequestedSessionId()).andStubReturn(sessionId);
EasyMock.expect(request.getRequestURI()).andStubReturn(requestURI);
EasyMock.expect(request.getCookies()).andStubReturn(cookies.toArray(new Cookie[cookies.size()]));
EasyMock.expect(request.getContext()).andStubReturn(ctx);
EasyMock.expect(ctx.getSessionCookieName()).andStubReturn(sessionCookieName);
EasyMock.expect(servletContext.getSessionCookieConfig()).andStubReturn(cookieConfig);
EasyMock.expect(request.getQueryString()).andStubReturn(queryString);
EasyMock.expect(ctx.getSessionCookiePath()).andStubReturn("/");
if (!enableIgnore) {
EasyMock.expect(Boolean.valueOf(ctx.getSessionCookiePathUsesTrailingSlash())).andStubReturn(Boolean.TRUE);
EasyMock.expect(request.getQueryString()).andStubReturn(queryString);
// Response will have cookie deleted
MyCookie expectedCookie = new MyCookie(cookieConfig.getName(), "");
expectedCookie.setPath(cookieConfig.getPath());
expectedCookie.setMaxAge(0);
// These two lines just mean EasyMock.expect(response.addCookie) but for a void method
response.addCookie(expectedCookie);
EasyMock.expect(ctx.getSessionCookieName()).andReturn(sessionCookieName); // Indirect call
String expectedRequestURI = requestURI;
if(null != queryString)
expectedRequestURI = expectedRequestURI + '?' + queryString;
response.setHeader("Location", expectedRequestURI);
response.setStatus(307);
}
}
Valve next = control.createMock(Valve.class);
if(expectInvokeNext) {
// Expect the "next" Valve to fire
// Next 2 lines are basically EasyMock.expect(next.invoke(req,res)) but for a void method
next.invoke(request, response);
EasyMock.expectLastCall();
}
// Get set to actually test
control.replay();
LoadBalancerDrainingValve valve = new LoadBalancerDrainingValve();
valve.setContainer(ctx);
valve.init();
valve.setNext(next);
valve.setIgnoreCookieName("ignore");
valve.setIgnoreCookieValue("true");
valve.invoke(request, response);
control.verify();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,346 @@
/*
* 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 org.apache.catalina.valves;
import java.io.IOException;
import javax.servlet.ServletException;
import org.junit.Assert;
import org.junit.Test;
import org.apache.catalina.Context;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
/**
* {@link RequestFilterValve} Tests
*/
public class TestRequestFilterValve {
private static final int OK = 200;
private static final int FORBIDDEN = 403;
private static final int CUSTOM = 499;
private static final String ADDR_ALLOW_PAT = "127\\.\\d*\\.\\d*\\.\\d*";
private static final String ADDR_DENY_PAT = "\\d*\\.\\d*\\.\\d*\\.1";
private static final String ADDR_ONLY_ALLOW = "127.0.0.2";
private static final String ADDR_ONLY_DENY = "192.168.0.1";
private static final String ADDR_ALLOW_AND_DENY = "127.0.0.1";
private static final String ADDR_NO_ALLOW_NO_DENY = "192.168.0.2";
private static final String HOST_ALLOW_PAT = "www\\.example\\.[a-zA-Z0-9-]*";
private static final String HOST_DENY_PAT = ".*\\.org";
private static final String HOST_ONLY_ALLOW = "www.example.com";
private static final String HOST_ONLY_DENY = "host.example.org";
private static final String HOST_ALLOW_AND_DENY = "www.example.org";
private static final String HOST_NO_ALLOW_NO_DENY = "host.example.com";
private static final int PORT = 8080;
private static final String PORT_MATCH_PATTERN = ";\\d*";
private static final String PORT_NO_MATCH_PATTERN = ";8081";
static class TerminatingValve extends ValveBase {
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
}
}
public static class MockResponse extends Response {
private int status = OK;
@Override
public void sendError(int status) throws IOException {
this.status = status;
}
@Override
public int getStatus() {
return status;
}
}
private void oneTest(String allow, String deny, boolean denyStatus,
boolean addConnectorPort, boolean auth,
String property, String type, boolean allowed) {
// PREPARE
RequestFilterValve valve = null;
Connector connector = new Connector();
Context context = new StandardContext();
Request request = new Request();
Response response = new MockResponse();
StringBuilder msg = new StringBuilder();
int expected = allowed ? OK : FORBIDDEN;
connector.setPort(PORT);
request.setConnector(connector);
request.getMappingData().context = context;
request.setCoyoteRequest(new org.apache.coyote.Request());
Assert.assertNotNull("Invalid test with null type", type);
if (property != null) {
if (type.equals("Addr")) {
valve = new RemoteAddrValve();
request.setRemoteAddr(property);
msg.append(" ip='" + property + "'");
} else if (type.equals("Host")) {
valve = new RemoteHostValve();
request.setRemoteHost(property);
msg.append(" host='" + property + "'");
}
}
Assert.assertNotNull("Invalid test type" + type, valve);
valve.setNext(new TerminatingValve());
if (allow != null) {
valve.setAllow(allow);
msg.append(" allow='" + allow + "'");
}
if (deny != null) {
valve.setDeny(deny);
msg.append(" deny='" + deny + "'");
}
if (denyStatus) {
valve.setDenyStatus(CUSTOM);
msg.append(" denyStatus='" + CUSTOM + "'");
if (!allowed) {
expected = CUSTOM;
}
}
if (addConnectorPort) {
if (valve instanceof RemoteAddrValve) {
((RemoteAddrValve)valve).setAddConnectorPort(true);
} else if (valve instanceof RemoteHostValve) {
((RemoteHostValve)valve).setAddConnectorPort(true);
} else {
Assert.fail("Can only set 'addConnectorPort' for RemoteAddrValve and RemoteHostValve");
}
msg.append(" addConnectorPort='true'");
}
if (auth) {
context.setPreemptiveAuthentication(true);
valve.setInvalidAuthenticationWhenDeny(true);
msg.append(" auth='true'");
}
// TEST
try {
valve.invoke(request, response);
} catch (IOException ex) {
//Ignore
} catch (ServletException ex) {
//Ignore
}
// VERIFY
if (!allowed && auth) {
Assert.assertEquals(msg.toString(), OK, response.getStatus());
Assert.assertEquals(msg.toString(), "invalid", request.getHeader("authorization"));
} else {
Assert.assertEquals(msg.toString(), expected, response.getStatus());
}
}
private void standardTests(String allow_pat, String deny_pat,
String OnlyAllow, String OnlyDeny,
String AllowAndDeny, String NoAllowNoDeny,
boolean auth, String type) {
String apat;
String dpat;
// Test without ports
apat = allow_pat;
dpat = deny_pat;
oneTest(null, null, false, false, auth, AllowAndDeny, type, false);
oneTest(null, null, true, false, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, false, auth, AllowAndDeny, type, true);
oneTest(apat, null, false, false, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, false, auth, AllowAndDeny, type, true);
oneTest(apat, null, true, false, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, false, auth, AllowAndDeny, type, false);
oneTest(null, dpat, false, false, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, false, auth, AllowAndDeny, type, false);
oneTest(null, dpat, true, false, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, false, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, false, auth, OnlyAllow, type, true);
oneTest(apat, dpat, false, false, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, false, auth, AllowAndDeny, type, false);
oneTest(apat, dpat, true, false, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, false, auth, OnlyAllow, type, true);
oneTest(apat, dpat, true, false, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, false, auth, AllowAndDeny, type, false);
// Test with port in pattern but forgotten "addConnectorPort"
apat = allow_pat + PORT_MATCH_PATTERN;
dpat = deny_pat + PORT_MATCH_PATTERN;
oneTest(null, null, false, false, auth, AllowAndDeny, type, false);
oneTest(null, null, true, false, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, false, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, false, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, false, auth, AllowAndDeny, type, false);
oneTest(apat, null, true, false, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, false, auth, AllowAndDeny, type, true);
oneTest(null, dpat, false, false, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, false, auth, AllowAndDeny, type, true);
oneTest(null, dpat, true, false, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, false, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, false, auth, OnlyAllow, type, false);
oneTest(apat, dpat, false, false, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, false, auth, AllowAndDeny, type, false);
oneTest(apat, dpat, true, false, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, false, auth, OnlyAllow, type, false);
oneTest(apat, dpat, true, false, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, false, auth, AllowAndDeny, type, false);
// Test with "addConnectorPort" but port not in pattern
apat = allow_pat;
dpat = deny_pat;
oneTest(null, null, false, true, auth, AllowAndDeny, type, false);
oneTest(null, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, true, true, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, true, auth, AllowAndDeny, type, true);
oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, true, auth, AllowAndDeny, type, true);
oneTest(null, dpat, true, true, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, true, auth, OnlyAllow, type, false);
oneTest(apat, dpat, false, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, dpat, true, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, true, auth, OnlyAllow, type, false);
oneTest(apat, dpat, true, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, true, auth, AllowAndDeny, type, false);
// Test "addConnectorPort" and with port matching in both patterns
apat = allow_pat + PORT_MATCH_PATTERN;
dpat = deny_pat + PORT_MATCH_PATTERN;
oneTest(null, null, false, true, auth, AllowAndDeny, type, false);
oneTest(null, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, AllowAndDeny, type, true);
oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, true, auth, AllowAndDeny, type, true);
oneTest(apat, null, true, true, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, true, auth, AllowAndDeny, type, false);
oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, true, auth, AllowAndDeny, type, false);
oneTest(null, dpat, true, true, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, true, auth, OnlyAllow, type, true);
oneTest(apat, dpat, false, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, dpat, true, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, true, auth, OnlyAllow, type, true);
oneTest(apat, dpat, true, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, true, auth, AllowAndDeny, type, false);
// Test "addConnectorPort" and with port not matching in both patterns
apat = allow_pat + PORT_NO_MATCH_PATTERN;
dpat = deny_pat + PORT_NO_MATCH_PATTERN;
oneTest(null, null, false, true, auth, AllowAndDeny, type, false);
oneTest(null, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, true, true, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, true, auth, AllowAndDeny, type, true);
oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, true, auth, AllowAndDeny, type, true);
oneTest(null, dpat, true, true, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, true, auth, OnlyAllow, type, false);
oneTest(apat, dpat, false, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, dpat, true, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, true, auth, OnlyAllow, type, false);
oneTest(apat, dpat, true, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, true, auth, AllowAndDeny, type, false);
// Test "addConnectorPort" and with port matching only in allow
apat = allow_pat + PORT_MATCH_PATTERN;
dpat = deny_pat + PORT_NO_MATCH_PATTERN;
oneTest(null, null, false, true, auth, AllowAndDeny, type, false);
oneTest(null, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, AllowAndDeny, type, true);
oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, true, auth, AllowAndDeny, type, true);
oneTest(apat, null, true, true, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, true, auth, AllowAndDeny, type, true);
oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, true, auth, AllowAndDeny, type, true);
oneTest(null, dpat, true, true, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, true, auth, OnlyAllow, type, true);
oneTest(apat, dpat, false, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, true, auth, AllowAndDeny, type, true);
oneTest(apat, dpat, true, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, true, auth, OnlyAllow, type, true);
oneTest(apat, dpat, true, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, true, auth, AllowAndDeny, type, true);
// Test "addConnectorPort" and with port matching only in deny
apat = allow_pat + PORT_NO_MATCH_PATTERN;
dpat = deny_pat + PORT_MATCH_PATTERN;
oneTest(null, null, false, true, auth, AllowAndDeny, type, false);
oneTest(null, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, null, true, true, auth, AllowAndDeny, type, false);
oneTest(apat, null, true, true, auth, NoAllowNoDeny, type, false);
oneTest(null, dpat, false, true, auth, AllowAndDeny, type, false);
oneTest(null, dpat, false, true, auth, NoAllowNoDeny, type, true);
oneTest(null, dpat, true, true, auth, AllowAndDeny, type, false);
oneTest(null, dpat, true, true, auth, NoAllowNoDeny, type, true);
oneTest(apat, dpat, false, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, false, true, auth, OnlyAllow, type, false);
oneTest(apat, dpat, false, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, false, true, auth, AllowAndDeny, type, false);
oneTest(apat, dpat, true, true, auth, NoAllowNoDeny, type, false);
oneTest(apat, dpat, true, true, auth, OnlyAllow, type, false);
oneTest(apat, dpat, true, true, auth, OnlyDeny, type, false);
oneTest(apat, dpat, true, true, auth, AllowAndDeny, type, false);
}
@Test
public void testRemoteAddrValveIPv4() {
standardTests(ADDR_ALLOW_PAT, ADDR_DENY_PAT,
ADDR_ONLY_ALLOW, ADDR_ONLY_DENY,
ADDR_ALLOW_AND_DENY, ADDR_NO_ALLOW_NO_DENY,
false, "Addr");
standardTests(ADDR_ALLOW_PAT, ADDR_DENY_PAT,
ADDR_ONLY_ALLOW, ADDR_ONLY_DENY,
ADDR_ALLOW_AND_DENY, ADDR_NO_ALLOW_NO_DENY,
true, "Addr");
}
@Test
public void testRemoteHostValve() {
standardTests(HOST_ALLOW_PAT, HOST_DENY_PAT,
HOST_ONLY_ALLOW, HOST_ONLY_DENY,
HOST_ALLOW_AND_DENY, HOST_NO_ALLOW_NO_DENY,
false, "Host");
standardTests(HOST_ALLOW_PAT, HOST_DENY_PAT,
HOST_ONLY_ALLOW, HOST_ONLY_DENY,
HOST_ALLOW_AND_DENY, HOST_NO_ALLOW_NO_DENY,
true, "Host");
}
}

View File

@@ -0,0 +1,333 @@
/*
* 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 org.apache.catalina.valves;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.logging.Level;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.apache.catalina.Globals;
import org.apache.catalina.Valve;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.connector.Request;
import org.apache.tomcat.unittest.TesterLogValidationFilter;
import org.easymock.EasyMock;
public class TestSSLValve {
public static class MockRequest extends Request {
public MockRequest() {
setConnector(EasyMock.createMock(Connector.class));
setCoyoteRequest(new org.apache.coyote.Request());
}
@Override
public void setAttribute(String name, Object value) {
getCoyoteRequest().getAttributes().put(name, value);
}
@Override
public Object getAttribute(String name) {
return getCoyoteRequest().getAttribute(name);
}
public void setHeader(String header, String value) {
getCoyoteRequest().getMimeHeaders().setValue(header).setString(value);
}
public void addHeader(String header, String value) {
getCoyoteRequest().getMimeHeaders().addValue(header).setString(value);
}
}
private static final String[] CERTIFICATE_LINES = new String[] { "-----BEGIN CERTIFICATE-----",
"MIIFXTCCA0WgAwIBAgIJANFf3YTJgYifMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV",
"BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX",
"aWRnaXRzIFB0eSBMdGQwHhcNMTcwNTI2MjEzNjM3WhcNMTgwNTI2MjEzNjM3WjBF",
"MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50",
"ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC",
"CgKCAgEA2ykNBanZz4cVITNpZcWNVmErUzqgSNrK361mj9vEdB1UkHatwal9jVrR",
"QvFgfiZ8Gl+/85t0ebJhJ+rIr1ww6JE7v2s2MThENj95K5EwZOmgvw+CBlBYsFIz",
"8BtjlVYy+v7RaGPXfjrFkexQP9UIaiIIog2ClDZirRvb+QxS930/YW5Qo+X6EX6W",
"/m/HvlorD25U4ni2FQ0y+EMO2e1jD88cAAMoP5f+Mf6NBK8I6yUeaSuMq7WqtHGV",
"e4F1WOg5z9J5c/M69rB0iQr5NUQwZ1mPYf5Kr0P6+TLh8DJphbVvmHJyT3bgofeV",
"JYl/kdjiXS5P/jwY9tfmhu04tsyzopWRUFCcj5zCiqZYaMn0wtDn08KaAh9oOlg8",
"Z6mJ9i5EybkLm63W7z7LxuM+qnYzq4wKkKdx8hbpASwPqzJkJeXFL/LzhKdZuHiR",
"clgPVYnm98URwhObh073dKguG/gkhcnpXcVBBVdVTJZYGBvTpQh0afXd9bcBwOzY",
"t4MDpGiQB2fLzBOEZhQ37kUcWPmZw5bNPxhx4yE96Md0rx/Gu4ipAHuqLemb1SL5",
"uWNesVmgY3OXaIamQIm9BCwkf8mMvoYdAT+lukTUZLtJ6s2w+Oxnl10tmb+6sTXy",
"UB3WcBTp/o3YjAyJPnM1Wq6nVNQ4W2+NbV5purGAP09sumxeJj8CAwEAAaNQME4w",
"HQYDVR0OBBYEFCGOYMvymUG2ZZT+lK4LvwEvx731MB8GA1UdIwQYMBaAFCGOYMvy",
"mUG2ZZT+lK4LvwEvx731MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB",
"AG6m4nDYCompUtRVude1qulwwAaYEMHyIIsfymI8uAE7d2o4bGjVpAUOdH/VWSOp",
"Rzx0oK6K9cHyiBlKHw5zSZdqcRi++tDX3P9Iy5tXO//zkhMEnSpk6RF2+9JXtyhx",
"Gma4yAET1yES+ybiFT21uZrGCC9r69rWG8JRZshc4RVWGwZsd0zrATVqfY0mZurm",
"xLgU4UOvkTczjlrLiklwwU68M1DLcILJ5FZGTWeTJ/q1wpIn9isK2siAW/VOcbuG",
"xdbGladnIFv+iQfuZG0yjcuMsBFsQiXi6ONM8GM+dr+61V63/1s73jYcOToEsTMM",
"3bHeVffoSkhZvOGTRCI6QhK9wqnIKhAYqu+NbV4OphfE3gOaK+T1cASXUtSQPXoa",
"sEoIVmbQsWRBhWvYShVqvINsH/hAT3Cf/+SslprtQUqiyt2ljdgrRFZdoyB3S7ky",
"KWoZRvHRj2cKU65LVYwx6U1A8SGmViz4aHMSai0wwKzOVv9MGHeRaVhlMmMsbdfu",
"wKoKJv0xYoVwEh1rB8TH8PjbL+6eFLeZXYVZnH71d5JHCghZ8W0a11ZuYkscSQWk",
"yoTBqEpJloWksrypqp3iL4PAL5+KkB2zp66+MVAg8LcEDFJggBBJCtv4SCWV7ZOB",
"WLu8gep+XCwSn0Wb6D3eFs4DoIiMvQ6g2rS/pk7o5eWj", "-----END CERTIFICATE-----" };
private SSLValve valve = new SSLValve();
private MockRequest mockRequest = new MockRequest();
private Valve mockNext = EasyMock.createMock(Valve.class);
@Before
public void setUp() throws Exception {
valve.setNext(mockNext);
mockNext.invoke(mockRequest, null);
EasyMock.replay(mockNext);
}
@Test
public void testSslHeader() {
final String headerName = "myheader";
final String headerValue = "BASE64_HEADER_VALUE";
mockRequest.setHeader(headerName, headerValue);
Assert.assertEquals(headerValue, valve.mygetHeader(mockRequest, headerName));
}
@Test
public void testSslHeaderNull() {
final String headerName = "myheader";
mockRequest.setHeader(headerName, null);
Assert.assertNull(valve.mygetHeader(mockRequest, headerName));
}
@Test
public void testSslHeaderNullModHeader() {
final String headerName = "myheader";
final String nullModHeaderValue = "(null)";
mockRequest.setHeader(headerName, nullModHeaderValue);
Assert.assertNull(valve.mygetHeader(mockRequest, nullModHeaderValue));
}
@Test
public void testSslHeaderNullName() throws Exception {
Assert.assertNull(valve.mygetHeader(mockRequest, null));
}
@Test
public void testSslHeaderMultiples() throws Exception {
final String headerName = "myheader";
final String headerValue = "BASE64_HEADER_VALUE";
mockRequest.addHeader(headerName, headerValue);
mockRequest.addHeader(headerName, "anyway won't be found");
Assert.assertEquals(headerValue, valve.mygetHeader(mockRequest, headerName));
}
@Test
public void testSslClientCertHeaderSingleSpace() throws Exception {
String singleSpaced = certificateSingleLine(" ");
mockRequest.setHeader(valve.getSslClientCertHeader(), singleSpaced);
valve.invoke(mockRequest, null);
assertCertificateParsed();
}
@Test
public void testSslClientCertHeaderMultiSpace() throws Exception {
String singleSpaced = certificateSingleLine(" ");
mockRequest.setHeader(valve.getSslClientCertHeader(), singleSpaced);
valve.invoke(mockRequest, null);
assertCertificateParsed();
}
@Test
public void testSslClientCertHeaderTab() throws Exception {
String singleSpaced = certificateSingleLine("\t");
mockRequest.setHeader(valve.getSslClientCertHeader(), singleSpaced);
valve.invoke(mockRequest, null);
assertCertificateParsed();
}
@Test
public void testSslClientCertNull() throws Exception {
TesterLogValidationFilter f = TesterLogValidationFilter.add(null, "", null,
"org.apache.catalina.valves.SSLValve");
valve.invoke(mockRequest, null);
EasyMock.verify(mockNext);
Assert.assertNull(mockRequest.getAttribute(Globals.CERTIFICATES_ATTR));
Assert.assertEquals(0, f.getMessageCount());
}
@Test
public void testSslClientCertShorter() throws Exception {
mockRequest.setHeader(valve.getSslClientCertHeader(), "shorter than hell");
TesterLogValidationFilter f = TesterLogValidationFilter.add(null, "", null,
"org.apache.catalina.valves.SSLValve");
valve.invoke(mockRequest, null);
EasyMock.verify(mockNext);
Assert.assertNull(mockRequest.getAttribute(Globals.CERTIFICATES_ATTR));
Assert.assertEquals(0, f.getMessageCount());
}
@Test
public void testSslClientCertIgnoredBegin() throws Exception {
String[] linesBegin = Arrays.copyOf(CERTIFICATE_LINES, CERTIFICATE_LINES.length);
linesBegin[0] = "3fisjcme3kdsakasdfsadkafsd3";
String begin = certificateSingleLine(linesBegin, " ");
mockRequest.setHeader(valve.getSslClientCertHeader(), begin);
valve.invoke(mockRequest, null);
assertCertificateParsed();
}
@Test
public void testSslClientCertBadFormat() throws Exception {
String[] linesDeleted = Arrays.copyOf(CERTIFICATE_LINES, CERTIFICATE_LINES.length / 2);
String deleted = certificateSingleLine(linesDeleted, " ");
mockRequest.setHeader(valve.getSslClientCertHeader(), deleted);
TesterLogValidationFilter f = TesterLogValidationFilter.add(Level.WARNING, null,
"java.security.cert.CertificateException", "org.apache.catalina.valves.SSLValve");
valve.invoke(mockRequest, null);
EasyMock.verify(mockNext);
Assert.assertNull(mockRequest.getAttribute(Globals.CERTIFICATES_ATTR));
Assert.assertEquals(1, f.getMessageCount());
}
@Test
public void testClientCertProviderNotFound() throws Exception {
EasyMock.expect(mockRequest.getConnector().getProperty("clientCertProvider")).andStubReturn("wontBeFound");
EasyMock.replay(mockRequest.getConnector());
mockRequest.setHeader(valve.getSslClientCertHeader(), certificateSingleLine(" "));
TesterLogValidationFilter f = TesterLogValidationFilter.add(Level.SEVERE, null,
"java.security.NoSuchProviderException", "org.apache.catalina.valves.SSLValve");
valve.invoke(mockRequest, null);
Assert.assertNull(mockRequest.getAttribute(Globals.CERTIFICATES_ATTR));
Assert.assertEquals(1, f.getMessageCount());
}
@Test
public void testSslCipherHeaderPresent() throws Exception {
String cipher = "ciphered-with";
mockRequest.setHeader(valve.getSslCipherHeader(), cipher);
valve.invoke(mockRequest, null);
Assert.assertEquals(cipher, mockRequest.getAttribute(Globals.CIPHER_SUITE_ATTR));
}
@Test
public void testSslSessionIdHeaderPresent() throws Exception {
String session = "ssl-session";
mockRequest.setHeader(valve.getSslSessionIdHeader(), session);
valve.invoke(mockRequest, null);
Assert.assertEquals(session, mockRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR));
}
@Test
public void testSslCipherUserKeySizeHeaderPresent() throws Exception {
Integer keySize = Integer.valueOf(452);
mockRequest.setHeader(valve.getSslCipherUserKeySizeHeader(), String.valueOf(keySize));
valve.invoke(mockRequest, null);
Assert.assertEquals(keySize, mockRequest.getAttribute(Globals.KEY_SIZE_ATTR));
}
@Test(expected = NumberFormatException.class)
public void testSslCipherUserKeySizeHeaderBadFormat() throws Exception {
mockRequest.setHeader(valve.getSslCipherUserKeySizeHeader(), "not-an-integer");
try {
valve.invoke(mockRequest, null);
} catch (NumberFormatException e) {
Assert.assertNull(mockRequest.getAttribute(Globals.KEY_SIZE_ATTR));
throw e;
}
}
private static String certificateSingleLine(String[] lines, String separator) {
StringBuilder singleSpaced = new StringBuilder();
for (String current : lines) {
singleSpaced.append(current).append(separator);
}
singleSpaced.deleteCharAt(singleSpaced.length() - 1);
return singleSpaced.toString();
}
private static String certificateSingleLine(String separator) {
return certificateSingleLine(CERTIFICATE_LINES, separator);
}
private void assertCertificateParsed() throws Exception {
TesterLogValidationFilter f = TesterLogValidationFilter.add(null, "", null,
"org.apache.catalina.valves.SSLValve");
EasyMock.verify(mockNext);
X509Certificate[] certificates = (X509Certificate[]) mockRequest.getAttribute(Globals.CERTIFICATES_ATTR);
Assert.assertNotNull(certificates);
Assert.assertEquals(1, certificates.length);
Assert.assertNotNull(certificates[0]);
Assert.assertEquals(0, f.getMessageCount());
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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 org.apache.catalina.valves;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.TomcatBaseTest;
import org.apache.tomcat.util.buf.ByteChunk;
public class TestStuckThreadDetectionValve extends TomcatBaseTest {
private StandardContext context;
private Tomcat tomcat;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
tomcat = getTomcatInstance();
File docBase = new File(System.getProperty("java.io.tmpdir"));
context = (StandardContext) tomcat.addContext("",
docBase.getAbsolutePath());
}
@Test
public void testDetection() throws Exception {
// second, we test the actual effect of the flag on the startup
StickingServlet stickingServlet = new StickingServlet(8000L);
Wrapper servlet = Tomcat.addServlet(context, "myservlet",
stickingServlet);
servlet.addMapping("/myservlet");
StuckThreadDetectionValve valve = new StuckThreadDetectionValve();
valve.setThreshold(2);
context.addValve(valve);
context.setBackgroundProcessorDelay(1);
tomcat.start();
Assert.assertEquals(0, valve.getStuckThreadIds().length);
final ByteChunk result = new ByteChunk();
Thread asyncThread = new Thread() {
@Override
public void run() {
try {
getUrl("http://localhost:" + getPort() + "/myservlet",
result, null);
} catch (IOException e) {
e.printStackTrace();
}
}
};
asyncThread.start();
try {
Thread.sleep(500L);
Assert.assertEquals(0, valve.getStuckThreadIds().length);
Thread.sleep(5000L);
Assert.assertEquals(1, valve.getStuckThreadIds().length);
} finally {
asyncThread.join(20000);
// check that we did not reach the join timeout
Assert.assertFalse(asyncThread.isAlive());
}
Assert.assertFalse(stickingServlet.wasInterrupted);
Assert.assertTrue(result.toString().startsWith("OK"));
}
@Test
public void testInterruption() throws Exception {
// second, we test the actual effect of the flag on the startup
StickingServlet stickingServlet = new StickingServlet(
TimeUnit.SECONDS.toMillis(20L));
Wrapper servlet = Tomcat.addServlet(context, "myservlet",
stickingServlet);
servlet.addMapping("/myservlet");
StuckThreadDetectionValve valve = new StuckThreadDetectionValve();
valve.setThreshold(2);
valve.setInterruptThreadThreshold(5);
context.addValve(valve);
context.setBackgroundProcessorDelay(1);
tomcat.start();
Assert.assertEquals(0, valve.getStuckThreadIds().length);
final ByteChunk result = new ByteChunk();
Thread asyncThread = new Thread() {
@Override
public void run() {
try {
getUrl("http://localhost:" + getPort() + "/myservlet",
result, null);
} catch (IOException e) {
e.printStackTrace();
}
}
};
asyncThread.start();
try {
Thread.sleep(4000L);
Assert.assertEquals(1, valve.getStuckThreadIds().length);
} finally {
asyncThread.join(20000);
// check that we did not reach the join timeout
Assert.assertFalse(asyncThread.isAlive());
}
Assert.assertTrue(stickingServlet.wasInterrupted);
Assert.assertEquals(0, valve.getStuckThreadIds().length);
Assert.assertTrue(result.toString().startsWith("OK"));
}
private static class StickingServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private final long delay;
boolean wasInterrupted = false;
StickingServlet(long delay) {
this.delay = delay;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
wasInterrupted = true;
}
resp.setContentType("text/plain");
resp.getWriter().println("OK");
}
}
}

View File

@@ -0,0 +1,125 @@
/*
* 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 org.apache.catalina.valves;
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.servlet.ServletException;
import org.junit.Assert;
import org.apache.catalina.AccessLog;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
public class TesterAccessLogValve extends ValveBase implements AccessLog {
private static final boolean RELAX_TIMING = Boolean.getBoolean("tomcat.test.relaxTiming");
// Timing tests need an error margin to prevent failures.
private static final long ERROR_MARGIN = RELAX_TIMING ? 2000 : 100;
private final Queue<Entry> entries = new ConcurrentLinkedQueue<>();
public TesterAccessLogValve() {
// Async requests are supported
super(true);
}
@Override
public void log(Request request, Response response, long time) {
entries.add(new Entry(request.getRequestURI(), response.getStatus(),
time));
}
@Override
public void setRequestAttributesEnabled(boolean requestAttributesEnabled) {
// NOOP - test code
}
@Override
public boolean getRequestAttributesEnabled() {
// Always false - test code
return false;
}
@Override
public void invoke(Request request, Response response) throws IOException,
ServletException {
// Just invoke next - access logging happens via log() method
getNext().invoke(request, response);
}
public int getEntryCount() {
return entries.size();
}
public void validateAccessLog(int count, int status, long minTime,
long maxTime) throws Exception {
// Wait (but not too long) until all expected entries appear (access log
// entry will be made after response has been returned to user)
for (int i = 0; i < 10 && entries.size() < count; i++) {
Thread.sleep(100);
}
StringBuilder entriesLog = new StringBuilder();
for (Entry entry : entries) {
entriesLog.append(entry.toString());
entriesLog.append(System.lineSeparator());
}
Assert.assertEquals(entriesLog.toString(), count, entries.size());
for (Entry entry : entries) {
Assert.assertEquals(status, entry.getStatus());
Assert.assertTrue(entry.toString() + " duration is not >= " + (minTime - ERROR_MARGIN),
entry.getTime() >= minTime - ERROR_MARGIN);
Assert.assertTrue(entry.toString() + " duration is not < " + (maxTime + ERROR_MARGIN),
entry.getTime() < maxTime + ERROR_MARGIN);
}
}
public static class Entry {
private final String uri;
private final int status;
private final long time;
public Entry(String uri, int status, long time) {
this.uri = uri;
this.status = status;
this.time = time;
}
public String getUri() {
return uri;
}
public int getStatus() {
return status;
}
public long getTime() {
return time;
}
@Override
public String toString() {
return "Uri: " + uri + ", Status: " + status + ", Time: " + time;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
/*
* 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 org.apache.catalina.valves.rewrite;
import java.util.HashMap;
import java.util.Map;
public class TesterRewriteMapA implements RewriteMap {
private static final Map<String,String> map = new HashMap<>();
static {
map.put("a", "aa");
map.put("aa", "aaaa");
map.put("b", "bb");
}
@Override
public String setParameters(String params) {
// NO-OP
return null;
}
@Override
public String lookup(String key) {
return map.get(key);
}
}