You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2016/09/15 17:19:45 UTC

[1/2] ambari git commit: AMBARI-18367. Create authentication filter to encapsulate the various Ambari authentication methods (rlevas)

Repository: ambari
Updated Branches:
  refs/heads/trunk edf1b9b9f -> d5cca62c8


http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
new file mode 100644
index 0000000..f042a70
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilterTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.ambari.server.security.authentication;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.crypto.RSASSASigner;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.AmbariEntryPoint;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
+import org.easymock.EasyMockSupport;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.servlet.FilterChain;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+
+public class AmbariJWTAuthenticationFilterTest extends EasyMockSupport {
+  private static RSAPublicKey publicKey;
+  private static RSAPrivateKey privateKey;
+
+  @BeforeClass
+  public static void generateKeyPair() throws NoSuchAlgorithmException {
+    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+    keyPairGenerator.initialize(512);
+    KeyPair keyPair = keyPairGenerator.generateKeyPair();
+    publicKey = (RSAPublicKey) keyPair.getPublic();
+    privateKey = (RSAPrivateKey) keyPair.getPrivate();
+  }
+
+  @Test
+  public void testDoFilterSuccess() throws Exception {
+    SignedJWT token = getSignedToken("foobar");
+
+    AmbariEntryPoint entryPoint = createMock(AmbariEntryPoint.class);
+
+    JwtAuthenticationProperties properties = createMock(JwtAuthenticationProperties.class);
+    expect(properties.getAuthenticationProviderUrl()).andReturn("some url").once();
+    expect(properties.getPublicKey()).andReturn(publicKey).once();
+    expect(properties.getAudiences()).andReturn(Collections.singletonList("foobar")).once();
+    expect(properties.getCookieName()).andReturn("chocolate chip").once();
+    expect(properties.getOriginalUrlQueryParam()).andReturn("question").once();
+
+    Configuration configuration = createMock(Configuration.class);
+    expect(configuration.getJwtProperties()).andReturn(properties).once();
+
+    User user = createMock(User.class);
+    expect(user.getUserName()).andReturn("test-user").once();
+    expect(user.getUserType()).andReturn(UserType.JWT).once();
+
+    Users users = createMock(Users.class);
+    expect(users.getUser("test-user", UserType.JWT)).andReturn(user).once();
+    expect(users.getUserAuthorities("test-user", UserType.JWT)).andReturn(null).once();
+
+    AuditLogger auditLogger = createMock(AuditLogger.class);
+    expect(auditLogger.isEnabled()).andReturn(false).times(2);
+
+    PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+
+    Cookie cookie = createMock(Cookie.class);
+    expect(cookie.getName()).andReturn("chocolate chip").once();
+    expect(cookie.getValue()).andReturn(token.serialize()).once();
+
+
+    HttpServletRequest servletRequest = createMock(HttpServletRequest.class);
+    expect(servletRequest.getCookies()).andReturn(new Cookie[]{cookie}).once();
+
+    HttpServletResponse servletResponse = createMock(HttpServletResponse.class);
+
+    FilterChain filterChain = createMock(FilterChain.class);
+    filterChain.doFilter(servletRequest, servletResponse);
+    expectLastCall().once();
+
+    replayAll();
+
+    AmbariJWTAuthenticationFilter filter = new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, auditLogger, permissionHelper);
+    filter.doFilter(servletRequest, servletResponse, filterChain);
+
+    verifyAll();
+  }
+
+  @Test
+  public void testDoFilterFailure() throws Exception {
+    AmbariEntryPoint entryPoint = createMock(AmbariEntryPoint.class);
+
+    JwtAuthenticationProperties properties = createMock(JwtAuthenticationProperties.class);
+    expect(properties.getAuthenticationProviderUrl()).andReturn("some url").once();
+    expect(properties.getPublicKey()).andReturn(publicKey).once();
+    expect(properties.getAudiences()).andReturn(Collections.singletonList("foobar")).once();
+    expect(properties.getCookieName()).andReturn("chocolate chip").once();
+    expect(properties.getOriginalUrlQueryParam()).andReturn("question").once();
+
+    Configuration configuration = createMock(Configuration.class);
+    expect(configuration.getJwtProperties()).andReturn(properties).once();
+
+    Users users = createMock(Users.class);
+
+    AuditLogger auditLogger = createMock(AuditLogger.class);
+    expect(auditLogger.isEnabled()).andReturn(false).times(2);
+
+    PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+
+    Cookie cookie = createMock(Cookie.class);
+    expect(cookie.getName()).andReturn("chocolate chip").once();
+    expect(cookie.getValue()).andReturn("invalid token").once();
+
+
+    HttpServletRequest servletRequest = createMock(HttpServletRequest.class);
+    expect(servletRequest.getCookies()).andReturn(new Cookie[]{cookie}).once();
+
+    HttpServletResponse servletResponse = createMock(HttpServletResponse.class);
+
+    FilterChain filterChain = createMock(FilterChain.class);
+    filterChain.doFilter(servletRequest, servletResponse);
+    expectLastCall().once();
+
+    replayAll();
+
+    AmbariJWTAuthenticationFilter filter = new AmbariJWTAuthenticationFilter(entryPoint, configuration, users, auditLogger, permissionHelper);
+    filter.doFilter(servletRequest, servletResponse, filterChain);
+
+    verifyAll();
+  }
+
+
+  private SignedJWT getSignedToken(String audience) throws JOSEException {
+    Calendar calendar = Calendar.getInstance();
+    calendar.setTimeInMillis(System.currentTimeMillis());
+    calendar.add(Calendar.DATE, 1); //add one day
+    return getSignedToken(calendar.getTime(), audience);
+  }
+
+  private SignedJWT getSignedToken(Date expirationTime, String audience) throws JOSEException {
+    RSASSASigner signer = new RSASSASigner(privateKey);
+
+    Calendar calendar = Calendar.getInstance();
+    calendar.setTimeInMillis(System.currentTimeMillis());
+    JWTClaimsSet claimsSet = new JWTClaimsSet();
+    claimsSet.setSubject("test-user");
+    claimsSet.setIssuer("unit-test");
+    claimsSet.setIssueTime(calendar.getTime());
+
+    claimsSet.setExpirationTime(expirationTime);
+
+    claimsSet.setAudience(audience);
+
+    SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet);
+    signedJWT.sign(signer);
+
+    return signedJWT;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
index 1d71fe6..10de0a9 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilterTest.java
@@ -30,6 +30,7 @@ import org.apache.ambari.server.audit.AuditLogger;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.DBAccessor;
 import org.apache.ambari.server.orm.dao.UserDAO;
+import org.apache.ambari.server.security.AmbariEntryPoint;
 import org.apache.ambari.server.security.TestAuthenticationFactory;
 import org.apache.ambari.server.state.stack.OsFamily;
 import org.apache.ambari.server.view.ViewRegistry;
@@ -324,7 +325,8 @@ public class AmbariAuthorizationFilterTest {
       }
     });
 
-    AmbariAuthorizationFilter filter = new AmbariAuthorizationFilter();
+    AmbariAuthorizationFilter filter = new AmbariAuthorizationFilter(createNiceMock(AmbariEntryPoint.class), injector.getInstance(Configuration.class),
+        injector.getInstance(Users.class), injector.getInstance(AuditLogger.class), injector.getInstance(PermissionHelper.class));
     injector.injectMembers(filter);
 
     filter.doFilter(request, response, chain);
@@ -338,14 +340,28 @@ public class AmbariAuthorizationFilterTest {
    * @param authentication the authentication to use
    * @param urlTests map of triples: url - http method - is allowed
    * @param expectRedirect true if the requests should redirect to login
-   * @throws Exception
+   * @throws Exception if an exception occurs
    */
   private void performGeneralDoFilterTest(Authentication authentication, Table<String, String, Boolean> urlTests, boolean expectRedirect) throws Exception {
     final SecurityContext securityContext = createNiceMock(SecurityContext.class);
     final FilterConfig filterConfig = createNiceMock(FilterConfig.class);
+
+    final Configuration configuration = EasyMock.createMock(Configuration.class);
+    expect(configuration.getDefaultApiAuthenticatedUser()).andReturn(null).anyTimes();
+
+    final AuditLogger auditLogger = EasyMock.createNiceMock(AuditLogger.class);
+    expect(auditLogger.isEnabled()).andReturn(false).anyTimes();
+
     final AmbariAuthorizationFilter filter = createMockBuilder(AmbariAuthorizationFilter.class)
-        .addMockedMethod("getSecurityContext").addMockedMethod("getViewRegistry").withConstructor().createMock();
-    injectMembers(filter);
+        .addMockedMethod("getSecurityContext")
+        .addMockedMethod("getViewRegistry")
+        .withConstructor(createNiceMock(AmbariEntryPoint.class),
+            configuration,
+            createNiceMock(Users.class),
+            auditLogger,
+            createNiceMock(PermissionHelper.class))
+        .createMock();
+
     final ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class);
 
     expect(filterConfig.getInitParameter("realm")).andReturn("AuthFilter").anyTimes();
@@ -355,7 +371,7 @@ public class AmbariAuthorizationFilterTest {
     expect(securityContext.getAuthentication()).andReturn(authentication).anyTimes();
     expect(viewRegistry.checkPermission(EasyMock.eq("DeniedView"), EasyMock.<String>anyObject(), EasyMock.<String>anyObject(), EasyMock.anyBoolean())).andReturn(false).anyTimes();
 
-    replay(filterConfig, filter, securityContext, viewRegistry);
+    replay(filterConfig, filter, securityContext, viewRegistry, configuration, auditLogger);
 
     for (final Cell<String, String, Boolean> urlTest: urlTests.cellSet()) {
       final FilterChain chain = EasyMock.createStrictMock(FilterChain.class);
@@ -399,26 +415,4 @@ public class AmbariAuthorizationFilterTest {
       }
     }
   }
-
-  private void injectMembers(AmbariAuthorizationFilter filter) {
-    final Configuration configuration = EasyMock.createMock(Configuration.class);
-    expect(configuration.getDefaultApiAuthenticatedUser()).andReturn(null).anyTimes();
-    final AuditLogger auditLogger = EasyMock.createNiceMock(AuditLogger.class);
-    expect(auditLogger.isEnabled()).andReturn(false).anyTimes();
-    Injector injector = Guice.createInjector(new AbstractModule() {
-      @Override
-      protected void configure() {
-        bind(Configuration.class).toInstance(configuration);
-        bind(Users.class).toInstance(EasyMock.createMock(Users.class));
-        bind(EntityManager.class).toInstance(EasyMock.createMock(EntityManager.class));
-        bind(UserDAO.class).toInstance(EasyMock.createMock(UserDAO.class));
-        bind(DBAccessor.class).toInstance(EasyMock.createMock(DBAccessor.class));
-        bind(PasswordEncoder.class).toInstance(EasyMock.createMock(PasswordEncoder.class));
-        bind(OsFamily.class).toInstance(EasyMock.createMock(OsFamily.class));
-        bind(AuditLogger.class).toInstance(auditLogger);
-      }
-    });
-    injector.injectMembers(filter);
-    replay(configuration, auditLogger);
-  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
index b08d1ac..5814203 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilterTest.java
@@ -24,13 +24,12 @@ import com.nimbusds.jose.JWSHeader;
 import com.nimbusds.jose.crypto.RSASSASigner;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.SignedJWT;
+import junit.framework.Assert;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
 import org.apache.ambari.server.security.authorization.User;
 import org.apache.ambari.server.security.authorization.UserType;
 import org.apache.ambari.server.security.authorization.Users;
-import org.easymock.EasyMock;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -46,10 +45,8 @@ import javax.servlet.http.HttpServletResponse;
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
@@ -57,6 +54,7 @@ import java.util.List;
 
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.createMockBuilder;
+import static org.easymock.EasyMock.createMock;
 import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expect;
@@ -299,4 +297,75 @@ public class JwtAuthenticationFilterTest {
     assertEquals(false, isValid);
 
   }
+
+  @Test
+  public void testShouldApplyTrue() throws JOSEException {
+    JwtAuthenticationProperties properties = createTestProperties();
+    JwtAuthenticationFilter filter = new JwtAuthenticationFilter(properties, null, null);
+
+    SignedJWT token = getInvalidToken();
+
+    Cookie cookie = createMock(Cookie.class);
+    expect(cookie.getName()).andReturn("non-default").atLeastOnce();
+    expect(cookie.getValue()).andReturn(token.serialize()).atLeastOnce();
+
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    expect(request.getCookies()).andReturn(new Cookie[]{cookie});
+
+    replay(request, cookie);
+
+    Assert.assertTrue(filter.shouldApply(request));
+
+    verify(request, cookie);
+  }
+
+  @Test
+  public void testShouldApplyTrueBadToken() throws JOSEException {
+    JwtAuthenticationProperties properties = createTestProperties();
+    JwtAuthenticationFilter filter = new JwtAuthenticationFilter(properties, null, null);
+
+    Cookie cookie = createMock(Cookie.class);
+    expect(cookie.getName()).andReturn("non-default").atLeastOnce();
+    expect(cookie.getValue()).andReturn("bad token").atLeastOnce();
+
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    expect(request.getCookies()).andReturn(new Cookie[]{cookie});
+
+    replay(request, cookie);
+
+    Assert.assertTrue(filter.shouldApply(request));
+
+    verify(request, cookie);
+  }
+
+  @Test
+  public void testShouldApplyFalseMissingCookie() throws JOSEException {
+    JwtAuthenticationProperties properties = createTestProperties();
+    JwtAuthenticationFilter filter = new JwtAuthenticationFilter(properties, null, null);
+
+    Cookie cookie = createMock(Cookie.class);
+    expect(cookie.getName()).andReturn("some-other-cookie").atLeastOnce();
+
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    expect(request.getCookies()).andReturn(new Cookie[]{cookie});
+
+    replay(request, cookie);
+
+    Assert.assertFalse(filter.shouldApply(request));
+
+    verify(request, cookie);
+  }
+
+  @Test
+  public void testShouldApplyFalseNotEnabled() throws JOSEException {
+    JwtAuthenticationFilter filter = new JwtAuthenticationFilter((JwtAuthenticationProperties) null, null, null);
+
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+
+    replay(request);
+
+    Assert.assertFalse(filter.shouldApply(request));
+
+    verify(request);
+  }
 }
\ No newline at end of file


[2/2] ambari git commit: AMBARI-18367. Create authentication filter to encapsulate the various Ambari authentication methods (rlevas)

Posted by rl...@apache.org.
AMBARI-18367. Create authentication filter to encapsulate the various Ambari authentication methods (rlevas)


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

Branch: refs/heads/trunk
Commit: d5cca62c85f97118ed9e2a3e14729d9e6cb6023d
Parents: edf1b9b
Author: Robert Levas <rl...@hortonworks.com>
Authored: Thu Sep 15 13:19:32 2016 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Thu Sep 15 13:19:40 2016 -0400

----------------------------------------------------------------------
 .../ambari/server/controller/AmbariServer.java  |  15 +-
 .../server/controller/ControllerModule.java     |  12 +-
 .../AmbariAuthenticationFilter.java             | 158 ++------------
 .../AmbariBasicAuthenticationFilter.java        | 211 +++++++++++++++++++
 .../AmbariDelegatingAuthenticationFilter.java   | 146 +++++++++++++
 .../AmbariJWTAuthenticationFilter.java          | 139 ++++++++++++
 .../AmbariAuthorizationFilter.java              |  49 ++++-
 .../AuthenticationJwtUserNotFoundException.java |  43 ++++
 .../jwt/JwtAuthenticationFilter.java            | 162 ++++++++------
 .../webapp/WEB-INF/spring-security.xml          |  31 ++-
 .../AmbariAuthenticationFilterTest.java         | 139 ------------
 .../AmbariBasicAuthenticationFilterTest.java    | 139 ++++++++++++
 ...mbariDelegatingAuthenticationFilterTest.java | 186 ++++++++++++++++
 .../AmbariJWTAuthenticationFilterTest.java      | 190 +++++++++++++++++
 .../AmbariAuthorizationFilterTest.java          |  48 ++---
 .../jwt/JwtAuthenticationFilterTest.java        |  77 ++++++-
 16 files changed, 1347 insertions(+), 398 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index deac313..0e6e6b1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -7,7 +7,7 @@
  * "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
+ *     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,
@@ -99,15 +99,12 @@ import org.apache.ambari.server.security.AmbariServerSecurityHeaderFilter;
 import org.apache.ambari.server.security.AmbariViewsSecurityHeaderFilter;
 import org.apache.ambari.server.security.CertificateManager;
 import org.apache.ambari.server.security.SecurityFilter;
-import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
-import org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter;
 import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
 import org.apache.ambari.server.security.authorization.AmbariLocalUserProvider;
 import org.apache.ambari.server.security.authorization.AmbariUserAuthorizationFilter;
 import org.apache.ambari.server.security.authorization.PermissionHelper;
 import org.apache.ambari.server.security.authorization.Users;
 import org.apache.ambari.server.security.authorization.internal.AmbariInternalAuthenticationProvider;
-import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter;
 import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator;
 import org.apache.ambari.server.security.unsecured.rest.CertificateDownload;
 import org.apache.ambari.server.security.unsecured.rest.CertificateSign;
@@ -319,6 +316,8 @@ public class AmbariServer {
           getBeanFactory();
 
       factory.registerSingleton("guiceInjector", injector);
+      factory.registerSingleton("ambariConfiguration", injector.getInstance(Configuration.class));
+      factory.registerSingleton("ambariUsers", injector.getInstance(Users.class));
       factory.registerSingleton("passwordEncoder",
         injector.getInstance(PasswordEncoder.class));
       factory.registerSingleton("auditLogger",
@@ -331,16 +330,10 @@ public class AmbariServer {
         injector.getInstance(AmbariLocalUserProvider.class));
       factory.registerSingleton("ambariLdapDataPopulator",
         injector.getInstance(AmbariLdapDataPopulator.class));
-      factory.registerSingleton("ambariAuthorizationFilter",
-        injector.getInstance(AmbariAuthorizationFilter.class));
       factory.registerSingleton("ambariUserAuthorizationFilter",
         injector.getInstance(AmbariUserAuthorizationFilter.class));
       factory.registerSingleton("ambariInternalAuthenticationProvider",
         injector.getInstance(AmbariInternalAuthenticationProvider.class));
-      factory.registerSingleton("ambariJwtAuthenticationFilter",
-        injector.getInstance(JwtAuthenticationFilter.class));
-      factory.registerSingleton("ambariAuthenticationFilter",
-        injector.getInstance(AmbariAuthenticationFilter.class));
 
       // Spring Security xml config depends on this Bean
       String[] contextLocations = {SPRING_CONTEXT_LOCATION};

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index bd34c25..af710ee 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -6,9 +6,9 @@
  * 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/>
+ *
+ *     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.
@@ -88,7 +88,6 @@ import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
 import org.apache.ambari.server.scheduler.ExecutionScheduler;
 import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
-import org.apache.ambari.server.security.AmbariEntryPoint;
 import org.apache.ambari.server.security.SecurityHelper;
 import org.apache.ambari.server.security.SecurityHelperImpl;
 import org.apache.ambari.server.security.authorization.AuthorizationHelper;
@@ -144,7 +143,6 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
 import org.springframework.core.type.filter.AssignableTypeFilter;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.StandardPasswordEncoder;
-import org.springframework.security.web.AuthenticationEntryPoint;
 import org.springframework.util.ClassUtils;
 import org.springframework.web.filter.DelegatingFilterProxy;
 
@@ -369,8 +367,6 @@ public class ControllerModule extends AbstractModule {
 
     bind(PersistedState.class).to(PersistedStateImpl.class);
 
-    bind(AuthenticationEntryPoint.class).to(AmbariEntryPoint.class).in(Scopes.SINGLETON);
-
     // factory to create LoggingRequestHelper instances for LogSearch integration
     bind(LoggingRequestHelperFactory.class).to(LoggingRequestHelperFactoryImpl.class);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
index 0a312f3..b3bc4c3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -7,7 +7,7 @@
  * "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
+ *     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,
@@ -15,151 +15,35 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.apache.ambari.server.security.authentication;
 
-import java.io.IOException;
+import javax.servlet.Filter;
 import javax.servlet.FilterChain;
-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.ambari.server.audit.event.AuditEvent;
-import org.apache.ambari.server.audit.AuditLogger;
-import org.apache.ambari.server.audit.event.LoginAuditEvent;
-import org.apache.ambari.server.security.AmbariEntryPoint;
-import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
-import org.apache.ambari.server.utils.RequestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.BadCredentialsException;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.crypto.codec.Base64;
-import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 
 /**
- * The purpose of this class is to check whether authentication is successful or not,
- * and make an audit event
+ * AmbariAuthenticationFilter is a {@link Filter} interface to be implemented
+ * by authentication filters used by the Ambari server. More specifically, implementations
+ * of this interface may be used in the {@link AmbariDelegatingAuthenticationFilter}.
+ *
+ * @see AmbariDelegatingAuthenticationFilter
  */
-public class AmbariAuthenticationFilter extends BasicAuthenticationFilter {
-  private static final Logger LOG = LoggerFactory.getLogger(AmbariAuthenticationFilter.class);
-
-  /**
-   * Audit logger
-   */
-  private AuditLogger auditLogger;
-
-  private PermissionHelper permissionHelper;
-
-  public AmbariAuthenticationFilter() {
-    super();
-  }
-
-  public AmbariAuthenticationFilter(AuthenticationManager authenticationManager, AuditLogger auditLogger, PermissionHelper permissionHelper, AmbariEntryPoint ambariEntryPoint) {
-    super(authenticationManager, ambariEntryPoint);
-    this.auditLogger = auditLogger;
-    this.permissionHelper = permissionHelper;
-  }
-
-  /**
-   * Checks whether the authentication information is filled. If it is not, then a login failed audit event is logged
-   * @param req
-   * @param res
-   * @param chain
-   * @throws IOException
-   * @throws ServletException
-   */
-  @Override
-  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
-    HttpServletRequest request = (HttpServletRequest) req;
-    String header = request.getHeader("Authorization");
-    if (auditLogger.isEnabled() && AuthorizationHelper.getAuthenticatedName() == null && (header == null || !header.startsWith("Basic "))) {
-      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
-        .withRemoteIp(RequestUtils.getRemoteAddress(request))
-        .withTimestamp(System.currentTimeMillis())
-        .withReasonOfFailure("Authentication required")
-        .withUserName(null)
-        .build();
-      auditLogger.log(loginFailedAuditEvent);
-    }
-    super.doFilter(req, res, chain);
-  }
-
-  /**
-   * If the authentication was successful, then an audit event is logged about the success
-   * @param request
-   * @param response
-   * @param authResult
-   * @throws IOException
-   */
-  @Override
-  protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
-    if(!auditLogger.isEnabled()) {
-      return;
-    }
-    AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
-      .withRemoteIp(RequestUtils.getRemoteAddress(request))
-      .withUserName(authResult.getName())
-      .withTimestamp(System.currentTimeMillis())
-      .withRoles(permissionHelper.getPermissionLabels(authResult))
-      .build();
-    auditLogger.log(loginSucceededAuditEvent);
-  }
+public interface AmbariAuthenticationFilter extends Filter {
 
   /**
-   * In the case of invalid username or password, the authentication fails and it is logged
-   * @param request
-   * @param response
-   * @param authEx
-   * @throws IOException
+   * Tests this AmbariAuthenticationFilter to see if it should be applied to the filter chain
+   * - meaning its {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)} method
+   * should be called.
+   * <p>
+   * Each implementation will have its own requirements on whether it should be applied and care must
+   * be taken such that <code>true</code> is returned on if warranted, else other implementations may
+   * not get a chance to execute
+   *
+   * @param httpServletRequest the HttpServletRequest
+   * @return true if this AmbariAuthenticationFilter should be applied to the filter chain; otherwise false.
    */
-  @Override
-  protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) throws IOException {
-    String header = request.getHeader("Authorization");
-    String username = null;
-    try {
-      String[] decodedAuth = decodeAuth(header, request);
-      username = decodedAuth[0];
-    } catch (Exception e) {
-      LOG.warn("Error occurred during decoding authorization header.",e);
-    }
-    if(auditLogger.isEnabled()) {
-      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
-        .withRemoteIp(RequestUtils.getRemoteAddress(request))
-        .withTimestamp(System.currentTimeMillis())
-        .withReasonOfFailure("Invalid username/password combination")
-        .withUserName(username)
-        .build();
-      auditLogger.log(loginFailedAuditEvent);
-    }
-  }
-
-  /**
-   * Helper function to decode Authorization header
-   * @param header
-   * @param request
-   * @return
-   * @throws IOException
-   */
-  private String[] decodeAuth(String header, HttpServletRequest request) throws IOException {
-    byte[] base64Token = header.substring(6).getBytes("UTF-8");
-
-    byte[] decoded;
-    try {
-      decoded = Base64.decode(base64Token);
-    } catch (IllegalArgumentException ex) {
-      throw new BadCredentialsException("Failed to decode basic authentication token");
-    }
-
-    String token = new String(decoded, this.getCredentialsCharset(request));
-    int delim = token.indexOf(":");
-    if(delim == -1) {
-      throw new BadCredentialsException("Invalid basic authentication token");
-    } else {
-      return new String[]{token.substring(0, delim), token.substring(delim + 1)};
-    }
-  }
+  boolean shouldApply(HttpServletRequest httpServletRequest);
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
new file mode 100644
index 0000000..9e83f73
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilter.java
@@ -0,0 +1,211 @@
+/*
+ * 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.ambari.server.security.authentication;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+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.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
+import org.apache.ambari.server.security.AmbariEntryPoint;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.utils.RequestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+
+/**
+ * AmbariBasicAuthenticationFilter extends a {@link BasicAuthenticationFilter} to allow for auditing
+ * of authentication attempts
+ * <p>
+ * This authentication filter is expected to be used withing an {@link AmbariDelegatingAuthenticationFilter}.
+ *
+ * @see AmbariDelegatingAuthenticationFilter
+ */
+public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter implements AmbariAuthenticationFilter {
+  private static final Logger LOG = LoggerFactory.getLogger(AmbariBasicAuthenticationFilter.class);
+
+  /**
+   * Audit logger
+   */
+  private AuditLogger auditLogger;
+
+  /**
+   * PermissionHelper to help create audit entries
+   */
+  private PermissionHelper permissionHelper;
+
+  /**
+   * Constructor.
+   *
+   * @param authenticationManager the Spring authencation manager
+   * @param ambariEntryPoint      the Spring entry point
+   * @param auditLogger           an Audit Logger
+   * @param permissionHelper      a permission helper
+   */
+  public AmbariBasicAuthenticationFilter(AuthenticationManager authenticationManager,
+                                         AmbariEntryPoint ambariEntryPoint,
+                                         AuditLogger auditLogger,
+                                         PermissionHelper permissionHelper) {
+    super(authenticationManager, ambariEntryPoint);
+    this.auditLogger = auditLogger;
+    this.permissionHelper = permissionHelper;
+  }
+
+  /**
+   * Tests to see if this {@link AmbariBasicAuthenticationFilter} should be applied in the authentication
+   * filter chain.
+   * <p>
+   * <code>true</code> will be returned if the HTTP request contains the basic authentication header;
+   * otherwise <code>false</code> will be returned.
+   * <p>
+   * The basic authentication header is named "Authorization" and the value begins with the string
+   * "Basic" following by the encoded username and password information.
+   * <p>
+   * For example:
+   * <code>
+   * Authorization: Basic YWRtaW46YWRtaW4=
+   * </code>
+   *
+   * @param httpServletRequest the HttpServletRequest the HTTP service request
+   * @return <code>true</code> if the HTTP request contains the basic authentication header; otherwise <code>false</code>
+   */
+  @Override
+  public boolean shouldApply(HttpServletRequest httpServletRequest) {
+    String header = httpServletRequest.getHeader("Authorization");
+    return (header != null) && header.startsWith("Basic ");
+  }
+
+  /**
+   * Checks whether the authentication information is filled. If it is not, then a login failed audit event is logged
+   *
+   * @param servletRequest  the request
+   * @param servletResponse the response
+   * @param chain           the Spring filter chain
+   * @throws IOException
+   * @throws ServletException
+   */
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
+    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+
+    if (auditLogger.isEnabled() && shouldApply(httpServletRequest) && (AuthorizationHelper.getAuthenticatedName() == null)) {
+      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+          .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
+          .withTimestamp(System.currentTimeMillis())
+          .withReasonOfFailure("Authentication required")
+          .withUserName(null)
+          .build();
+      auditLogger.log(loginFailedAuditEvent);
+    }
+
+    super.doFilter(servletRequest, servletResponse, chain);
+  }
+
+  /**
+   * If the authentication was successful, then an audit event is logged about the success
+   *
+   * @param servletRequest  the request
+   * @param servletResponse the response
+   * @param authResult      the Authentication result
+   * @throws IOException
+   */
+  @Override
+  protected void onSuccessfulAuthentication(HttpServletRequest servletRequest,
+                                            HttpServletResponse servletResponse,
+                                            Authentication authResult) throws IOException {
+    if (auditLogger.isEnabled()) {
+      AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
+          .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
+          .withUserName(authResult.getName())
+          .withTimestamp(System.currentTimeMillis())
+          .withRoles(permissionHelper.getPermissionLabels(authResult))
+          .build();
+      auditLogger.log(loginSucceededAuditEvent);
+    }
+  }
+
+  /**
+   * In the case of invalid username or password, the authentication fails and it is logged
+   *
+   * @param servletRequest  the request
+   * @param servletResponse the response
+   * @param authExecption   the exception, if any, causing the unsuccessful authentication attempt
+   * @throws IOException
+   */
+  @Override
+  protected void onUnsuccessfulAuthentication(HttpServletRequest servletRequest,
+                                              HttpServletResponse servletResponse,
+                                              AuthenticationException authExecption) throws IOException {
+    String header = servletRequest.getHeader("Authorization");
+    String username = null;
+    try {
+      username = getUsernameFromAuth(header, getCredentialsCharset(servletRequest));
+    } catch (Exception e) {
+      LOG.warn("Error occurred during decoding authorization header.", e);
+    }
+    if (auditLogger.isEnabled()) {
+      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+          .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
+          .withTimestamp(System.currentTimeMillis())
+          .withReasonOfFailure("Invalid username/password combination")
+          .withUserName(username)
+          .build();
+      auditLogger.log(loginFailedAuditEvent);
+    }
+  }
+
+  /**
+   * Helper function to decode Authorization header
+   *
+   * @param authenticationValue the authentication value to parse
+   * @param charSet             the character set of the authentication value
+   * @return the username parsed from the authentication header value
+   * @throws IOException
+   */
+  private String getUsernameFromAuth(String authenticationValue, String charSet) throws IOException {
+    byte[] base64Token = authenticationValue.substring(6).getBytes("UTF-8");
+
+    byte[] decoded;
+    try {
+      decoded = Base64.decode(base64Token);
+    } catch (IllegalArgumentException ex) {
+      throw new BadCredentialsException("Failed to decode basic authentication token");
+    }
+
+    String token = new String(decoded, charSet);
+    int delimiter = token.indexOf(":");
+    if (delimiter == -1) {
+      throw new BadCredentialsException("Invalid basic authentication token");
+    } else {
+      return token.substring(0, delimiter);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilter.java
new file mode 100644
index 0000000..aab87a2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilter.java
@@ -0,0 +1,146 @@
+/*
+ * 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.ambari.server.security.authentication;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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 java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * The AmbariDelegatingAuthenticationFilter is an authentication filter that holds zero or more
+ * {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s.
+ * <p>
+ * This container iterates though the contained Filters to delegate {@link Filter} operations.
+ * For {@link Filter#init(FilterConfig)} and {@link Filter#destroy()} operations, all contained filters
+ * will be called.  For {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}, each
+ * filter will be accessed in order to test whether is should be used or skipped.  Once a filter
+ * claims it is to be used for the operation, interation stops ensuring at most only one of the contained
+ * filters is invoked.
+ */
+public class AmbariDelegatingAuthenticationFilter implements Filter {
+  private static final Logger LOG = LoggerFactory.getLogger(AmbariDelegatingAuthenticationFilter.class);
+
+  /**
+   * The ordered collections of {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s
+   */
+  private final Collection<AmbariAuthenticationFilter> filters;
+
+  /**
+   * Constructor.
+   *
+   * @param filters an ordered collections of {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s
+   */
+  public AmbariDelegatingAuthenticationFilter(Collection<AmbariAuthenticationFilter> filters) {
+
+    this.filters = (filters == null) ? Collections.<AmbariAuthenticationFilter>emptyList() : filters;
+
+    if (this.filters.isEmpty()) {
+      LOG.warn("The delegated filters list is empty. No authentication tests will be performed by this " +
+          "authentication filter.");
+    } else if (LOG.isDebugEnabled()) {
+      StringBuffer filterNames = new StringBuffer();
+
+      for (AmbariAuthenticationFilter filter : this.filters) {
+        filterNames.append("\n\t");
+        filterNames.append(filter.getClass().getName());
+      }
+
+      LOG.debug("This authentication filter will attempt to authenticate a user using one of the " +
+              "following delegated authentication filters: {}",
+          filterNames);
+    }
+  }
+
+  /**
+   * Iterates over the contained {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s
+   * to invoke each's init method.
+   *
+   * @param filterConfig a filter configuration
+   * @throws ServletException
+   */
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+    for (AmbariAuthenticationFilter filter : filters) {
+      filter.init(filterConfig);
+    }
+  }
+
+  /**
+   * Iterates over the contained {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s
+   * to test each to see if they should be invoked. If one tests positive, its doFilter method will be
+   * invoked and processing will stop ensuring only at most one of the contained filter is invoked.
+   *
+   * @param servletRequest  the request
+   * @param servletResponse the response
+   * @param chain           the Spring filter change
+   * @throws IOException
+   * @throws ServletException
+   */
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
+      throws IOException, ServletException {
+    boolean handled = false;
+    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+
+    for (AmbariAuthenticationFilter filter : filters) {
+      if (LOG.isTraceEnabled()) {
+        LOG.trace("Attempting to apply authentication filter {}", filter.getClass().getName());
+      }
+
+      if (filter.shouldApply(httpServletRequest)) {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Using authentication filter {} since it applies", filter.getClass().getName());
+        }
+
+        filter.doFilter(servletRequest, servletResponse, chain);
+        handled = true;
+        break;
+      } else {
+        if (LOG.isDebugEnabled()) {
+          LOG.debug("Filter {} does not apply skipping", filter.getClass().getName());
+        }
+      }
+    }
+
+    if (!handled) {
+      LOG.debug("No delegated filters applied while attempting to authenticate a user, continuing with the filter chain.");
+      chain.doFilter(servletRequest, servletResponse);
+    }
+  }
+
+  /**
+   * Iterates over the contained {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s
+   * to invoke each's destroy method.
+   */
+  @Override
+  public void destroy() {
+    for (AmbariAuthenticationFilter filter : filters) {
+      filter.destroy();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
new file mode 100644
index 0000000..2c15a38
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
@@ -0,0 +1,139 @@
+/*
+ * 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.ambari.server.security.authentication;
+
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.ambari.server.security.authorization.jwt.AuthenticationJwtUserNotFoundException;
+import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter;
+import org.apache.ambari.server.utils.RequestUtils;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * AmbariBasicAuthenticationFilter extends a {@link org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter}
+ * to allow for auditing of authentication attempts.
+ * <p>
+ * This authentication filter is expected to be used withing an {@link AmbariDelegatingAuthenticationFilter}.
+ *
+ * @see AmbariDelegatingAuthenticationFilter
+ */
+public class AmbariJWTAuthenticationFilter extends JwtAuthenticationFilter implements AmbariAuthenticationFilter {
+
+  /**
+   * Audit logger
+   */
+  private AuditLogger auditLogger;
+
+  /**
+   * PermissionHelper to help create audit entries
+   */
+  private PermissionHelper permissionHelper;
+
+
+  /**
+   * Constructor.
+   *
+   * @param ambariEntryPoint the Spring entry point
+   * @param configuration    the Ambari configuration
+   * @param users            the Ambari users object
+   * @param auditLogger      an Audit Logger
+   * @param permissionHelper a permission helper
+   */
+  public AmbariJWTAuthenticationFilter(AuthenticationEntryPoint ambariEntryPoint,
+                                       Configuration configuration,
+                                       Users users,
+                                       AuditLogger auditLogger,
+                                       PermissionHelper permissionHelper) {
+    super(configuration, ambariEntryPoint, users);
+    this.auditLogger = auditLogger;
+    this.permissionHelper = permissionHelper;
+  }
+
+  /**
+   * Checks whether the authentication information is filled. If it is not, then a login failed audit event is logged
+   *
+   * @param servletRequest  the request
+   * @param servletResponse the response
+   * @param chain           the Spring filter chain
+   * @throws IOException
+   * @throws ServletException
+   */
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
+    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+
+    if (auditLogger.isEnabled() && shouldApply(httpServletRequest) && (AuthorizationHelper.getAuthenticatedName() == null)) {
+      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+          .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
+          .withTimestamp(System.currentTimeMillis())
+          .withReasonOfFailure("Authentication required")
+          .withUserName(null)
+          .build();
+      auditLogger.log(loginFailedAuditEvent);
+    }
+
+    super.doFilter(servletRequest, servletResponse, chain);
+  }
+
+  @Override
+  protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
+    if (auditLogger.isEnabled()) {
+      AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
+          .withRemoteIp(RequestUtils.getRemoteAddress(request))
+          .withUserName(authResult.getName())
+          .withTimestamp(System.currentTimeMillis())
+          .withRoles(permissionHelper.getPermissionLabels(authResult))
+          .build();
+      auditLogger.log(loginSucceededAuditEvent);
+    }
+  }
+
+  @Override
+  protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
+    if (auditLogger.isEnabled()) {
+      String username = null;
+      if (authException instanceof AuthenticationJwtUserNotFoundException) {
+        username = ((AuthenticationJwtUserNotFoundException) authException).getUsername();
+      }
+
+      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+          .withRemoteIp(RequestUtils.getRemoteAddress(request))
+          .withTimestamp(System.currentTimeMillis())
+          .withReasonOfFailure(authException.getLocalizedMessage())
+          .withUserName(username)
+          .build();
+      auditLogger.log(loginFailedAuditEvent);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index 2f676b4..ac26a43 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.security.authorization;
 
-import com.google.inject.Inject;
 import org.apache.ambari.server.audit.event.AccessUnauthorizedAuditEvent;
 import org.apache.ambari.server.audit.event.AuditEvent;
 import org.apache.ambari.server.audit.AuditLogger;
@@ -26,11 +25,13 @@ import org.apache.ambari.server.audit.event.LoginAuditEvent;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.apache.ambari.server.security.AmbariEntryPoint;
 import org.apache.ambari.server.security.authorization.internal.InternalAuthenticationToken;
 import org.apache.ambari.server.utils.RequestUtils;
 import org.apache.ambari.server.view.ViewRegistry;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -91,27 +92,56 @@ public class AmbariAuthorizationFilter implements Filter {
   protected static final String LOGIN_REDIRECT_BASE = "/#/login?targetURI=";
 
   /**
+   * The Ambari authentication entry point
+   */
+  private final AmbariEntryPoint entryPoint;
+
+  /**
    * Access to Ambari configuration data
    */
-  @Inject
-  private Configuration configuration;
+  private final Configuration configuration;
 
   /**
    * Access to user information
    */
-  @Inject
-  private Users users;
+  private final Users users;
 
-  @Inject
-  private AuditLogger auditLogger;
+  /**
+   * The audit logger
+   */
+  private final AuditLogger auditLogger;
 
-  @Inject PermissionHelper permissionHelper;
+  /**
+   * A Permission Helper used to provided inforamtion for the Audit Logger
+   */
+  private final PermissionHelper permissionHelper;
 
   /**
    * The realm to use for the basic http auth
    */
   private String realm;
 
+  /**
+   * Constructor.
+   *
+   * @param entryPoint       the authentication entrypoint
+   * @param configuration    the Ambari configuration
+   * @param users            Ambari user access
+   * @param auditLogger      the Audit logger
+   * @param permissionHelper the permission helper
+   */
+  public AmbariAuthorizationFilter(AmbariEntryPoint entryPoint,
+                                   Configuration configuration,
+                                   Users users,
+                                   AuditLogger auditLogger,
+                                   PermissionHelper permissionHelper) {
+    this.entryPoint = entryPoint;
+    this.configuration = configuration;
+    this.users = users;
+    this.auditLogger = auditLogger;
+    this.permissionHelper = permissionHelper;
+  }
+
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
     realm = getParameterValue(filterConfig, REALM_PARAM, DEFAULT_REALM);
@@ -160,8 +190,7 @@ public class AmbariAuthorizationFilter implements Filter {
           String redirectURL = httpResponse.encodeRedirectURL(LOGIN_REDIRECT_BASE + requestedURL);
           httpResponse.sendRedirect(redirectURL);
         } else {
-          httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required");
-          httpResponse.flushBuffer();
+          entryPoint.commence(httpRequest, httpResponse, new AuthenticationCredentialsNotFoundException("Missing authentication token"));
         }
         return;
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java
new file mode 100644
index 0000000..f18af10
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/AuthenticationJwtUserNotFoundException.java
@@ -0,0 +1,43 @@
+/*
+ * 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.ambari.server.security.authorization.jwt;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * AuthenticationJwtUserNotFoundException is an AuthenticationException implementation to be thrown
+ * when the user specified in a JTW token is not found in the Ambari user database.
+ */
+public class AuthenticationJwtUserNotFoundException extends AuthenticationException {
+  private final String username;
+
+  public AuthenticationJwtUserNotFoundException(String username, String message) {
+    super(message);
+    this.username = username;
+  }
+
+  public AuthenticationJwtUserNotFoundException(String username, String message, Throwable throwable) {
+    super(message, throwable);
+    this.username = username;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
index 760621e..890326f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
@@ -17,13 +17,13 @@
  */
 package org.apache.ambari.server.security.authorization.jwt;
 
-import com.google.inject.Inject;
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWSObject;
 import com.nimbusds.jose.JWSVerifier;
 import com.nimbusds.jose.crypto.RSASSAVerifier;
 import com.nimbusds.jwt.SignedJWT;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
 import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
 import org.apache.ambari.server.security.authorization.User;
 import org.apache.ambari.server.security.authorization.UserType;
@@ -34,6 +34,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.AuthenticationEntryPoint;
 
@@ -52,8 +53,8 @@ import java.util.List;
  * Filter is used to validate JWT token and authenticate user.
  * It is also responsive for creating user in local Ambari database for further management
  */
-public class JwtAuthenticationFilter implements Filter {
-  Logger LOG = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
+public class JwtAuthenticationFilter implements AmbariAuthenticationFilter {
+  private static final Logger LOG = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
 
   private final JwtAuthenticationProperties jwtProperties;
 
@@ -67,7 +68,6 @@ public class JwtAuthenticationFilter implements Filter {
   private AuthenticationEntryPoint entryPoint;
   private Users users;
 
-  @Inject
   public JwtAuthenticationFilter(Configuration configuration, AuthenticationEntryPoint entryPoint, Users users) {
     this.entryPoint = entryPoint;
     this.users = users;
@@ -83,6 +83,28 @@ public class JwtAuthenticationFilter implements Filter {
     loadJwtProperties();
   }
 
+  /**
+   * Tests to see if this JwtAuthenticationFilter should be applied in the authentication
+   * filter chain.
+   * <p>
+   * <code>true</code> will be returned if JWT authentication is enabled and the HTTP request contains
+   * a JWT authentication token cookie; otherwise <code>false</code> will be returned.
+   *
+   * @param httpServletRequest the HttpServletRequest the HTTP service request
+   * @return <code>true</code> if the HTTP request contains the basic authentication header; otherwise <code>false</code>
+   */
+  @Override
+  public boolean shouldApply(HttpServletRequest httpServletRequest) {
+    boolean shouldApply = false;
+
+    if (jwtProperties != null) {
+      String serializedJWT = getJWTFromCookie(httpServletRequest);
+      shouldApply = (serializedJWT != null && isAuthenticationRequired(serializedJWT));
+    }
+
+    return shouldApply;
+  }
+
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
 
@@ -91,7 +113,7 @@ public class JwtAuthenticationFilter implements Filter {
   @Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 
-    if(jwtProperties == null){
+    if (jwtProperties == null) {
       //disable filter if not configured
       filterChain.doFilter(servletRequest, servletResponse);
       return;
@@ -100,71 +122,68 @@ public class JwtAuthenticationFilter implements Filter {
     HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
     HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
 
-    String serializedJWT = getJWTFromCookie(httpServletRequest);
-    if (serializedJWT != null && isAuthenticationRequired(serializedJWT)) {
-      SignedJWT jwtToken;
-      try {
-        jwtToken = SignedJWT.parse(serializedJWT);
-
-        boolean valid = validateToken(jwtToken);
-
-        if (valid) {
-          String userName = jwtToken.getJWTClaimsSet().getSubject();
-          User user = users.getUser(userName, UserType.JWT);
-          //fixme temporary solution for LDAP username conflicts, auth ldap users via JWT
-          if (user == null) {
-            user = users.getUser(userName, UserType.LDAP);
-          }
-
-          if (user == null) {
+    try {
+      String serializedJWT = getJWTFromCookie(httpServletRequest);
+      if (serializedJWT != null && isAuthenticationRequired(serializedJWT)) {
+        try {
+          SignedJWT jwtToken = SignedJWT.parse(serializedJWT);
 
-            //TODO this is temporary check for conflicts, until /users API will change to use user_id instead of name as PK
-            User existingUser = users.getUser(userName, UserType.LOCAL);
-            if (existingUser != null) {
+          boolean valid = validateToken(jwtToken);
 
-              LOG.error("Access for JWT user [{}] restricted. Detected conflict with local user ", userName);
+          if (valid) {
+            String userName = jwtToken.getJWTClaimsSet().getSubject();
+            User user = users.getUser(userName, UserType.JWT);
+            //fixme temporary solution for LDAP username conflicts, auth ldap users via JWT
+            if (user == null) {
+              user = users.getUser(userName, UserType.LDAP);
             }
 
-            //TODO we temporary expect that LDAP is configured to same server as JWT source
-            httpServletResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
-                    "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
-
-            //interrupt filter chain
-            return;
-          }
-
-          Collection<AmbariGrantedAuthority> userAuthorities =
-                  users.getUserAuthorities(user.getUserName(), user.getUserType());
-
-          JwtAuthentication authentication = new JwtAuthentication(serializedJWT, user, userAuthorities);
-          authentication.setAuthenticated(true);
+            if (user == null) {
+              //TODO this is temporary check for conflicts, until /users API will change to use user_id instead of name as PK
+              User existingUser = users.getUser(userName, UserType.LOCAL);
+              if (existingUser != null) {
+                LOG.error("Access for JWT user [{}] restricted. Detected conflict with local user ", userName);
+              }
 
-          SecurityContextHolder.getContext().setAuthentication(authentication);
+              //TODO we temporary expect that LDAP is configured to same server as JWT source
+              throw new AuthenticationJwtUserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
+            }
 
+            Collection<AmbariGrantedAuthority> userAuthorities =
+                users.getUserAuthorities(user.getUserName(), user.getUserType());
 
-        } else {
-          //clear security context if authentication was required, but failed
-          SecurityContextHolder.clearContext();
+            JwtAuthentication authentication = new JwtAuthentication(serializedJWT, user, userAuthorities);
+            authentication.setAuthenticated(true);
 
-          LOG.warn("JWT authentication failed");
-          if (ignoreFailure) {
-            filterChain.doFilter(servletRequest, servletResponse);
+            SecurityContextHolder.getContext().setAuthentication(authentication);
+            onSuccessfulAuthentication(httpServletRequest, httpServletResponse, authentication);
           } else {
-            //used to indicate authentication failure, not used here as we have more than one filter
-            entryPoint.commence(httpServletRequest, httpServletResponse, new BadCredentialsException("Invalid JWT " +
-                    "token"));
+            throw new BadCredentialsException("Invalid JWT token");
           }
+        } catch (ParseException e) {
+          LOG.warn("Unable to parse the JWT token", e);
+          throw new BadCredentialsException("Unable to parse the JWT token - " + e.getLocalizedMessage());
         }
+      } else {
+        LOG.trace("No JWT cookie found, do nothing");
+      }
+
+      filterChain.doFilter(servletRequest, servletResponse);
+    } catch (AuthenticationException e) {
+      LOG.warn("JWT authentication failed - {}", e.getLocalizedMessage());
 
+      //clear security context if authentication was required, but failed
+      SecurityContextHolder.clearContext();
 
-      } catch (ParseException e) {
-        LOG.warn("Unable to parse the JWT token", e);
+      onUnsuccessfulAuthentication(httpServletRequest, httpServletResponse, e);
+
+      if (ignoreFailure) {
+        filterChain.doFilter(servletRequest, servletResponse);
+      } else {
+        //used to indicate authentication failure, not used here as we have more than one filter
+        entryPoint.commence(httpServletRequest, httpServletResponse, e);
       }
-    } else {
-      LOG.trace("No JWT cookie found, do nothing");
     }
-
-    filterChain.doFilter(servletRequest, servletResponse);
   }
 
   private void loadJwtProperties() {
@@ -179,18 +198,19 @@ public class JwtAuthenticationFilter implements Filter {
 
   /**
    * Do not try to validate JWT if user already authenticated via other provider
+   *
    * @return true, if JWT validation required
    */
   private boolean isAuthenticationRequired(String token) {
     Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication();
 
     //authenticate if no auth
-    if(existingAuth == null || !existingAuth.isAuthenticated() ){
+    if (existingAuth == null || !existingAuth.isAuthenticated()) {
       return true;
     }
 
     //revalidate if token was changed
-    if(existingAuth instanceof JwtAuthentication && !StringUtils.equals(token, (String) existingAuth.getCredentials())){
+    if (existingAuth instanceof JwtAuthentication && !StringUtils.equals(token, (String) existingAuth.getCredentials())) {
       return true;
     }
 
@@ -224,6 +244,7 @@ public class JwtAuthenticationFilter implements Filter {
     }
     return serializedJWT;
   }
+
   /**
    * Create the URL to be used for authentication of the user in the absence of
    * a JWT token within the incoming request.
@@ -304,8 +325,7 @@ public class JwtAuthenticationFilter implements Filter {
    * issued token claims list for audience. Override this method in subclasses
    * in order to customize the audience validation behavior.
    *
-   * @param jwtToken
-   *          the JWT token where the allowed audiences will be found
+   * @param jwtToken the JWT token where the allowed audiences will be found
    * @return true if an expected audience is present, otherwise false
    */
   protected boolean validateAudiences(SignedJWT jwtToken) {
@@ -366,6 +386,30 @@ public class JwtAuthenticationFilter implements Filter {
     return valid;
   }
 
+  /**
+   * Called to declare an authentication attempt was successful.  Classes may override this method
+   * to perform additional tasks when authentication completes.
+   *
+   * @param request    the request
+   * @param response   the response
+   * @param authResult the authenticated user
+   * @throws IOException
+   */
+  protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
+  }
+
+  /**
+   * Called to declare an authentication attempt failed.  Classes may override this method
+   * to perform additional tasks when authentication fails.
+   *
+   * @param request       the request
+   * @param response      the response
+   * @param authException the cause for the faulure
+   * @throws IOException
+   */
+  protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
+  }
+
   @Override
   public void destroy() {
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
index e1697e2..a86973c 100644
--- a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
+++ b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
@@ -26,8 +26,7 @@
         disable-url-rewriting="true" entry-point-ref="ambariEntryPoint">
     <intercept-url pattern="/**" access="isAuthenticated()"/>
     <custom-filter ref="ambariUserAuthorizationFilter" before="BASIC_AUTH_FILTER"/>
-    <custom-filter ref="ambariAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
-    <custom-filter ref="ambariJwtAuthenticationFilter" after="BASIC_AUTH_FILTER" />
+    <custom-filter ref="ambariDelegatingAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
     <custom-filter ref="ambariAuthorizationFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
   </http>
 
@@ -46,10 +45,36 @@
   <beans:bean id="ambariEntryPoint" class="org.apache.ambari.server.security.AmbariEntryPoint">
   </beans:bean>
 
-  <beans:bean id="ambariAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter">
+  <beans:bean id="ambariDelegatingAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariDelegatingAuthenticationFilter">
+    <beans:constructor-arg>
+      <beans:list>
+        <beans:ref bean="ambariBasicAuthenticationFilter"/>
+        <beans:ref bean="ambariJwtAuthenticationFilter"/>
+      </beans:list>
+    </beans:constructor-arg>
+  </beans:bean>
+
+  <beans:bean id="ambariBasicAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariBasicAuthenticationFilter">
     <beans:constructor-arg ref="authenticationManager"/>
+    <beans:constructor-arg ref="ambariEntryPoint"/>
     <beans:constructor-arg ref="auditLogger"/>
     <beans:constructor-arg ref="permissionHelper"/>
+  </beans:bean>
+
+  <beans:bean id="ambariJwtAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariJWTAuthenticationFilter">
     <beans:constructor-arg ref="ambariEntryPoint"/>
+    <beans:constructor-arg ref="ambariConfiguration"/>
+    <beans:constructor-arg ref="ambariUsers"/>
+    <beans:constructor-arg ref="auditLogger"/>
+    <beans:constructor-arg ref="permissionHelper"/>
   </beans:bean>
+
+  <beans:bean id="ambariAuthorizationFilter" class="org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter">
+    <beans:constructor-arg ref="ambariEntryPoint"/>
+    <beans:constructor-arg ref="ambariConfiguration"/>
+    <beans:constructor-arg ref="ambariUsers"/>
+    <beans:constructor-arg ref="auditLogger"/>
+    <beans:constructor-arg ref="permissionHelper"/>
+  </beans:bean>
+
 </beans:beans>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilterTest.java
deleted file mode 100644
index 0f2b104..0000000
--- a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilterTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * 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.ambari.server.security.authentication;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.ambari.server.audit.event.AuditEvent;
-import org.apache.ambari.server.audit.AuditLogger;
-import org.apache.ambari.server.security.AmbariEntryPoint;
-import org.apache.ambari.server.security.authorization.AuthorizationHelper;
-import org.apache.ambari.server.security.authorization.PermissionHelper;
-import org.junit.runner.RunWith;
-import org.powermock.api.easymock.PowerMock;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-import org.springframework.security.crypto.codec.Base64;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest(AuthorizationHelper.class)
-public class AmbariAuthenticationFilterTest {
-
-  private AmbariAuthenticationFilter underTest;
-
-  private AuditLogger mockedAuditLogger;
-
-  private PermissionHelper permissionHelper;
-
-  private AmbariEntryPoint entryPoint;
-
-  @Before
-  public void setUp() {
-    mockedAuditLogger = createMock(AuditLogger.class);
-    permissionHelper = createMock(PermissionHelper.class);
-    entryPoint = createMock(AmbariEntryPoint.class);
-    underTest = new AmbariAuthenticationFilter(null, mockedAuditLogger, permissionHelper, entryPoint);
-    replay(entryPoint);
-  }
-
-  @Test
-  public void testDoFilter() throws IOException, ServletException {
-    // GIVEN
-    HttpServletRequest request = createMock(HttpServletRequest.class);
-    HttpServletResponse response = createMock(HttpServletResponse.class);
-    FilterChain filterChain = createMock(FilterChain.class);
-    expect(request.getHeader("Authorization")).andReturn("header").andReturn(null);
-    expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
-    expect(mockedAuditLogger.isEnabled()).andReturn(true);
-    mockedAuditLogger.log(anyObject(AuditEvent.class));
-    expectLastCall().times(1);
-    filterChain.doFilter(request, response);
-    expectLastCall();
-    replay(mockedAuditLogger, request, filterChain);
-    // WHEN
-    underTest.doFilter(request, response, filterChain);
-    // THEN
-    verify(mockedAuditLogger, request, filterChain);
-  }
-
-  @Test
-  public void testOnSuccessfulAuthentication() throws IOException, ServletException {
-    // GIVEN
-    HttpServletRequest request = createMock(HttpServletRequest.class);
-    HttpServletResponse response = createMock(HttpServletResponse.class);
-    Authentication authentication = createMock(Authentication.class);
-    PowerMock.mockStatic(AuthorizationHelper.class);
-
-    Map<String, List<String>> roles = new HashMap<>();
-    roles.put("a", Arrays.asList("r1", "r2", "r3"));
-    expect(permissionHelper.getPermissionLabels(authentication))
-      .andReturn(roles);
-    expect(AuthorizationHelper.getAuthorizationNames(authentication))
-      .andReturn(Arrays.asList("perm1", "perm2"));
-    expect(AuthorizationHelper.getAuthenticatedName()).andReturn("perm1");
-    expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
-    expect(authentication.getName()).andReturn("admin");
-    expect(mockedAuditLogger.isEnabled()).andReturn(true);
-    mockedAuditLogger.log(anyObject(AuditEvent.class));
-    expectLastCall().times(1);
-    replay(mockedAuditLogger, request, authentication, permissionHelper);
-    PowerMock.replayAll();
-    // WHEN
-    underTest.onSuccessfulAuthentication(request, response, authentication);
-    // THEN
-    verify(mockedAuditLogger, request);
-  }
-
-  @Test
-  public void testOnUnsuccessfulAuthentication() throws IOException, ServletException {
-    // GIVEN
-    HttpServletRequest request = createMock(HttpServletRequest.class);
-    HttpServletResponse response = createMock(HttpServletResponse.class);
-    AuthenticationException authEx = createMock(AuthenticationException.class);
-    expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
-    expect(request.getHeader("Authorization")).andReturn(
-      "Basic " + new String(Base64.encode("admin:admin".getBytes("UTF-8"))));
-    expect(mockedAuditLogger.isEnabled()).andReturn(true);
-    mockedAuditLogger.log(anyObject(AuditEvent.class));
-    expectLastCall().times(1);
-    replay(mockedAuditLogger, request, authEx);
-    // WHEN
-    underTest.onUnsuccessfulAuthentication(request, response, authEx);
-    // THEN
-    verify(mockedAuditLogger, request, authEx);
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
new file mode 100644
index 0000000..7344b62
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariBasicAuthenticationFilterTest.java
@@ -0,0 +1,139 @@
+/**
+ * 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.ambari.server.security.authentication;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.security.AmbariEntryPoint;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.junit.runner.RunWith;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import org.springframework.security.crypto.codec.Base64;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(AuthorizationHelper.class)
+public class AmbariBasicAuthenticationFilterTest {
+
+  private AmbariBasicAuthenticationFilter underTest;
+
+  private AuditLogger mockedAuditLogger;
+
+  private PermissionHelper permissionHelper;
+
+  private AmbariEntryPoint entryPoint;
+
+  @Before
+  public void setUp() {
+    mockedAuditLogger = createMock(AuditLogger.class);
+    permissionHelper = createMock(PermissionHelper.class);
+    entryPoint = createMock(AmbariEntryPoint.class);
+    underTest = new AmbariBasicAuthenticationFilter(null, entryPoint, mockedAuditLogger, permissionHelper);
+    replay(entryPoint);
+  }
+
+  @Test
+  public void testDoFilter() throws IOException, ServletException {
+    // GIVEN
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    HttpServletResponse response = createMock(HttpServletResponse.class);
+    FilterChain filterChain = createMock(FilterChain.class);
+    expect(request.getHeader("Authorization")).andReturn("Basic ").andReturn(null);
+    expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
+    expect(mockedAuditLogger.isEnabled()).andReturn(true);
+    mockedAuditLogger.log(anyObject(AuditEvent.class));
+    expectLastCall().times(1);
+    filterChain.doFilter(request, response);
+    expectLastCall();
+    replay(mockedAuditLogger, request, filterChain);
+    // WHEN
+    underTest.doFilter(request, response, filterChain);
+    // THEN
+    verify(mockedAuditLogger, request, filterChain);
+  }
+
+  @Test
+  public void testOnSuccessfulAuthentication() throws IOException, ServletException {
+    // GIVEN
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    HttpServletResponse response = createMock(HttpServletResponse.class);
+    Authentication authentication = createMock(Authentication.class);
+    PowerMock.mockStatic(AuthorizationHelper.class);
+
+    Map<String, List<String>> roles = new HashMap<>();
+    roles.put("a", Arrays.asList("r1", "r2", "r3"));
+    expect(permissionHelper.getPermissionLabels(authentication))
+      .andReturn(roles);
+    expect(AuthorizationHelper.getAuthorizationNames(authentication))
+      .andReturn(Arrays.asList("perm1", "perm2"));
+    expect(AuthorizationHelper.getAuthenticatedName()).andReturn("perm1");
+    expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
+    expect(authentication.getName()).andReturn("admin");
+    expect(mockedAuditLogger.isEnabled()).andReturn(true);
+    mockedAuditLogger.log(anyObject(AuditEvent.class));
+    expectLastCall().times(1);
+    replay(mockedAuditLogger, request, authentication, permissionHelper);
+    PowerMock.replayAll();
+    // WHEN
+    underTest.onSuccessfulAuthentication(request, response, authentication);
+    // THEN
+    verify(mockedAuditLogger, request);
+  }
+
+  @Test
+  public void testOnUnsuccessfulAuthentication() throws IOException, ServletException {
+    // GIVEN
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    HttpServletResponse response = createMock(HttpServletResponse.class);
+    AuthenticationException authEx = createMock(AuthenticationException.class);
+    expect(request.getHeader("X-Forwarded-For")).andReturn("1.2.3.4");
+    expect(request.getHeader("Authorization")).andReturn(
+      "Basic " + new String(Base64.encode("admin:admin".getBytes("UTF-8"))));
+    expect(mockedAuditLogger.isEnabled()).andReturn(true);
+    mockedAuditLogger.log(anyObject(AuditEvent.class));
+    expectLastCall().times(1);
+    replay(mockedAuditLogger, request, authEx);
+    // WHEN
+    underTest.onUnsuccessfulAuthentication(request, response, authEx);
+    // THEN
+    verify(mockedAuditLogger, request, authEx);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/d5cca62c/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilterTest.java
new file mode 100644
index 0000000..d775136
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/AmbariDelegatingAuthenticationFilterTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.ambari.server.security.authentication;
+
+import org.easymock.EasyMockSupport;
+import org.junit.Test;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+
+public class AmbariDelegatingAuthenticationFilterTest extends EasyMockSupport {
+  @Test
+  public void testInit() throws Exception {
+    FilterConfig filterConfig = createMock(FilterConfig.class);
+
+    AmbariAuthenticationFilter filter1 = createMock(AmbariAuthenticationFilter.class);
+    filter1.init(filterConfig);
+    expectLastCall().once();
+
+    AmbariAuthenticationFilter filter2 = createMock(AmbariAuthenticationFilter.class);
+    filter2.init(filterConfig);
+    expectLastCall().once();
+
+    AmbariAuthenticationFilter filter3 = createMock(AmbariAuthenticationFilter.class);
+    filter3.init(filterConfig);
+    expectLastCall().once();
+
+    replayAll();
+
+    Filter filter = new AmbariDelegatingAuthenticationFilter(Arrays.asList(filter1, filter2, filter3));
+    filter.init(filterConfig);
+
+    verifyAll();
+  }
+
+  @Test
+  public void testDoFilterNoneApply() throws Exception {
+    HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
+    HttpServletResponse httpServletResponse = createMock(HttpServletResponse.class);
+
+    AmbariAuthenticationFilter filter1 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter1.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    AmbariAuthenticationFilter filter2 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter2.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    AmbariAuthenticationFilter filter3 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter3.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    FilterChain filterChain = createMock(FilterChain.class);
+    filterChain.doFilter(httpServletRequest, httpServletResponse);
+    expectLastCall().once();
+
+    replayAll();
+
+    Filter filter = new AmbariDelegatingAuthenticationFilter(Arrays.asList(filter1, filter2, filter3));
+    filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
+
+    verifyAll();
+  }
+
+  @Test
+  public void testDoFilterFirstApplies() throws Exception {
+    HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
+    HttpServletResponse httpServletResponse = createMock(HttpServletResponse.class);
+
+    FilterChain filterChain = createMock(FilterChain.class);
+
+    AmbariAuthenticationFilter filter1 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter1.shouldApply(httpServletRequest)).andReturn(true).once();
+    filter1.doFilter(httpServletRequest, httpServletResponse, filterChain);
+    expectLastCall().once();
+
+    AmbariAuthenticationFilter filter2 = createMock(AmbariAuthenticationFilter.class);
+
+    AmbariAuthenticationFilter filter3 = createMock(AmbariAuthenticationFilter.class);
+
+    replayAll();
+
+    Filter filter = new AmbariDelegatingAuthenticationFilter(Arrays.asList(filter1, filter2, filter3));
+    filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
+
+    verifyAll();
+  }
+
+  @Test
+  public void testDoFilterLastApplies() throws Exception {
+    HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
+    HttpServletResponse httpServletResponse = createMock(HttpServletResponse.class);
+
+    FilterChain filterChain = createMock(FilterChain.class);
+
+    AmbariAuthenticationFilter filter1 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter1.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    AmbariAuthenticationFilter filter2 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter2.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    AmbariAuthenticationFilter filter3 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter3.shouldApply(httpServletRequest)).andReturn(true).once();
+    filter3.doFilter(httpServletRequest, httpServletResponse, filterChain);
+    expectLastCall().once();
+
+    replayAll();
+
+    Filter filter = new AmbariDelegatingAuthenticationFilter(Arrays.asList(filter1, filter2, filter3));
+    filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
+
+    verifyAll();
+  }
+
+  @Test
+  public void testDoFilterNthApplies() throws Exception {
+    HttpServletRequest httpServletRequest = createMock(HttpServletRequest.class);
+    HttpServletResponse httpServletResponse = createMock(HttpServletResponse.class);
+
+    FilterChain filterChain = createMock(FilterChain.class);
+
+    AmbariAuthenticationFilter filter1 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter1.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    AmbariAuthenticationFilter filter2 = createMock(AmbariAuthenticationFilter.class);
+    expect(filter2.shouldApply(httpServletRequest)).andReturn(false).once();
+
+    AmbariAuthenticationFilter filterN = createMock(AmbariAuthenticationFilter.class);
+    expect(filterN.shouldApply(httpServletRequest)).andReturn(true).once();
+    filterN.doFilter(httpServletRequest, httpServletResponse, filterChain);
+    expectLastCall().once();
+
+    AmbariAuthenticationFilter filter3 = createMock(AmbariAuthenticationFilter.class);
+
+    replayAll();
+
+    Filter filter = new AmbariDelegatingAuthenticationFilter(Arrays.asList(filter1, filter2, filterN, filter3));
+    filter.doFilter(httpServletRequest, httpServletResponse, filterChain);
+
+    verifyAll();
+  }
+
+  @Test
+  public void testDestroy() throws Exception {
+    AmbariAuthenticationFilter filter1 = createMock(AmbariAuthenticationFilter.class);
+    filter1.destroy();
+    expectLastCall().once();
+
+    AmbariAuthenticationFilter filter2 = createMock(AmbariAuthenticationFilter.class);
+    filter2.destroy();
+    expectLastCall().once();
+
+    AmbariAuthenticationFilter filter3 = createMock(AmbariAuthenticationFilter.class);
+    filter3.destroy();
+    expectLastCall().once();
+
+    replayAll();
+
+    Filter filter = new AmbariDelegatingAuthenticationFilter(Arrays.asList(filter1, filter2, filter3));
+    filter.destroy();
+
+    verifyAll();
+
+  }
+
+}
\ No newline at end of file