blob: 191b561081b613acb9a561aa1996ff96fcf6f259 [file] [log] [blame]
/*
* 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.knox.gateway.dispatch;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.knox.test.TestUtils;
import org.apache.knox.test.mock.MockHttpServletResponse;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.Test;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.apache.knox.gateway.dispatch.DefaultDispatch.SET_COOKIE;
import static org.apache.knox.gateway.dispatch.DefaultDispatch.WWW_AUTHENTICATE;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class ConfigurableDispatchTest {
@Test( timeout = TestUtils.SHORT_TIMEOUT )
public void testGetDispatchUrl() {
HttpServletRequest request;
String path;
String query;
URI uri;
ConfigurableDispatch dispatch = new ConfigurableDispatch();
path = "http://test-host:42/test-path";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( null ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test-path" ) );
path = "http://test-host:42/test,path";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( null ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test,path" ) );
path = "http://test-host:42/test%2Cpath";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( null ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test%2Cpath" ) );
path = "http://test-host:42/test%2Cpath";
query = "test%26name=test%3Dvalue";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( query ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test%2Cpath?test%26name=test%3Dvalue" ) );
}
@Test( timeout = TestUtils.SHORT_TIMEOUT )
public void testGetDispatchUrlNoUrlEncoding() {
HttpServletRequest request;
String path;
String query;
URI uri;
ConfigurableDispatch dispatch = new ConfigurableDispatch();
dispatch.setRemoveUrlEncoding(Boolean.TRUE.toString());
path = "http://test-host:42/test-path";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( null ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test-path" ) );
path = "http://test-host:42/test,path";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( null ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test,path" ) );
// encoding in the patch remains
path = "http://test-host:42/test%2Cpath";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( null ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test%2Cpath" ) );
// encoding in query string is removed
path = "http://test-host:42/test%2Cpath";
query = "test%26name=test%3Dvalue";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( query ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:42/test%2Cpath?test&name=test=value" ) );
// double quotes removed
path = "https://test-host:42/api/v1/views/TEZ/versions/0.7.0.2.6.2.0-205/instances/TEZ_CLUSTER_INSTANCE/resources/atsproxy/ws/v1/timeline/TEZ_DAG_ID";
query = "limit=9007199254740991&primaryFilter=applicationId:%22application_1518808140659_0007%22&_=1519053586839";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( query ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "https://test-host:42/api/v1/views/TEZ/versions/0.7.0.2.6.2.0-205/instances/TEZ_CLUSTER_INSTANCE/resources/atsproxy/ws/v1/timeline/TEZ_DAG_ID?limit=9007199254740991&primaryFilter=applicationId:%22application_1518808140659_0007%22&_=1519053586839" ) );
// encode < and > sign
path = "http://test-host:8080/api/v1/clusters/mmolnar-knox2/configurations/service_config_versions";
query = "group_id%3E0&fields=*&_=1541527314780";
request = EasyMock.createNiceMock( HttpServletRequest.class );
EasyMock.expect( request.getRequestURI() ).andReturn( path ).anyTimes();
EasyMock.expect( request.getRequestURL() ).andReturn( new StringBuffer( path ) ).anyTimes();
EasyMock.expect( request.getQueryString() ).andReturn( query ).anyTimes();
EasyMock.replay( request );
uri = dispatch.getDispatchUrl( request );
assertThat( uri.toASCIIString(), is( "http://test-host:8080/api/v1/clusters/mmolnar-knox2/configurations/service_config_versions?group_id%3E0&fields=*&_=1541527314780" ) );
}
@Test( timeout = TestUtils.SHORT_TIMEOUT )
public void testRequestExcludeHeadersDefault() {
ConfigurableDispatch dispatch = new ConfigurableDispatch();
Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.AUTHORIZATION, "Basic ...");
headers.put(HttpHeaders.ACCEPT, "abc");
headers.put("TEST", "test");
HttpServletRequest inboundRequest = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(inboundRequest.getHeaderNames()).andReturn(Collections.enumeration(headers.keySet())).anyTimes();
Capture<String> capturedArgument = Capture.newInstance();
EasyMock.expect(inboundRequest.getHeader(EasyMock.capture(capturedArgument)))
.andAnswer(() -> headers.get(capturedArgument.getValue())).anyTimes();
EasyMock.replay(inboundRequest);
HttpUriRequest outboundRequest = new HttpGet();
dispatch.copyRequestHeaderFields(outboundRequest, inboundRequest);
Header[] outboundRequestHeaders = outboundRequest.getAllHeaders();
assertThat(outboundRequestHeaders.length, is(2));
assertThat(outboundRequestHeaders[0].getName(), is(HttpHeaders.ACCEPT));
assertThat(outboundRequestHeaders[1].getName(), is("TEST"));
}
@Test( timeout = TestUtils.SHORT_TIMEOUT )
public void testRequestExcludeHeadersConfig() {
ConfigurableDispatch dispatch = new ConfigurableDispatch();
dispatch.setRequestExcludeHeaders(String.join(",", Arrays.asList(HttpHeaders.ACCEPT, "TEST")));
Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.AUTHORIZATION, "Basic ...");
headers.put(HttpHeaders.ACCEPT, "abc");
headers.put("TEST", "test");
HttpServletRequest inboundRequest = EasyMock.createNiceMock(HttpServletRequest.class);
EasyMock.expect(inboundRequest.getHeaderNames()).andReturn(Collections.enumeration(headers.keySet())).anyTimes();
Capture<String> capturedArgument = Capture.newInstance();
EasyMock.expect(inboundRequest.getHeader(EasyMock.capture(capturedArgument)))
.andAnswer(() -> headers.get(capturedArgument.getValue())).anyTimes();
EasyMock.replay(inboundRequest);
HttpUriRequest outboundRequest = new HttpGet();
dispatch.copyRequestHeaderFields(outboundRequest, inboundRequest);
Header[] outboundRequestHeaders = outboundRequest.getAllHeaders();
assertThat(outboundRequestHeaders.length, is(1));
assertThat(outboundRequestHeaders[0].getName(), is(HttpHeaders.AUTHORIZATION));
}
@Test
public void testResponseExcludeHeadersDefault() {
ConfigurableDispatch dispatch = new ConfigurableDispatch();
Header[] headers = new Header[]{
new BasicHeader(SET_COOKIE, "abc"),
new BasicHeader(WWW_AUTHENTICATE, "negotiate"),
new BasicHeader("TEST", "testValue"),
new BasicHeader("Accept", "applcation/json")
};
HttpResponse inboundResponse = EasyMock.createNiceMock(HttpResponse.class);
EasyMock.expect(inboundResponse.getAllHeaders()).andReturn(headers).anyTimes();
EasyMock.replay(inboundResponse);
HttpServletResponse outboundResponse = new MockHttpServletResponse();
dispatch.copyResponseHeaderFields(outboundResponse, inboundResponse);
assertThat(outboundResponse.getHeaderNames().size(), is(2));
assertThat(outboundResponse.getHeader("TEST"), is("testValue"));
assertThat(outboundResponse.getHeader("Accept"), is("applcation/json"));
}
@Test
public void testResponseExcludeHeadersConfig() {
ConfigurableDispatch dispatch = new ConfigurableDispatch();
dispatch.setResponseExcludeHeaders(String.join(",", Arrays.asList("test", "caseINSENSITIVEheader")));
Header[] headers = new Header[]{
new BasicHeader(SET_COOKIE, "abc"),
new BasicHeader(WWW_AUTHENTICATE, "negotiate"),
new BasicHeader("TEST", "testValue"),
new BasicHeader("caseInsensitiveHeader", "caseInsensitiveHeaderValue")
};
HttpResponse inboundResponse = EasyMock.createNiceMock(HttpResponse.class);
EasyMock.expect(inboundResponse.getAllHeaders()).andReturn(headers).anyTimes();
EasyMock.replay(inboundResponse);
HttpServletResponse outboundResponse = new MockHttpServletResponse();
dispatch.copyResponseHeaderFields(outboundResponse, inboundResponse);
assertThat(outboundResponse.getHeaderNames().size(), is(2));
assertThat(outboundResponse.getHeader(SET_COOKIE), is("abc"));
assertThat(outboundResponse.getHeader(WWW_AUTHENTICATE), is("negotiate"));
}
@Test
public void shouldExcludeCertainPartsFromSetCookieHeader() throws Exception {
final Header[] headers = new Header[] { new BasicHeader(SET_COOKIE, "Domain=localhost; Secure; HttpOnly; Max-Age=1") };
final HttpResponse inboundResponse = EasyMock.createNiceMock(HttpResponse.class);
EasyMock.expect(inboundResponse.getAllHeaders()).andReturn(headers).anyTimes();
EasyMock.replay(inboundResponse);
final ConfigurableDispatch dispatch = new ConfigurableDispatch();
final String setCookieExludeHeaders = SET_COOKIE + ": Domain=localhost; HttpOnly";
dispatch.setResponseExcludeHeaders(setCookieExludeHeaders);
final HttpServletResponse outboundResponse = new MockHttpServletResponse();
dispatch.copyResponseHeaderFields(outboundResponse, inboundResponse);
assertThat(outboundResponse.getHeaderNames().size(), is(1));
assertThat(outboundResponse.getHeader(SET_COOKIE), is("Secure; Max-Age=1"));
}
}