knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From m...@apache.org
Subject [24/24] knox git commit: Merge branch 'master' into KNOX-998-Package_Restructuring
Date Fri, 08 Sep 2017 15:15:17 GMT
Merge branch 'master' into KNOX-998-Package_Restructuring

# Conflicts:
#	gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/DefaultValidatorTest.java
#	gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/HeaderPreAuthFederationFilterTest.java
#	gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/IPValidatorTest.java
#	gateway-provider-security-preauth/src/test/java/org/apache/knox/gateway/provider/federation/PreAuthServiceTest.java
#	gateway-test/src/test/java/org/apache/knox/gateway/GatewayLdapDynamicGroupFuncTest.java
#	gateway-test/src/test/java/org/apache/knox/gateway/GatewayLdapGroupFuncTest.java
#	gateway-test/src/test/java/org/apache/knox/gateway/Knox242FuncTest.java
#	gateway-test/src/test/java/org/apache/knox/gateway/KnoxCliLdapFuncTestNegative.java


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/50f46e9e
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/50f46e9e
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/50f46e9e

Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 50f46e9eed9ccc27a54cb71a090322b023fd7a8b
Parents: 2e6713b e88c7a9
Author: Sandeep More <more@apache.org>
Authored: Fri Sep 8 10:53:16 2017 -0400
Committer: Sandeep More <more@apache.org>
Committed: Fri Sep 8 10:53:16 2017 -0400

----------------------------------------------------------------------
 .../ha/dispatch/DefaultHaDispatchTest.java      |   7 +-
 .../function/UsernameFunctionProcessor.java     |   2 +-
 .../filter/HadoopGroupProviderFilterTest.java   |  12 +-
 .../SwitchCaseIdentityAssertionFilter.java      |   2 +-
 .../rewrite/impl/FrontendFunctionProcessor.java |   2 +-
 .../impl/html/HtmlImportFunctionProcessor.java  |   2 +-
 .../rewrite/impl/html/HtmlPrefixProcessor.java  |   2 +-
 .../rewrite/impl/json/JsonFilterReader.java     |   4 +-
 .../gateway/filter/AclsAuthorizationFilter.java |   6 +-
 .../jwt/filter/AbstractJWTFilter.java           |  55 +++--
 .../jwt/filter/JWTFederationFilter.java         |   8 +-
 .../jwt/filter/SSOCookieFederationFilter.java   |   6 +-
 .../federation/AbstractJWTFilterTest.java       | 214 ++++++++++++++++---
 .../federation/JWTFederationFilterTest.java     |  14 +-
 .../provider/federation/JWTTokenTest.java       |   3 +-
 .../federation/SSOCookieProviderTest.java       |  61 +-----
 .../knox/gateway/picketlink/PicketlinkTest.java |   3 +-
 .../federation/DefaultValidatorTest.java        |   2 +-
 .../HeaderPreAuthFederationFilterTest.java      |   7 +-
 .../provider/federation/IPValidatorTest.java    |   2 +-
 .../provider/federation/PreAuthSSOTest.java     |   3 +-
 .../provider/federation/PreAuthServiceTest.java |   3 +-
 .../webappsec/deploy/WebAppSecContributor.java  |   6 +-
 .../apache/knox/gateway/webappsec/CSRFTest.java |   3 +-
 .../webappsec/XFrameOptionsFilterTest.java      |  12 +-
 .../home/conf/topologies/manager.xml            |   2 +-
 .../filter/CompositeEnumerationTest.java        |   2 +-
 .../org/apache/knox/gateway/GatewayServer.java  |   8 +-
 .../impl/ApplicationDeploymentContributor.java  |   2 +-
 .../ServiceDefinitionDeploymentContributor.java |   2 +-
 .../gateway/dispatch/UrlConnectionDispatch.java |   2 +-
 .../topology/validation/TopologyValidator.java  |   2 +-
 .../org/apache/knox/gateway/util/KnoxCLI.java   |   2 +-
 .../apache/knox/gateway/AuditLoggingTest.java   |  13 +-
 .../org/apache/knox/gateway/TempletonDemo.java  |   8 +-
 .../gateway/deploy/DeploymentFactoryTest.java   |   2 +-
 .../service/admin/TopologiesResource.java       |   2 +-
 .../gateway/rm/dispatch/RMHaDispatchTest.java   |  11 +-
 .../hdfs/dispatch/WebHdfsHaDispatchTest.java    |   7 +-
 .../knox/gateway/security/SubjectUtils.java     |   4 +-
 .../gateway/dispatch/DefaultDispatchTest.java   |  16 +-
 .../security/principal/PrincipalMapperTest.java |   8 +-
 gateway-test-release-utils/pom.xml              |  37 ----
 .../apache/knox/gateway/GatewayTestConfig.java  |  12 +-
 .../apache/knox/gateway/GatewayTestDriver.java  |  15 --
 gateway-test-release/webhdfs-kerb-test/pom.xml  |  30 +++
 gateway-test-release/webhdfs-test/pom.xml       |  30 +++
 gateway-test/pom.xml                            |  30 +++
 .../gateway/AmbariServiceDefinitionTest.java    |  17 +-
 .../knox/gateway/GatewayAdminFuncTest.java      |  23 --
 .../gateway/GatewayAdminTopologyFuncTest.java   |  22 --
 .../apache/knox/gateway/GatewayAppFuncTest.java |   2 +-
 .../knox/gateway/GatewayBasicFuncTest.java      |  65 ++++--
 .../knox/gateway/GatewayDeployFuncTest.java     |  22 --
 .../knox/gateway/GatewayHealthFuncTest.java     |  24 ---
 .../GatewayLdapDynamicGroupFuncTest.java        |  24 ---
 .../knox/gateway/GatewayLdapGroupFuncTest.java  |  27 +--
 .../gateway/GatewayLdapPosixGroupFuncTest.java  |  22 +-
 .../gateway/GatewayLocalServiceFuncTest.java    |  23 --
 .../knox/gateway/GatewayMultiFuncTest.java      |   3 +-
 .../knox/gateway/GatewaySampleFuncTest.java     |  23 --
 .../apache/knox/gateway/GatewaySslFuncTest.java |   2 +-
 .../apache/knox/gateway/Knox242FuncTest.java    |  23 --
 .../gateway/KnoxCliLdapFuncTestNegative.java    |  29 ---
 .../gateway/KnoxCliLdapFuncTestPositive.java    |  27 ---
 .../apache/knox/gateway/KnoxCliSysBindTest.java |  27 ---
 .../deploy/DeploymentFactoryFuncTest.java       |  25 ---
 .../knox/gateway/util/IpAddressValidator.java   |   2 +-
 .../gateway/util/IpAddressValidatorTest.java    |   3 +-
 .../apache/knox/gateway/util/JsonUtilsTest.java |   3 +-
 .../org/apache/knox/gateway/util/UrlsTest.java  |   4 +-
 .../knox/gateway/config/AdapterSampleTest.java  |  19 +-
 .../apache/knox/gateway/config/FuncTest.java    |  12 +-
 .../BeanConfigurationAdapterDescriptorTest.java |   2 +-
 .../knox/gateway/util/urltemplate/Expander.java |   4 +-
 .../knox/gateway/util/urltemplate/Matcher.java  |   2 +-
 .../knox/gateway/util/urltemplate/Template.java |   2 +-
 .../gateway/util/urltemplate/ExpanderTest.java  |   2 +-
 78 files changed, 523 insertions(+), 650 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatchTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatchTest.java
index 0f19e79,0000000..0470555
mode 100644,000000..100644
--- a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatchTest.java
+++ b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/dispatch/DefaultHaDispatchTest.java
@@@ -1,106 -1,0 +1,109 @@@
 +/**
 + * 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.ha.dispatch;
 +
 +import org.apache.knox.gateway.ha.provider.HaDescriptor;
 +import org.apache.knox.gateway.ha.provider.HaProvider;
 +import org.apache.knox.gateway.ha.provider.HaServletContextListener;
 +import org.apache.knox.gateway.ha.provider.impl.DefaultHaProvider;
 +import org.apache.knox.gateway.ha.provider.impl.HaDescriptorFactory;
 +import org.apache.knox.gateway.servlet.SynchronousServletOutputStreamAdapter;
 +import org.apache.http.client.methods.HttpRequestBase;
 +import org.apache.http.client.methods.HttpUriRequest;
- import org.apache.http.impl.client.DefaultHttpClient;
++import org.apache.http.impl.client.CloseableHttpClient;
++import org.apache.http.impl.client.HttpClientBuilder;
 +import org.apache.http.params.BasicHttpParams;
 +import org.easymock.EasyMock;
 +import org.easymock.IAnswer;
 +import org.junit.Assert;
 +import org.junit.Test;
 +
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletContext;
 +import javax.servlet.http.HttpServletRequest;
 +import javax.servlet.http.HttpServletResponse;
 +import java.io.IOException;
 +import java.net.URI;
 +import java.util.ArrayList;
 +import java.util.concurrent.atomic.AtomicInteger;
 +
 +public class DefaultHaDispatchTest {
 +
 +  @Test
 +  public void testConnectivityFailover() throws Exception {
 +    String serviceName = "OOZIE";
 +    HaDescriptor descriptor = HaDescriptorFactory.createDescriptor();
 +    descriptor.addServiceConfig(HaDescriptorFactory.createServiceConfig(serviceName, "true", "1", "1000", "2", "1000", null, null));
 +    HaProvider provider = new DefaultHaProvider(descriptor);
 +    URI uri1 = new URI( "http://unreachable-host" );
 +    URI uri2 = new URI( "http://reachable-host" );
 +    ArrayList<String> urlList = new ArrayList<String>();
 +    urlList.add(uri1.toString());
 +    urlList.add(uri2.toString());
 +    provider.addHaService(serviceName, urlList);
 +    FilterConfig filterConfig = EasyMock.createNiceMock(FilterConfig.class);
 +    ServletContext servletContext = EasyMock.createNiceMock(ServletContext.class);
 +
 +    EasyMock.expect(filterConfig.getServletContext()).andReturn(servletContext).anyTimes();
 +    EasyMock.expect(servletContext.getAttribute(HaServletContextListener.PROVIDER_ATTRIBUTE_NAME)).andReturn(provider).anyTimes();
 +
 +    BasicHttpParams params = new BasicHttpParams();
 +
 +    HttpUriRequest outboundRequest = EasyMock.createNiceMock(HttpRequestBase.class);
 +    EasyMock.expect(outboundRequest.getMethod()).andReturn( "GET" ).anyTimes();
 +    EasyMock.expect(outboundRequest.getURI()).andReturn( uri1  ).anyTimes();
 +    EasyMock.expect(outboundRequest.getParams()).andReturn( params ).anyTimes();
 +
 +    HttpServletRequest inboundRequest = EasyMock.createNiceMock(HttpServletRequest.class);
 +    EasyMock.expect(inboundRequest.getRequestURL()).andReturn( new StringBuffer(uri2.toString()) ).once();
 +    EasyMock.expect(inboundRequest.getAttribute("dispatch.ha.failover.counter")).andReturn(new AtomicInteger(0)).once();
 +    EasyMock.expect(inboundRequest.getAttribute("dispatch.ha.failover.counter")).andReturn(new AtomicInteger(1)).once();
 +
 +    HttpServletResponse outboundResponse = EasyMock.createNiceMock(HttpServletResponse.class);
 +    EasyMock.expect(outboundResponse.getOutputStream()).andAnswer( new IAnswer<SynchronousServletOutputStreamAdapter>() {
 +      @Override
 +      public SynchronousServletOutputStreamAdapter answer() throws Throwable {
 +        return new SynchronousServletOutputStreamAdapter() {
 +          @Override
 +          public void write( int b ) throws IOException {
 +            throw new IOException( "unreachable-host" );
 +          }
 +        };
 +      }
 +    }).once();
 +    EasyMock.replay(filterConfig, servletContext, outboundRequest, inboundRequest, outboundResponse);
 +    Assert.assertEquals(uri1.toString(), provider.getActiveURL(serviceName));
 +    DefaultHaDispatch dispatch = new DefaultHaDispatch();
-     dispatch.setHttpClient(new DefaultHttpClient());
++    HttpClientBuilder builder = HttpClientBuilder.create();
++    CloseableHttpClient client = builder.build();
++    dispatch.setHttpClient(client);
 +    dispatch.setHaProvider(provider);
 +    dispatch.setServiceRole(serviceName);
 +    dispatch.init();
 +    long startTime = System.currentTimeMillis();
 +    try {
 +      dispatch.executeRequest(outboundRequest, inboundRequest, outboundResponse);
 +    } catch (IOException e) {
 +      //this is expected after the failover limit is reached
 +    }
 +    long elapsedTime = System.currentTimeMillis() - startTime;
 +    Assert.assertEquals(uri2.toString(), provider.getActiveURL(serviceName));
 +    //test to make sure the sleep took place
 +    Assert.assertTrue(elapsedTime > 1000);
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/function/UsernameFunctionProcessor.java
----------------------------------------------------------------------
diff --cc gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/function/UsernameFunctionProcessor.java
index 7d3c4d0,0000000..25e1364
mode 100644,000000..100644
--- a/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/function/UsernameFunctionProcessor.java
+++ b/gateway-provider-identity-assertion-common/src/main/java/org/apache/knox/gateway/identityasserter/common/function/UsernameFunctionProcessor.java
@@@ -1,72 -1,0 +1,72 @@@
 +/**
 + * 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.identityasserter.common.function;
 +
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 +import org.apache.knox.gateway.i18n.GatewaySpiMessages;
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.security.SubjectUtils;
 +
 +import javax.security.auth.Subject;
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +public class UsernameFunctionProcessor
 +    implements UrlRewriteFunctionProcessor<UsernameFunctionDescriptor> {
 +
 +  private static final GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class );
 +//  private PrincipalMapper mapper = null;
 +
 +  @Override
 +  public String name() {
 +    return UsernameFunctionDescriptor.FUNCTION_NAME;
 +  }
 +
 +  @Override
 +  public void initialize( UrlRewriteEnvironment environment, UsernameFunctionDescriptor descriptor ) throws Exception {
 +//    if( environment != null ) {
 +//      GatewayServices services = environment.getAttribute( GatewayServices.GATEWAY_SERVICES_ATTRIBUTE );
 +//      if( services != null ) {
 +//        mapper = (PrincipalMapper)services.getService( "PrincipalMapperService" /*GatewayServices.PRINCIPAL_MAPPER_SERVICE*/ );
 +//      }
 +//    }
 +  }
 +
 +  @Override
 +  public void destroy() throws Exception {
 +  }
 +
 +  @Override
 +  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
 +    List<String> results = null;
 +    Subject subject = SubjectUtils.getCurrentSubject( );
 +    if( subject != null ) {
 +      results = new ArrayList<String>( 1 );
 +      String username = SubjectUtils.getEffectivePrincipalName(subject);
 +      results.add( username );
-     } else if( parameters != null && parameters.size() > 0 ) {
++    } else if( parameters != null && !parameters.isEmpty() ) {
 +      results = new ArrayList<String>( 1 );
 +      results.add( parameters.get( 0 ) );
 +    }
 +    return results;
 +  }
 +
 +}
 +

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-identity-assertion-hadoop-groups/src/test/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilterTest.java
----------------------------------------------------------------------
diff --cc gateway-provider-identity-assertion-hadoop-groups/src/test/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilterTest.java
index d5f5501,0000000..91806fd
mode 100644,000000..100644
--- a/gateway-provider-identity-assertion-hadoop-groups/src/test/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilterTest.java
+++ b/gateway-provider-identity-assertion-hadoop-groups/src/test/java/org/apache/knox/gateway/identityasserter/hadoop/groups/filter/HadoopGroupProviderFilterTest.java
@@@ -1,218 -1,0 +1,218 @@@
 +/**
 + * 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.identityasserter.hadoop.groups.filter;
 +
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.MatcherAssert.assertThat;
 +
 +import java.security.Principal;
 +import java.util.Arrays;
++import java.util.Collections;
 +import java.util.List;
- import java.util.Vector;
 +
 +import javax.security.auth.Subject;
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletContext;
 +import javax.servlet.ServletException;
 +
 +import org.apache.knox.gateway.security.PrimaryPrincipal;
 +import org.apache.hadoop.security.LdapGroupsMapping;
 +import org.apache.hadoop.security.ShellBasedUnixGroupsMapping;
 +import org.easymock.EasyMock;
 +import org.junit.Test;
 +
 +/**
 + * Test for {@link HadoopGroupProviderFilter}
-  * 
++ *
 + * @since 0.11.0
 + */
 +public class HadoopGroupProviderFilterTest {
 +
 +  /**
 +   * System username
 +   */
 +  private static final String failUsername = "highly_unlikely_username_to_have";
 +
 +  /**
 +   * System username
 +   */
 +  private static final String username = System.getProperty("user.name");
 +
 +  /**
 +   * Configuration object needed by for hadoop classes
 +   */
 +
 +  /**
 +   * Hadoop Groups implementation.
 +   */
 +
 +  /* create an instance */
 +  public HadoopGroupProviderFilterTest() {
 +    super();
 +  }
 +
 +  /**
 +   * Test that valid groups are retrieved for a legitimate user.
-    * 
++   *
 +   * @throws ServletException
 +   */
 +  @Test
 +  public void testGroups() throws ServletException {
 +
 +    final FilterConfig config = EasyMock.createNiceMock(FilterConfig.class);
 +    EasyMock.expect(config.getInitParameter("principal.mapping") ).andReturn( "" ).anyTimes();
 +    ServletContext context = EasyMock.createNiceMock(ServletContext.class);
 +    EasyMock.expect(config.getServletContext() ).andReturn( context ).anyTimes();
 +    EasyMock.expect(context.getInitParameter("principal.mapping") ).andReturn( "" ).anyTimes();
 +    EasyMock.replay( config );
 +    EasyMock.replay( context );
 +
 +    final HadoopGroupProviderFilter filter = new HadoopGroupProviderFilter();
 +
 +    final Subject subject = new Subject();
 +    subject.getPrincipals().add(new PrimaryPrincipal(username));
 +
 +    filter.init(config);
 +    final String principal = filter.mapUserPrincipal(
 +        ((Principal) subject.getPrincipals(PrimaryPrincipal.class).toArray()[0])
 +            .getName());
 +    final String[] groups = filter.mapGroupPrincipals(principal, subject);
 +
 +    assertThat(principal, is(username));
 +    assertThat(
 +        "No groups assosciated with the user, most likely this is a failure, it is only OK when 'bash -c groups' command returns 0 groups. ",
 +        groups.length > 0);
 +
 +  }
 +
 +  /**
 +   * Test that no groups are retrieved for a dummy user.
-    * 
++   *
 +   * @throws ServletException
 +   */
 +  @Test
 +  public void testUnknownUser() throws ServletException {
 +
 +    final FilterConfig config = EasyMock.createNiceMock(FilterConfig.class);
 +    EasyMock.expect(config.getInitParameter("principal.mapping") ).andReturn( "" ).anyTimes();
 +    ServletContext context = EasyMock.createNiceMock(ServletContext.class);
 +    EasyMock.expect(config.getServletContext() ).andReturn( context ).anyTimes();
 +    EasyMock.expect(context.getInitParameter("principal.mapping") ).andReturn( "" ).anyTimes();
 +    EasyMock.replay( config );
 +    EasyMock.replay( context );
 +
 +    final HadoopGroupProviderFilter filter = new HadoopGroupProviderFilter();
 +
 +    final Subject subject = new Subject();
 +    subject.getPrincipals().add(new PrimaryPrincipal(failUsername));
 +
 +    filter.init(config);
 +    final String principal = filter.mapUserPrincipal(
 +        ((Principal) subject.getPrincipals(PrimaryPrincipal.class).toArray()[0])
 +            .getName());
 +    final String[] groups = filter.mapGroupPrincipals(principal, subject);
 +
 +    assertThat(principal, is(failUsername));
 +    assertThat(
 +        "Somehow groups were found for this user, how is it possible ! check 'bash -c groups' command ",
 +        groups.length == 0);
 +
 +  }
 +
 +  /**
 +   * Test for a bad config (nonexistent). This test proves, we are not falling
 +   * back on {@link ShellBasedUnixGroupsMapping} because we explicitly use
 +   * {@link LdapGroupsMapping} and in case of bad config we get empty groups
 +   * (Hadoop way).
-    * 
++   *
 +   * @throws ServletException
 +   */
 +  @SuppressWarnings({ "unchecked", "rawtypes" })
 +  @Test
 +  public void badConfigTest() throws ServletException {
 +
 +    final List<String> keysList = Arrays.asList("hadoop.security.group.mapping",
 +        "hadoop.security.group.mapping.ldap.bind.user",
 +        "hadoop.security.group.mapping.ldap.bind.password",
 +        "hadoop.security.group.mapping.ldap.url",
 +        "hadoop.security.group.mapping.ldap.search.filter.group",
 +        "hadoop.security.group.mapping.ldap.search.attr.member",
 +        "hadoop.security.group.mapping.ldap.search.filter.user");
 +
 +    final FilterConfig config = EasyMock.createNiceMock(FilterConfig.class);
 +    EasyMock.expect(config.getInitParameter("principal.mapping") ).andReturn( "" ).anyTimes();
 +    ServletContext context = EasyMock.createNiceMock(ServletContext.class);
 +    EasyMock.expect(config.getServletContext() ).andReturn( context ).anyTimes();
 +    EasyMock.expect(context.getInitParameter("principal.mapping") ).andReturn( "" ).anyTimes();
 +
 +    EasyMock.expect(config.getInitParameter("hadoop.security.group.mapping"))
 +        .andReturn("org.apache.hadoop.security.LdapGroupsMapping").anyTimes();
 +    EasyMock
 +        .expect(config
 +            .getInitParameter("hadoop.security.group.mapping.ldap.bind.user"))
 +        .andReturn("uid=dummy,ou=people,dc=hadoop,dc=apache,dc=org").anyTimes();
 +    EasyMock
 +        .expect(config.getInitParameter(
 +            "hadoop.security.group.mapping.ldap.bind.password"))
 +        .andReturn("unbind-me-please").anyTimes();
 +    EasyMock
 +        .expect(
 +            config.getInitParameter("hadoop.security.group.mapping.ldap.url"))
 +        .andReturn("ldap://nomansland:33389").anyTimes();
 +    EasyMock
 +        .expect(config.getInitParameter(
 +            "hadoop.security.group.mapping.ldap.search.filter.group"))
 +        .andReturn("(objectclass=groupOfNames)").anyTimes();
 +    EasyMock
 +        .expect(config.getInitParameter(
 +            "hadoop.security.group.mapping.ldap.search.attr.member"))
 +        .andReturn("member").anyTimes();
 +    EasyMock
 +        .expect(config.getInitParameter(
 +            "hadoop.security.group.mapping.ldap.search.filter.user"))
 +        .andReturn(
 +            "(&amp;(|(objectclass=person)(objectclass=applicationProcess))(cn={0}))")
 +        .anyTimes();
 +    EasyMock.expect(config.getInitParameterNames())
-         .andReturn(new Vector(keysList).elements()).anyTimes();
++        .andReturn(Collections.enumeration((keysList))).anyTimes();
 +
 +    EasyMock.replay( config );
 +    EasyMock.replay( context );
 +
 +    final HadoopGroupProviderFilter filter = new HadoopGroupProviderFilter();
 +
 +    final Subject subject = new Subject();
 +    subject.getPrincipals().add(new PrimaryPrincipal(username));
 +
 +    filter.init(config);
 +    final String principal = filter.mapUserPrincipal(
 +        ((Principal) subject.getPrincipals(PrimaryPrincipal.class).toArray()[0])
 +            .getName());
 +    final String[] groups = filter.mapGroupPrincipals(principal, subject);
 +
 +    assertThat(principal, is(username));
 +
 +    /*
 +     * Unfortunately, Hadoop does not let us know what went wrong all we get is
 +     * empty groups
 +     */
 +    assertThat(groups.length, is(0));
 +
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-identity-assertion-switchcase/src/main/java/org/apache/knox/gateway/identityasserter/switchcase/SwitchCaseIdentityAssertionFilter.java
----------------------------------------------------------------------
diff --cc gateway-provider-identity-assertion-switchcase/src/main/java/org/apache/knox/gateway/identityasserter/switchcase/SwitchCaseIdentityAssertionFilter.java
index 9405c49,0000000..01e874d
mode 100644,000000..100644
--- a/gateway-provider-identity-assertion-switchcase/src/main/java/org/apache/knox/gateway/identityasserter/switchcase/SwitchCaseIdentityAssertionFilter.java
+++ b/gateway-provider-identity-assertion-switchcase/src/main/java/org/apache/knox/gateway/identityasserter/switchcase/SwitchCaseIdentityAssertionFilter.java
@@@ -1,98 -1,0 +1,98 @@@
 +/**
 + * 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.identityasserter.switchcase;
 +
 +import java.util.Set;
 +import javax.security.auth.Subject;
 +import javax.servlet.FilterConfig;
 +import javax.servlet.ServletException;
 +
 +import org.apache.knox.gateway.identityasserter.common.filter.CommonIdentityAssertionFilter;
 +import org.apache.knox.gateway.security.GroupPrincipal;
 +
 +public class SwitchCaseIdentityAssertionFilter extends
 +    CommonIdentityAssertionFilter {
 +
 +  private static final String USER_INIT_PARAM = "principal.case";
 +  private static final String GROUP_INIT_PARAM = "group.principal.case";
 +
 +  private enum SwitchCase { UPPER, LOWER, NONE }
 +
 +  private SwitchCase userCase = SwitchCase.LOWER;
 +  private SwitchCase groupCase = SwitchCase.LOWER;
 +
 +  @Override
 +  public void init( FilterConfig filterConfig ) throws ServletException {
 +    super.init(filterConfig);
 +
 +    String s;
 +    s = filterConfig.getInitParameter( USER_INIT_PARAM );
 +    if ( s != null ) {
 +      s = s.trim().toUpperCase();
 +      try {
 +        userCase = SwitchCase.valueOf( s );
 +        groupCase = userCase;
 +      } catch ( IllegalArgumentException e ) {
 +        // Ignore it and use the default.
 +      }
 +    }
 +    s = filterConfig.getInitParameter( GROUP_INIT_PARAM );
 +    if ( s != null ) {
 +      s = s.trim().toUpperCase();
 +      try {
 +        groupCase = SwitchCase.valueOf( s );
 +      } catch ( IllegalArgumentException e ) {
 +        // Ignore it and use the default.
 +      }
 +    }
 +  }
 +
 +  @Override
 +  public String mapUserPrincipal( String principalName ) {
 +    return switchCase( principalName, userCase );
 +  }
 +
 +  @Override
 +  public String[] mapGroupPrincipals( String mappedPrincipalName, Subject subject ) {
 +    String[] groupNames = null;
 +    if ( groupCase != SwitchCase.NONE ) {
 +      Set<GroupPrincipal> groups = subject.getPrincipals( GroupPrincipal.class );
-       if( groups != null && groups.size() > 0 ) {
++      if( groups != null && !groups.isEmpty() ) {
 +        groupNames = new String[ groups.size() ];
 +        int i = 0;
 +        for( GroupPrincipal group : groups ) {
 +          groupNames[ i++ ] = switchCase( group.getName(), groupCase );
 +        }
 +      }
 +    }
 +    return groupNames;
 +  }
 +
 +  private String switchCase( String name, SwitchCase switchCase ) {
 +    if ( name != null ) {
 +      switch( switchCase ) {
 +        case UPPER:
 +          return name.toUpperCase();
 +        case LOWER:
 +          return name.toLowerCase();
 +      }
 +    }
 +    return name;
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/FrontendFunctionProcessor.java
----------------------------------------------------------------------
diff --cc gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/FrontendFunctionProcessor.java
index 5964510,0000000..77ca25e
mode 100644,000000..100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/FrontendFunctionProcessor.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/FrontendFunctionProcessor.java
@@@ -1,125 -1,0 +1,125 @@@
 +/**
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +package org.apache.knox.gateway.filter.rewrite.impl;
 +
 +import org.apache.knox.gateway.filter.rewrite.api.FrontendFunctionDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 +import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteResources;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteResolver;
 +import org.apache.knox.gateway.i18n.resources.ResourcesFactory;
 +import org.apache.knox.gateway.services.GatewayServices;
 +
 +import java.net.URI;
 +import java.util.Arrays;
 +import java.util.HashMap;
 +import java.util.List;
 +import java.util.Map;
 +
 +public class FrontendFunctionProcessor implements UrlRewriteFunctionProcessor<FrontendFunctionDescriptor> {
 +
 +  private static UrlRewriteResources RES = ResourcesFactory.get( UrlRewriteResources.class );
 +
 +  private Map<String,UrlRewriteResolver> resolvers;
 +
 +  @Override
 +  public String name() {
 +    return FrontendFunctionDescriptor.FUNCTION_NAME;
 +  }
 +
 +  @Override
 +  public void initialize( UrlRewriteEnvironment environment, FrontendFunctionDescriptor descriptor ) throws Exception {
 +    if( environment == null ) {
 +      throw new IllegalArgumentException( "environment==null" );
 +    }
 +    URI frontend = environment.getAttribute( FrontendFunctionDescriptor.FRONTEND_URI_ATTRIBUTE );
 +    resolvers = new HashMap<>();
 +    if( frontend == null ) {
 +      resolvers.put( "url", new ParamResolver( "gateway.url" ) );
 +      resolvers.put( "addr", new ParamResolver( "gateway.addr" ) );
 +      resolvers.put( "scheme", new ParamResolver( "gateway.scheme" ) );
 +      resolvers.put( "host", new ParamResolver( "gateway.host" ) );
 +      resolvers.put( "port", new ParamResolver( "gateway.port" ) );
 +      resolvers.put( "path", new ParamResolver( "gateway.path" ) );
 +    } else {
 +      resolvers.put( "url", new FixedResolver( frontend.toString() ) );
 +      resolvers.put( "addr", new FixedResolver( frontend.getHost() + ":" + frontend.getPort() ) );
 +      resolvers.put( "scheme", new FixedResolver( frontend.getScheme() ) );
 +      resolvers.put( "host", new FixedResolver( frontend.getHost() ) );
 +      resolvers.put( "port", new FixedResolver( Integer.toString( frontend.getPort() ) ) );
 +      resolvers.put( "path", new FixedResolver( frontend.getPath() ) );
 +    }
 +    resolvers.put( "topology", new FixedResolver( (String)environment.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE) ) );
 +    resolvers.put( "address", resolvers.get( "addr" ) );
 +  }
 +
 +  @Override
 +  public void destroy() throws Exception {
 +    resolvers.clear();
 +  }
 +
 +  @Override
 +  public List<String> resolve( UrlRewriteContext context, List<String> parameters ) throws Exception {
 +    String parameter = "url";
-     if( parameters != null && parameters.size() > 0 ) {
++    if( parameters != null && !parameters.isEmpty() ) {
 +      String first = parameters.get( 0 );
 +      if( first != null ) {
 +        parameter = first;
 +      }
 +    }
 +    parameter = parameter.trim().toLowerCase();
 +    UrlRewriteResolver resolver = resolvers.get( parameter );
 +    if( resolver == null ) {
 +      throw new IllegalArgumentException( RES.invalidFrontendFunctionParameter( parameter ) );
 +    }
 +    List<String> results = resolver.resolve( context, parameters );
 +    return results;
 +  }
 +
 +  private static class ParamResolver implements UrlRewriteResolver {
 +
 +    private String paramName;
 +
 +    private ParamResolver( String paramName ) {
 +      this.paramName = paramName;
 +    }
 +
 +    @Override
 +    public List<String> resolve( UrlRewriteContext context, List<String> parameter ) throws Exception {
 +      return context.getParameters().resolve( paramName );
 +    }
 +
 +  }
 +
 +  private static class FixedResolver implements UrlRewriteResolver {
 +
 +    private List<String> fixedValues;
 +
 +    private FixedResolver( String... fixedValues ) {
 +      this.fixedValues = Arrays.asList( fixedValues );
 +    }
 +
 +    @Override
 +    public List<String> resolve( UrlRewriteContext context, List<String> parameter ) throws Exception {
 +      return fixedValues;
 +    }
 +
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
----------------------------------------------------------------------
diff --cc gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
index 280f1b5,0000000..0b3b3c6
mode 100644,000000..100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlImportFunctionProcessor.java
@@@ -1,90 -1,0 +1,90 @@@
 +/**
 + * 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
 + * <p>
 + * http://www.apache.org/licenses/LICENSE-2.0
 + * <p>
 + * 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.rewrite.impl.html;
 +
 +import org.apache.knox.gateway.filter.rewrite.api.FrontendFunctionDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptorFactory;
 +import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFunctionProcessorFactory;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 +
 +import java.util.Arrays;
 +import java.util.List;
 +
 +/**
 + * This function enhances the 'frontend' function with the ability to add a prefix to the rewritten frontend portion
 + * along with the '@import' literal. This is a workaround for the requirement to provide the ability to rewrite
 + * a portion of html content that contains a tag like the following
 + *
 + * <head> <style type=\"text/css\">@import "pretty.css";</style></head>
 + *
 + * and needs to be rewritten to something like
 + *
 + * <head> <style type=\"text/css\">@import "http://localhost:8443/sandbox/service/pretty.css";</style></head>
 + *
 + * The rewrite rule could then contain the $import function that would delegate to the frontend function.
 + *
 + * If there are more than one params passed, the first one is used as a prefix to the value of the frontend function.
 + *
 + */
 +public class HtmlImportFunctionProcessor implements UrlRewriteFunctionProcessor<HtmlImportFunctionDescriptor> {
 +
 +  private static final String IMPORT_LITERAL = "@import";
 +
 +  private UrlRewriteFunctionProcessor frontend;
 +
 +  @Override
 +  public void initialize(UrlRewriteEnvironment environment, HtmlImportFunctionDescriptor descriptor) throws Exception {
 +    UrlRewriteFunctionDescriptor frontendDescriptor = UrlRewriteFunctionDescriptorFactory
 +        .create(FrontendFunctionDescriptor.FUNCTION_NAME);
 +    frontend = UrlRewriteFunctionProcessorFactory.create(FrontendFunctionDescriptor.FUNCTION_NAME, frontendDescriptor);
 +    frontend.initialize(environment, frontendDescriptor);
 +  }
 +
 +  @Override
 +  public void destroy() throws Exception {
 +    frontend.destroy();
 +  }
 +
 +  @Override
 +  public List<String> resolve(UrlRewriteContext context, List<String> parameters) throws Exception {
 +    String prefix = "";
 +    if ( parameters != null && parameters.size() > 1 ) {
 +      prefix = parameters.get(0);
 +      parameters = parameters.subList(1, parameters.size());
 +    }
 +    List<String> frontendValues = frontend.resolve(context, parameters);
 +    StringBuffer buffer = new StringBuffer(IMPORT_LITERAL);
 +    buffer.append(" ");
 +    buffer.append(prefix);
-     if ( frontendValues != null && frontendValues.size() > 0 ) {
++    if ( frontendValues != null && !frontendValues.isEmpty() ) {
 +      for ( String value : frontendValues ) {
 +        buffer.append(value);
 +      }
 +    }
 +    return Arrays.asList(buffer.toString());
 +  }
 +
 +  @Override
 +  public String name() {
 +    return HtmlImportFunctionDescriptor.FUNCTION_NAME;
 +  }
 +
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
----------------------------------------------------------------------
diff --cc gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
index d7983ef,0000000..7fe26ad
mode 100644,000000..100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/html/HtmlPrefixProcessor.java
@@@ -1,104 -1,0 +1,104 @@@
 +/**
 + * 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
 + * <p>
 + * http://www.apache.org/licenses/LICENSE-2.0
 + * <p>
 + * 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.rewrite.impl.html;
 +
 +import org.apache.knox.gateway.filter.rewrite.api.FrontendFunctionDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteEnvironment;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFunctionDescriptorFactory;
 +import org.apache.knox.gateway.filter.rewrite.impl.UrlRewriteFunctionProcessorFactory;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteContext;
 +import org.apache.knox.gateway.filter.rewrite.spi.UrlRewriteFunctionProcessor;
 +
 +import java.util.Arrays;
 +import java.util.List;
 +
 +/**
 + * This function enhances the 'frontend' function with the ability to add a
 + * prefix to the rewritten frontend portion along with the literals
 + * provided as an argument.
 + * <p>
 + * <div ng-include src=\"'components/navbar/navbar.html?v=1498928142479'\"></div>
 + * <p>
 + * and needs to be rewritten to something like
 + * <p>
 + * <div ng-include src=\"'http://localhost:8443/sandbox/service/components/navbar/navbar.html?v=1498928142479'\"></div>
 + * <p>
 + * The rewrite rule could then contain the $prefix function that would delegate
 + * to the frontend function.
 + * <p>
 + * The parameter to the function would be the symbol used as a prefix.
 + */
 +
 +public class HtmlPrefixProcessor
 +    implements UrlRewriteFunctionProcessor<HtmlPrefixDescriptor> {
 +
 +  private UrlRewriteFunctionProcessor frontend;
 +
 +  /**
 +   * Create an instance
 +   */
 +  public HtmlPrefixProcessor() {
 +    super();
 +  }
 +
 +  @Override
 +  public void initialize(final UrlRewriteEnvironment environment,
 +      final HtmlPrefixDescriptor descriptor) throws Exception {
 +
 +    final UrlRewriteFunctionDescriptor frontendDescriptor = UrlRewriteFunctionDescriptorFactory
 +        .create(FrontendFunctionDescriptor.FUNCTION_NAME);
 +
 +    frontend = UrlRewriteFunctionProcessorFactory
 +        .create(FrontendFunctionDescriptor.FUNCTION_NAME, frontendDescriptor);
 +
 +    frontend.initialize(environment, frontendDescriptor);
 +  }
 +
 +  @Override
 +  public String name() {
 +    return HtmlPrefixDescriptor.FUNCTION_NAME;
 +  }
 +
 +  @Override
 +  public void destroy() throws Exception {
 +    frontend.destroy();
 +  }
 +
 +  @Override
 +  public List<String> resolve(UrlRewriteContext context,
 +      List<String> parameters) throws Exception {
 +    String prefix = "";
 +
 +    if ((parameters != null) && (parameters.size() > 1)) {
 +      prefix = parameters.get(0);
 +      parameters = parameters.subList(1, parameters.size());
 +    }
 +
 +    final List<String> frontendValues = frontend.resolve(context, parameters);
 +
 +    final StringBuffer buffer = new StringBuffer();
 +    buffer.append(prefix);
-     if (frontendValues != null && frontendValues.size() > 0) {
++    if (frontendValues != null && !frontendValues.isEmpty()) {
 +      for (final String value : frontendValues) {
 +        buffer.append(value);
 +      }
 +    }
 +
 +    return Arrays.asList(buffer.toString());
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
----------------------------------------------------------------------
diff --cc gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
index 8286dbc,0000000..dfceb42
mode 100644,000000..100644
--- a/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
+++ b/gateway-provider-rewrite/src/main/java/org/apache/knox/gateway/filter/rewrite/impl/json/JsonFilterReader.java
@@@ -1,644 -1,0 +1,644 @@@
 +/**
 + * 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.rewrite.impl.json;
 +
 +import com.fasterxml.jackson.core.JsonFactory;
 +import com.fasterxml.jackson.core.JsonGenerator;
 +import com.fasterxml.jackson.core.JsonParser;
 +import com.fasterxml.jackson.core.JsonToken;
 +import com.fasterxml.jackson.databind.JsonNode;
 +import com.fasterxml.jackson.databind.ObjectMapper;
 +import com.fasterxml.jackson.databind.node.ArrayNode;
 +import com.fasterxml.jackson.databind.node.ObjectNode;
 +import com.fasterxml.jackson.databind.node.TextNode;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterApplyDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterBufferDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterContentDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterDetectDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterGroupDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.api.UrlRewriteFilterPathDescriptor;
 +import org.apache.knox.gateway.filter.rewrite.i18n.UrlRewriteMessages;
 +import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.util.JsonPath;
 +
 +import java.io.IOException;
 +import java.io.Reader;
 +import java.io.StringWriter;
 +import java.util.List;
 +import java.util.Stack;
 +import java.util.regex.Pattern;
 +
 +class JsonFilterReader extends Reader {
 +
 +  private static final UrlRewriteMessages LOG = MessagesFactory.get( UrlRewriteMessages.class );
 +
 +  private static final UrlRewriteFilterPathDescriptor.Compiler<JsonPath.Expression> JPATH_COMPILER = new JsonPathCompiler();
 +  private static final UrlRewriteFilterPathDescriptor.Compiler<Pattern> REGEX_COMPILER = new RegexCompiler();
 +
 +  private JsonFactory factory;
 +  private JsonParser parser;
 +  private JsonGenerator generator;
 +  private ObjectMapper mapper;
 +
 +  private Reader reader;
 +  private int offset;
 +  private StringWriter writer;
 +  private StringBuffer buffer;
 +  private Stack<Level> stack;
 +  private Level bufferingLevel;
 +  private UrlRewriteFilterBufferDescriptor bufferingConfig;
 +  private UrlRewriteFilterGroupDescriptor config;
 +
 +
 +  public JsonFilterReader( Reader reader, UrlRewriteFilterContentDescriptor config ) throws IOException {
 +    this.reader = reader;
 +    factory = new JsonFactory();
 +    mapper = new ObjectMapper();
 +    parser = factory.createParser( reader );
 +    writer = new StringWriter();
 +    buffer = writer.getBuffer();
 +    offset = 0;
 +    generator = factory.createGenerator( writer );
 +    stack = new Stack<Level>();
 +    bufferingLevel = null;
 +    bufferingConfig = null;
 +    this.config = config;
 +  }
 +
 +  @Override
 +  public int read( char[] destBuffer, int destOffset, int destCount ) throws IOException {
 +    int count = 0;
 +    int available = buffer.length() - offset;
 +
 +    if( available == 0 ) {
 +      JsonToken token = parser.nextToken();
 +      if( token == null ) {
 +        count = -1;
 +      } else {
 +        processCurrentToken();
 +        available = buffer.length() - offset;
 +      }
 +    }
 +
 +    if( available > 0 ) {
 +      count = Math.min( destCount, available );
 +      buffer.getChars( offset, offset+count, destBuffer, destOffset );
 +      offset += count;
 +      if( offset == buffer.length() ) {
 +        offset = 0;
 +        buffer.setLength( 0 );
 +      }
 +    }
 +
 +    return count;
 +  }
 +
 +  private void processCurrentToken() throws IOException {
 +    switch( parser.getCurrentToken() ) {
 +      case START_OBJECT:
 +        processStartObject();
 +        break;
 +      case END_OBJECT:
 +        processEndObject();
 +        break;
 +      case START_ARRAY:
 +        processStartArray();
 +        break;
 +      case END_ARRAY:
 +        processEndArray();
 +        break;
 +      case FIELD_NAME:
 +        processFieldName(); // Could be the name of an object, array or value.
 +        break;
 +      case VALUE_STRING:
 +        processValueString();
 +        break;
 +      case VALUE_NUMBER_INT:
 +      case VALUE_NUMBER_FLOAT:
 +        processValueNumber();
 +        break;
 +      case VALUE_TRUE:
 +      case VALUE_FALSE:
 +        processValueBoolean();
 +        break;
 +      case VALUE_NULL:
 +        processValueNull();
 +        break;
 +      case NOT_AVAILABLE:
 +        // Ignore it.
 +        break;
 +    }
 +    generator.flush();
 +  }
 +
 +  private Level pushLevel( String field, JsonNode node, JsonNode scopeNode, UrlRewriteFilterGroupDescriptor scopeConfig ) {
 +    if( !stack.isEmpty() ) {
 +      Level top = stack.peek();
 +      if( scopeNode == null ) {
 +        scopeNode = top.scopeNode;
 +        scopeConfig = top.scopeConfig;
 +      }
 +    }
 +    Level level = new Level( field, node, scopeNode, scopeConfig );
 +    stack.push( level );
 +    return level;
 +  }
 +
 +  private void processStartObject() throws IOException {
 +    JsonNode node;
 +    Level child;
 +    Level parent;
 +    if( stack.isEmpty() ) {
 +      node = mapper.createObjectNode();
 +      child = pushLevel( null, node, node, config );
 +    } else {
 +      child = stack.peek();
 +      if( child.node == null ) {
 +        child.node = mapper.createObjectNode();
 +        parent = stack.get( stack.size()-2 );
 +        switch( parent.node.asToken() ) {
 +          case START_ARRAY:
 +            ((ArrayNode)parent.node ).add( child.node );
 +            break;
 +          case START_OBJECT:
 +            ((ObjectNode)parent.node ).put( child.field, child.node );
 +            break;
 +          default:
 +            throw new IllegalStateException();
 +        }
 +      } else if( child.isArray() ) {
 +        parent = child;
 +        node = mapper.createObjectNode();
 +        child = pushLevel( null, node, null, null );
 +        ((ArrayNode)parent.node ).add( child.node );
 +      } else {
 +        throw new IllegalStateException();
 +      }
 +    }
 +    if( bufferingLevel == null ) {
 +      if( !startBuffering( child ) ) {
 +        generator.writeStartObject();
 +      }
 +    }
 +  }
 +
 +  private void processEndObject() throws IOException {
 +    Level child;
 +    Level parent;
 +    child = stack.pop();
 +    if( bufferingLevel == child ) {
 +      filterBufferedNode( child );
 +      mapper.writeTree( generator, child.node );
 +      bufferingLevel = null;
 +      bufferingConfig = null;
 +    } else if( bufferingLevel == null ) {
 +      generator.writeEndObject();
 +      if( !stack.isEmpty() ) {
 +        parent = stack.peek();
 +        switch( parent.node.asToken() ) {
 +          case START_ARRAY:
 +            ((ArrayNode)parent.node ).removeAll();
 +            break;
 +          case START_OBJECT:
 +            ((ObjectNode)parent.node ).removeAll();
 +            break;
 +          default:
 +            throw new IllegalStateException();
 +        }
 +      }
 +    }
 +  }
 +
 +  private void processStartArray() throws IOException {
 +    JsonNode node;
 +    Level child;
 +    Level parent;
 +    if( stack.isEmpty() ) {
 +      node = mapper.createArrayNode();
 +      child = pushLevel( null, node, node, config );
 +    } else {
 +      child = stack.peek();
 +      if( child.node == null ) {
 +        child.node = mapper.createArrayNode();
 +        parent = stack.get( stack.size() - 2 );
 +        switch( parent.node.asToken() ) {
 +          case START_ARRAY:
 +            ((ArrayNode)parent.node ).add( child.node );
 +            break;
 +          case START_OBJECT:
 +            ((ObjectNode)parent.node ).put( child.field, child.node );
 +            break;
 +          default:
 +            throw new IllegalStateException();
 +        }
 +      } else if( child.isArray() ) {
 +        parent = child;
 +        child = pushLevel( null, mapper.createArrayNode(), null, null );
 +        ((ArrayNode)parent.node ).add( child.node );
 +      } else {
 +        throw new IllegalStateException();
 +      }
 +    }
 +    if( bufferingLevel == null ) {
 +      if( !startBuffering( child ) ) {
 +        generator.writeStartArray();
 +      }
 +    }
 +  }
 +
 +  private void processEndArray() throws IOException {
 +    Level child;
 +    Level parent;
 +    child = stack.pop();
 +    if( bufferingLevel == child ) {
 +      filterBufferedNode( child );
 +      mapper.writeTree( generator, child.node );
 +      bufferingLevel = null;
 +      bufferingConfig = null;
 +    } else if( bufferingLevel == null ) {
 +      generator.writeEndArray();
 +      if( !stack.isEmpty() ) {
 +        parent = stack.peek();
 +        switch( parent.node.asToken() ) {
 +          case START_ARRAY:
 +            ((ArrayNode)parent.node ).removeAll();
 +            break;
 +          case START_OBJECT:
 +            ((ObjectNode)parent.node ).removeAll();
 +            break;
 +          default:
 +            throw new IllegalStateException();
 +        }
 +      }
 +    }
 +  }
 +
 +  private void processFieldName() throws IOException {
 +    Level child = pushLevel( parser.getCurrentName(), null, null, null );
 +    try {
 +      child.field = filterFieldName( child.field );
 +    } catch( Exception e ) {
 +      LOG.failedToFilterFieldName( child.field, e );
 +      // Write original name.
 +    }
 +    if( bufferingLevel == null ) {
 +      generator.writeFieldName( child.field );
 +    }
 +  }
 +
 +  private void processValueString() throws IOException {
 +    Level child;
 +    Level parent;
 +    String value = null;
 +    parent = stack.peek();
 +    if( parent.isArray() ) {
 +      ArrayNode array = (ArrayNode)parent.node;
 +      array.add( parser.getText() );
 +      if( bufferingLevel == null ) {
 +        value = filterStreamValue( parent );
 +        array.set( array.size()-1, new TextNode( value ) );
 +      } else {
 +        array.removeAll();
 +      }
 +    } else {
 +      child = stack.pop();
 +      parent = stack.peek();
 +      ((ObjectNode)parent.node ).put( child.field, parser.getText() );
 +      if( bufferingLevel == null ) {
 +        child.node = parent.node; // Populate the JsonNode of the child for filtering.
 +        value = filterStreamValue( child );
 +      }
 +    }
 +    if( bufferingLevel == null ) {
 +      if( parent.node.isArray() ) {
 +        ((ArrayNode)parent.node).removeAll();
 +      } else {
 +        ((ObjectNode)parent.node).removeAll();
 +      }
 +      generator.writeString( value );
 +    }
 +  }
 +
 +  private void processValueNumber() throws IOException {
 +    Level child;
 +    Level parent;
 +    parent = stack.peek();
 +    if( parent.isArray() ) {
 +      if( bufferingLevel != null ) {
 +        ArrayNode array = (ArrayNode)parent.node;
 +        processBufferedArrayValueNumber( array );
 +      }
 +    } else {
 +      child = stack.pop();
 +      if( bufferingLevel != null ) {
 +        parent = stack.peek();
 +        ObjectNode object = (ObjectNode)parent.node;
 +        processBufferedFieldValueNumber( child, object );
 +      }
 +    }
 +    if( bufferingLevel == null ) {
 +      processedUnbufferedValueNumber();
 +    }
 +  }
 +
 +  private void processedUnbufferedValueNumber() throws IOException {
 +    switch( parser.getNumberType() ) {
 +      case INT:
 +        generator.writeNumber( parser.getIntValue() );
 +        break;
 +      case LONG:
 +        generator.writeNumber( parser.getLongValue() );
 +        break;
 +      case BIG_INTEGER:
 +        generator.writeNumber( parser.getBigIntegerValue() );
 +        break;
 +      case FLOAT:
 +        generator.writeNumber( parser.getFloatValue() );
 +        break;
 +      case DOUBLE:
 +        generator.writeNumber( parser.getDoubleValue() );
 +        break;
 +      case BIG_DECIMAL:
 +        generator.writeNumber( parser.getDecimalValue() );
 +        break;
 +    }
 +  }
 +
 +  private void processBufferedFieldValueNumber( Level child, ObjectNode object ) throws IOException {
 +    //object.put( child.field, parser.getDecimalValue() );
 +    switch( parser.getNumberType() ) {
 +      case INT:
 +        object.put( child.field, parser.getIntValue() );
 +        break;
 +      case LONG:
 +        object.put( child.field, parser.getLongValue() );
 +        break;
 +      case BIG_INTEGER:
 +        object.put( child.field, parser.getDecimalValue() );
 +        break;
 +      case FLOAT:
 +        object.put( child.field, parser.getFloatValue() );
 +        break;
 +      case DOUBLE:
 +        object.put( child.field, parser.getDoubleValue() );
 +        break;
 +      case BIG_DECIMAL:
 +        object.put( child.field, parser.getDecimalValue() );
 +        break;
 +    }
 +  }
 +
 +  private void processBufferedArrayValueNumber( ArrayNode array ) throws IOException {
 +    //array.add( parser.getDecimalValue() );
 +    switch( parser.getNumberType() ) {
 +      case INT:
 +        array.add( parser.getIntValue() );
 +        break;
 +      case LONG:
 +        array.add( parser.getLongValue() );
 +        break;
 +      case BIG_INTEGER:
 +        array.add( parser.getDecimalValue() );
 +        break;
 +      case FLOAT:
 +        array.add( parser.getFloatValue() );
 +        break;
 +      case DOUBLE:
 +        array.add( parser.getDoubleValue() );
 +        break;
 +      case BIG_DECIMAL:
 +        array.add( parser.getDecimalValue() );
 +        break;
 +    }
 +  }
 +
 +  private void processValueBoolean() throws IOException {
 +    Level child;
 +    Level parent;
 +    parent = stack.peek();
 +    if( parent.isArray() ) {
 +      ((ArrayNode)parent.node ).add( parser.getBooleanValue() );
 +      //dump();
 +      if( bufferingLevel == null ) {
 +        ((ArrayNode)parent.node ).removeAll();
 +      }
 +    } else {
 +      child = stack.pop();
 +      parent = stack.peek();
 +      ((ObjectNode)parent.node ).put( child.field, parser.getBooleanValue() );
 +      //dump();
 +      if( bufferingLevel == null ) {
 +        ((ObjectNode)parent.node ).remove( child.field );
 +      }
 +    }
 +    if( bufferingLevel == null ) {
 +      generator.writeBoolean( parser.getBooleanValue() );
 +    }
 +  }
 +
 +  private void processValueNull() throws IOException {
 +    Level child;
 +    Level parent = stack.peek();
 +    if( parent.isArray() ) {
 +      ((ArrayNode)parent.node ).addNull();
 +      //dump();
 +      if( bufferingLevel == null ) {
 +        ((ArrayNode)parent.node ).removeAll();
 +      }
 +    } else {
 +      child = stack.pop();
 +      parent = stack.peek();
 +      ((ObjectNode)parent.node ).putNull( child.field );
 +      //dump();
 +      if( bufferingLevel == null ) {
 +        ((ObjectNode)parent.node ).remove( child.field );
 +      }
 +    }
 +    if( bufferingLevel == null ) {
 +      generator.writeNull();
 +    }
 +  }
 +
 +  protected boolean startBuffering( Level node ) {
 +    boolean buffered = false;
 +    UrlRewriteFilterGroupDescriptor scope = node.scopeConfig;
 +    if( scope != null ) {
 +      for( UrlRewriteFilterPathDescriptor selector : scope.getSelectors() ) {
 +        JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
 +        List<JsonPath.Match> matches = path.evaluate( node.scopeNode );
-         if( matches != null && matches.size() > 0 ) {
++        if( matches != null && !matches.isEmpty() ) {
 +          if( selector instanceof UrlRewriteFilterBufferDescriptor ) {
 +            bufferingLevel = node;
 +            bufferingConfig = (UrlRewriteFilterBufferDescriptor)selector;
 +            buffered = true;
 +          }
 +          break;
 +        }
 +      }
 +    }
 +    return buffered;
 +  }
 +
 +  protected String filterStreamValue( Level node ) {
 +    String value;
 +    if( node.isArray() ) {
 +      value = node.node.get( 0 ).asText();
 +    } else {
 +      value = node.node.get( node.field ).asText();
 +    }
 +    String rule = null;
 +    UrlRewriteFilterGroupDescriptor scope = node.scopeConfig;
 +    //TODO: Scan the top level apply rules for the first match.
 +    if( scope != null ) {
 +      for( UrlRewriteFilterPathDescriptor selector : scope.getSelectors() ) {
 +        JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
 +        List<JsonPath.Match> matches = path.evaluate( node.scopeNode );
-         if( matches != null && matches.size() > 0 ) {
++        if( matches != null && !matches.isEmpty() ) {
 +          JsonPath.Match match = matches.get( 0 );
 +          if( match.getNode().isTextual() ) {
 +            if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
 +              UrlRewriteFilterApplyDescriptor apply = (UrlRewriteFilterApplyDescriptor)selector;
 +              rule = apply.rule();
 +              break;
 +            }
 +          }
 +        }
 +      }
 +    }
 +    try {
 +      value = filterValueString( node.field, value, rule );
 +      if( node.isArray() ) {
 +        ((ArrayNode)node.node).set( 0, new TextNode( value ) );
 +      } else {
 +        ((ObjectNode)node.node).put( node.field, value );
 +      }
 +    } catch( Exception e ) {
 +      LOG.failedToFilterValue( value, rule, e );
 +    }
 +    return value;
 +  }
 +
 +  private void filterBufferedNode( Level node ) {
 +    for( UrlRewriteFilterPathDescriptor selector : bufferingConfig.getSelectors() ) {
 +      JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
 +      List<JsonPath.Match> matches = path.evaluate( node.node );
 +      for( JsonPath.Match match : matches ) {
 +        if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
 +          if( match.getNode().isTextual() ) {
 +            filterBufferedValue( match, (UrlRewriteFilterApplyDescriptor)selector );
 +          }
 +        } else if( selector instanceof UrlRewriteFilterDetectDescriptor ) {
 +          UrlRewriteFilterDetectDescriptor detectConfig = (UrlRewriteFilterDetectDescriptor)selector;
 +          JsonPath.Expression detectPath = (JsonPath.Expression)detectConfig.compiledPath( JPATH_COMPILER );
 +          List<JsonPath.Match> detectMatches = detectPath.evaluate( node.node );
 +          for( JsonPath.Match detectMatch : detectMatches ) {
 +            if( detectMatch.getNode().isTextual() ) {
 +              String detectValue = detectMatch.getNode().asText();
 +              Pattern detectPattern = detectConfig.compiledValue( REGEX_COMPILER );
 +              if( detectPattern.matcher( detectValue ).matches() ) {
 +                filterBufferedValues( node, detectConfig.getSelectors() );
 +              }
 +            }
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private void filterBufferedValues( Level node, List<UrlRewriteFilterPathDescriptor> selectors ) {
 +    for( UrlRewriteFilterPathDescriptor selector : selectors ) {
 +      JsonPath.Expression path = (JsonPath.Expression)selector.compiledPath( JPATH_COMPILER );
 +      List<JsonPath.Match> matches = path.evaluate( node.node );
 +      for( JsonPath.Match match : matches ) {
 +        if( match.getNode().isTextual() ) {
 +          if( selector instanceof UrlRewriteFilterApplyDescriptor ) {
 +            filterBufferedValue( match, (UrlRewriteFilterApplyDescriptor)selector );
 +          }
 +        }
 +      }
 +    }
 +  }
 +
 +  private void filterBufferedValue( JsonPath.Match match, UrlRewriteFilterApplyDescriptor apply ) {
 +    String field = match.getField();
 +    String value = match.getNode().asText();
 +    try {
 +      value = filterValueString( field, value, apply.rule() );
 +      ((ObjectNode)match.getParent().getNode()).put( field, value );
 +    } catch( Exception e ) {
 +      LOG.failedToFilterValue( value, apply.rule(), e );
 +    }
 +  }
 +
 +  protected String filterFieldName( String field ) {
 +    return field;
 +  }
 +
 +  protected String filterValueString( String name, String value, String rule ) {
 +    return value;
 +  }
 +
 +  @Override
 +  public void close() throws IOException {
 +    generator.close();
 +    writer.close();
 +    parser.close();
 +    reader.close();
 +  }
 +
 +  private static class Level {
 +    String field;
 +    JsonNode node;
 +    JsonNode scopeNode;
 +    UrlRewriteFilterGroupDescriptor scopeConfig;
 +    private Level( String field, JsonNode node, JsonNode scopeNode, UrlRewriteFilterGroupDescriptor scopeConfig ) {
 +      this.field = field;
 +      this.node = node;
 +      this.scopeNode = scopeNode;
 +      this.scopeConfig = scopeConfig;
 +    }
 +    public boolean isArray() {
 +      return node != null && node.isArray();
 +    }
 +  }
 +
 +  private static class JsonPathCompiler implements UrlRewriteFilterPathDescriptor.Compiler<JsonPath.Expression> {
 +    @Override
 +    public JsonPath.Expression compile( String expression, JsonPath.Expression compiled ) {
 +      return JsonPath.compile( expression );
 +    }
 +  }
 +
 +  private static class RegexCompiler implements UrlRewriteFilterPathDescriptor.Compiler<Pattern> {
 +    @Override
 +    public Pattern compile( String expression, Pattern compiled ) {
 +      if( compiled != null ) {
 +        return compiled;
 +      } else {
 +        return Pattern.compile( expression );
 +      }
 +    }
 +  }
 +
 +//  private void dump() throws IOException {
 +//    mapper.writeTree( factory.createGenerator( System.out ), stack.get( 0 ).node );
 +//    System.out.println();
 +//  }
 +
 +}
 +

http://git-wip-us.apache.org/repos/asf/knox/blob/50f46e9e/gateway-provider-security-authz-acls/src/main/java/org/apache/knox/gateway/filter/AclsAuthorizationFilter.java
----------------------------------------------------------------------
diff --cc gateway-provider-security-authz-acls/src/main/java/org/apache/knox/gateway/filter/AclsAuthorizationFilter.java
index 0002974,0000000..f26c753
mode 100644,000000..100644
--- a/gateway-provider-security-authz-acls/src/main/java/org/apache/knox/gateway/filter/AclsAuthorizationFilter.java
+++ b/gateway-provider-security-authz-acls/src/main/java/org/apache/knox/gateway/filter/AclsAuthorizationFilter.java
@@@ -1,212 -1,0 +1,212 @@@
 +/**
 + * 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 javax.security.auth.Subject;
 +import javax.servlet.Filter;
 +import javax.servlet.FilterChain;
 +import javax.servlet.FilterConfig;
 +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.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.i18n.messages.MessagesFactory;
 +import org.apache.knox.gateway.security.GroupPrincipal;
 +import org.apache.knox.gateway.security.ImpersonatedPrincipal;
 +import org.apache.knox.gateway.security.PrimaryPrincipal;
 +
 +import java.io.IOException;
 +import java.security.AccessController;
 +import java.security.Principal;
 +
 +public class AclsAuthorizationFilter implements Filter {
 +  private static AclsAuthorizationMessages log = MessagesFactory.get( AclsAuthorizationMessages.class );
 +  private static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME,
 +          AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
 +
 +  private String resourceRole = null;
 +  private String aclProcessingMode = null;
 +  private AclParser parser = new AclParser();
 +
 +  
 +  @Override
 +  public void init(FilterConfig filterConfig) throws ServletException {
 +    resourceRole = getInitParameter(filterConfig, "resource.role");
 +    log.initializingForResourceRole(resourceRole);
 +    aclProcessingMode = getInitParameter(filterConfig, resourceRole + ".acl.mode");
 +    if (aclProcessingMode == null) {
 +      aclProcessingMode = getInitParameter(filterConfig, "acl.mode");
 +      if (aclProcessingMode == null) {
 +        aclProcessingMode = "AND";
 +      }
 +    }
 +    log.aclProcessingMode(aclProcessingMode);
 +    String acls = getInitParameter(filterConfig, resourceRole + ".acl");
 +    parser.parseAcls(resourceRole, acls);
 +  }
 +
 +  private String getInitParameter(FilterConfig filterConfig, String paramName) {
 +    return filterConfig.getInitParameter(paramName.toLowerCase());
 +  }
 +
 +  public void destroy() {
 +  }
 +
 +  public void doFilter(ServletRequest request, ServletResponse response,
 +      FilterChain chain) throws IOException, ServletException {
 +    boolean accessGranted = enforceAclAuthorizationPolicy(request, response, chain);
 +    log.accessGranted(accessGranted);
 +    String sourceUrl = (String)request.getAttribute( AbstractGatewayFilter.SOURCE_REQUEST_CONTEXT_URL_ATTRIBUTE_NAME );
 +    if (accessGranted) {
 +      auditor.audit( Action.AUTHORIZATION, sourceUrl, ResourceType.URI, ActionOutcome.SUCCESS );
 +      chain.doFilter(request, response);
 +    }
 +    else {
 +      auditor.audit( Action.AUTHORIZATION, sourceUrl, ResourceType.URI, ActionOutcome.FAILURE );
 +      sendForbidden((HttpServletResponse) response);
 +    }
 +  }
 +
 +  private boolean enforceAclAuthorizationPolicy(ServletRequest request,
 +      ServletResponse response, FilterChain chain) {
 +    HttpServletRequest req = (HttpServletRequest) request;
 +    
 +    // before enforcing acls check whether there are no acls defined 
 +    // which would mean that there are no restrictions
 +    if (parser.users.size() == 0 && parser.groups.size() == 0 && parser.ipv.getIPAddresses().size() == 0) {
 +      return true;
 +    }
 +
 +    boolean userAccess = false;
 +    boolean groupAccess = false;
 +    boolean ipAddrAccess = false;
 +    
 +    Subject subject = Subject.getSubject(AccessController.getContext());
 +    Principal primaryPrincipal = (Principal)subject.getPrincipals(PrimaryPrincipal.class).toArray()[0];
 +    log.primaryPrincipal(primaryPrincipal.getName());
 +    Object[] impersonations = subject.getPrincipals(ImpersonatedPrincipal.class).toArray();
 +    if (impersonations.length > 0) {
 +      log.impersonatedPrincipal(((Principal)impersonations[0]).getName());
 +      userAccess = checkUserAcls((Principal)impersonations[0]);
 +      log.impersonatedPrincipalHasAccess(userAccess);
 +    }
 +    else {
 +      userAccess = checkUserAcls(primaryPrincipal);
 +      log.primaryPrincipalHasAccess(userAccess);
 +    }
 +    Object[] groups = subject.getPrincipals(GroupPrincipal.class).toArray();
 +    if (groups.length > 0) {
 +//      System.out.println("GroupPrincipal: " + ((Principal)groups[0]).getName());
 +      groupAccess = checkGroupAcls(groups);
 +      log.groupPrincipalHasAccess(groupAccess);
 +    }
 +    else {
 +      // if we have no groups in the subject then make
 +      // it true if there is an anyGroup acl
 +      // for AND mode and acls like *;*;127.0.0.* we need to
 +      // make it pass
-       if (parser.anyGroup && aclProcessingMode.equals("AND")) {
++      if (parser.anyGroup && "AND".equals(aclProcessingMode)) {
 +        groupAccess = true;
 +      }
 +    }
 +    log.remoteIPAddress(req.getRemoteAddr());
 +    ipAddrAccess = checkRemoteIpAcls(req.getRemoteAddr());
 +    log.remoteIPAddressHasAccess(ipAddrAccess);
 +    
-     if (aclProcessingMode.equals("OR")) {
++    if ("OR".equals(aclProcessingMode)) {
 +      // need to interpret '*' as excluded for OR semantics
 +      // to make sense and not grant access to everyone by mistake.
 +      // exclusion in OR is equivalent to denied
 +      // so, let's set each one that contains '*' to false.
 +      if (parser.anyUser) userAccess = false;
 +      if (parser.anyGroup) groupAccess = false;
 +      if (parser.ipv.allowsAnyIP()) ipAddrAccess = false;
 +      
 +      return (userAccess || groupAccess || ipAddrAccess);
 +    }
-     else if (aclProcessingMode.equals("AND")) {
++    else if ("AND".equals(aclProcessingMode)) {
 +      return (userAccess && groupAccess && ipAddrAccess);
 +    }
 +    return false;
 +  }
 +
 +  private boolean checkRemoteIpAcls(String remoteAddr) {
 +    boolean allowed = false;
 +    if (remoteAddr == null) {
 +      return false;
 +    }
 +    allowed = parser.ipv.validateIpAddress(remoteAddr);
 +    return allowed;
 +  }
 +
 +  private boolean checkUserAcls(Principal user) {
 +    boolean allowed = false;
 +    if (user == null) {
 +      return false;
 +    }
 +    if (parser.anyUser) {
 +      allowed = true;
 +    }
 +    else {
 +      if (parser.users.contains(user.getName())) {
 +        allowed = true;
 +      }
 +    }
 +    return allowed;
 +  }
 +
 +  private boolean checkGroupAcls(Object[] userGroups) {
 +    boolean allowed = false;
 +    if (userGroups == null) {
 +      return false;
 +    }
 +    if (parser.anyGroup) {
 +      allowed = true;
 +    }
 +    else {
 +      for (int i = 0; i < userGroups.length; i++) {
 +        if (parser.groups.contains(((Principal)userGroups[i]).getName())) {
 +          allowed = true;
 +          break;
 +        }
 +      }
 +    }
 +    return allowed;
 +  }
 +
 +  private void sendForbidden(HttpServletResponse res) {
 +    sendErrorCode(res, 403);
 +  }
 +
 +  private void sendErrorCode(HttpServletResponse res, int code) {
 +    try {
 +      res.sendError(code);
 +    } catch (IOException e) {
 +      // TODO: log appropriately
 +      e.printStackTrace();
 +    }
 +  }
 +}


Mime
View raw message