You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/08 15:15:15 UTC
[22/24] knox git commit: Merge branch 'master' into
KNOX-998-Package_Restructuring
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
index 5babe90,0000000..8cfffb9
mode 100644,000000..100644
--- a/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
+++ b/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthSSOTest.java
@@@ -1,30 -1,0 +1,29 @@@
+
+/**
+ * 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.provider.federation;
+
- import junit.framework.TestCase;
+
+import org.junit.Test;
+
- public class PreAuthSSOTest extends TestCase {
++public class PreAuthSSOTest extends org.junit.Assert {
+ @Test
+ public void testPreAuth() throws Exception {
+ assertTrue(true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
index bf023e7,0000000..f42a8a3
mode 100644,000000..100644
--- a/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
+++ b/gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
@@@ -1,115 -1,0 +1,114 @@@
+/**
+ * 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.provider.federation;
+
+import junit.framework.TestCase;
- import org.apache.knox.gateway.preauth.filter.*;
+import org.apache.knox.gateway.preauth.filter.DefaultValidator;
+import org.apache.knox.gateway.preauth.filter.IPValidator;
+import org.apache.knox.gateway.preauth.filter.PreAuthService;
+import org.apache.knox.gateway.preauth.filter.PreAuthValidationException;
+import org.apache.knox.gateway.preauth.filter.PreAuthValidator;
+import org.junit.Test;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
- public class PreAuthServiceTest extends TestCase {
++public class PreAuthServiceTest extends org.junit.Assert {
+
+ @Test
+ public void testValidatorMap() {
+ Map<String, PreAuthValidator> valMap = PreAuthService.getValidatorMap();
+ assertNotNull(valMap.get(IPValidator.IP_VALIDATION_METHOD_VALUE));
+ assertEquals(valMap.get(IPValidator.IP_VALIDATION_METHOD_VALUE).getName(), IPValidator.IP_VALIDATION_METHOD_VALUE);
+ assertNotNull(valMap.get(DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE));
+ assertEquals(valMap.get(DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE).getName(), DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
+
+ //Negative test
+ assertNull(valMap.get("NonExists"));
+ }
+
+ @Test
+ public void testDefaultValidator() throws ServletException,
+ PreAuthValidationException {
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final FilterConfig filterConfig = mock(FilterConfig.class);
+ when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn
+ (DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
+ List<PreAuthValidator> validators = PreAuthService.getValidators(filterConfig);
+ assertEquals(validators.size(), 1);
+ assertEquals(validators.get(0).getName(), DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
+ assertTrue(PreAuthService.validate(request, filterConfig, validators));
+ }
+
+ @Test
+ public void testIPValidator() throws ServletException, PreAuthValidationException {
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getRemoteAddr()).thenReturn("10.1.23.42");
+ final FilterConfig filterConfig = mock(FilterConfig.class);
+ when(filterConfig.getInitParameter(IPValidator.IP_ADDRESSES_PARAM)).thenReturn("5.4.3.2,10.1.23.42");
+ when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn(IPValidator
+ .IP_VALIDATION_METHOD_VALUE);
+ List<PreAuthValidator> validators = PreAuthService.getValidators(filterConfig);
+ assertEquals(validators.size(), 1);
+ assertEquals(validators.get(0).getName(), IPValidator.IP_VALIDATION_METHOD_VALUE);
+ assertTrue(PreAuthService.validate(request, filterConfig, validators));
+ //Negative testing
+ when(request.getRemoteAddr()).thenReturn("10.10.22.33");
+ assertFalse(PreAuthService.validate(request, filterConfig, validators));
+ }
+
+ @Test
+ public void testMultipleValidatorsPositive() throws ServletException, PreAuthValidationException {
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getRemoteAddr()).thenReturn("10.1.23.42");
+ final FilterConfig filterConfig = mock(FilterConfig.class);
+ when(filterConfig.getInitParameter(IPValidator.IP_ADDRESSES_PARAM)).thenReturn("5.4.3.2,10.1.23.42");
+ when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn
+ (DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE + "," + IPValidator.IP_VALIDATION_METHOD_VALUE );
+ List<PreAuthValidator> validators = PreAuthService.getValidators(filterConfig);
+ assertEquals(validators.size(), 2);
+ assertEquals(validators.get(0).getName(), DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE);
+ assertEquals(validators.get(1).getName(), IPValidator.IP_VALIDATION_METHOD_VALUE);
+
+ assertTrue(PreAuthService.validate(request, filterConfig, validators));
+ //Negative testing
+ when(request.getRemoteAddr()).thenReturn("10.10.22.33");
+ assertFalse(PreAuthService.validate(request, filterConfig, validators));
+
+ }
+
+ @Test
+ public void testMultipleValidatorsNegative() throws ServletException, PreAuthValidationException {
+ final FilterConfig filterConfig = mock(FilterConfig.class);
+ when(filterConfig.getInitParameter(PreAuthService.VALIDATION_METHOD_PARAM)).thenReturn
+ (DefaultValidator.DEFAULT_VALIDATION_METHOD_VALUE + ", NOT_EXISTED_VALIDATOR" );
+ try {
+ PreAuthService.getValidators(filterConfig);
+ fail("Should throw exception due to invalid validator");
+ } catch (Exception e) {
+ //Expected
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
index 383dffe,0000000..a182b37
mode 100644,000000..100644
--- a/gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
+++ b/gateway-provider-security-webappsec/src/main/java/org/apache/knox/gateway/webappsec/deploy/WebAppSecContributor.java
@@@ -1,107 -1,0 +1,107 @@@
+/**
+ * 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.webappsec.deploy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.knox.gateway.deploy.DeploymentContext;
+import org.apache.knox.gateway.deploy.ProviderDeploymentContributorBase;
+import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
+import org.apache.knox.gateway.descriptor.ResourceDescriptor;
+import org.apache.knox.gateway.topology.Provider;
+import org.apache.knox.gateway.topology.Service;
+
+public class WebAppSecContributor extends
+ ProviderDeploymentContributorBase {
+ private static final String ROLE = "webappsec";
+ private static final String NAME = "WebAppSec";
+ private static final String CSRF_SUFFIX = "_CSRF";
+ private static final String CSRF_FILTER_CLASSNAME = "org.apache.knox.gateway.webappsec.filter.CSRFPreventionFilter";
+ private static final String CSRF_ENABLED = "csrf.enabled";
+ private static final String CORS_SUFFIX = "_CORS";
+ private static final String CORS_FILTER_CLASSNAME = "com.thetransactioncompany.cors.CORSFilter";
+ private static final String CORS_ENABLED = "cors.enabled";
+ private static final String XFRAME_OPTIONS_SUFFIX = "_XFRAMEOPTIONS";
+ private static final String XFRAME_OPTIONS_FILTER_CLASSNAME = "org.apache.knox.gateway.webappsec.filter.XFrameOptionsFilter";
+ private static final String XFRAME_OPTIONS_ENABLED = "xframe.options.enabled";
+
+
+ @Override
+ public String getRole() {
+ return ROLE;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public void initializeContribution(DeploymentContext context) {
+ super.initializeContribution(context);
+ }
+
+ @Override
+ public void contributeFilter(DeploymentContext context, Provider provider, Service service,
+ ResourceDescriptor resource, List<FilterParamDescriptor> params) {
+
+ Provider webappsec = context.getTopology().getProvider(ROLE, NAME);
+ if (webappsec != null && webappsec.isEnabled()) {
+ Map<String,String> map = provider.getParams();
+ if (params == null) {
+ params = new ArrayList<FilterParamDescriptor>();
+ }
+
+ Map<String, String> providerParams = provider.getParams();
+ // CORS support
+ String corsEnabled = map.get(CORS_ENABLED);
- if ( corsEnabled != null && corsEnabled.equals("true")) {
++ if ( corsEnabled != null && "true".equals(corsEnabled)) {
+ provisionConfig(resource, providerParams, params, "cors.");
+ resource.addFilter().name( getName() + CORS_SUFFIX ).role( getRole() ).impl( CORS_FILTER_CLASSNAME ).params( params );
+ }
+
+ // CRSF
+ params = new ArrayList<FilterParamDescriptor>();
+ String csrfEnabled = map.get(CSRF_ENABLED);
- if ( csrfEnabled != null && csrfEnabled.equals("true")) {
++ if ( csrfEnabled != null && "true".equals(csrfEnabled)) {
+ provisionConfig(resource, providerParams, params, "csrf.");
+ resource.addFilter().name( getName() + CSRF_SUFFIX ).role( getRole() ).impl( CSRF_FILTER_CLASSNAME ).params( params );
+ }
+
+ // X-Frame-Options - clickjacking protection
+ params = new ArrayList<FilterParamDescriptor>();
+ String xframeOptionsEnabled = map.get(XFRAME_OPTIONS_ENABLED);
- if ( xframeOptionsEnabled != null && xframeOptionsEnabled.equals("true")) {
++ if ( xframeOptionsEnabled != null && "true".equals(xframeOptionsEnabled)) {
+ provisionConfig(resource, providerParams, params, "xframe.");
+ resource.addFilter().name( getName() + XFRAME_OPTIONS_SUFFIX ).role( getRole() ).impl( XFRAME_OPTIONS_FILTER_CLASSNAME ).params( params );
+ }
+ }
+ }
+
+ private void provisionConfig(ResourceDescriptor resource, Map<String,String> providerParams,
+ List<FilterParamDescriptor> params, String prefix) {
+ for(Entry<String, String> entry : providerParams.entrySet()) {
+ if (entry.getKey().startsWith(prefix)) {
+ params.add( resource.createFilterParam().name( entry.getKey().toLowerCase() ).value( entry.getValue() ) );
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
index f21d3c2,0000000..4f9ea33
mode 100644,000000..100644
--- a/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
+++ b/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/CSRFTest.java
@@@ -1,29 -1,0 +1,28 @@@
+/**
+ * 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.webappsec;
+
- import junit.framework.TestCase;
+
+import org.junit.Test;
+
- public class CSRFTest extends TestCase {
++public class CSRFTest extends org.junit.Assert {
+ @Test
+ public void testCsrf() throws Exception {
+ assertTrue(true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
index 2bb7bda,0000000..5a3c96f
mode 100644,000000..100644
--- a/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
+++ b/gateway-provider-security-webappsec/src/test/java/org/apache/knox/gateway/webappsec/XFrameOptionsFilterTest.java
@@@ -1,193 -1,0 +1,193 @@@
+/**
+ * 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.webappsec;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Properties;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.knox.gateway.webappsec.filter.XFrameOptionsFilter;
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class XFrameOptionsFilterTest {
+ /**
+ *
+ */
+ private static final String X_FRAME_OPTIONS = "X-Frame-Options";
+ String options = null;
+ Collection<String> headerNames = null;
+ Collection<String> headers = null;
+
+ @Test
+ public void testDefaultOptionsValue() throws Exception {
+ try {
+ XFrameOptionsFilter filter = new XFrameOptionsFilter();
+ Properties props = new Properties();
+ props.put("xframe.options.enabled", "true");
+ filter.init(new TestFilterConfig(props));
+
+ HttpServletRequest request = EasyMock.createNiceMock(
+ HttpServletRequest.class);
+ HttpServletResponse response = EasyMock.createNiceMock(
+ HttpServletResponse.class);
+ EasyMock.replay(request);
+ EasyMock.replay(response);
+
+ TestFilterChain chain = new TestFilterChain();
+ filter.doFilter(request, response, chain);
+ Assert.assertTrue("doFilterCalled should not be false.",
- chain.doFilterCalled == true);
++ chain.doFilterCalled );
+ Assert.assertTrue("Options value incorrect should be DENY but is: "
- + options, options.equals("DENY"));
++ + options, "DENY".equals(options));
+
+ Assert.assertTrue("X-Frame-Options count not equal to 1.", headers.size() == 1);
+ } catch (ServletException se) {
+ fail("Should NOT have thrown a ServletException.");
+ }
+ }
+
+ @Test
+ public void testConfiguredOptionsValue() throws Exception {
+ try {
+ XFrameOptionsFilter filter = new XFrameOptionsFilter();
+ Properties props = new Properties();
+ props.put("xframe.options.enabled", "true");
+ props.put("xframe.options", "SAMEORIGIN");
+ filter.init(new TestFilterConfig(props));
+
+ HttpServletRequest request = EasyMock.createNiceMock(
+ HttpServletRequest.class);
+ HttpServletResponse response = EasyMock.createNiceMock(
+ HttpServletResponse.class);
+ EasyMock.replay(request);
+ EasyMock.replay(response);
+
+ TestFilterChain chain = new TestFilterChain();
+ filter.doFilter(request, response, chain);
+ Assert.assertTrue("doFilterCalled should not be false.",
- chain.doFilterCalled == true);
++ chain.doFilterCalled );
+ Assert.assertTrue("Options value incorrect should be SAMEORIGIN but is: "
- + options, options.equals("SAMEORIGIN"));
++ + options, "SAMEORIGIN".equals(options));
+
+ Assert.assertTrue("X-Frame-Options count not equal to 1.", headers.size() == 1);
+ } catch (ServletException se) {
+ fail("Should NOT have thrown a ServletException.");
+ }
+ }
+
+// @Test
+// public void testExistingXFrameOptionHeader() throws Exception {
+// try {
+// XFrameOptionsFilter filter = new XFrameOptionsFilter();
+// Properties props = new Properties();
+// props.put("xframe.options.enabled", "true");
+// props.put("xframe.options", "SAMEORIGIN");
+// filter.init(new TestFilterConfig(props));
+//
+// HttpServletRequest request = EasyMock.createNiceMock(
+// HttpServletRequest.class);
+// HttpServletResponse response = EasyMock.createNiceMock(
+// HttpServletResponse.class);
+// EasyMock.replay(request);
+// EasyMock.replay(response);
+//
+// TestFilterChain chain = new TestFilterChain();
+// filter.doFilter(request, response, chain);
+// Assert.assertTrue("doFilterCalled should not be false.",
- // chain.doFilterCalled == true);
++// chain.doFilterCalled );
+// Assert.assertTrue("Options value incorrect should be SAMEORIGIN but is: "
- // + options, options.equals("SAMEORIGIN"));
++// + options, "SAMEORIGIN".equals(options));
+//
+// Assert.assertTrue("X-Frame-Options count not equal to 1.", headers.size() == 1);
+// } catch (ServletException se) {
+// fail("Should NOT have thrown a ServletException.");
+// }
+// }
+
+ class TestFilterConfig implements FilterConfig {
+ Properties props = null;
+
+ public TestFilterConfig(Properties props) {
+ this.props = props;
+ }
+
+ @Override
+ public String getFilterName() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterConfig#getServletContext()
+ */
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterConfig#getInitParameter(java.lang.String)
+ */
+ @Override
+ public String getInitParameter(String name) {
+ return props.getProperty(name, null);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterConfig#getInitParameterNames()
+ */
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return null;
+ }
+
+ }
+
+ class TestFilterChain implements FilterChain {
+ boolean doFilterCalled = false;
+
+ /* (non-Javadoc)
+ * @see javax.servlet.FilterChain#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
+ */
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+ doFilterCalled = true;
+ options = ((HttpServletResponse)response).getHeader(X_FRAME_OPTIONS);
+ headerNames = ((HttpServletResponse)response).getHeaderNames();
+ headers = ((HttpServletResponse)response).getHeaders(X_FRAME_OPTIONS);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-release/home/conf/topologies/manager.xml
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
----------------------------------------------------------------------
diff --cc gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
index 25e9d5e,0000000..b069cb3
mode 100644,000000..100644
--- a/gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
+++ b/gateway-server-xforwarded-filter/src/test/java/org/apache/knox/gateway/filter/CompositeEnumerationTest.java
@@@ -1,117 -1,0 +1,117 @@@
+/**
+ * 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.filter;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
- import static junit.framework.TestCase.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
++import static org.junit.Assert.fail;
+
+public class CompositeEnumerationTest {
+
+ @Test
+ public void testBasics() {
+
+ String[] a = new String[]{ "1", "2" };
+ Enumeration<String> ea = Collections.enumeration( Arrays.asList( a ) );
+
+ String[] b = new String[]{ "3", "4" };
+ Enumeration<String> eb = Collections.enumeration( Arrays.asList( b ) );
+
+ CompositeEnumeration<String> ce = new CompositeEnumeration<String>( ea, eb );
+
+ assertThat( ce.nextElement(), is( "1" ) );
+ assertThat( ce.nextElement(), is( "2" ) );
+ assertThat( ce.nextElement(), is( "3" ) );
+ assertThat( ce.nextElement(), is( "4" ) );
+ assertThat( ce.hasMoreElements(), is( false ) );
+
+ }
+
+ @Test
+ public void testSingleValues() {
+ String[] a = new String[]{ "1" };
+ Enumeration<String> ea = Collections.enumeration( Arrays.asList( a ) );
+
+ String[] b = new String[]{ "2" };
+ Enumeration<String> eb = Collections.enumeration( Arrays.asList( b ) );
+
+ CompositeEnumeration<String> ce = new CompositeEnumeration<String>( ea, eb );
+
+ assertThat( ce.nextElement(), is( "1" ) );
+ assertThat( ce.nextElement(), is( "2" ) );
+ assertThat( ce.hasMoreElements(), is( false ) );
+ }
+
+ @Test
+ public void testEmptyEnumerations() {
+
+ String[] a = new String[]{ "1", "2" };
+ String[] b = new String[]{ "3", "4" };
+ String[] c = new String[]{};
+
+ Enumeration<String> e1 = Collections.enumeration( Arrays.asList( a ) );
+ Enumeration<String> e2 = Collections.enumeration( Arrays.asList( c ) );
+ CompositeEnumeration<String> ce = new CompositeEnumeration<String>( e1, e2 );
+ assertThat( ce.nextElement(), is( "1" ) );
+ assertThat( ce.nextElement(), is( "2" ) );
+ assertThat( ce.hasMoreElements(), is( false ) );
+
+ e1 = Collections.enumeration( Arrays.asList( c ) );
+ e2 = Collections.enumeration( Arrays.asList( a ) );
+ ce = new CompositeEnumeration<String>( e1, e2 );
+ assertThat( ce.nextElement(), is( "1" ) );
+ assertThat( ce.nextElement(), is( "2" ) );
+ assertThat( ce.hasMoreElements(), is( false ) );
+
+ e1 = Collections.enumeration( Arrays.asList( c ) );
+ e2 = Collections.enumeration( Arrays.asList( c ) );
+ ce = new CompositeEnumeration<String>( e1, e2 );
+ assertThat( ce.hasMoreElements(), is( false ) );
+ }
+
+ @Test
+ public void testEmpty() {
+ CompositeEnumeration<String> ce = new CompositeEnumeration<String>();
+ assertThat( ce.hasMoreElements(), is( false ) );
+
+ try {
+ ce.nextElement();
+ fail( "Should have throws NoSuchElementExcpetion" );
+ } catch( NoSuchElementException e ) {
+ // Expected.
+ }
+ }
+
+ @Test
+ public void testNulls() {
+ try {
+ CompositeEnumeration<String> ce = new CompositeEnumeration<String>( null );
+ fail( "Expected IllegalArgumentException" );
+ } catch( IllegalArgumentException e ) {
+ // Expected.
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 36c24de,0000000..70eca7f
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@@ -1,1029 -1,0 +1,1029 @@@
+/**
+ * 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;
+
+import net.lingala.zip4j.core.ZipFile;
+import net.lingala.zip4j.exception.ZipException;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.knox.gateway.audit.api.Action;
+import org.apache.knox.gateway.audit.api.ActionOutcome;
+import org.apache.knox.gateway.audit.api.AuditServiceFactory;
+import org.apache.knox.gateway.audit.api.Auditor;
+import org.apache.knox.gateway.audit.api.ResourceType;
+import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
+import org.apache.knox.gateway.deploy.DeploymentException;
+import org.apache.knox.gateway.deploy.DeploymentFactory;
+import org.apache.knox.gateway.filter.CorrelationHandler;
+import org.apache.knox.gateway.filter.PortMappingHelperHandler;
+import org.apache.knox.gateway.filter.RequestUpdateHandler;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.registry.ServiceRegistry;
+import org.apache.knox.gateway.services.security.SSLService;
+import org.apache.knox.gateway.services.topology.TopologyService;
+import org.apache.knox.gateway.topology.Application;
+import org.apache.knox.gateway.topology.Topology;
+import org.apache.knox.gateway.topology.TopologyEvent;
+import org.apache.knox.gateway.topology.TopologyListener;
+import org.apache.knox.gateway.trace.AccessHandler;
+import org.apache.knox.gateway.trace.ErrorHandler;
+import org.apache.knox.gateway.trace.TraceHandler;
+import org.apache.knox.gateway.util.Urls;
+import org.apache.knox.gateway.util.XmlUtils;
+import org.apache.knox.gateway.websockets.GatewayWebsocketHandler;
+import org.apache.log4j.PropertyConfigurator;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.NetworkConnector;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.servlets.gzip.GzipHandler;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.webapp.Configuration;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
+import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+public class GatewayServer {
+ private static final GatewayResources res = ResourcesFactory.get(GatewayResources.class);
+ private static final GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
+ private static final Auditor auditor = AuditServiceFactory.getAuditService().getAuditor(AuditConstants.DEFAULT_AUDITOR_NAME,
+ AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME);
+ private static final String DEFAULT_CONNECTOR_NAME = "default";
+
+ private static GatewayServer server;
+ private static GatewayServices services;
+
+ private static Properties buildProperties;
+
+ private Server jetty;
+ private GatewayConfig config;
+ private ContextHandlerCollection contexts;
+ private TopologyService monitor;
+ private TopologyListener listener;
+ private Map<String, WebAppContext> deployments;
+
+ public static void main( String[] args ) {
+ try {
+ configureLogging();
+ logSysProps();
+ CommandLine cmd = GatewayCommandLine.parse( args );
+ if( cmd.hasOption( GatewayCommandLine.HELP_LONG ) ) {
+ GatewayCommandLine.printHelp();
+ } else if( cmd.hasOption( GatewayCommandLine.VERSION_LONG ) ) {
+ printVersion();
+ } else if( cmd.hasOption( GatewayCommandLine.REDEPLOY_LONG ) ) {
+ redeployTopologies( cmd.getOptionValue( GatewayCommandLine.REDEPLOY_LONG ) );
+ } else {
+ buildProperties = loadBuildProperties();
+ services = instantiateGatewayServices();
+ if (services == null) {
+ log.failedToInstantiateGatewayServices();
+ }
+ GatewayConfig config = new GatewayConfigImpl();
+ if (config.isHadoopKerberosSecured()) {
+ configureKerberosSecurity( config );
+ }
+ Map<String,String> options = new HashMap<>();
+ options.put(GatewayCommandLine.PERSIST_LONG, Boolean.toString(cmd.hasOption(GatewayCommandLine.PERSIST_LONG)));
+ services.init(config, options);
+ if (!cmd.hasOption(GatewayCommandLine.NOSTART_LONG)) {
+ startGateway( config, services );
+ }
+ }
+ } catch ( ParseException e ) {
+ log.failedToParseCommandLine( e );
+ GatewayCommandLine.printHelp();
+ } catch ( Exception e ) {
+ log.failedToStartGateway( e );
+ // Make sure the process exits.
+ System.exit(1);
+ }
+ }
+
+ private static void printVersion() {
+ System.out.println( res.gatewayVersionMessage( // I18N not required.
+ getBuildVersion(),
+ getBuildHash() ) );
+ }
+
+ public static String getBuildHash() {
+ String hash = "unknown";
+ if( buildProperties != null ) {
+ hash = buildProperties.getProperty( "build.hash", hash );
+ }
+ return hash;
+ }
+
+ public static String getBuildVersion() {
+ String version = "unknown";
+ if( buildProperties != null ) {
+ version = buildProperties.getProperty( "build.version", version );
+ }
+ return version;
+ }
+
+ private static GatewayServices instantiateGatewayServices() {
+ ServiceLoader<GatewayServices> loader = ServiceLoader.load( GatewayServices.class );
+ Iterator<GatewayServices> services = loader.iterator();
+ if (services.hasNext()) {
+ return services.next();
+ }
+ return null;
+ }
+
+ public static synchronized GatewayServices getGatewayServices() {
+ return services;
+ }
+
+ private static void logSysProp( String name ) {
+ log.logSysProp( name, System.getProperty( name ) );
+ }
+
+ private static void logSysProps() {
+ logSysProp( "user.name" );
+ logSysProp( "user.dir" );
+ logSysProp( "java.runtime.name" );
+ logSysProp( "java.runtime.version" );
+ logSysProp( "java.home" );
+ }
+
+ private static void configureLogging() {
+ PropertyConfigurator.configure( System.getProperty( "log4j.configuration" ) );
+// String fileName = config.getGatewayConfDir() + File.separator + "log4j.properties";
+// File file = new File( fileName );
+// if( file.isFile() && file.canRead() ) {
+// FileInputStream stream;
+// try {
+// stream = new FileInputStream( file );
+// Properties properties = new Properties();
+// properties.load( stream );
+// PropertyConfigurator.configure( properties );
+// log.loadedLoggingConfig( fileName );
+// } catch( IOException e ) {
+// log.failedToLoadLoggingConfig( fileName );
+// }
+// }
+ }
+
+ private static void configureKerberosSecurity( GatewayConfig config ) {
+ System.setProperty(GatewayConfig.HADOOP_KERBEROS_SECURED, "true");
+ System.setProperty(GatewayConfig.KRB5_CONFIG, config.getKerberosConfig());
+ System.setProperty(GatewayConfig.KRB5_DEBUG,
+ Boolean.toString(config.isKerberosDebugEnabled()));
+ System.setProperty(GatewayConfig.KRB5_LOGIN_CONFIG, config.getKerberosLoginConfig());
+ System.setProperty(GatewayConfig.KRB5_USE_SUBJECT_CREDS_ONLY, "false");
+ }
+
+ private static Properties loadBuildProperties() {
+ Properties properties = new Properties();
+ InputStream inputStream = GatewayServer.class.getClassLoader().getResourceAsStream( "build.properties" );
+ if( inputStream != null ) {
+ try {
+ properties.load( inputStream );
+ inputStream.close();
+ } catch( IOException e ) {
+ // Ignore.
+ }
+ }
+ return properties;
+ }
+
+ public static void redeployTopologies( String topologyName ) {
+ TopologyService ts = getGatewayServices().getService(GatewayServices.TOPOLOGY_SERVICE);
+ ts.reloadTopologies();
+ ts.redeployTopologies(topologyName);
+ }
+
+ private void cleanupTopologyDeployments() {
+ File deployDir = new File( config.getGatewayDeploymentDir() );
+ TopologyService ts = getGatewayServices().getService(GatewayServices.TOPOLOGY_SERVICE);
+ for( Topology topology : ts.getTopologies() ) {
+ cleanupTopologyDeployments( deployDir, topology );
+ }
+ }
+
+ private void cleanupTopologyDeployments( File deployDir, Topology topology ) {
+ log.cleanupDeployments( topology.getName() );
+ File[] files = deployDir.listFiles( new RegexFilenameFilter( topology.getName() + "\\.(war|topo)\\.[0-9A-Fa-f]+" ) );
+ if( files != null ) {
+ Arrays.sort( files, new FileModificationTimeDescendingComparator() );
+ int verLimit = config.getGatewayDeploymentsBackupVersionLimit();
+ long ageLimit = config.getGatewayDeploymentsBackupAgeLimit();
+ long keepTime = System.currentTimeMillis() - ageLimit;
+ for( int i=1; i<files.length; i++ ) {
+ File file = files[i];
+ if( ( ( verLimit >= 0 ) && ( i > verLimit ) ) ||
+ ( ( ageLimit >= 0 ) && ( file.lastModified() < keepTime ) ) ) {
+ log.cleanupDeployment( file.getAbsolutePath() );
+ FileUtils.deleteQuietly( file );
+ }
+ }
+ }
+ }
+
+ public static GatewayServer startGateway( GatewayConfig config, GatewayServices svcs ) throws Exception {
+ log.startingGateway();
+ server = new GatewayServer( config );
+ synchronized ( server ) {
+ //KM[ Commented this out because is causes problems with
+ // multiple services instance used in a single test process.
+ // I'm not sure what drive including this check though.
+ //if (services == null) {
+ services = svcs;
+ //}
+ //KM]
+ services.start();
+ DeploymentFactory.setGatewayServices(services);
+ server.start();
+ // Coverity CID 1352654
+ URI uri = server.jetty.getURI();
+
+ // Logging for topology <-> port
+ InetSocketAddress[] addresses = new InetSocketAddress[server.jetty
+ .getConnectors().length];
+ for (int i = 0, n = addresses.length; i < n; i++) {
+ NetworkConnector connector = (NetworkConnector) server.jetty
+ .getConnectors()[i];
+ if (connector != null) {
+ for(ConnectionFactory x : connector.getConnectionFactories()) {
+ if(x instanceof HttpConnectionFactory) {
+ ((HttpConnectionFactory)x).getHttpConfiguration().setSendServerVersion(config.isGatewayServerHeaderEnabled());
+ }
+ }
+ if (connector.getName() == null) {
+ log.startedGateway(
+ connector != null ? connector.getLocalPort() : -1);
+ } else {
+ log.startedGateway(connector != null ? connector.getName() : "",
+ connector != null ? connector.getLocalPort() : -1);
+ }
+ }
+ }
+
+ return server;
+ }
+ }
+
+ public GatewayServer( GatewayConfig config ) {
+ this(config, null);
+ }
+
+ public GatewayServer( GatewayConfig config, Properties options ) {
+ this.config = config;
+ this.listener = new InternalTopologyListener();
+ }
+
+ /**
+ * Create a connector for Gateway Server to listen on.
+ *
+ * @param server Jetty server
+ * @param config GatewayConfig
+ * @param port If value is > 0 then the given value is used else we
+ * use the port provided in GatewayConfig.
+ * @param topologyName Connector name, only used when not null
+ * @return
+ * @throws IOException
+ * @throws CertificateException
+ * @throws NoSuchAlgorithmException
+ * @throws KeyStoreException
+ */
+ private static Connector createConnector(final Server server,
+ final GatewayConfig config, final int port, final String topologyName)
+ throws IOException, CertificateException, NoSuchAlgorithmException,
+ KeyStoreException {
+
+ ServerConnector connector;
+
+ // Determine the socket address and check availability.
+ InetSocketAddress address = config.getGatewayAddress();
+ checkAddressAvailability( address );
+
+ final int connectorPort = port > 0 ? port : address.getPort();
+
+ checkPortConflict(connectorPort, topologyName, config);
+
+ HttpConfiguration httpConfig = new HttpConfiguration();
+ httpConfig.setRequestHeaderSize( config.getHttpServerRequestHeaderBuffer() );
+ //httpConfig.setRequestBufferSize( config.getHttpServerRequestBuffer() );
+ httpConfig.setResponseHeaderSize( config.getHttpServerResponseHeaderBuffer() );
+ httpConfig.setOutputBufferSize( config.getHttpServerResponseBuffer() );
+
+ if (config.isSSLEnabled()) {
+ HttpConfiguration httpsConfig = new HttpConfiguration( httpConfig );
+ httpsConfig.setSecureScheme( "https" );
+ httpsConfig.setSecurePort( connectorPort );
+ httpsConfig.addCustomizer( new SecureRequestCustomizer() );
+ SSLService ssl = services.getService("SSLService");
+ String keystoreFileName = config.getGatewaySecurityDir() + File.separatorChar + "keystores" + File.separatorChar + "gateway.jks";
+ SslContextFactory sslContextFactory = (SslContextFactory)ssl.buildSslContextFactory( keystoreFileName );
+ connector = new ServerConnector( server, sslContextFactory, new HttpConnectionFactory( httpsConfig ) );
+ } else {
+ connector = new ServerConnector( server );
+ }
+ connector.setHost( address.getHostName() );
+ connector.setPort( connectorPort );
+
+ if(!StringUtils.isBlank(topologyName)) {
+ connector.setName(topologyName);
+ }
+
+ long idleTimeout = config.getGatewayIdleTimeout();
+ if (idleTimeout > 0l) {
+ connector.setIdleTimeout(idleTimeout);
+ }
+
+ return connector;
+ }
+
+ private static HandlerCollection createHandlers(
+ final GatewayConfig config,
+ final GatewayServices services,
+ final ContextHandlerCollection contexts,
+ final Map<String, Integer> topologyPortMap) {
+ HandlerCollection handlers = new HandlerCollection();
+ RequestLogHandler logHandler = new RequestLogHandler();
+
+ logHandler.setRequestLog( new AccessHandler() );
+
+ TraceHandler traceHandler = new TraceHandler();
+ traceHandler.setHandler( contexts );
+ traceHandler.setTracedBodyFilter( System.getProperty( "org.apache.knox.gateway.trace.body.status.filter" ) );
+
+ CorrelationHandler correlationHandler = new CorrelationHandler();
+ correlationHandler.setHandler( traceHandler );
+
+ /* KNOX-732: Handler for GZip compression */
+ GzipHandler gzipHandler = new GzipHandler();
+ String[] mimeTypes = {};
+ if (config.getMimeTypesToCompress() != null
+ && !config.getMimeTypesToCompress().isEmpty()) {
+ mimeTypes = (String[]) config.getMimeTypesToCompress().toArray();
+ }
+ gzipHandler.addIncludedMimeTypes(mimeTypes);
+ gzipHandler.setHandler(correlationHandler);
+
+ // Used to correct the {target} part of request with Topology Port Mapping feature
+ final PortMappingHelperHandler portMappingHandler = new PortMappingHelperHandler(config);
+ portMappingHandler.setHandler(gzipHandler);
+
+ // If topology to port mapping feature is enabled then we add new Handler {RequestForwardHandler}
+ // to the chain, this handler listens on the configured port (in gateway-site.xml)
+ // and simply forwards requests to the correct context path.
+
+ // The reason for adding ContextHandler is so that we can add a connector
+ // to it on which the handler listens (exclusively).
+
+
+ if (config.isGatewayPortMappingEnabled()) {
+
+ for (final Map.Entry<String, Integer> entry : topologyPortMap
+ .entrySet()) {
+ log.createJettyHandler(entry.getKey());
+ final ContextHandler topologyContextHandler = new ContextHandler();
+
+ final RequestUpdateHandler updateHandler = new RequestUpdateHandler(
+ config, entry.getKey(), services);
+
+ topologyContextHandler.setHandler(updateHandler);
+ topologyContextHandler.setVirtualHosts(
+ new String[] { "@" + entry.getKey().toLowerCase() });
+
+ handlers.addHandler(topologyContextHandler);
+ }
+
+ }
+
+ handlers.addHandler(logHandler);
+
- if (config.isWebsocketEnabled()) {
++ if (config.isWebsocketEnabled()) {
+ final GatewayWebsocketHandler websocketHandler = new GatewayWebsocketHandler(
+ config, services);
+ websocketHandler.setHandler(portMappingHandler);
+
+ handlers.addHandler(websocketHandler);
+
+ } else {
+ handlers.addHandler(portMappingHandler);
+ }
+
+ return handlers;
+ }
+
+ /**
+ * Sanity Check to make sure configured ports are free and there is not port
+ * conflict.
+ *
+ * @param port
+ * @param topologyName
+ * @param config
+ * @throws IOException
+ */
+ public static void checkPortConflict(final int port,
+ final String topologyName, final GatewayConfig config)
+ throws IOException {
+
+ // Throw an exception if port in use
+ if (isPortInUse(port)) {
+ if (topologyName == null) {
+ log.portAlreadyInUse(port);
+ } else {
+ log.portAlreadyInUse(port, topologyName);
+ }
+ throw new IOException(String.format(" Port %d already in use. ", port));
+ }
+
+ // if topology name is blank which means we have all topologies listening on this port
+ if (StringUtils.isBlank(topologyName)) {
+ // If we have Default Topology old and new configuration (Port Mapping) throw error.
- if (config.getGatewayPortMappings().containsValue(new Integer(port))
++ if (config.getGatewayPortMappings().containsValue(Integer.valueOf(port))
+ && !StringUtils.isBlank(config.getDefaultTopologyName())) {
+ log.portAlreadyInUse(port);
+ throw new IOException(String.format(
+ " Please map port %d using either \"gateway.port.mapping.sandbox\" or "
+ + "\"default.app.topology.name\" property, "
+ + "specifying both is not a valid configuration. ",
+ port));
+ }
+ } else {
+ // Topology name is not blank so check amongst other ports if we have a conflict
+ for (final Map.Entry<String, Integer> entry : config
+ .getGatewayPortMappings().entrySet()) {
+ if (entry.getKey().equalsIgnoreCase(topologyName)) {
+ continue;
+ }
+
+ if (entry.getValue() == port) {
+ log.portAlreadyInUse(port, topologyName);
+ throw new IOException(String.format(
+ " Topologies %s and %s use the same port %d, ports for topologies (if defined) have to be unique. ",
+ entry.getKey(), topologyName, port));
+ }
+
+ }
+
+ }
+
+ }
+
+ private synchronized void start() throws Exception {
+ // Create the global context handler.
+ contexts = new ContextHandlerCollection();
+
+ // A map to keep track of current deployments by cluster name.
+ deployments = new ConcurrentHashMap<>();
+
+ // Start Jetty.
+ jetty = new Server( new QueuedThreadPool( config.getThreadPoolMax() ) );
+
+ /* topologyName is null because all topology listen on this port */
+ jetty.addConnector( createConnector( jetty, config, config.getGatewayPort(), null) );
+
+
+ // Add Annotations processing into the Jetty server to support JSPs
+ Configuration.ClassList classlist = Configuration.ClassList.setServerDefault( jetty );
+ classlist.addBefore(
+ "org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
+ "org.eclipse.jetty.annotations.AnnotationConfiguration" );
+
+ // Load the current topologies.
+ File topologiesDir = calculateAbsoluteTopologiesDir();
+ log.loadingTopologiesFromDirectory(topologiesDir.getAbsolutePath());
+ monitor = services.getService(GatewayServices.TOPOLOGY_SERVICE);
+ monitor.addTopologyChangeListener(listener);
+ monitor.reloadTopologies();
+
+ final Collection<Topology> topologies = monitor.getTopologies();
+ final Map<String, Integer> topologyPortMap = config.getGatewayPortMappings();
+
+ // List of all the topology that are deployed
+ final List<String> deployedTopologyList = new ArrayList<String>();
+
+ for (final Topology t : topologies) {
+ deployedTopologyList.add(t.getName());
+ }
+
+
+ // Check whether the configured topologies for port mapping exist, if not
+ // log WARN message and continue
+ checkMappedTopologiesExist(topologyPortMap, deployedTopologyList);
+
+ final HandlerCollection handlers = createHandlers( config, services, contexts, topologyPortMap);
+
+ // Check whether a topology wants dedicated port,
+ // if yes then we create a connector that listens on the provided port.
+
+ log.gatewayTopologyPortMappingEnabled(config.isGatewayPortMappingEnabled());
+ if (config.isGatewayPortMappingEnabled()) {
+ for (Map.Entry<String, Integer> entry : topologyPortMap.entrySet()) {
+ // Add connector for only valid topologies, i.e. deployed topologies.
+ // and NOT for Default Topology listening on standard gateway port.
+ if(deployedTopologyList.contains(entry.getKey()) && (entry.getValue().intValue() != config.getGatewayPort()) ) {
+ log.createJettyConnector(entry.getKey().toLowerCase(), entry.getValue());
+ jetty.addConnector(createConnector(jetty, config, entry.getValue(),
+ entry.getKey().toLowerCase()));
+ }
+ }
+ }
+
+ jetty.setHandler(handlers);
+
+ try {
+ jetty.start();
+ }
+ catch (IOException e) {
+ log.failedToStartGateway( e );
+ throw e;
+ }
+
+ cleanupTopologyDeployments();
+
+ // Start the topology monitor.
+ log.monitoringTopologyChangesInDirectory(topologiesDir.getAbsolutePath());
+ monitor.startMonitor();
+ }
+
+ public synchronized void stop() throws Exception {
+ log.stoppingGateway();
+ services.stop();
+ monitor.stopMonitor();
+ jetty.stop();
+ jetty.join();
+ log.stoppedGateway();
+ }
+
+ /**
+ * Check whether a port is free
+ *
+ * @param port
+ * @return true if port in use else false
+ */
+ public static boolean isPortInUse(final int port) {
+
+ Socket socket = null;
+ try {
+ socket = new Socket("localhost", port);
+ return true;
+ } catch (final UnknownHostException e) {
+ return false;
+ } catch (final IOException e) {
+ return false;
+ } finally {
+ IOUtils.closeQuietly(socket);
+ }
+
+ }
+
+ /**
+ * Checks whether the topologies defined in gateway-xml as part of Topology
+ * Port mapping feature exists. If it does not Log a message and move on.
+ *
+ * @param configTopologies
+ * @param topologies
+ * @return
+ */
+ private void checkMappedTopologiesExist(
+ final Map<String, Integer> configTopologies,
+ final List<String> topologies) throws IOException {
+
+ for(final Map.Entry<String, Integer> entry : configTopologies.entrySet()) {
+
+ // If the topologies defined in gateway-config.xml are not found in gateway
+ if (!topologies.contains(entry.getKey())) {
+ log.topologyPortMappingCannotFindTopology(entry.getKey(), entry.getValue());
+ }
+
+ }
+
+ }
+
+ public URI getURI() {
+ return jetty.getURI();
+ }
+
+ public InetSocketAddress[] getAddresses() {
+ InetSocketAddress[] addresses = new InetSocketAddress[ jetty.getConnectors().length ];
+ for( int i=0, n=addresses.length; i<n; i++ ) {
+ NetworkConnector connector = (NetworkConnector)jetty.getConnectors()[ i ];
+ String host = connector.getHost();
+ if( host == null ) {
+ addresses[ i ] = new InetSocketAddress( connector.getLocalPort() );
+ } else {
+ addresses[ i ] = new InetSocketAddress( host, connector.getLocalPort() );
+ }
+ }
+ return addresses;
+ }
+
+ private ErrorHandler createErrorHandler() {
+ ErrorHandler errorHandler = new ErrorHandler();
+ errorHandler.setShowStacks( false );
+ errorHandler.setTracedBodyFilter( System.getProperty( "org.apache.knox.gateway.trace.body.status.filter" ) );
+ return errorHandler;
+ }
+
+ private WebAppContext createWebAppContext( Topology topology, File warFile, String warPath ) throws IOException, ZipException, TransformerException, SAXException, ParserConfigurationException {
+ String topoName = topology.getName();
+ WebAppContext context = new WebAppContext();
+ String contextPath;
+ contextPath = "/" + Urls.trimLeadingAndTrailingSlashJoin( config.getGatewayPath(), topoName, warPath );
+ context.setContextPath( contextPath );
+ context.setWar( warFile.getAbsolutePath() );
+ context.setAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE, topoName );
+ context.setAttribute( "org.apache.knox.gateway.frontend.uri", getFrontendUri( context, config ) );
+ context.setAttribute( GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE, config );
+ // Add support for JSPs.
+ context.setAttribute(
+ "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
+ ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$" );
+ context.setTempDirectory( FileUtils.getFile( warFile, "META-INF", "temp" ) );
+ context.setErrorHandler( createErrorHandler() );
+ context.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
+
+ return context;
+ }
+
+ private static void explodeWar( File source, File target ) throws IOException, ZipException {
+ if( source.isDirectory() ) {
+ FileUtils.copyDirectory( source, target );
+ } else {
+ ZipFile zip = new ZipFile( source );
+ zip.extractAll( target.getAbsolutePath() );
+ }
+ }
+
+ private void mergeWebXmlOverrides( File webInfDir ) throws IOException, SAXException, ParserConfigurationException, TransformerException {
+ File webXmlFile = new File( webInfDir, "web.xml" );
+ Document webXmlDoc;
+ if( webXmlFile.exists() ) {
+ // Backup original web.xml file.
+ File originalWebXmlFile = new File( webInfDir, "original-web.xml" );
+ FileUtils.copyFile( webXmlFile, originalWebXmlFile );
+ webXmlDoc = XmlUtils.readXml( webXmlFile );
+ } else {
+ webXmlDoc = XmlUtils.createDocument();
+ webXmlDoc.appendChild( webXmlDoc.createElement( "web-app" ) );
+ }
+ File overrideWebXmlFile = new File( webInfDir, "override-web.xml" );
+ if( overrideWebXmlFile.exists() ) {
+ Document overrideWebXmlDoc = XmlUtils.readXml( overrideWebXmlFile );
+ Element originalRoot = webXmlDoc.getDocumentElement();
+ Element overrideRoot = overrideWebXmlDoc.getDocumentElement();
+ NodeList overrideNodes = overrideRoot.getChildNodes();
+ for( int i = 0, n = overrideNodes.getLength(); i < n; i++ ) {
+ Node overrideNode = overrideNodes.item( i );
+ if( overrideNode.getNodeType() == Node.ELEMENT_NODE ) {
+ Node importedNode = webXmlDoc.importNode( overrideNode, true );
+ originalRoot.appendChild( importedNode );
+ }
+ }
-
++
+ XmlUtils.writeXml( webXmlDoc, new FileWriter(webXmlFile) );
+ }
+ }
+
+ private synchronized void internalDeployApplications( Topology topology, File topoDir ) throws IOException, ZipException, ParserConfigurationException, TransformerException, SAXException {
+ if( topology != null ) {
+ Collection<Application> applications = topology.getApplications();
+ if( applications != null ) {
+ for( Application application : applications ) {
+ List<String> urls = application.getUrls();
+ if( urls == null || urls.isEmpty() ) {
+ internalDeployApplication( topology, topoDir, application, application.getName() );
+ } else {
+ for( String url : urls ) {
+ internalDeployApplication( topology, topoDir, application, url );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private synchronized void internalDeployApplication( Topology topology, File topoDir, Application application, String url ) throws IOException, ZipException, TransformerException, SAXException, ParserConfigurationException {
+ File appsDir = new File( config.getGatewayApplicationsDir() );
+ File appDir = new File( appsDir, application.getName() );
+ File[] implFiles = appDir.listFiles( new RegexFilenameFilter( "app|app\\..*" ) );
+ if( implFiles == null || implFiles.length == 0 ) {
+ throw new DeploymentException( "Failed to find application in " + appDir );
+ }
+ File implFile = implFiles[0];
+ File warDir = new File( topoDir, Urls.encode( "/" + Urls.trimLeadingAndTrailingSlash( url ) ) );
+ File webInfDir = new File( warDir, "WEB-INF" );
+ explodeWar( implFile, warDir );
+ mergeWebXmlOverrides( webInfDir );
+ createArchiveTempDir( warDir );
+ }
+
+ private synchronized void internalActivateTopology( Topology topology, File topoDir ) throws IOException, ZipException, ParserConfigurationException, TransformerException, SAXException {
+ log.activatingTopology( topology.getName() );
+ File[] files = topoDir.listFiles( new RegexFilenameFilter( "%.*" ) );
+ if( files != null ) {
+ for( File file : files ) {
+ internalActivateArchive( topology, file );
+ }
+ }
+ }
+
+ private synchronized void internalActivateArchive( Topology topology, File warDir ) throws IOException, ZipException, ParserConfigurationException, TransformerException, SAXException {
+ log.activatingTopologyArchive( topology.getName(), warDir.getName() );
+ try {
+ WebAppContext newContext = createWebAppContext( topology, warDir, Urls.decode( warDir.getName() ) );
+ WebAppContext oldContext = deployments.get( newContext.getContextPath() );
+ deployments.put( newContext.getContextPath(), newContext );
+ if( oldContext != null ) {
+ contexts.removeHandler( oldContext );
+ }
+ contexts.addHandler( newContext );
+ if( contexts.isRunning() && !newContext.isRunning() ) {
+ newContext.start();
+ }
+
+ } catch( Exception e ) {
+ auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE );
+ log.failedToDeployTopology( topology.getName(), e );
+ }
+ }
+
+
+ private synchronized void internalDeactivateTopology( Topology topology ) {
+
+ log.deactivatingTopology( topology.getName() );
+
+ String topoName = topology.getName();
+ String topoPath = "/" + Urls.trimLeadingAndTrailingSlashJoin( config.getGatewayPath(), topoName );
+ String topoPathSlash = topoPath + "/";
+
+ ServiceRegistry sr = getGatewayServices().getService(GatewayServices.SERVICE_REGISTRY_SERVICE);
+ if (sr != null) {
+ sr.removeClusterServices( topoName );
+ }
+
+ // Find all the deployed contexts we need to deactivate.
+ List<WebAppContext> deactivate = new ArrayList<WebAppContext>();
+ if( deployments != null ) {
+ for( WebAppContext app : deployments.values() ) {
+ String appPath = app.getContextPath();
+ if( appPath.equals( topoPath ) || appPath.startsWith( topoPathSlash ) ) {
+ deactivate.add( app );
+ }
+ }
+ }
+
+ // Deactivate the required deployed contexts.
+ for( WebAppContext context : deactivate ) {
+ String contextPath = context.getContextPath();
+ deployments.remove( contextPath );
+ contexts.removeHandler( context );
+ try {
+ context.stop();
+ } catch( Exception e ) {
+ auditor.audit(Action.UNDEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE);
+ log.failedToUndeployTopology( topology.getName(), e );
+ }
+ }
+ deactivate.clear();
+
+ }
+
+ // Using an inner class to hide the handleTopologyEvent method from consumers of GatewayServer.
+ private class InternalTopologyListener implements TopologyListener {
+
+ @Override
+ public void handleTopologyEvent( List<TopologyEvent> events ) {
+ synchronized ( GatewayServer.this ) {
+ for( TopologyEvent event : events ) {
+ Topology topology = event.getTopology();
+ File deployDir = calculateAbsoluteDeploymentsDir();
+ if( event.getType().equals( TopologyEvent.Type.DELETED ) ) {
+ handleDeleteDeployment(topology, deployDir);
+ } else {
+ handleCreateDeployment(topology, deployDir);
+ }
+ }
+ }
+ }
+
+ private void handleDeleteDeployment(Topology topology, File deployDir) {
+ log.deletingTopology( topology.getName() );
+ File[] files = deployDir.listFiles( new RegexFilenameFilter( topology.getName() + "\\.(war|topo)\\.[0-9A-Fa-f]+" ) );
+ if( files != null ) {
+ auditor.audit(Action.UNDEPLOY, topology.getName(), ResourceType.TOPOLOGY,
+ ActionOutcome.UNAVAILABLE);
+ internalDeactivateTopology( topology );
+ for( File file : files ) {
+ log.deletingDeployment( file.getAbsolutePath() );
+ FileUtils.deleteQuietly( file );
+ }
+ }
+ }
+
+ private void handleCreateDeployment(Topology topology, File deployDir) {
+ try {
+ File topoDir = calculateDeploymentDir( topology );
+ if( !topoDir.exists() ) {
+ auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
+
+// KNOX-564 - Topology should fail to deploy with no providers configured.
+//TODO:APPS:This should only fail if there are services in the topology.
+ if(topology.getProviders().isEmpty()) {
+ throw new DeploymentException("No providers found inside topology.");
+ }
+
+ log.deployingTopology( topology.getName(), topoDir.getAbsolutePath() );
+ internalDeactivateTopology( topology ); // KNOX-152
+
+ EnterpriseArchive ear = DeploymentFactory.createDeployment( config, topology );
+ if( !deployDir.exists() && !deployDir.mkdirs() ) {
+ throw new DeploymentException( "Failed to create topology deployment temporary directory: " + deployDir.getAbsolutePath() );
+ }
+ File tmp = ear.as( ExplodedExporter.class ).exportExploded( deployDir, topoDir.getName() + ".tmp" );
+ if( !tmp.renameTo( topoDir ) ) {
+ FileUtils.deleteQuietly( tmp );
+ throw new DeploymentException( "Failed to create topology deployment directory: " + topoDir.getAbsolutePath() );
+ }
+ internalDeployApplications( topology, topoDir );
+ internalActivateTopology( topology, topoDir );
+ log.deployedTopology( topology.getName());
+ } else {
+ auditor.audit( Action.REDEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.UNAVAILABLE );
+ log.redeployingTopology( topology.getName(), topoDir.getAbsolutePath() );
+ internalActivateTopology( topology, topoDir );
+ log.redeployedTopology( topology.getName() );
+ }
+ cleanupTopologyDeployments( deployDir, topology );
+ } catch( Throwable e ) {
+ auditor.audit( Action.DEPLOY, topology.getName(), ResourceType.TOPOLOGY, ActionOutcome.FAILURE );
+ log.failedToDeployTopology( topology.getName(), e );
+ }
+ }
+
+ }
+
+ private File createArchiveTempDir( File warDir ) {
+ File tempDir = FileUtils.getFile( warDir, "META-INF", "temp" );
+ if( !tempDir.exists() && !tempDir.mkdirs() ) {
+ throw new DeploymentException( "Failed to create archive temporary directory: " + tempDir.getAbsolutePath() );
+ }
+ return tempDir;
+ }
+
+ private static File calculateAbsoluteTopologiesDir( GatewayConfig config ) {
+ File topoDir = new File( config.getGatewayTopologyDir() );
+ topoDir = topoDir.getAbsoluteFile();
+ return topoDir;
+ }
+
+ private static File calculateAbsoluteDeploymentsDir( GatewayConfig config ) {
+ File deployDir = new File( config.getGatewayDeploymentDir() );
+ deployDir = deployDir.getAbsoluteFile();
+ return deployDir;
+ }
+
+ private File calculateAbsoluteTopologiesDir() {
+ return calculateAbsoluteTopologiesDir( config );
+ }
+
+ private File calculateAbsoluteDeploymentsDir() {
+ return calculateAbsoluteDeploymentsDir( config );
+ }
+
+ private File calculateDeploymentDir( Topology topology ) {
+ File dir = new File( calculateAbsoluteDeploymentsDir(), calculateDeploymentName( topology ) );
+ return dir;
+ }
+
+ private String calculateDeploymentExtension( Topology topology ) {
+ return ".topo.";
+ }
+
+ private String calculateDeploymentName( Topology topology ) {
+ String name = topology.getName() + calculateDeploymentExtension( topology ) + Long.toHexString( topology.getTimestamp() );
+ return name;
+ }
+
+ private static void checkAddressAvailability( InetSocketAddress address ) throws IOException {
+ ServerSocket socket = new ServerSocket();
+ socket.bind( address );
+ socket.close();
+ }
+
+ private static class RegexFilenameFilter implements FilenameFilter {
+
+ Pattern pattern;
+
+ RegexFilenameFilter( String regex ) {
+ pattern = Pattern.compile( regex );
+ }
+
+ @Override
+ public boolean accept( File dir, String name ) {
+ return pattern.matcher( name ).matches();
+ }
+ }
+
+ public URI getFrontendUri( WebAppContext context, GatewayConfig config ) {
+ URI frontendUri = null;
+ String frontendStr = config.getFrontendUrl();
+ if( frontendStr != null && !frontendStr.trim().isEmpty() ) {
+ String topoName = (String)context.getAttribute( GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE );
+ try {
+ frontendStr = frontendStr.trim();
+ if( frontendStr.endsWith( "/" ) ) {
+ frontendUri = new URI( frontendStr + topoName );
+ } else {
+ frontendUri = new URI( frontendStr + "/" + topoName );
+ }
+ } catch( URISyntaxException e ) {
+ throw new IllegalArgumentException( e );
+ }
+ }
+ return frontendUri;
+ }
+
+ private static class FileModificationTimeDescendingComparator implements Comparator<File>, Serializable {
+ /**
- *
++ *
+ */
+ private static final long serialVersionUID = -2269785204848916823L;
+
+ @Override
+ public int compare( File left, File right ) {
+ long leftTime = ( left == null ? Long.MIN_VALUE : left.lastModified() );
+ long rightTime = ( right == null ? Long.MIN_VALUE : right.lastModified() );
+ if( leftTime > rightTime ) {
+ return -1;
+ } else if ( leftTime < rightTime ) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
----------------------------------------------------------------------
diff --cc gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
index 6b8574e,0000000..e02c0e5
mode 100644,000000..100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/deploy/impl/ApplicationDeploymentContributor.java
@@@ -1,228 -1,0 +1,228 @@@
+/**
+ * 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.deploy.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
+import org.apache.knox.gateway.deploy.DeploymentContext;
+import org.apache.knox.gateway.deploy.DeploymentException;
+import org.apache.knox.gateway.deploy.ServiceDeploymentContributorBase;
+import org.apache.knox.gateway.descriptor.FilterDescriptor;
+import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
+import org.apache.knox.gateway.descriptor.ResourceDescriptor;
+import org.apache.knox.gateway.filter.XForwardedHeaderFilter;
+import org.apache.knox.gateway.filter.rewrite.api.CookieScopeServletFilter;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptor;
+import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteRulesDescriptorFactory;
+import org.apache.knox.gateway.service.definition.Policy;
+import org.apache.knox.gateway.service.definition.Rewrite;
+import org.apache.knox.gateway.service.definition.Route;
+import org.apache.knox.gateway.service.definition.ServiceDefinition;
+import org.apache.knox.gateway.topology.Application;
+import org.apache.knox.gateway.topology.Service;
+import org.apache.knox.gateway.topology.Version;
+
+public class ApplicationDeploymentContributor extends ServiceDeploymentContributorBase {
+
+ private static final String SERVICE_DEFINITION_FILE_NAME = "service.xml";
+ private static final String REWRITE_RULES_FILE_NAME = "rewrite.xml";
+ private static final String XFORWARDED_FILTER_NAME = "XForwardedHeaderFilter";
+ private static final String XFORWARDED_FILTER_ROLE = "xforwardedheaders";
+ private static final String COOKIE_SCOPING_FILTER_NAME = "CookieScopeServletFilter";
+ private static final String COOKIE_SCOPING_FILTER_ROLE = "cookiescopef";
+
+ private ServiceDefinition serviceDefinition;
+
+ private UrlRewriteRulesDescriptor serviceRules;
+
+ private static ServiceDefinition loadServiceDefinition( Application application, File file ) throws JAXBException, FileNotFoundException, IOException {
+ ServiceDefinition definition;
+ if( !file.exists() ) {
+ definition = new ServiceDefinition();
+ definition.setName( application.getName() );
+ List<Route> routes = new ArrayList<Route>(1);
+ Route route;
+ route = new Route();
+ route.setPath( "/?**" );
+ routes.add( route );
+ route = new Route();
+ route.setPath( "/**?**" );
+ routes.add( route );
+ definition.setRoutes( routes );
+ } else {
+ JAXBContext context = JAXBContext.newInstance( ServiceDefinition.class );
+ Unmarshaller unmarshaller = context.createUnmarshaller();
+ try( FileInputStream inputStream = new FileInputStream( file ) ) {
+ definition = (ServiceDefinition) unmarshaller.unmarshal( inputStream );
+ }
+ }
+ return definition;
+ }
+
+ private static UrlRewriteRulesDescriptor loadRewriteRules( Application application, File file ) throws IOException {
+ UrlRewriteRulesDescriptor rules;
+ if( !file.exists() ) {
+ rules = UrlRewriteRulesDescriptorFactory.load( "xml", new StringReader( "<rules/>" ) );
+ } else {
+ FileReader reader = new FileReader( file );
+ rules = UrlRewriteRulesDescriptorFactory.load( "xml", reader );
+ reader.close();
+ }
+ return rules;
+ }
+
+ public ApplicationDeploymentContributor( GatewayConfig config, Application application ) throws
+ DeploymentException {
+ try {
+ File appsDir = new File( config.getGatewayApplicationsDir() );
+ File appDir = new File( appsDir, application.getName() );
+ File serviceFile = new File( appDir, SERVICE_DEFINITION_FILE_NAME );
+ File rewriteFile = new File( appDir, REWRITE_RULES_FILE_NAME );
+ serviceDefinition = loadServiceDefinition( application, serviceFile );
+ serviceRules = loadRewriteRules( application, rewriteFile );
+ } catch ( IOException e ) {
+ throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
+ } catch ( JAXBException e ){
+ throw new DeploymentException( "Failed to deploy application: " + application.getName(), e );
+ }
+ }
+
+ @Override
+ public String getRole() {
+ return serviceDefinition.getRole();
+ }
+
+ @Override
+ public String getName() {
+ return serviceDefinition.getName();
+ }
+
+ @Override
+ public Version getVersion() {
+ return new Version(serviceDefinition.getVersion());
+ }
+
+ @Override
+ public void contributeService(DeploymentContext context, Service service) throws Exception {
+ contributeRewriteRules(context, service);
+ contributeResources(context, service);
+ }
+
+ private void contributeRewriteRules(DeploymentContext context, Service service) {
+ if ( serviceRules != null ) {
+ UrlRewriteRulesDescriptor clusterRules = context.getDescriptor("rewrite");
+ // Coverity CID 1352312
+ if( clusterRules != null ) {
+ clusterRules.addRules( serviceRules );
+ }
+ }
+ }
+
+ private void contributeResources(DeploymentContext context, Service service) {
+ Map<String, String> filterParams = new HashMap<>();
+ List<Route> bindings = serviceDefinition.getRoutes();
+ for ( Route binding : bindings ) {
+ List<Rewrite> filters = binding.getRewrites();
+ if ( filters != null && !filters.isEmpty() ) {
+ filterParams.clear();
+ for ( Rewrite filter : filters ) {
+ filterParams.put(filter.getTo(), filter.getApply());
+ }
+ }
+ try {
+ contributeResource(context, service, binding, filterParams);
+ } catch ( URISyntaxException e ) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ private void contributeResource( DeploymentContext context, Service service, Route binding, Map<String, String> filterParams) throws URISyntaxException {
+ List<FilterParamDescriptor> params = new ArrayList<FilterParamDescriptor>();
+ ResourceDescriptor resource = context.getGatewayDescriptor().addResource();
+ resource.role(service.getRole());
+ resource.pattern(binding.getPath());
+ //add x-forwarded filter if enabled in config
+ if (context.getGatewayConfig().isXForwardedEnabled()) {
+ resource.addFilter().name(XFORWARDED_FILTER_NAME).role(XFORWARDED_FILTER_ROLE).impl(XForwardedHeaderFilter.class);
+ }
+ if (context.getGatewayConfig().isCookieScopingToPathEnabled()) {
+ FilterDescriptor filter = resource.addFilter().name(COOKIE_SCOPING_FILTER_NAME).role(COOKIE_SCOPING_FILTER_ROLE).impl(CookieScopeServletFilter.class);
+ filter.param().name(GatewayConfigImpl.HTTP_PATH).value(context.getGatewayConfig().getGatewayPath());
+ }
+ List<Policy> policyBindings = binding.getPolicies();
+ if ( policyBindings == null ) {
+ policyBindings = serviceDefinition.getPolicies();
+ }
+ if ( policyBindings == null ) {
+ //add default set
+ addDefaultPolicies(context, service, filterParams, params, resource);
+ } else {
+ addPolicies(context, service, filterParams, params, resource, policyBindings);
+ }
+ }
+
+ private void addPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource, List<Policy> policyBindings) throws URISyntaxException {
+ for ( Policy policyBinding : policyBindings ) {
+ String role = policyBinding.getRole();
+ if ( role == null ) {
+ throw new IllegalArgumentException("Policy defined has no role for service " + service.getName());
+ }
+ role = role.trim().toLowerCase();
- if ( role.equals("rewrite") ) {
++ if ( "rewrite".equals(role) ) {
+ addRewriteFilter(context, service, filterParams, params, resource);
+ } else if ( topologyContainsProviderType(context, role) ) {
+ context.contributeFilter(service, resource, role, policyBinding.getName(), null);
+ }
+ }
+ }
+
+ private void addDefaultPolicies( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource) throws URISyntaxException {
+ addWebAppSecFilters(context, service, resource);
+ addAuthenticationFilter(context, service, resource);
+ addRewriteFilter(context, service, filterParams, params, resource);
+ addIdentityAssertionFilter(context, service, resource);
+ addAuthorizationFilter(context, service, resource);
+ }
+
+ private void addRewriteFilter( DeploymentContext context, Service service, Map<String, String> filterParams, List<FilterParamDescriptor> params, ResourceDescriptor resource) throws URISyntaxException {
+ if ( !filterParams.isEmpty() ) {
+ for ( Map.Entry<String, String> filterParam : filterParams.entrySet() ) {
+ params.add(resource.createFilterParam().name(filterParam.getKey()).value(filterParam.getValue()));
+ }
+ }
+ addRewriteFilter(context, service, resource, params);
+ }
+
+}