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 2017/10/17 15:58:25 UTC

[2/2] ambari git commit: AMBARI-21217. Update JWT Authentication process to work with improved user management facility (rlevas)

AMBARI-21217. Update JWT Authentication process to work with improved user management facility (rlevas)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 553e4f9d25573c54860d08b0494caefd77398977
Parents: 7bb4de1
Author: Robert Levas <rl...@hortonworks.com>
Authored: Tue Oct 17 11:56:42 2017 -0400
Committer: Robert Levas <rl...@hortonworks.com>
Committed: Tue Oct 17 11:58:06 2017 -0400

----------------------------------------------------------------------
 .../ambari/server/api/AmbariErrorHandler.java   |   2 +-
 .../server/configuration/Configuration.java     |   4 +-
 .../ambari/server/controller/AmbariServer.java  |   3 +
 .../AmbariAuthenticationEventHandlerImpl.java   |  20 +-
 .../AmbariAuthenticationFilter.java             |  10 +
 .../AmbariAuthenticationProvider.java           |  21 +-
 .../AmbariBasicAuthenticationFilter.java        |   5 +
 .../AmbariJWTAuthenticationFilter.java          | 114 -----
 .../AmbariLocalAuthenticationProvider.java      |  28 +-
 .../AmbariUserAuthentication.java               |  79 +++
 .../authentication/UserNotFoundException.java   |   9 +
 .../jwt/AmbariJwtAuthenticationFilter.java      | 419 ++++++++++++++++
 .../jwt/AmbariJwtAuthenticationProvider.java    | 126 +++++
 .../jwt/JwtAuthenticationProperties.java        |  87 ++++
 .../jwt/JwtAuthenticationToken.java             |  55 +++
 .../AmbariKerberosAuthenticationFilter.java     |   6 +
 .../AmbariPamAuthenticationProvider.java        |   1 +
 .../authorization/AmbariUserAuthentication.java |  76 ---
 .../AmbariUserAuthorizationFilter.java          |   1 +
 .../authorization/jwt/JwtAuthentication.java    |  34 --
 .../jwt/JwtAuthenticationFilter.java            | 448 -----------------
 .../jwt/JwtAuthenticationProperties.java        |  87 ----
 .../security/ldap/AmbariLdapDataPopulator.java  |   2 +-
 .../webapp/WEB-INF/spring-security.xml          |   4 +-
 .../server/security/SecurityHelperImplTest.java |   2 +-
 .../AbstractAuthenticationProviderTest.java     |   1 -
 .../AmbariJWTAuthenticationFilterTest.java      | 225 ---------
 .../AmbariLocalAuthenticationProviderTest.java  |   1 -
 .../jwt/AmbariJwtAuthenticationFilterTest.java  | 492 +++++++++++++++++++
 .../jwt/JwtAuthenticationPropertiesTest.java    |  51 ++
 .../AmbariPamAuthenticationProviderTest.java    |   1 +
 .../authorization/AuthorizationHelperTest.java  |   1 +
 .../jwt/JwtAuthenticationFilterTest.java        | 371 --------------
 .../jwt/JwtAuthenticationPropertiesTest.java    |  51 --
 34 files changed, 1395 insertions(+), 1442 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
index a57effc..de416d7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/api/AmbariErrorHandler.java
@@ -26,7 +26,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
+import org.apache.ambari.server.security.authentication.jwt.JwtAuthenticationProperties;
 import org.eclipse.jetty.http.HttpStatus;
 import org.eclipse.jetty.http.MimeTypes;
 import org.eclipse.jetty.server.AbstractHttpConnection;

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index 62e8b86..2b14b4d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -63,10 +63,10 @@ import org.apache.ambari.server.orm.PersistenceType;
 import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
 import org.apache.ambari.server.orm.entities.StageEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
+import org.apache.ambari.server.security.authentication.jwt.JwtAuthenticationProperties;
 import org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosAuthenticationProperties;
 import org.apache.ambari.server.security.authorization.LdapServerProperties;
 import org.apache.ambari.server.security.authorization.UserAuthenticationType;
-import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationProperties;
 import org.apache.ambari.server.security.encryption.CertificateUtils;
 import org.apache.ambari.server.security.encryption.CredentialProvider;
 import org.apache.ambari.server.state.services.MetricsRetrievalService;
@@ -5299,7 +5299,7 @@ public class Configuration {
     if (enableJwt) {
       String providerUrl = getProperty(JWT_AUTH_PROVIDER_URL);
       if (providerUrl == null) {
-        LOG.error("JWT authentication provider URL not specified. JWT auth will be disabled.", providerUrl);
+        LOG.error("JWT authentication provider URL not specified. JWT auth will be disabled.");
         return null;
       }
       String publicKeyPath = getProperty(JWT_PUBLIC);

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/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 0d24ef2..bb8e0fe 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
@@ -101,6 +101,7 @@ import org.apache.ambari.server.security.CertificateManager;
 import org.apache.ambari.server.security.SecurityFilter;
 import org.apache.ambari.server.security.authentication.AmbariAuthenticationEventHandlerImpl;
 import org.apache.ambari.server.security.authentication.AmbariLocalAuthenticationProvider;
+import org.apache.ambari.server.security.authentication.jwt.AmbariJwtAuthenticationProvider;
 import org.apache.ambari.server.security.authorization.AmbariLdapAuthenticationProvider;
 import org.apache.ambari.server.security.authorization.AmbariPamAuthenticationProvider;
 import org.apache.ambari.server.security.authorization.AmbariUserAuthorizationFilter;
@@ -349,6 +350,8 @@ public class AmbariServer {
         injector.getInstance(AmbariInternalAuthenticationProvider.class));
       factory.registerSingleton("ambariPamAuthenticationProvider",
 	      injector.getInstance(AmbariPamAuthenticationProvider.class));
+      factory.registerSingleton("ambariJwtAuthenticationProvider",
+	      injector.getInstance(AmbariJwtAuthenticationProvider.class));
 
       // Spring Security xml config depends on this Bean
       String[] contextLocations = {SPRING_CONTEXT_LOCATION};

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
index 4cfce2a..e651d22 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationEventHandlerImpl.java
@@ -107,15 +107,21 @@ public class AmbariAuthenticationEventHandlerImpl implements AmbariAuthenticatio
     }
 
     if (!StringUtils.isEmpty(username)) {
-      // Increment the user's consecutive authentication failure count.
-      consecutiveFailures = users.incrementConsecutiveAuthenticationFailures(username);
-
-      // If consecutiveFailures is NULL, then no user entry was found for the specified username.
-      if(consecutiveFailures == null) {
-        logMessage = String.format("Failed to authenticate %s: The user does not exist in the Ambari database", username);
+      // Only increment the authentication failure count if the authentication filter declares to
+      // do so.
+      if(filter.shouldIncrementFailureCount()) {
+        // Increment the user's consecutive authentication failure count.
+        consecutiveFailures = users.incrementConsecutiveAuthenticationFailures(username);
+
+        // If consecutiveFailures is NULL, then no user entry was found for the specified username.
+        if (consecutiveFailures == null) {
+          logMessage = String.format("Failed to authenticate %s: The user does not exist in the Ambari database", username);
+        } else {
+          logMessage = String.format("Failed to authenticate %s (attempt #%d): %s", username, consecutiveFailures, message);
+        }
       }
       else {
-        logMessage = String.format("Failed to authenticate %s (attempt #%d): %s", username, consecutiveFailures, message);
+        logMessage = String.format("Failed to authenticate %s: %s", username, message);
       }
     } else {
       logMessage = String.format("Failed to authenticate an unknown user: %s", message);

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/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 b3bc4c3..f5d5617 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
@@ -46,4 +46,14 @@ public interface AmbariAuthenticationFilter extends Filter {
    * @return true if this AmbariAuthenticationFilter should be applied to the filter chain; otherwise false.
    */
   boolean shouldApply(HttpServletRequest httpServletRequest);
+
+  /**
+   * Tests this AmbariAuthenticationFilter to see if authentication failures should count towards
+   * the consecutive authentication failure count.
+   * <p>
+   * This should typically be false for remote authentication sources such as LDAP or JWT.
+   *
+   * @return true if authentication failure should be counted; false, otherwise
+   */
+  boolean shouldIncrementFailureCount();
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java
index 3d20cb9..d3d5b88 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationProvider.java
@@ -34,13 +34,13 @@ import org.springframework.security.authentication.AuthenticationProvider;
  * <p>
  * This class contains common methods that may be used by authentication providers.
  */
-abstract class AmbariAuthenticationProvider implements AuthenticationProvider {
+public abstract class AmbariAuthenticationProvider implements AuthenticationProvider {
   private static final Logger LOG = LoggerFactory.getLogger(AmbariAuthenticationProvider.class);
 
   private Users users;
   private Configuration configuration;
 
-  AmbariAuthenticationProvider(Users users, Configuration configuration) {
+  protected AmbariAuthenticationProvider(Users users, Configuration configuration) {
     this.users = users;
     this.configuration = configuration;
   }
@@ -49,24 +49,31 @@ abstract class AmbariAuthenticationProvider implements AuthenticationProvider {
    * Gets the {@link UserEntity} for the user with the specified username.
    * <p>
    * The entity is validated such that the account is allowed to log in before returning. For example,
-   * if the account is not acitve, no user may not login as that account.
+   * if the account is not active, no user may not login as that account.
    *
    * @param userName
    * @return
    */
-  UserEntity getUserEntity(String userName) {
+  protected UserEntity getUserEntity(String userName) {
     LOG.debug("Loading user by name: {}", userName);
     UserEntity userEntity = users.getUserEntity(userName);
 
     if (userEntity == null) {
       LOG.info("User not found: {}", userName);
-      throw new InvalidUsernamePasswordCombinationException(userName);
+      throw new UserNotFoundException(userName);
     }
 
     if (!userEntity.getActive()) {
       LOG.info("User account is disabled: {}", userName);
+      throw new AccountDisabledException(userName);
+    }
+
+    int maxConsecutiveFailures = configuration.getMaxAuthenticationFailures();
+    if (maxConsecutiveFailures > 0 && userEntity.getConsecutiveFailures() >= maxConsecutiveFailures) {
+      LOG.info("User account is locked out due to too many authentication failures ({}/{}): {}",
+          userEntity.getConsecutiveFailures(), maxConsecutiveFailures, userName);
       if (configuration.showLockedOutUserMessage()) {
-        throw new AccountDisabledException(userName);
+        throw new TooManyLoginFailuresException(userName);
       } else {
         throw new InvalidUsernamePasswordCombinationException(userName);
       }
@@ -83,7 +90,7 @@ abstract class AmbariAuthenticationProvider implements AuthenticationProvider {
    * @param type       the {@link UserAuthenticationType} to retrieve
    * @return a {@link UserAuthenticationEntity} if found; otherwise null
    */
-  UserAuthenticationEntity getAuthenticationEntity(UserEntity userEntity, UserAuthenticationType type) {
+  protected UserAuthenticationEntity getAuthenticationEntity(UserEntity userEntity, UserAuthenticationType type) {
     Collection<UserAuthenticationEntity> authenticationEntities = (userEntity == null) ? null : userEntity.getAuthenticationEntities();
     if (authenticationEntities != null) {
       for (UserAuthenticationEntity authenticationEntity : authenticationEntities) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/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
index 3667012..f617a60 100644
--- 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
@@ -92,6 +92,11 @@ public class AmbariBasicAuthenticationFilter extends BasicAuthenticationFilter i
     return (header != null) && header.startsWith("Basic ");
   }
 
+  @Override
+  public boolean shouldIncrementFailureCount() {
+    return true;
+  }
+
   /**
    * Checks whether the authentication information is filled. If it is not, then a login failed audit event is logged
    *

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/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
deleted file mode 100644
index 3d35578..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariJWTAuthenticationFilter.java
+++ /dev/null
@@ -1,114 +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 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.configuration.Configuration;
-import org.apache.ambari.server.security.authorization.Users;
-import org.apache.ambari.server.security.authorization.jwt.JwtAuthenticationFilter;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.AuthenticationException;
-import org.springframework.security.web.AuthenticationEntryPoint;
-
-/**
- * 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 {
-
-  /**
-   * Ambari authentication event handler
-   */
-  private final AmbariAuthenticationEventHandler eventHandler;
-
-
-  /**
-   * Constructor.
-   *
-   * @param ambariEntryPoint the Spring entry point
-   * @param configuration    the Ambari configuration
-   * @param users            the Ambari users object
-   * @param eventHandler     the Ambari authentication event handler
-   */
-  public AmbariJWTAuthenticationFilter(AuthenticationEntryPoint ambariEntryPoint,
-                                       Configuration configuration,
-                                       Users users,
-                                       AmbariAuthenticationEventHandler eventHandler) {
-    super(configuration, ambariEntryPoint, users);
-
-    if(eventHandler == null) {
-      throw new IllegalArgumentException("The AmbariAuthenticationEventHandler must not be null");
-    }
-
-    this.eventHandler = eventHandler;
-  }
-
-  /**
-   * 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 {
-
-    if (eventHandler != null) {
-      eventHandler.beforeAttemptAuthentication(this, servletRequest, servletResponse);
-    }
-
-    super.doFilter(servletRequest, servletResponse, chain);
-  }
-
-  @Override
-  protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
-    if (eventHandler != null) {
-      eventHandler.onSuccessfulAuthentication(this, request, response, authResult);
-    }
-  }
-
-  @Override
-  protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
-    if (eventHandler != null) {
-      AmbariAuthenticationException cause;
-
-      if (authException instanceof AmbariAuthenticationException) {
-        cause = (AmbariAuthenticationException) authException;
-      } else {
-        cause = new AmbariAuthenticationException(null, authException.getMessage(), authException);
-      }
-
-      eventHandler.onUnsuccessfulAuthentication(this, request, response, cause);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java
index dcdf471..7ef6524 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariLocalAuthenticationProvider.java
@@ -20,7 +20,6 @@ package org.apache.ambari.server.security.authentication;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
-import org.apache.ambari.server.security.authorization.AmbariUserAuthentication;
 import org.apache.ambari.server.security.authorization.User;
 import org.apache.ambari.server.security.authorization.UserAuthenticationType;
 import org.apache.ambari.server.security.authorization.Users;
@@ -59,25 +58,28 @@ public class AmbariLocalAuthenticationProvider extends AmbariAuthenticationProvi
   public Authentication authenticate(Authentication authentication) throws AuthenticationException {
     String userName = authentication.getName().trim();
 
-    UserEntity userEntity = getUserEntity(userName);
+    UserEntity userEntity;
+    try {
+      userEntity = getUserEntity(userName);
 
-    if (userEntity == null) {
-      LOG.info("User not found: {}", userName);
-      throw new InvalidUsernamePasswordCombinationException(userName);
+      if (userEntity == null) {
+        LOG.info("User not found: {}", userName);
+        throw new InvalidUsernamePasswordCombinationException(userName);
+      }
     }
-
-    int maxConsecutiveFailures = configuration.getMaxAuthenticationFailures();
-    if (maxConsecutiveFailures > 0 && userEntity.getConsecutiveFailures() >= maxConsecutiveFailures) {
-      LOG.info("User account is locked out due to too many authentication failures ({}/{}): {}",
-          userEntity.getConsecutiveFailures(), maxConsecutiveFailures, userName);
+    catch(UserNotFoundException e) {
+      // Do not give away information about the existence or status of a user
+      throw new InvalidUsernamePasswordCombinationException(userName, e);
+    }
+    catch (AccountDisabledException | TooManyLoginFailuresException e) {
       if (configuration.showLockedOutUserMessage()) {
-        throw new TooManyLoginFailuresException(userName);
+        throw e;
       } else {
-        throw new InvalidUsernamePasswordCombinationException(userName);
+        // Do not give away information about the existence or status of a user
+        throw new InvalidUsernamePasswordCombinationException(userName, e);
       }
     }
 
-
     if (authentication.getCredentials() == null) {
       LOG.info("Authentication failed: no credentials provided: {}", userName);
       throw new InvalidUsernamePasswordCombinationException(userName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariUserAuthentication.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariUserAuthentication.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariUserAuthentication.java
new file mode 100644
index 0000000..41347ad
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariUserAuthentication.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util.Collection;
+
+import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.UserIdAuthentication;
+import org.springframework.security.core.Authentication;
+
+public class AmbariUserAuthentication implements Authentication, UserIdAuthentication {
+
+  private String serializedToken;
+  private User user;
+  private Collection<AmbariGrantedAuthority> userAuthorities;
+  private boolean authenticated = false;
+
+  public AmbariUserAuthentication(String token, User user, Collection<AmbariGrantedAuthority> userAuthorities) {
+    this.serializedToken = token;
+    this.user = user;
+    this.userAuthorities = userAuthorities;
+  }
+
+  @Override
+  public Collection<? extends AmbariGrantedAuthority> getAuthorities() {
+    return userAuthorities;
+  }
+
+  @Override
+  public String getCredentials() {
+    return serializedToken;
+  }
+
+  @Override
+  public Object getDetails() {
+    return null;
+  }
+
+  @Override
+  public User getPrincipal() {
+    return user;
+  }
+
+  @Override
+  public boolean isAuthenticated() {
+    return authenticated;
+  }
+
+  @Override
+  public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
+    this.authenticated = authenticated;
+  }
+
+  @Override
+  public String getName() {
+    return user.getUserName();
+  }
+
+  @Override
+  public Integer getUserId() {
+    return user.getUserId();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
index 0f2fbb6..0760d9b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/UserNotFoundException.java
@@ -23,6 +23,15 @@ package org.apache.ambari.server.security.authentication;
  * when the user specified in an authentication attempt is not found in the Ambari user database.
  */
 public class UserNotFoundException extends AmbariAuthenticationException {
+  public static final String MESSAGE = "User does not exist.";
+
+  public UserNotFoundException(String userName) {
+    super(userName, MESSAGE);
+  }
+
+  public UserNotFoundException(String userName, Throwable cause) {
+    super(userName, MESSAGE, cause);
+  }
 
   public UserNotFoundException(String username, String message) {
     super(username, message);

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java
new file mode 100644
index 0000000..dcaf3e8
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationFilter.java
@@ -0,0 +1,419 @@
+/*
+ * 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.jwt;
+
+import java.io.IOException;
+import java.security.interfaces.RSAPublicKey;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationEventHandler;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationException;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
+import org.apache.ambari.server.security.authentication.AmbariDelegatingAuthenticationFilter;
+import org.apache.ambari.server.security.authentication.AmbariUserAuthentication;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.authentication.AuthenticationProvider;
+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;
+
+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;
+
+/**
+ * AmbariBasicAuthenticationFilter  is used to validate JWT token and authenticate users.
+ * <p>
+ * This authentication filter is expected to be used withing an {@link AmbariDelegatingAuthenticationFilter}.
+ *
+ * @see AmbariDelegatingAuthenticationFilter
+ */
+public class AmbariJwtAuthenticationFilter implements AmbariAuthenticationFilter {
+  private static final Logger LOG = LoggerFactory.getLogger(AmbariJwtAuthenticationFilter.class);
+
+  /**
+   * Ambari authentication event handler
+   */
+  private final AmbariAuthenticationEventHandler eventHandler;
+
+  /**
+   * Authentication entry point implementation
+   */
+  private final AuthenticationEntryPoint ambariEntryPoint;
+
+  /**
+   * The /JWT authentication provider
+   */
+  private final AuthenticationProvider authenticationProvider;
+
+  /**
+   * Authentication properties for JWT authenticatioin
+   * <p>
+   * If null JWT authentication has not been enabled
+   */
+  private final JwtAuthenticationProperties jwtProperties;
+
+  /**
+   * The name of the HTTP cookie containing the authentication token
+   */
+  private final String jwtCookieName;
+
+  /**
+   * The expected/allowed JWT audiences
+   * <p>
+   * If empty, any audience is allowed
+   */
+  private final List<String> audiences;
+
+  /**
+   * The public key of the token producer, used to verify the signed token
+   */
+  private final RSAPublicKey publicKey;
+
+  /**
+   * Constructor.
+   *
+   * @param ambariEntryPoint the Spring entry point
+   * @param configuration    the Ambari configuration
+   * @param eventHandler     the Ambari authentication event handler
+   */
+  AmbariJwtAuthenticationFilter(AuthenticationEntryPoint ambariEntryPoint,
+                                Configuration configuration,
+                                AuthenticationProvider authenticationProvider,
+                                AmbariAuthenticationEventHandler eventHandler) {
+    if (eventHandler == null) {
+      throw new IllegalArgumentException("The AmbariAuthenticationEventHandler must not be null");
+    }
+
+    this.ambariEntryPoint = ambariEntryPoint;
+    this.eventHandler = eventHandler;
+
+    this.jwtProperties = configuration.getJwtProperties();
+    this.authenticationProvider = authenticationProvider;
+
+    if (jwtProperties == null) {
+      this.jwtCookieName = null;
+      this.audiences = null;
+      this.publicKey = null;
+    } else {
+      this.jwtCookieName = jwtProperties.getCookieName();
+      this.audiences = jwtProperties.getAudiences();
+      this.publicKey = jwtProperties.getPublicKey();
+    }
+  }
+
+  /**
+   * Tests to see if this JwtAuthenticationFilter shold 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 boolean shouldIncrementFailureCount() {
+    return false;
+  }
+
+  @Override
+  public void init(FilterConfig filterConfig) throws ServletException {
+
+  }
+
+  /**
+   * 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 {
+
+    if (eventHandler != null) {
+      eventHandler.beforeAttemptAuthentication(this, servletRequest, servletResponse);
+    }
+
+    if (jwtProperties == null) {
+      //disable filter if not configured
+      chain.doFilter(servletRequest, servletResponse);
+      return;
+    }
+
+    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+    HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
+
+    try {
+      String serializedJWT = getJWTFromCookie(httpServletRequest);
+      if (serializedJWT != null && isAuthenticationRequired(serializedJWT)) {
+        try {
+          SignedJWT jwtToken = SignedJWT.parse(serializedJWT);
+
+          boolean valid = validateToken(jwtToken);
+
+          if (valid) {
+            String userName = jwtToken.getJWTClaimsSet().getSubject();
+
+            Authentication authentication = authenticationProvider.authenticate(new JwtAuthenticationToken(userName, serializedJWT, null));
+            SecurityContextHolder.getContext().setAuthentication(authentication);
+
+            if (eventHandler != null) {
+              eventHandler.onSuccessfulAuthentication(this, httpServletRequest, httpServletResponse, authentication);
+            }
+          } else {
+            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");
+      }
+
+      chain.doFilter(servletRequest, servletResponse);
+    } catch (AuthenticationException e) {
+      LOG.warn("JWT authentication failed - {}", e.getLocalizedMessage());
+
+      //clear security context if authentication was required, but failed
+      SecurityContextHolder.clearContext();
+
+      if (eventHandler != null) {
+        AmbariAuthenticationException cause;
+
+        if (e instanceof AmbariAuthenticationException) {
+          cause = (AmbariAuthenticationException) e;
+        } else {
+          cause = new AmbariAuthenticationException(null, e.getMessage(), e);
+        }
+
+        eventHandler.onUnsuccessfulAuthentication(this, httpServletRequest, httpServletResponse, cause);
+      }
+
+      //used to indicate authentication failure, not used here as we have more than one filter
+      ambariEntryPoint.commence(httpServletRequest, httpServletResponse, e);
+    }
+  }
+
+  @Override
+  public void destroy() {
+  }
+
+  /**
+   * 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()) {
+      return true;
+    }
+
+    //revalidate if token was changed
+    if (existingAuth instanceof AmbariUserAuthentication && !StringUtils.equals(token, (String) existingAuth.getCredentials())) {
+      return true;
+    }
+
+    //always try to authenticate in case of anonymous user
+    return (existingAuth instanceof AnonymousAuthenticationToken);
+  }
+
+  /**
+   * Encapsulate the acquisition of the JWT token from HTTP cookies within the
+   * request.
+   *
+   * @param req servlet request to get the JWT token from
+   * @return serialized JWT token
+   */
+  String getJWTFromCookie(HttpServletRequest req) {
+    String serializedJWT = null;
+    Cookie[] cookies = req.getCookies();
+    if (cookies != null) {
+      for (Cookie cookie : cookies) {
+        if (jwtCookieName.equals(cookie.getName())) {
+          LOG.info("{} cookie has been found and is being processed", jwtCookieName);
+          serializedJWT = cookie.getValue();
+          break;
+        }
+      }
+    }
+    return serializedJWT;
+  }
+
+  /**
+   * This method provides a single method for validating the JWT for use in
+   * request processing. It provides for the override of specific aspects of
+   * this implementation through submethods used within but also allows for the
+   * override of the entire token validation algorithm.
+   *
+   * @param jwtToken the token to validate
+   * @return true if valid
+   */
+  private boolean validateToken(SignedJWT jwtToken) {
+    boolean sigValid = validateSignature(jwtToken);
+    if (!sigValid) {
+      LOG.warn("Signature could not be verified");
+    }
+    boolean audValid = validateAudiences(jwtToken);
+    if (!audValid) {
+      LOG.warn("Audience validation failed.");
+    }
+    boolean expValid = validateExpiration(jwtToken);
+    if (!expValid) {
+      LOG.info("Expiration validation failed.");
+    }
+
+    return sigValid && audValid && expValid;
+  }
+
+  /**
+   * Verify the signature of the JWT token in this method. This method depends
+   * on the public key that was established during init based upon the
+   * provisioned public key. Override this method in subclasses in order to
+   * customize the signature verification behavior.
+   *
+   * @param jwtToken the token that contains the signature to be validated
+   * @return valid true if signature verifies successfully; false otherwise
+   */
+  boolean validateSignature(SignedJWT jwtToken) {
+    boolean valid = false;
+    if (JWSObject.State.SIGNED == jwtToken.getState()) {
+      LOG.debug("JWT token is in a SIGNED state");
+      if (jwtToken.getSignature() != null) {
+        LOG.debug("JWT token signature is not null");
+        try {
+          JWSVerifier verifier = new RSASSAVerifier(publicKey);
+          if (jwtToken.verify(verifier)) {
+            valid = true;
+            LOG.debug("JWT token has been successfully verified");
+          } else {
+            LOG.warn("JWT signature verification failed.");
+          }
+        } catch (JOSEException je) {
+          LOG.warn("Error while validating signature", je);
+        }
+      }
+    }
+    return valid;
+  }
+
+  /**
+   * Validate whether any of the accepted audience claims is present in the
+   * 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
+   * @return true if an expected audience is present, otherwise false
+   */
+  boolean validateAudiences(SignedJWT jwtToken) {
+    boolean valid = false;
+    try {
+      List<String> tokenAudienceList = jwtToken.getJWTClaimsSet().getAudience();
+      // if there were no expected audiences configured then just
+      // consider any audience acceptable
+      if (audiences == null) {
+        valid = true;
+      } else {
+        // if any of the configured audiences is found then consider it
+        // acceptable
+        if (tokenAudienceList == null) {
+          LOG.warn("JWT token has no audiences, validation failed.");
+          return false;
+        }
+        LOG.info("Audience List: {}", audiences);
+        for (String aud : tokenAudienceList) {
+          LOG.info("Found audience: {}", aud);
+          if (audiences.contains(aud)) {
+            LOG.debug("JWT token audience has been successfully validated");
+            valid = true;
+            break;
+          }
+        }
+        if (!valid) {
+          LOG.warn("JWT audience validation failed.");
+        }
+      }
+    } catch (ParseException pe) {
+      LOG.warn("Unable to parse the JWT token.", pe);
+    }
+    return valid;
+  }
+
+  /**
+   * Validate that the expiration time of the JWT token has not been violated.
+   * If it has then throw an AuthenticationException. Override this method in
+   * subclasses in order to customize the expiration validation behavior.
+   *
+   * @param jwtToken the token that contains the expiration date to validate
+   * @return valid true if the token has not expired; false otherwise
+   */
+  boolean validateExpiration(SignedJWT jwtToken) {
+    boolean valid = false;
+    try {
+      Date expires = jwtToken.getJWTClaimsSet().getExpirationTime();
+      if (expires == null || new Date().before(expires)) {
+        LOG.debug("JWT token expiration date has been successfully validated");
+        valid = true;
+      } else {
+        LOG.warn("JWT expiration date validation failed.");
+      }
+    } catch (ParseException pe) {
+      LOG.warn("JWT expiration date validation failed.", pe);
+    }
+    return valid;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java
new file mode 100644
index 0000000..9a5b825
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/AmbariJwtAuthenticationProvider.java
@@ -0,0 +1,126 @@
+/*
+ * 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.jwt;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
+import org.apache.ambari.server.orm.entities.UserEntity;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationException;
+import org.apache.ambari.server.security.authentication.AmbariAuthenticationProvider;
+import org.apache.ambari.server.security.authentication.AmbariUserAuthentication;
+import org.apache.ambari.server.security.authentication.UserNotFoundException;
+import org.apache.ambari.server.security.authorization.User;
+import org.apache.ambari.server.security.authorization.UserAuthenticationType;
+import org.apache.ambari.server.security.authorization.Users;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+
+import com.google.inject.Inject;
+
+/**
+ * AmbariLocalAuthenticationProvider is an {@link org.springframework.security.authentication.AuthenticationProvider}
+ * implementation used to authenticate users using username and password details from the local Ambari database.
+ * <p>
+ * Users will fail to authenticate, even if they supply the correct credentials if the account is locked out
+ * by being disabled or locked due to too many consecutive failure.
+ */
+public class AmbariJwtAuthenticationProvider extends AmbariAuthenticationProvider {
+  private static final Logger LOG = LoggerFactory.getLogger(AmbariJwtAuthenticationProvider.class);
+
+  /**
+   * Helper object to provide logic for working with users.
+   */
+  private Users users;
+
+  /**
+   * Constructor.
+   *
+   * @param users         the users helper
+   * @param configuration the configuration
+   */
+  @Inject
+  public AmbariJwtAuthenticationProvider(Users users, Configuration configuration) {
+    super(users, configuration);
+    this.users = users;
+  }
+
+  @Override
+  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+    String userName = authentication.getName().trim();
+
+    UserEntity userEntity;
+    try {
+      userEntity = getUserEntity(userName);
+
+      if (userEntity == null) {
+        LOG.info("User not found: {}", userName);
+        throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
+      }
+    } catch (UserNotFoundException e) {
+      throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.", e);
+    }
+
+    if (authentication.getCredentials() == null) {
+      LOG.info("Authentication failed: no token provided: {}", userName);
+      throw new AmbariAuthenticationException(userName, "Unexpected error due to missing JWT token");
+    }
+
+    // If the user was found and allowed to log in, make sure that user is allowed to authentcate using a JWT token.
+    boolean authOK = false;
+    UserAuthenticationEntity authenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.JWT);
+    if (authenticationEntity != null) {
+      authOK = true;
+    } else {
+      // TODO: Determine if LDAP users can authenticate using JWT - for now we assume yes.
+      // If a JWT entity was not found, see if an LDAP entity exists. If so, this user was synced
+      // with a remote server and this should be allowed to authenticate using JWT
+      authenticationEntity = getAuthenticationEntity(userEntity, UserAuthenticationType.LDAP);
+
+      if (authenticationEntity != null) {
+        try {
+          users.addJWTAuthentication(userEntity, userName);
+          authOK = true;
+        } catch (AmbariException e) {
+          LOG.error(String.format("Failed to add the JWT authentication method for %s: %s", userName, e.getLocalizedMessage()), e);
+          throw new AmbariAuthenticationException(userName, "Unexpected error has occurred", e);
+        }
+      }
+    }
+
+    if (authOK) {
+      // The user was  authenticated, return the authenticated user object
+      LOG.debug("Authentication succeeded - a matching user was found: {}", userName);
+      User user = new User(userEntity);
+      Authentication auth = new AmbariUserAuthentication(authentication.getCredentials().toString(), user, users.getUserAuthorities(userEntity));
+      auth.setAuthenticated(true);
+      return auth;
+    } else {
+      // The user was not authenticated, fail
+      LOG.debug("Authentication failed: password does not match stored value: {}", userName);
+      throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
+    }
+  }
+
+  @Override
+  public boolean supports(Class<?> authentication) {
+    return JwtAuthenticationToken.class.isAssignableFrom(authentication);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationProperties.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationProperties.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationProperties.java
new file mode 100644
index 0000000..162f7d9
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationProperties.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jwt;
+
+import java.security.interfaces.RSAPublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Class describes parameters of external JWT authentication provider
+ */
+public class JwtAuthenticationProperties {
+  private String authenticationProviderUrl = null;
+  private RSAPublicKey publicKey = null;
+  private List<String> audiences = null;
+  private String cookieName = "hadoop-jwt";
+  private String originalUrlQueryParam = null;
+
+  public String getAuthenticationProviderUrl() {
+    return authenticationProviderUrl;
+  }
+
+  public void setAuthenticationProviderUrl(String authenticationProviderUrl) {
+    this.authenticationProviderUrl = authenticationProviderUrl;
+  }
+
+  public RSAPublicKey getPublicKey() {
+    return publicKey;
+  }
+
+  public void setPublicKey(RSAPublicKey publicKey) {
+    this.publicKey = publicKey;
+  }
+
+  public List<String> getAudiences() {
+    return audiences;
+  }
+
+  public void setAudiences(List<String> audiences) {
+    this.audiences = audiences;
+  }
+
+  public void setAudiencesString(String audiencesString) {
+    if (StringUtils.isNotEmpty(audiencesString)) {
+      // parse into the list
+      String[] audArray = audiencesString.split(",");
+      audiences = new ArrayList<>();
+      Collections.addAll(audiences, audArray);
+    } else {
+      audiences = null;
+    }
+  }
+
+  public String getCookieName() {
+    return cookieName;
+  }
+
+  public void setCookieName(String cookieName) {
+    this.cookieName = cookieName;
+  }
+
+  public String getOriginalUrlQueryParam() {
+    return originalUrlQueryParam;
+  }
+
+  public void setOriginalUrlQueryParam(String originalUrlQueryParam) {
+    this.originalUrlQueryParam = originalUrlQueryParam;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationToken.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationToken.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationToken.java
new file mode 100644
index 0000000..113a6ff
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/jwt/JwtAuthenticationToken.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jwt;
+
+import java.util.Collection;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+
+/**
+ * {@link AbstractAuthenticationToken} implementation for JWT authentication tokens.
+ */
+public class JwtAuthenticationToken extends AbstractAuthenticationToken {
+  private final String username;
+  private final String token;
+
+  /**
+   * Constructor.
+   *
+   * @param username           the principal's username
+   * @param token              the JWT token (or credential)
+   * @param grantedAuthorities the granted authorities
+   */
+  public JwtAuthenticationToken(String username, String token, Collection<? extends GrantedAuthority> grantedAuthorities) {
+    super(grantedAuthorities);
+    this.username = username;
+    this.token = token;
+  }
+
+  @Override
+  public Object getCredentials() {
+    return token;
+  }
+
+  @Override
+  public Object getPrincipal() {
+    return username;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
index 23fa171..41275a5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
@@ -135,6 +135,12 @@ public class AmbariKerberosAuthenticationFilter extends SpnegoAuthenticationProc
     }
   }
 
+  @Override
+  public boolean shouldIncrementFailureCount() {
+    // Always return false since authentication happens remotely.
+    return false;
+  }
+
   /**
    * Performs the logic for this filter.
    * <p>

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
index 0823729..a88bcab 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariPamAuthenticationProvider.java
@@ -28,6 +28,7 @@ import org.apache.ambari.server.orm.entities.GroupEntity;
 import org.apache.ambari.server.orm.entities.MemberEntity;
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.security.ClientSecurityType;
+import org.apache.ambari.server.security.authentication.AmbariUserAuthentication;
 import org.apache.ambari.server.security.authentication.pam.PamAuthenticationFactory;
 import org.jvnet.libpam.PAM;
 import org.jvnet.libpam.PAMException;

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java
deleted file mode 100644
index 9445882..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthentication.java
+++ /dev/null
@@ -1,76 +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.authorization;
-
-import java.util.Collection;
-
-import org.springframework.security.core.Authentication;
-
-public class AmbariUserAuthentication implements Authentication, UserIdAuthentication {
-
-  private String serializedToken;
-  private User user;
-  private Collection<AmbariGrantedAuthority> userAuthorities;
-  private boolean authenticated = false;
-
-  public AmbariUserAuthentication(String token, User user, Collection<AmbariGrantedAuthority> userAuthorities) {
-    this.serializedToken = token;
-    this.user = user;
-    this.userAuthorities = userAuthorities;
-  }
-
-  @Override
-  public Collection<? extends AmbariGrantedAuthority> getAuthorities() {
-    return userAuthorities;
-  }
-
-  @Override
-  public String getCredentials() {
-    return serializedToken;
-  }
-
-  @Override
-  public Object getDetails() {
-    return null;
-  }
-
-  @Override
-  public User getPrincipal() {
-    return user;
-  }
-
-  @Override
-  public boolean isAuthenticated() {
-    return authenticated;
-  }
-
-  @Override
-  public void setAuthenticated(boolean authenticated) throws IllegalArgumentException {
-    this.authenticated = authenticated;
-  }
-
-  @Override
-  public String getName() {
-    return user.getUserName();
-  }
-
-  @Override
-  public Integer getUserId() {
-    return user.getUserId();
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
index 8fbd816..9cad29d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariUserAuthorizationFilter.java
@@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletResponse;
 
 import org.apache.ambari.server.orm.entities.UserEntity;
 import org.apache.ambari.server.scheduler.ExecutionScheduleManager;
+import org.apache.ambari.server.security.authentication.AmbariUserAuthentication;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenClientFilter;
 import org.apache.ambari.server.security.authorization.internal.InternalTokenStorage;
 import org.apache.commons.lang.math.NumberUtils;

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java
deleted file mode 100644
index 7b21ce6..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthentication.java
+++ /dev/null
@@ -1,34 +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.authorization.jwt;
-
-import java.util.Collection;
-
-import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
-import org.apache.ambari.server.security.authorization.AmbariUserAuthentication;
-import org.apache.ambari.server.security.authorization.User;
-
-/**
- * Internal token which describes JWT authentication
- */
-public class JwtAuthentication extends AmbariUserAuthentication {
-
-  public JwtAuthentication(String token, User user, Collection<AmbariGrantedAuthority> userAuthorities) {
-    super(token, user, userAuthorities);
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/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
deleted file mode 100644
index f42df6c..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationFilter.java
+++ /dev/null
@@ -1,448 +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.authorization.jwt;
-
-import java.io.IOException;
-import java.security.interfaces.RSAPublicKey;
-import java.text.ParseException;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.configuration.Configuration;
-import org.apache.ambari.server.orm.entities.UserAuthenticationEntity;
-import org.apache.ambari.server.orm.entities.UserEntity;
-import org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter;
-import org.apache.ambari.server.security.authentication.UserNotFoundException;
-import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
-import org.apache.ambari.server.security.authorization.UserAuthenticationType;
-import org.apache.ambari.server.security.authorization.Users;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-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;
-
-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;
-
-/**
- * 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 AmbariAuthenticationFilter {
-  private static final Logger LOG = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
-
-  private final JwtAuthenticationProperties jwtProperties;
-
-  private String originalUrlQueryParam = "originalUrl";
-  private String authenticationProviderUrl = null;
-  private RSAPublicKey publicKey = null;
-  private List<String> audiences = null;
-  private String cookieName = "hadoop-jwt";
-
-  private boolean ignoreFailure = false;
-  private AuthenticationEntryPoint entryPoint;
-  private Users users;
-
-  public JwtAuthenticationFilter(Configuration configuration, AuthenticationEntryPoint entryPoint, Users users) {
-    this.entryPoint = entryPoint;
-    this.users = users;
-    jwtProperties = configuration.getJwtProperties();
-    loadJwtProperties();
-  }
-
-  public JwtAuthenticationFilter(JwtAuthenticationProperties jwtProperties, AuthenticationEntryPoint entryPoint,
-                                 Users users) {
-    this.jwtProperties = jwtProperties;
-    this.entryPoint = entryPoint;
-    this.users = users;
-    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 {
-
-  }
-
-  // TODO: ************
-  // TODO: This is to be revisited for AMBARI-21217 (Update JWT Authentication process to work with improved user management facility)
-  // TODO: ************
-  @Override
-  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
-
-    if (jwtProperties == null) {
-      //disable filter if not configured
-      filterChain.doFilter(servletRequest, servletResponse);
-      return;
-    }
-
-    HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
-    HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
-
-    try {
-      String serializedJWT = getJWTFromCookie(httpServletRequest);
-      if (serializedJWT != null && isAuthenticationRequired(serializedJWT)) {
-        try {
-          SignedJWT jwtToken = SignedJWT.parse(serializedJWT);
-
-          boolean valid = validateToken(jwtToken);
-
-          if (valid) {
-            String userName = jwtToken.getJWTClaimsSet().getSubject();
-            UserEntity userEntity = users.getUserEntity(userName);
-
-            if (userEntity == null) {
-              //TODO we temporary expect that LDAP is configured to same server as JWT source
-              throw new UserNotFoundException(userName, "Cannot find user from JWT. Please, ensure LDAP is configured and users are synced.");
-            } else {
-              // Check to see if the user is allowed to authenticate using JWT or LDAP
-              Collection<UserAuthenticationEntity> authenticationEntities = userEntity.getAuthenticationEntities();
-              boolean hasJWT = false;
-              boolean hasLDAP = false;
-
-              if (authenticationEntities != null) {
-                for (UserAuthenticationEntity entity : authenticationEntities) {
-                  if (entity.getAuthenticationType() == UserAuthenticationType.JWT) {
-                    // TODO: possibly check the authentication key to see if it is relevant
-                    hasJWT = true;
-                    break;
-                  } else if (entity.getAuthenticationType() == UserAuthenticationType.LDAP) {
-                    hasLDAP = true;
-                  }
-                }
-              }
-
-              if(!hasJWT) {
-                if (hasLDAP) {
-                  // TODO: Determine if LDAP users can authenticate using JWT
-                  try {
-                    users.addJWTAuthentication(userEntity, userName);
-                  } catch (AmbariException e) {
-                    LOG.error(String.format("Failed to add the JWT authentication method for %s: %s", userName, e.getLocalizedMessage()), e);
-                  }
-                  hasJWT = true;
-                }
-              }
-
-              if (!hasJWT) {
-                throw new UserNotFoundException(userName, "User is not authorized to authenticate from JWT. Please, ensure LDAP is configured and users are synced.");
-              }
-            }
-
-            // If we made it this far, the user was found and is authorized to authenticate via JWT
-            Collection<AmbariGrantedAuthority> userAuthorities = users.getUserAuthorities(userEntity);
-
-            JwtAuthentication authentication = new JwtAuthentication(serializedJWT, users.getUser(userEntity), userAuthorities);
-            authentication.setAuthenticated(true);
-
-            SecurityContextHolder.getContext().setAuthentication(authentication);
-            onSuccessfulAuthentication(httpServletRequest, httpServletResponse, authentication);
-          } else {
-            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();
-
-      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);
-      }
-    }
-  }
-
-  private void loadJwtProperties() {
-    if (jwtProperties != null) {
-      authenticationProviderUrl = jwtProperties.getAuthenticationProviderUrl();
-      publicKey = jwtProperties.getPublicKey();
-      audiences = jwtProperties.getAudiences();
-      cookieName = jwtProperties.getCookieName();
-      originalUrlQueryParam = jwtProperties.getOriginalUrlQueryParam();
-    }
-  }
-
-  /**
-   * 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()) {
-      return true;
-    }
-
-    //revalidate if token was changed
-    if (existingAuth instanceof JwtAuthentication && !StringUtils.equals(token, (String) existingAuth.getCredentials())) {
-      return true;
-    }
-
-    //always try to authenticate in case of anonymous user
-    return (existingAuth instanceof AnonymousAuthenticationToken);
-  }
-
-  /**
-   * Encapsulate the acquisition of the JWT token from HTTP cookies within the
-   * request.
-   *
-   * @param req servlet request to get the JWT token from
-   * @return serialized JWT token
-   */
-  protected String getJWTFromCookie(HttpServletRequest req) {
-    String serializedJWT = null;
-    Cookie[] cookies = req.getCookies();
-    if (cookies != null) {
-      for (Cookie cookie : cookies) {
-        if (cookieName.equals(cookie.getName())) {
-          LOG.info(cookieName
-              + " cookie has been found and is being processed");
-          serializedJWT = cookie.getValue();
-          break;
-        }
-      }
-    }
-    return serializedJWT;
-  }
-
-  /**
-   * Create the URL to be used for authentication of the user in the absence of
-   * a JWT token within the incoming request.
-   *
-   * @param request for getting the original request URL
-   * @return url to use as login url for redirect
-   */
-  protected String constructLoginURL(HttpServletRequest request) {
-    String delimiter = "?";
-    if (authenticationProviderUrl.contains("?")) {
-      delimiter = "&";
-    }
-    String loginURL = authenticationProviderUrl + delimiter
-        + originalUrlQueryParam + "="
-        + request.getRequestURL();
-    return loginURL;
-  }
-
-  /**
-   * This method provides a single method for validating the JWT for use in
-   * request processing. It provides for the override of specific aspects of
-   * this implementation through submethods used within but also allows for the
-   * override of the entire token validation algorithm.
-   *
-   * @param jwtToken the token to validate
-   * @return true if valid
-   */
-  protected boolean validateToken(SignedJWT jwtToken) {
-    boolean sigValid = validateSignature(jwtToken);
-    if (!sigValid) {
-      LOG.warn("Signature could not be verified");
-    }
-    boolean audValid = validateAudiences(jwtToken);
-    if (!audValid) {
-      LOG.warn("Audience validation failed.");
-    }
-    boolean expValid = validateExpiration(jwtToken);
-    if (!expValid) {
-      LOG.info("Expiration validation failed.");
-    }
-
-    return sigValid && audValid && expValid;
-  }
-
-  /**
-   * Verify the signature of the JWT token in this method. This method depends
-   * on the public key that was established during init based upon the
-   * provisioned public key. Override this method in subclasses in order to
-   * customize the signature verification behavior.
-   *
-   * @param jwtToken the token that contains the signature to be validated
-   * @return valid true if signature verifies successfully; false otherwise
-   */
-  protected boolean validateSignature(SignedJWT jwtToken) {
-    boolean valid = false;
-    if (JWSObject.State.SIGNED == jwtToken.getState()) {
-      LOG.debug("JWT token is in a SIGNED state");
-      if (jwtToken.getSignature() != null) {
-        LOG.debug("JWT token signature is not null");
-        try {
-          JWSVerifier verifier = new RSASSAVerifier(publicKey);
-          if (jwtToken.verify(verifier)) {
-            valid = true;
-            LOG.debug("JWT token has been successfully verified");
-          } else {
-            LOG.warn("JWT signature verification failed.");
-          }
-        } catch (JOSEException je) {
-          LOG.warn("Error while validating signature", je);
-        }
-      }
-    }
-    return valid;
-  }
-
-  /**
-   * Validate whether any of the accepted audience claims is present in the
-   * 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
-   * @return true if an expected audience is present, otherwise false
-   */
-  protected boolean validateAudiences(SignedJWT jwtToken) {
-    boolean valid = false;
-    try {
-      List<String> tokenAudienceList = jwtToken.getJWTClaimsSet()
-          .getAudience();
-      // if there were no expected audiences configured then just
-      // consider any audience acceptable
-      if (audiences == null) {
-        valid = true;
-      } else {
-        // if any of the configured audiences is found then consider it
-        // acceptable
-        if (tokenAudienceList == null) {
-          LOG.warn("JWT token has no audiences, validation failed.");
-          return false;
-        }
-        for (String aud : tokenAudienceList) {
-          if (audiences.contains(aud)) {
-            LOG.debug("JWT token audience has been successfully validated");
-            valid = true;
-            break;
-          }
-        }
-        if (!valid) {
-          LOG.warn("JWT audience validation failed.");
-        }
-      }
-    } catch (ParseException pe) {
-      LOG.warn("Unable to parse the JWT token.", pe);
-    }
-    return valid;
-  }
-
-  /**
-   * Validate that the expiration time of the JWT token has not been violated.
-   * If it has then throw an AuthenticationException. Override this method in
-   * subclasses in order to customize the expiration validation behavior.
-   *
-   * @param jwtToken the token that contains the expiration date to validate
-   * @return valid true if the token has not expired; false otherwise
-   */
-  protected boolean validateExpiration(SignedJWT jwtToken) {
-    boolean valid = false;
-    try {
-      Date expires = jwtToken.getJWTClaimsSet().getExpirationTime();
-      if (expires == null || new Date().before(expires)) {
-        LOG.debug("JWT token expiration date has been "
-            + "successfully validated");
-        valid = true;
-      } else {
-        LOG.warn("JWT expiration date validation failed.");
-      }
-    } catch (ParseException pe) {
-      LOG.warn("JWT expiration date validation failed.", pe);
-    }
-    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/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java
deleted file mode 100644
index cb456fa..0000000
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/jwt/JwtAuthenticationProperties.java
+++ /dev/null
@@ -1,87 +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.authorization.jwt;
-
-import java.security.interfaces.RSAPublicKey;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.lang.StringUtils;
-
-/**
- * Class describes parameters of external JWT authentication provider
- */
-public class JwtAuthenticationProperties {
-  private String authenticationProviderUrl = null;
-  private RSAPublicKey publicKey = null;
-  private List<String> audiences = null;
-  private String cookieName = "hadoop-jwt";
-  private String originalUrlQueryParam = null;
-
-  public String getAuthenticationProviderUrl() {
-    return authenticationProviderUrl;
-  }
-
-  public void setAuthenticationProviderUrl(String authenticationProviderUrl) {
-    this.authenticationProviderUrl = authenticationProviderUrl;
-  }
-
-  public RSAPublicKey getPublicKey() {
-    return publicKey;
-  }
-
-  public void setPublicKey(RSAPublicKey publicKey) {
-    this.publicKey = publicKey;
-  }
-
-  public List<String> getAudiences() {
-    return audiences;
-  }
-
-  public void setAudiences(List<String> audiences) {
-    this.audiences = audiences;
-  }
-
-  public void setAudiencesString(String audiencesString) {
-    if (StringUtils.isNotEmpty(audiencesString)) {
-      // parse into the list
-      String[] audArray = audiencesString.split(",");
-      audiences = new ArrayList<>();
-      Collections.addAll(audiences, audArray);
-    } else {
-      audiences = null;
-    }
-  }
-
-  public String getCookieName() {
-    return cookieName;
-  }
-
-  public void setCookieName(String cookieName) {
-    this.cookieName = cookieName;
-  }
-
-  public String getOriginalUrlQueryParam() {
-    return originalUrlQueryParam;
-  }
-
-  public void setOriginalUrlQueryParam(String originalUrlQueryParam) {
-    this.originalUrlQueryParam = originalUrlQueryParam;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/553e4f9d/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
index 32dd6dc..c3451dd 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/ldap/AmbariLdapDataPopulator.java
@@ -671,7 +671,7 @@ public class AmbariLdapDataPopulator {
         }
       }
     } while (configuration.getLdapServerProperties().isPaginationEnabled()
-        && processor.getCookie().getCookie() != null);
+        && (processor.getCookie() != null) && (processor.getCookie().getCookie() != null));
     return users;
   }