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); + } + +}