AMBARI-18406. Create authentication filter to perform Kerberos authentication 
for Ambari (rlevas)


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

Branch: refs/heads/branch-dev-patch-upgrade
Commit: b4320b5a8d29b812e9fe86da69a219a17d5e4ea7
Parents: 8425f1f
Author: Robert Levas <rle...@hortonworks.com>
Authored: Tue Sep 20 14:45:23 2016 -0400
Committer: Robert Levas <rle...@hortonworks.com>
Committed: Tue Sep 20 14:45:23 2016 -0400

----------------------------------------------------------------------
 ambari-project/pom.xml                          |   5 +
 ambari-server/pom.xml                           |   6 +-
 .../server/configuration/Configuration.java     |  30 ++-
 .../server/controller/KerberosHelper.java       |   2 +
 .../server/controller/KerberosHelperImpl.java   |  18 +-
 .../server/security/AmbariEntryPoint.java       |  15 +-
 .../AmbariAuthToLocalUserDetailsService.java    | 139 +++++++++++
 .../AmbariKerberosAuthenticationFilter.java     | 172 ++++++++++++++
 .../kerberos/AmbariKerberosTicketValidator.java |  93 ++++++++
 .../AbstractPrepareKerberosServerAction.java    |  10 +-
 .../ConfigureAmbariIdentitiesServerAction.java  | 235 +++++++++++++++++++
 .../ConfigureAmbariIndetityServerAction.java    | 208 ----------------
 .../kerberos/CreatePrincipalsServerAction.java  |   5 +-
 .../kerberos/KerberosServerAction.java          |  12 +-
 .../webapp/WEB-INF/spring-security.xml          |  32 ++-
 .../server/controller/KerberosHelperTest.java   |   6 +-
 ...AmbariAuthToLocalUserDetailsServiceTest.java |  92 ++++++++
 .../AmbariKerberosAuthenticationFilterTest.java | 133 +++++++++++
 .../AmbariKerberosTicketValidatorTest.java      |  49 ++++
 19 files changed, 1021 insertions(+), 241 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-project/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-project/pom.xml b/ambari-project/pom.xml
index 2615b46..4f045fe 100644
--- a/ambari-project/pom.xml
+++ b/ambari-project/pom.xml
@@ -132,6 +132,11 @@
         <version>3.1.2.RELEASE</version>
       </dependency>
       <dependency>
+        <groupId>org.springframework.security.kerberos</groupId>
+        <artifactId>spring-security-kerberos-web</artifactId>
+        <version>1.0.1.RELEASE</version>
+      </dependency>
+      <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-mock</artifactId>
         <version>2.0.8</version>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 323ce22..32267c8 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -44,7 +44,7 @@
     
<stacksSrcLocation>src/main/resources/stacks/${stack.distribution}</stacksSrcLocation>
     <tarballResourcesFolder>src/main/resources</tarballResourcesFolder>
     <skipPythonTests>false</skipPythonTests>
-    <hadoop.version>2.7.1</hadoop.version>
+    <hadoop.version>2.7.2</hadoop.version>
     <empty.dir>src/main/package</empty.dir> <!-- any directory in project with 
not very big amount of files (not to waste-load them) -->
   </properties>
   <build>
@@ -985,6 +985,10 @@
       <artifactId>spring-security-web</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.springframework.security.kerberos</groupId>
+      <artifactId>spring-security-kerberos-web</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-mock</artifactId>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/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 b2fa4c0..f1058b6 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
@@ -5284,9 +5284,11 @@ public class Configuration {
         try {
           orderedUserTypes.add(UserType.valueOf(type.toUpperCase()));
         } catch (IllegalArgumentException e) {
-          throw new IllegalArgumentException(String.format("While processing 
ordered user types from %s, " +
+          String message = String.format("While processing ordered user types 
from %s, " +
                   "%s was found to be an invalid user type.",
-              KERBEROS_AUTH_USER_TYPES.getKey(), type), e);
+              KERBEROS_AUTH_USER_TYPES.getKey(), type);
+          LOG.error(message);
+          throw new IllegalArgumentException(message, e);
         }
       }
     }
@@ -5320,9 +5322,11 @@ public class Configuration {
     // Validate the SPNEGO principal name to ensure it was set.
     // Log any found issues.
     if (StringUtils.isEmpty(kerberosAuthProperties.getSpnegoPrincipalName())) {
-      throw new IllegalArgumentException(String.format("The SPNEGO principal 
name specified in %s is empty. " +
+      String message = String.format("The SPNEGO principal name specified in 
%s is empty. " +
               "This will cause issues authenticating users using Kerberos.",
-          KERBEROS_AUTH_SPNEGO_PRINCIPAL.getKey()));
+          KERBEROS_AUTH_SPNEGO_PRINCIPAL.getKey());
+      LOG.error(message);
+      throw new IllegalArgumentException(message);
     }
 
     // Get the SPNEGO keytab file. There is nothing special to process for 
this value.
@@ -5331,19 +5335,25 @@ public class Configuration {
     // Validate the SPNEGO keytab file to ensure it was set, it exists and it 
is readable by Ambari.
     // Log any found issues.
     if (StringUtils.isEmpty(kerberosAuthProperties.getSpnegoKeytabFilePath())) 
{
-      throw new IllegalArgumentException(String.format("The SPNEGO keytab file 
path specified in %s is empty. " +
+      String message = String.format("The SPNEGO keytab file path specified in 
%s is empty. " +
               "This will cause issues authenticating users using Kerberos.",
-          KERBEROS_AUTH_SPNEGO_KEYTAB_FILE.getKey()));
+          KERBEROS_AUTH_SPNEGO_KEYTAB_FILE.getKey());
+      LOG.error(message);
+      throw new IllegalArgumentException(message);
     } else {
       File keytabFile = new 
File(kerberosAuthProperties.getSpnegoKeytabFilePath());
       if (!keytabFile.exists()) {
-        throw new IllegalArgumentException(String.format("The SPNEGO keytab 
file path (%s) specified in %s does not exist. " +
+        String message = String.format("The SPNEGO keytab file path (%s) 
specified in %s does not exist. " +
                 "This will cause issues authenticating users using Kerberos.",
-            keytabFile.getAbsolutePath(), 
KERBEROS_AUTH_SPNEGO_KEYTAB_FILE.getKey()));
+            keytabFile.getAbsolutePath(), 
KERBEROS_AUTH_SPNEGO_KEYTAB_FILE.getKey());
+        LOG.error(message);
+        throw new IllegalArgumentException(message);
       } else if (!keytabFile.canRead()) {
-        throw new IllegalArgumentException(String.format("The SPNEGO keytab 
file path (%s) specified in %s cannot be read. " +
+        String message = String.format("The SPNEGO keytab file path (%s) 
specified in %s cannot be read. " +
                 "This will cause issues authenticating users using Kerberos.",
-            keytabFile.getAbsolutePath(), 
KERBEROS_AUTH_SPNEGO_KEYTAB_FILE.getKey()));
+            keytabFile.getAbsolutePath(), 
KERBEROS_AUTH_SPNEGO_KEYTAB_FILE.getKey());
+        LOG.error(message);
+        throw new IllegalArgumentException(message);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
index c4d21fc..1153d01 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
@@ -70,6 +70,8 @@ public interface KerberosHelper {
 
   String AMBARI_IDENTITY_NAME = "ambari-server";
 
+  String SPNEGO_IDENTITY_NAME = "spnego";
+
   String CREATE_AMBARI_PRINCIPAL = "create_ambari_principal";
 
   String MANAGE_IDENTITIES = "manage_identities";

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
index 5bc5cd8..a3c6fd4 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java
@@ -61,7 +61,7 @@ import 
org.apache.ambari.server.security.encryption.CredentialStoreService;
 import org.apache.ambari.server.serveraction.ActionLog;
 import org.apache.ambari.server.serveraction.ServerAction;
 import org.apache.ambari.server.serveraction.kerberos.CleanupServerAction;
-import 
org.apache.ambari.server.serveraction.kerberos.ConfigureAmbariIndetityServerAction;
+import 
org.apache.ambari.server.serveraction.kerberos.ConfigureAmbariIdentitiesServerAction;
 import 
org.apache.ambari.server.serveraction.kerberos.CreateKeytabFilesServerAction;
 import 
org.apache.ambari.server.serveraction.kerberos.CreatePrincipalsServerAction;
 import 
org.apache.ambari.server.serveraction.kerberos.DestroyPrincipalsServerAction;
@@ -761,7 +761,7 @@ public class KerberosHelperImpl implements KerberosHelper {
    * @param ambariServerIdentity the ambari server's {@link 
KerberosIdentityDescriptor}
    * @param configurations       a map of compiled configrations used for 
variable replacment
    * @throws AmbariException
-   * @see 
ConfigureAmbariIndetityServerAction#installAmbariServerIdentity(String, String, 
String, ActionLog)
+   * @see 
ConfigureAmbariIdentitiesServerAction#installAmbariServerIdentity(String, 
String, String, ActionLog)
    */
   private void installAmbariIdentity(KerberosIdentityDescriptor 
ambariServerIdentity,
                                      Map<String, Map<String, String>> 
configurations) throws AmbariException {
@@ -775,7 +775,7 @@ public class KerberosHelperImpl implements KerberosHelper {
         if(keytabDescriptor != null) {
           String keytabFilePath = 
variableReplacementHelper.replaceVariables(keytabDescriptor.getFile(), 
configurations);
 
-          injector.getInstance(ConfigureAmbariIndetityServerAction.class)
+          injector.getInstance(ConfigureAmbariIdentitiesServerAction.class)
               .installAmbariServerIdentity(principal, 
ambariServerPrincipalEntity.getCachedKeytabPath(), keytabFilePath, null);
         }
       }
@@ -1259,7 +1259,7 @@ public class KerberosHelperImpl implements KerberosHelper 
{
                 serviceName, componentName, kerberosDescriptor, filterContext);
 
             if (hostname.equals(ambariServerHostname)) {
-              addAmbariServerIdentity(kerberosEnvConfig.getProperties(), 
kerberosDescriptor, identities);
+              addAmbariServerIdentities(kerberosEnvConfig.getProperties(), 
kerberosDescriptor, identities);
             }
 
             if (!identities.isEmpty()) {
@@ -1346,7 +1346,7 @@ public class KerberosHelperImpl implements KerberosHelper 
{
    * @param kerberosDescriptor    the kerberos descriptor
    * @param identities            the collection of identities to add to
    */
-  void addAmbariServerIdentity(Map<String, String> kerberosEnvProperties, 
KerberosDescriptor kerberosDescriptor, List<KerberosIdentityDescriptor> 
identities) {
+  void addAmbariServerIdentities(Map<String, String> kerberosEnvProperties, 
KerberosDescriptor kerberosDescriptor, List<KerberosIdentityDescriptor> 
identities) {
     // Determine if we should _calculate_ the Ambari service identity.
     // If kerberos-env/create_ambari_principal is not set to false the 
identity should be calculated.
     boolean createAmbariPrincipal = (kerberosEnvProperties == null) || 
!"false".equalsIgnoreCase(kerberosEnvProperties.get(CREATE_AMBARI_PRINCIPAL));
@@ -1357,6 +1357,12 @@ public class KerberosHelperImpl implements 
KerberosHelper {
       if (ambariServerIdentity != null) {
         identities.add(ambariServerIdentity);
       }
+
+      // Add the spnego principal for the Ambari server host....
+      KerberosIdentityDescriptor spnegoIdentity = 
kerberosDescriptor.getIdentity(KerberosHelper.SPNEGO_IDENTITY_NAME);
+      if (spnegoIdentity != null) {
+        identities.add(spnegoIdentity);
+      }
     }
   }
 
@@ -2799,7 +2805,7 @@ public class KerberosHelperImpl implements KerberosHelper 
{
           clusterHostInfoJson,
           "{}",
           hostParamsJson,
-          ConfigureAmbariIndetityServerAction.class,
+          ConfigureAmbariIdentitiesServerAction.class,
           event,
           commandParameters,
           "Configure Ambari Identity",

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariEntryPoint.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariEntryPoint.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariEntryPoint.java
index 2028f46..e37976f 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariEntryPoint.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/AmbariEntryPoint.java
@@ -28,6 +28,19 @@ import java.io.IOException;
 public class AmbariEntryPoint implements AuthenticationEntryPoint {
   @Override
   public void commence(HttpServletRequest request, HttpServletResponse 
response, AuthenticationException authException) throws IOException, 
ServletException {
-    response.sendError(HttpServletResponse.SC_FORBIDDEN, 
authException.getMessage());
+    /* 
*****************************************************************************************
+     * To maintain backward compatibility and respond with the appropriate 
response when
+     * authentication is needed, by default return an HTTP 403 status.
+     *
+     * However if requested by the user, respond such that the client is 
challenged to Negotiate
+     * and reissue the request with a Kerberos token.  This response is an 
HTTP 401 status with the
+     * WWW-Authenticate: Negotiate" header.
+     * 
******************************************************************************************
 */
+    if 
("true".equalsIgnoreCase(request.getHeader("X-Negotiate-Authentication"))) {
+      response.setHeader("WWW-Authenticate", "Negotiate");
+      response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication 
requested");
+    } else {
+      response.sendError(HttpServletResponse.SC_FORBIDDEN, 
authException.getMessage());
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.java
new file mode 100644
index 0000000..3c62646
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsService.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.kerberos;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+import org.apache.ambari.server.security.authorization.UserType;
+import org.apache.ambari.server.security.authorization.Users;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.security.authentication.util.KerberosName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * AmbariAuthToLocalUserDetailsService is a {@link UserDetailsService} that 
translates
+ * a Kerberos principal name into a local username that may be used when 
looking up
+ * and Ambari user account.
+ */
+public class AmbariAuthToLocalUserDetailsService implements UserDetailsService 
{
+  private static final Logger LOG = 
LoggerFactory.getLogger(AmbariAuthToLocalUserDetailsService.class);
+
+  private final Users users;
+
+  private final List<UserType> userTypeOrder;
+
+  /**
+   * Constructor.
+   * <p>
+   * Given the Ambari {@link Configuration}, initializes the {@link 
KerberosName} class using
+   * the <code>auth-to-local</code> rules from {@link 
AmbariKerberosAuthenticationProperties#getAuthToLocalRules()}.
+   *
+   * @param configuration the Ambari configuration data
+   * @param users         the Ambari users access object
+   * @throws AmbariException if an error occurs parsing the user-provided 
auth-to-local rules
+   */
+  public AmbariAuthToLocalUserDetailsService(Configuration configuration, 
Users users) throws AmbariException {
+    String authToLocalRules = null;
+    List<UserType> orderedUserTypes = null;
+
+    if (configuration != null) {
+      AmbariKerberosAuthenticationProperties properties = 
configuration.getKerberosAuthenticationProperties();
+
+      if (properties != null) {
+        authToLocalRules = properties.getAuthToLocalRules();
+        orderedUserTypes = properties.getOrderedUserTypes();
+      }
+    }
+
+    if (StringUtils.isEmpty(authToLocalRules)) {
+      authToLocalRules = "DEFAULT";
+    }
+
+    if ((orderedUserTypes == null) || orderedUserTypes.isEmpty()) {
+      orderedUserTypes = Collections.singletonList(UserType.LDAP);
+    }
+
+    KerberosName.setRules(authToLocalRules);
+
+    this.users = users;
+    this.userTypeOrder = orderedUserTypes;
+  }
+
+  @Override
+  public UserDetails loadUserByUsername(String principal) throws 
UsernameNotFoundException {
+    KerberosName kerberosName = new KerberosName(principal);
+
+    try {
+      String username = kerberosName.getShortName();
+
+      if (username == null) {
+        String message = String.format("Failed to translate %s to a local 
username during Kerberos authentication.", principal);
+        LOG.warn(message);
+        throw new UsernameNotFoundException(message);
+      }
+
+      LOG.info("Translated {} to {} using auth-to-local rules during Kerberos 
authentication.", principal, username);
+      return createUser(username);
+    } catch (IOException e) {
+      String message = String.format("Failed to translate %s to a local 
username during Kerberos authentication: %s", principal, 
e.getLocalizedMessage());
+      LOG.warn(message);
+      throw new UsernameNotFoundException(message, e);
+    }
+  }
+
+  /**
+   * Given a username, finds an appropriate account in the Ambari database.
+   * <p>
+   * User accounts are searched in order of preferred user type as specified 
in the Ambari configuration
+   * ({@link Configuration#KERBEROS_AUTH_USER_TYPES}).
+   *
+   * @param username a username
+   * @return the user details of the found user, or <code>null</code> if an 
appropriate user was not found
+   */
+  private UserDetails createUser(String username) {
+    // Iterate over the ordered user types... when an account for the 
username/type combination is
+    // found, build the related AmbariUserAuthentication instance and return 
it.  Only the first
+    // match matters... this may be an issue and cause some ambiguity in the 
event multiple user
+    // types are specified in the configuration and multiple accounts for the 
same username, but
+    // different types (LOCAL vs LDAP, etc...).
+    for (UserType userType : userTypeOrder) {
+      org.apache.ambari.server.security.authorization.User user = 
users.getUser(username, userType);
+
+      if (user != null) {
+        Collection<AmbariGrantedAuthority> userAuthorities = 
users.getUserAuthorities(user.getUserName(), user.getUserType());
+        return new User(username, "", userAuthorities);
+      }
+    }
+
+    String message = String.format("Failed find user account for user with 
username of %s during Kerberos authentication.", username);
+    LOG.warn(message);
+    throw new UsernameNotFoundException(message);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/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
new file mode 100644
index 0000000..a5a3922
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilter.java
@@ -0,0 +1,172 @@
+/*
+ * 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.kerberos;
+
+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.authentication.AmbariAuthenticationFilter;
+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.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import 
org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import 
org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import 
org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+
+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;
+
+/**
+ * AmbariKerberosAuthenticationFilter extends the {@link 
SpnegoAuthenticationProcessingFilter} class
+ * to perform Kerberos-based authentication for Ambari.
+ * <p>
+ * If configured, auditing is performed using {@link AuditLogger}.
+ */
+public class AmbariKerberosAuthenticationFilter extends 
SpnegoAuthenticationProcessingFilter implements AmbariAuthenticationFilter {
+
+  /**
+   * Audit logger
+   */
+  private final AuditLogger auditLogger;
+
+  /**
+   * A Boolean value indicating whether Kerberos authentication is enabled or 
not.
+   */
+  private final boolean kerberosAuthenticationEnabled;
+
+  /**
+   * Constructor.
+   * <p>
+   * Given supplied data, sets up the the {@link 
SpnegoAuthenticationProcessingFilter} to perform
+   * authentication and audit logging if configured do to so.
+   *
+   * @param authenticationManager the Spring authentication manager
+   * @param entryPoint            the Spring entry point
+   * @param configuration         the Ambari configuration data
+   * @param auditLogger           an audit logger
+   * @param permissionHelper      a permission helper to aid in audit logging
+   */
+  public AmbariKerberosAuthenticationFilter(AuthenticationManager 
authenticationManager, final AuthenticationEntryPoint entryPoint, Configuration 
configuration, final AuditLogger auditLogger, final PermissionHelper 
permissionHelper) {
+    AmbariKerberosAuthenticationProperties kerberosAuthenticationProperties = 
(configuration == null)
+        ? null
+        : configuration.getKerberosAuthenticationProperties();
+
+    kerberosAuthenticationEnabled = (kerberosAuthenticationProperties != null) 
&& kerberosAuthenticationProperties.isKerberosAuthenticationEnabled();
+
+    this.auditLogger = auditLogger;
+
+    setAuthenticationManager(authenticationManager);
+
+    setFailureHandler(new AuthenticationFailureHandler() {
+      @Override
+      public void onAuthenticationFailure(HttpServletRequest 
httpServletRequest, HttpServletResponse httpServletResponse, 
AuthenticationException e) throws IOException, ServletException {
+        if (auditLogger.isEnabled()) {
+          AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+              .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
+              .withTimestamp(System.currentTimeMillis())
+              .withReasonOfFailure(e.getLocalizedMessage())
+              .build();
+          auditLogger.log(loginFailedAuditEvent);
+        }
+
+        entryPoint.commence(httpServletRequest, httpServletResponse, e);
+      }
+    });
+
+    setSuccessHandler(new AuthenticationSuccessHandler() {
+      @Override
+      public void onAuthenticationSuccess(HttpServletRequest 
httpServletRequest, HttpServletResponse httpServletResponse, Authentication 
authentication) throws IOException, ServletException {
+        if (auditLogger.isEnabled()) {
+          AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
+              .withRemoteIp(RequestUtils.getRemoteAddress(httpServletRequest))
+              .withUserName(authentication.getName())
+              .withTimestamp(System.currentTimeMillis())
+              .withRoles(permissionHelper.getPermissionLabels(authentication))
+              .build();
+          auditLogger.log(loginSucceededAuditEvent);
+        }
+      }
+    });
+  }
+
+  /**
+   * Tests to determine if this authentication filter is applicable given the 
Ambari configuration
+   * and the user's HTTP request.
+   * <p>
+   * If the Ambari configuration indicates the Kerberos authentication is 
enabled and the HTTP request
+   * contains the appropriate <code>Authorization</code> header, than this 
filter may be applied;
+   * otherwise it should be skipped.
+   *
+   * @param httpServletRequest the request
+   * @return true if this filter should be applied; false otherwise
+   */
+  @Override
+  public boolean shouldApply(HttpServletRequest httpServletRequest) {
+    if (kerberosAuthenticationEnabled) {
+      String header = httpServletRequest.getHeader("Authorization");
+      return (header != null) && (header.startsWith("Negotiate ") || 
header.startsWith("Kerberos "));
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Performs the logic for this filter.
+   * <p>
+   * Checks whether the authentication information is filled. If it is not, 
then a login failed audit event is logged.
+   * <p>
+   * Then, forwards the workflow to {@link 
SpnegoAuthenticationProcessingFilter#doFilter(ServletRequest, ServletResponse, 
FilterChain)}
+   *
+   * @param servletRequest  the request
+   * @param servletResponse the response
+   * @param filterChain     the Spring filter chain
+   * @throws IOException
+   * @throws ServletException
+   */
+  @Override
+  public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain) throws IOException, ServletException {
+    HttpServletRequest httpServletRequest = (HttpServletRequest) 
servletRequest;
+
+    if (shouldApply(httpServletRequest)) {
+      if (auditLogger.isEnabled() && 
(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, filterChain);
+    } else {
+      filterChain.doFilter(servletRequest, servletResponse);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidator.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidator.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidator.java
new file mode 100644
index 0000000..bb57108
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidator.java
@@ -0,0 +1,93 @@
+/*
+ * 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.kerberos;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.security.authentication.BadCredentialsException;
+import 
org.springframework.security.kerberos.authentication.KerberosTicketValidation;
+import 
org.springframework.security.kerberos.authentication.KerberosTicketValidator;
+import 
org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator;
+
+/**
+ * AmbariKerberosTicketValidator is a {@link KerberosTicketValidator} 
implementation that delegates
+ * to a {@link SunJaasKerberosTicketValidator}, if Kerberos authentication is 
enabled.
+ * <p>
+ * If Kerberos authentication is enabled, the following properties are set:
+ * <ul>
+ * <li>{@link SunJaasKerberosTicketValidator#setServicePrincipal(String)} 
using the Ambari server property from {@link 
Configuration#KERBEROS_AUTH_SPNEGO_PRINCIPAL}</li>
+ * <li>{@link SunJaasKerberosTicketValidator#setKeyTabLocation(Resource)} 
using the Ambari server property from {@link 
Configuration#KERBEROS_AUTH_SPNEGO_KEYTAB_FILE}</li>
+ * </ul>
+ */
+public class AmbariKerberosTicketValidator implements KerberosTicketValidator, 
InitializingBean {
+
+  private final SunJaasKerberosTicketValidator kerberosTicketValidator;
+
+  /**
+   * Creates a new AmbariKerberosTicketValidator
+   *
+   * @param configuration the Ambari server configuration
+   */
+  public AmbariKerberosTicketValidator(Configuration configuration) {
+
+    AmbariKerberosAuthenticationProperties properties = (configuration == null)
+        ? null
+        : configuration.getKerberosAuthenticationProperties();
+
+    if ((properties != null) && properties.isKerberosAuthenticationEnabled()) {
+      kerberosTicketValidator = new SunJaasKerberosTicketValidator();
+      
kerberosTicketValidator.setServicePrincipal(properties.getSpnegoPrincipalName());
+
+      if (properties.getSpnegoKeytabFilePath() != null) {
+        kerberosTicketValidator.setKeyTabLocation(new 
FileSystemResource(properties.getSpnegoKeytabFilePath()));
+      }
+    } else {
+      // Don't create the SunJaasKerberosTicketValidator if Kerberos 
authentication is not enabled.
+      kerberosTicketValidator = null;
+    }
+  }
+
+  @Override
+  public void afterPropertiesSet() throws Exception {
+    // If Kerberos authentication is enabled, forward this method invocation 
to the backing
+    // SunJaasKerberosTicketValidator instance.
+    if (kerberosTicketValidator != null) {
+      kerberosTicketValidator.afterPropertiesSet();
+    }
+  }
+
+  @Override
+  public KerberosTicketValidation validateTicket(byte[] bytes) throws 
BadCredentialsException {
+    // If Kerberos authentication is enabled, forward this method invocation 
to the backing
+    // SunJaasKerberosTicketValidator instance.
+    return (kerberosTicketValidator == null)
+        ? null
+        : kerberosTicketValidator.validateTicket(bytes);
+  }
+
+  public void setDebug(boolean debug) {
+    // If Kerberos authentication is enabled, forward this method invocation 
to the backing
+    // SunJaasKerberosTicketValidator instance.
+    if (kerberosTicketValidator != null) {
+      kerberosTicketValidator.setDebug(debug);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
index b6b0713..c283a65 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
@@ -156,7 +156,15 @@ public abstract class AbstractPrepareKerberosServerAction 
extends KerberosServer
             if (ambariServerIdentity != null) {
               List<KerberosIdentityDescriptor> componentIdentities = 
Collections.singletonList(ambariServerIdentity);
               kerberosHelper.addIdentities(kerberosIdentityDataFileWriter, 
componentIdentities,
-                identityFilter, KerberosHelper.AMBARI_SERVER_HOST_NAME, 
"AMBARI_SEVER", "AMBARI_SEVER", kerberosConfigurations, configurations);
+                identityFilter, KerberosHelper.AMBARI_SERVER_HOST_NAME, 
"AMBARI_SERVER", "AMBARI_SERVER", kerberosConfigurations, configurations);
+              propertiesToIgnore = 
gatherPropertiesToIgnore(componentIdentities, propertiesToIgnore);
+            }
+
+            KerberosIdentityDescriptor spnegoIdentity = 
kerberosDescriptor.getIdentity(KerberosHelper.SPNEGO_IDENTITY_NAME);
+            if (spnegoIdentity != null) {
+              List<KerberosIdentityDescriptor> componentIdentities = 
Collections.singletonList(spnegoIdentity);
+              kerberosHelper.addIdentities(kerberosIdentityDataFileWriter, 
componentIdentities,
+                identityFilter, KerberosHelper.AMBARI_SERVER_HOST_NAME, 
"AMBARI_SERVER", "SPNEGO", kerberosConfigurations, configurations);
               propertiesToIgnore = 
gatherPropertiesToIgnore(componentIdentities, propertiesToIgnore);
             }
           }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
new file mode 100644
index 0000000..9c2c622
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIdentitiesServerAction.java
@@ -0,0 +1,235 @@
+/*
+ * 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.serveraction.kerberos;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+import com.google.inject.Inject;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.controller.utilities.KerberosChecker;
+import org.apache.ambari.server.orm.dao.HostDAO;
+import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
+import org.apache.ambari.server.orm.entities.HostEntity;
+import org.apache.ambari.server.serveraction.ActionLog;
+import org.apache.ambari.server.utils.ShellCommandUtil;
+import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ConfigureAmbariIdentitiesServerAction is a ServerAction implementation that 
creates keytab files as
+ * instructed.
+ * <p/>
+ * This class mainly relies on the KerberosServerAction to iterate through 
metadata identifying
+ * the Kerberos keytab files that need to be created. For each identity in the 
metadata, this
+ * implementation's
+ * {@link KerberosServerAction#processIdentity(Map, String, 
KerberosOperationHandler, Map, Map)}
+ * is invoked attempting the creation of the relevant keytab file.
+ */
+public class ConfigureAmbariIdentitiesServerAction extends 
KerberosServerAction {
+
+
+  private static final String KEYTAB_PATTERN = "keyTab=\"(.+)?\"";
+  private static final String PRINCIPAL_PATTERN = "principal=\"(.+)?\"";
+
+  private final static Logger LOG = 
LoggerFactory.getLogger(ConfigureAmbariIdentitiesServerAction.class);
+
+  @Inject
+  private KerberosPrincipalHostDAO kerberosPrincipalHostDAO;
+
+  @Inject
+  private HostDAO hostDAO;
+
+  /**
+   * Called to execute this action.  Upon invocation, calls
+   * {@link KerberosServerAction#processIdentities(Map)} )}
+   * to iterate through the Kerberos identity metadata and call
+   * {@link ConfigureAmbariIdentitiesServerAction#processIdentities(Map)}
+   * for each identity to process.
+   *
+   * @param requestSharedDataContext a Map to be used a shared data among all 
ServerActions related
+   *                                 to a given request
+   * @return a CommandReport indicating the result of this action
+   * @throws AmbariException
+   * @throws InterruptedException
+   */
+  @Override
+  public CommandReport execute(ConcurrentMap<String, Object> 
requestSharedDataContext) throws
+      AmbariException, InterruptedException {
+    return processIdentities(requestSharedDataContext);
+  }
+
+
+  /**
+   * Creates keytab file for ambari-server identity.
+   * <p/>
+   * It is expected that the {@link CreatePrincipalsServerAction}
+   * (or similar) and {@link CreateKeytabFilesServerAction} has executed 
before this action.
+   *
+   * @param identityRecord           a Map containing the data for the current 
identity record
+   * @param evaluatedPrincipal       a String indicating the relevant principal
+   * @param operationHandler         a KerberosOperationHandler used to 
perform Kerberos-related
+   *                                 tasks for specific Kerberos 
implementations
+   *                                 (MIT, Active Directory, etc...)
+   * @param kerberosConfiguration    a Map of configuration properties from 
kerberos-env
+   * @param requestSharedDataContext a Map to be used a shared data among all 
ServerActions related
+   *                                 to a given request  @return a 
CommandReport, indicating an error
+   *                                 condition; or null, indicating a success 
condition
+   * @throws AmbariException if an error occurs while processing the identity 
record
+   */
+  @Override
+  protected CommandReport processIdentity(Map<String, String> identityRecord, 
String evaluatedPrincipal,
+                                          KerberosOperationHandler 
operationHandler,
+                                          Map<String, String> 
kerberosConfiguration,
+                                          Map<String, Object> 
requestSharedDataContext)
+      throws AmbariException {
+    CommandReport commandReport = null;
+
+    if (identityRecord != null) {
+      String message;
+      String dataDirectory = getDataDirectoryPath();
+
+      if (dataDirectory == null) {
+        message = "The data directory has not been set. Generated keytab files 
can not be stored.";
+        LOG.error(message);
+        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", 
actionLog.getStdOut(), actionLog.getStdErr());
+      } else {
+
+        String hostName = 
identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
+        if (hostName != null && 
hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
+          String destKeytabFilePath = 
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
+          File hostDirectory = new File(dataDirectory, hostName);
+          File srcKeytabFile = new File(hostDirectory, 
DigestUtils.sha1Hex(destKeytabFilePath));
+
+          if (srcKeytabFile.exists()) {
+            installAmbariServerIdentity(evaluatedPrincipal, 
srcKeytabFile.getAbsolutePath(), destKeytabFilePath, actionLog);
+
+            if 
("AMBARI_SERVER".equals(identityRecord.get(KerberosIdentityDataFileReader.COMPONENT)))
 {
+              // Create/update the JAASFile...
+              configureJAAS(evaluatedPrincipal, destKeytabFilePath, actionLog);
+            }
+          }
+        }
+      }
+    }
+
+    return commandReport;
+  }
+
+  /**
+   * Installs the Ambari Server Kerberos identity by copying its keytab file 
to the specified location
+   * and then creating the Ambari Server JAAS File.
+   *
+   * @param principal          the ambari server principal name
+   * @param srcKeytabFilePath  the source location of the ambari server keytab 
file
+   * @param destKeytabFilePath the destination location of the ambari server 
keytab file
+   * @param actionLog          the logger
+   * @return true if success; false otherwise
+   * @throws AmbariException
+   */
+  public boolean installAmbariServerIdentity(String principal,
+                                             String srcKeytabFilePath,
+                                             String destKeytabFilePath,
+                                             ActionLog actionLog) throws 
AmbariException {
+
+    // Use sudo to copy the file into place....
+    try {
+      ShellCommandUtil.Result result;
+
+      // Ensure the parent directory exists...
+      File destKeytabFile = new File(destKeytabFilePath);
+      result = ShellCommandUtil.mkdir(destKeytabFile.getParent(), true);
+      if (!result.isSuccessful()) {
+        throw new AmbariException(result.getStderr());
+      }
+
+      // Copy the keytab file into place...
+      result = ShellCommandUtil.copyFile(srcKeytabFilePath, 
destKeytabFilePath, true, true);
+      if (!result.isSuccessful()) {
+        throw new AmbariException(result.getStderr());
+      } else {
+        String ambariServerHostName = StageUtils.getHostName();
+        HostEntity ambariServerHostEntity = 
hostDAO.findByName(ambariServerHostName);
+        Long ambariServerHostID = (ambariServerHostEntity == null)
+            ? null
+            : ambariServerHostEntity.getHostId();
+
+        if (ambariServerHostID == null) {
+          String message = String.format("Failed to add the 
kerberos_principal_host record for %s on " +
+                  "the Ambari server host since the host id for Ambari server 
host, %s, was not found." +
+                  "  This is not an error if an Ambari agent is not installed 
on the Ambari server host.",
+              principal, ambariServerHostName);
+          LOG.warn(message);
+          actionLog.writeStdErr(message);
+        } else if (!kerberosPrincipalHostDAO.exists(principal, 
ambariServerHostID)) {
+          kerberosPrincipalHostDAO.create(principal, ambariServerHostID);
+        }
+
+        actionLog.writeStdOut(String.format("Created Ambari server keytab file 
for %s at %s", principal, destKeytabFile));
+      }
+    } catch (InterruptedException | IOException e) {
+      throw new AmbariException(e.getLocalizedMessage(), e);
+    }
+
+    return true;
+  }
+
+  private void configureJAAS(String evaluatedPrincipal, String keytabFilePath, 
ActionLog actionLog) {
+    String jaasConfPath = 
System.getProperty(KerberosChecker.JAVA_SECURITY_AUTH_LOGIN_CONFIG);
+    if (jaasConfPath != null) {
+      File jaasConfigFile = new File(jaasConfPath);
+      try {
+        String jaasConfig = FileUtils.readFileToString(jaasConfigFile);
+        File oldJaasConfigFile = new File(jaasConfPath + ".bak");
+        FileUtils.writeStringToFile(oldJaasConfigFile, jaasConfig);
+        jaasConfig = jaasConfig.replaceFirst(KEYTAB_PATTERN, "keyTab=\"" + 
keytabFilePath + "\"");
+        jaasConfig = jaasConfig.replaceFirst(PRINCIPAL_PATTERN, "principal=\"" 
+ evaluatedPrincipal + "\"");
+        FileUtils.writeStringToFile(jaasConfigFile, jaasConfig);
+        String message = String.format("JAAS config file %s modified 
successfully for principal %s.", jaasConfigFile
+            .getName(), evaluatedPrincipal);
+        if (actionLog != null) {
+          actionLog.writeStdOut(message);
+        }
+      } catch (IOException e) {
+        String message = String.format("Failed to configure JAAS file %s for 
%s - %s", jaasConfigFile,
+            evaluatedPrincipal, e.getMessage());
+        if (actionLog != null) {
+          actionLog.writeStdErr(message);
+        }
+        LOG.error(message, e);
+      }
+    } else {
+      String message = String.format("Failed to configure JAAS, config file 
should be passed to Ambari server as: " +
+          "%s.", KerberosChecker.JAVA_SECURITY_AUTH_LOGIN_CONFIG);
+      if (actionLog != null) {
+        actionLog.writeStdErr(message);
+      }
+      LOG.error(message);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIndetityServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIndetityServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIndetityServerAction.java
deleted file mode 100644
index 96540ef..0000000
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/ConfigureAmbariIndetityServerAction.java
+++ /dev/null
@@ -1,208 +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.serveraction.kerberos;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.actionmanager.HostRoleStatus;
-import org.apache.ambari.server.agent.CommandReport;
-import org.apache.ambari.server.controller.KerberosHelper;
-import org.apache.ambari.server.controller.utilities.KerberosChecker;
-import org.apache.ambari.server.serveraction.ActionLog;
-import org.apache.ambari.server.utils.ShellCommandUtil;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * ConfigureAmbariIndetityServerAction is a ServerAction implementation that 
creates keytab files as
- * instructed.
- * <p/>
- * This class mainly relies on the KerberosServerAction to iterate through 
metadata identifying
- * the Kerberos keytab files that need to be created. For each identity in the 
metadata, this
- * implementation's
- * {@link KerberosServerAction#processIdentity(Map, String, 
KerberosOperationHandler, Map, Map)}
- * is invoked attempting the creation of the relevant keytab file.
- */
-public class ConfigureAmbariIndetityServerAction extends KerberosServerAction {
-
-
-  private static final String KEYTAB_PATTERN = "keyTab=\"(.+)?\"";
-  private static final String PRINCIPAL_PATTERN = "principal=\"(.+)?\"";
-
-  private final static Logger LOG = 
LoggerFactory.getLogger(ConfigureAmbariIndetityServerAction.class);
-
-  /**
-   * Called to execute this action.  Upon invocation, calls
-   * {@link KerberosServerAction#processIdentities(Map)} )}
-   * to iterate through the Kerberos identity metadata and call
-   * {@link ConfigureAmbariIndetityServerAction#processIdentities(Map)}
-   * for each identity to process.
-   *
-   * @param requestSharedDataContext a Map to be used a shared data among all 
ServerActions related
-   *                                 to a given request
-   * @return a CommandReport indicating the result of this action
-   * @throws AmbariException
-   * @throws InterruptedException
-   */
-  @Override
-  public CommandReport execute(ConcurrentMap<String, Object> 
requestSharedDataContext) throws
-    AmbariException, InterruptedException {
-    return processIdentities(requestSharedDataContext);
-  }
-
-
-  /**
-   * Creates keytab file for ambari-server identity.
-   * <p/>
-   * It is expected that the {@link CreatePrincipalsServerAction}
-   * (or similar) and {@link CreateKeytabFilesServerAction} has executed 
before this action.
-   *
-   * @param identityRecord           a Map containing the data for the current 
identity record
-   * @param evaluatedPrincipal       a String indicating the relevant principal
-   * @param operationHandler         a KerberosOperationHandler used to 
perform Kerberos-related
-   *                                 tasks for specific Kerberos 
implementations
-   *                                 (MIT, Active Directory, etc...)
-   * @param kerberosConfiguration    a Map of configuration properties from 
kerberos-env
-   * @param requestSharedDataContext a Map to be used a shared data among all 
ServerActions related
-   *                                 to a given request  @return a 
CommandReport, indicating an error
-   *                                 condition; or null, indicating a success 
condition
-   * @throws AmbariException if an error occurs while processing the identity 
record
-   */
-  @Override
-  protected CommandReport processIdentity(Map<String, String> identityRecord, 
String evaluatedPrincipal,
-                                          KerberosOperationHandler 
operationHandler,
-                                          Map<String, String> 
kerberosConfiguration,
-                                          Map<String, Object> 
requestSharedDataContext)
-    throws AmbariException {
-    CommandReport commandReport = null;
-
-    if (identityRecord != null) {
-      String message;
-      String dataDirectory = getDataDirectoryPath();
-
-      if (operationHandler == null) {
-        message = String.format("Failed to create keytab file for %s, missing 
KerberosOperationHandler", evaluatedPrincipal);
-        actionLog.writeStdErr(message);
-        LOG.error(message);
-        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", 
actionLog.getStdOut(), actionLog.getStdErr());
-      } else if (dataDirectory == null) {
-        message = "The data directory has not been set. Generated keytab files 
can not be stored.";
-        LOG.error(message);
-        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", 
actionLog.getStdOut(), actionLog.getStdErr());
-      } else {
-
-        String hostName = 
identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
-        if (hostName != null && 
hostName.equalsIgnoreCase(KerberosHelper.AMBARI_SERVER_HOST_NAME)) {
-          String destKeytabFilePath = 
identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
-          File hostDirectory = new File(dataDirectory, hostName);
-          File srcKeytabFile = new File(hostDirectory, 
DigestUtils.sha1Hex(destKeytabFilePath));
-
-          if(srcKeytabFile.exists()) {
-            installAmbariServerIdentity(evaluatedPrincipal, 
srcKeytabFile.getAbsolutePath(), destKeytabFilePath, actionLog);
-          }
-        }
-      }
-    }
-
-    return commandReport;
-  }
-
-  /**
-   * Installs the Ambari Server Kerberos identity by copying its keytab file 
to the specified location
-   * and then creating the Ambari Server JAAS File.
-   *
-   * @param principal          the ambari server principal name
-   * @param srcKeytabFilePath  the source location of the ambari server keytab 
file
-   * @param destKeytabFilePath the destination location of the ambari server 
keytab file
-   * @param actionLog          the logger
-   * @return true if success; false otherwise
-   * @throws AmbariException
-   */
-  public boolean installAmbariServerIdentity(String principal,
-                                             String srcKeytabFilePath,
-                                             String destKeytabFilePath,
-                                             ActionLog actionLog) throws 
AmbariException {
-
-    // Use sudo to copy the file into place....
-    try {
-      ShellCommandUtil.Result result;
-
-      // Ensure the parent directory exists...
-      File destKeytabFile = new File(destKeytabFilePath);
-      result = ShellCommandUtil.mkdir(destKeytabFile.getParent(), true);
-      if (!result.isSuccessful()) {
-        throw new AmbariException(result.getStderr());
-      }
-
-      // Copy the keytab file into place...
-      result = ShellCommandUtil.copyFile(srcKeytabFilePath, 
destKeytabFilePath, true, true);
-      if (!result.isSuccessful()) {
-        throw new AmbariException(result.getStderr());
-      }
-    } catch (InterruptedException | IOException e) {
-      throw new AmbariException(e.getLocalizedMessage(), e);
-    }
-
-    // Create/update the JAASFile...
-    configureJAAS(principal, destKeytabFilePath, actionLog);
-
-    return true;
-  }
-
-  private void configureJAAS(String evaluatedPrincipal, String keytabFilePath, 
ActionLog actionLog) {
-    String jaasConfPath = 
System.getProperty(KerberosChecker.JAVA_SECURITY_AUTH_LOGIN_CONFIG);
-    if (jaasConfPath != null) {
-      File jaasConfigFile = new File(jaasConfPath);
-      try {
-        String jaasConfig = FileUtils.readFileToString(jaasConfigFile);
-        File oldJaasConfigFile = new File(jaasConfPath + ".bak");
-        FileUtils.writeStringToFile(oldJaasConfigFile, jaasConfig);
-        jaasConfig = jaasConfig.replaceFirst(KEYTAB_PATTERN, "keyTab=\"" + 
keytabFilePath + "\"");
-        jaasConfig = jaasConfig.replaceFirst(PRINCIPAL_PATTERN, "principal=\"" 
+ evaluatedPrincipal + "\"");
-        FileUtils.writeStringToFile(jaasConfigFile, jaasConfig);
-        String message = String.format("JAAS config file %s modified 
successfully for principal %s.", jaasConfigFile
-          .getName(), evaluatedPrincipal);
-        if (actionLog != null) {
-          actionLog.writeStdOut(message);
-        }
-      } catch (IOException e) {
-        String message = String.format("Failed to configure JAAS file %s for 
%s - %s", jaasConfigFile,
-          evaluatedPrincipal, e.getMessage());
-        if (actionLog != null) {
-          actionLog.writeStdErr(message);
-        }
-        LOG.error(message, e);
-      }
-    } else {
-      String message = String.format("Failed to configure JAAS, config file 
should be passed to Ambari server as: " +
-        "%s.", KerberosChecker.JAVA_SECURITY_AUTH_LOGIN_CONFIG);
-      if (actionLog != null) {
-        actionLog.writeStdErr(message);
-      }
-      LOG.error(message);
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
index e31e6ff..b99c25a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.serveraction.kerberos;
 
-import com.google.common.base.Optional;
 import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
@@ -145,7 +144,7 @@ public class CreatePrincipalsServerAction extends 
KerberosServerAction {
           // This principal has been processed and a keytab file has been 
distributed... do not process it.
           processPrincipal = false;
         } else {
-          // This principal has been processed but a keytab file for it has 
been distributed... process it.
+          // This principal has been processed but a keytab file for it has 
not been distributed... process it.
           processPrincipal = true;
         }
       }
@@ -232,7 +231,7 @@ public class CreatePrincipalsServerAction extends 
KerberosServerAction {
       String password = securePasswordHelper.createSecurePassword(length, 
minLowercaseLetters, minUppercaseLetters, minDigits, minPunctuation, 
minWhitespace);
 
       try {
-        /**
+        /*
          * true indicates a new principal was created, false indicates an 
existing principal was updated
          */
         boolean created;

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
index db210e0..1d8c1ca 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
@@ -28,6 +28,7 @@ import 
org.apache.ambari.server.security.credential.PrincipalKeyCredential;
 import org.apache.ambari.server.serveraction.AbstractServerAction;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.utils.StageUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -514,12 +515,19 @@ public abstract class KerberosServerAction extends 
AbstractServerAction {
 
     if (record != null) {
       String principal = record.get(KerberosIdentityDataFileReader.PRINCIPAL);
-      String host = record.get(KerberosIdentityDataFileReader.HOSTNAME);
 
       if (principal != null) {
+        String hostname = record.get(KerberosIdentityDataFileReader.HOSTNAME);
+
+        if(KerberosHelper.AMBARI_SERVER_HOST_NAME.equals(hostname)) {
+          // Replace KerberosHelper.AMBARI_SERVER_HOST_NAME with the actual 
hostname where the Ambari
+          // server is... this host
+          hostname = StageUtils.getHostName();
+        }
+
         // Evaluate the principal "pattern" found in the record to generate 
the "evaluated principal"
         // by replacing the _HOST and _REALM variables.
-        String evaluatedPrincipal = principal.replace("_HOST", 
host).replace("_REALM", defaultRealm);
+        String evaluatedPrincipal = principal.replace("_HOST", 
hostname).replace("_REALM", defaultRealm);
 
         commandReport = processIdentity(record, evaluatedPrincipal, 
operationHandler, kerberosConfiguration, requestSharedDataContext);
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/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 a86973c..500c0bf 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
@@ -30,16 +30,11 @@
     <custom-filter ref="ambariAuthorizationFilter" 
before="FILTER_SECURITY_INTERCEPTOR"/>
   </http>
 
-  <!--<ldap-server id="ldapServer" root="dc=ambari,dc=apache,dc=org"/>-->
-
   <authentication-manager alias="authenticationManager">
-
     <authentication-provider ref="ambariLocalAuthenticationProvider"/>
-
     <authentication-provider ref="ambariLdapAuthenticationProvider"/>
-
     <authentication-provider ref="ambariInternalAuthenticationProvider"/>
-
+    <authentication-provider ref="kerberosServiceAuthenticationProvider"/>
   </authentication-manager>
 
   <beans:bean id="ambariEntryPoint" 
class="org.apache.ambari.server.security.AmbariEntryPoint">
@@ -49,6 +44,7 @@
     <beans:constructor-arg>
       <beans:list>
         <beans:ref bean="ambariBasicAuthenticationFilter"/>
+        <beans:ref bean="ambariKerberosAuthenticationFilter"/>
         <beans:ref bean="ambariJwtAuthenticationFilter"/>
       </beans:list>
     </beans:constructor-arg>
@@ -69,6 +65,14 @@
     <beans:constructor-arg ref="permissionHelper"/>
   </beans:bean>
 
+  <beans:bean id="ambariKerberosAuthenticationFilter" 
class="org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosAuthenticationFilter">
+    <beans:constructor-arg ref="authenticationManager"/>
+    <beans:constructor-arg ref="ambariEntryPoint"/>
+    <beans:constructor-arg ref="ambariConfiguration"/>
+    <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"/>
@@ -77,4 +81,20 @@
     <beans:constructor-arg ref="permissionHelper"/>
   </beans:bean>
 
+  <beans:bean id="kerberosServiceAuthenticationProvider" 
class="org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider">
+    <beans:property name="ticketValidator">
+      <beans:bean 
class="org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosTicketValidator">
+        <beans:constructor-arg ref="ambariConfiguration"/>
+        <beans:property name="debug" value="false"/>
+      </beans:bean>
+    </beans:property>
+
+    <beans:property name="userDetailsService" 
ref="authToLocalUserDetailsService"/>
+  </beans:bean>
+
+  <beans:bean id="authToLocalUserDetailsService" 
class="org.apache.ambari.server.security.authentication.kerberos.AmbariAuthToLocalUserDetailsService">
+    <beans:constructor-arg ref="ambariConfiguration"/>
+    <beans:constructor-arg ref="ambariUsers"/>
+  </beans:bean>
+
 </beans:beans>

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
index 3c97ce9..7e6a056 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
@@ -104,7 +104,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -3755,6 +3754,7 @@ public class KerberosHelperTest extends EasyMockSupport {
     KerberosDescriptor kerberosDescriptor = 
createMock(KerberosDescriptor.class);
     if (createAmbariPrincipal) {
       
expect(kerberosDescriptor.getIdentity(KerberosHelper.AMBARI_IDENTITY_NAME)).andReturn(ambariKerberosIdentity).once();
+      
expect(kerberosDescriptor.getIdentity(KerberosHelper.SPNEGO_IDENTITY_NAME)).andReturn(ambariKerberosIdentity).once();
     }
 
     List<KerberosIdentityDescriptor> identities = new 
ArrayList<KerberosIdentityDescriptor>();
@@ -3764,12 +3764,12 @@ public class KerberosHelperTest extends EasyMockSupport 
{
     // Needed by infrastructure
     injector.getInstance(AmbariMetaInfo.class).init();
 
-    kerberosHelper.addAmbariServerIdentity(kerberosEnvProperties, 
kerberosDescriptor, identities);
+    kerberosHelper.addAmbariServerIdentities(kerberosEnvProperties, 
kerberosDescriptor, identities);
 
     verifyAll();
 
     if (createAmbariPrincipal) {
-      Assert.assertEquals(1, identities.size());
+      Assert.assertEquals(2, identities.size());
       Assert.assertSame(ambariKerberosIdentity, identities.get(0));
     } else {
       Assert.assertTrue(identities.isEmpty());

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
new file mode 100644
index 0000000..e980808
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariAuthToLocalUserDetailsServiceTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.kerberos;
+
+import junit.framework.Assert;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.AmbariGrantedAuthority;
+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.EasyMockSupport;
+import org.junit.Test;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.easymock.EasyMock.expect;
+
+public class AmbariAuthToLocalUserDetailsServiceTest extends EasyMockSupport {
+  @Test
+  public void loadUserByUsernameSuccess() throws Exception {
+    AmbariKerberosAuthenticationProperties properties = new 
AmbariKerberosAuthenticationProperties();
+
+    Configuration configuration = createMock(Configuration.class);
+    
expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
+
+    User user = createMock(User.class);
+    expect(user.getUserName()).andReturn("user1").once();
+    expect(user.getUserType()).andReturn(UserType.LDAP).once();
+
+    Collection<AmbariGrantedAuthority> userAuthorities = 
Collections.singletonList(createNiceMock(AmbariGrantedAuthority.class));
+
+    Users users = createMock(Users.class);
+    expect(users.getUser("user1", UserType.LDAP)).andReturn(user).once();
+    expect(users.getUserAuthorities("user1", 
UserType.LDAP)).andReturn(userAuthorities).once();
+
+    replayAll();
+
+    UserDetailsService userdetailsService = new 
AmbariAuthToLocalUserDetailsService(configuration, users);
+
+    UserDetails userDetails = 
userdetailsService.loadUserByUsername("us...@example.com");
+
+    verifyAll();
+
+    Assert.assertNotNull(userDetails);
+    Assert.assertEquals("user1", userDetails.getUsername());
+    Assert.assertEquals(userAuthorities.size(), 
userDetails.getAuthorities().size());
+    Assert.assertEquals("", userDetails.getPassword());
+  }
+
+  @Test(expected = UsernameNotFoundException.class)
+  public void loadUserByUsernameUserNotFound() throws Exception {
+    AmbariKerberosAuthenticationProperties properties = new 
AmbariKerberosAuthenticationProperties();
+
+    Configuration configuration = createMock(Configuration.class);
+    
expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
+
+    Users users = createMock(Users.class);
+    expect(users.getUser("user1", UserType.LDAP)).andReturn(null).once();
+    expect(users.getUser("user1", UserType.LOCAL)).andReturn(null).once();
+
+    replayAll();
+
+    UserDetailsService userdetailsService = new 
AmbariAuthToLocalUserDetailsService(configuration, users);
+
+    userdetailsService.loadUserByUsername("us...@example.com");
+
+    verifyAll();
+
+    Assert.fail("UsernameNotFoundException was not thrown");
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
new file mode 100644
index 0000000..d855cda
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosAuthenticationFilterTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.kerberos;
+
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.easymock.EasyMockSupport;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.web.AuthenticationEntryPoint;
+
+import javax.servlet.http.HttpServletRequest;
+
+import static org.easymock.EasyMock.expect;
+
+public class AmbariKerberosAuthenticationFilterTest extends EasyMockSupport {
+  @Test
+  public void shouldApplyTrue() throws Exception {
+    HttpServletRequest httpServletRequest = 
createMock(HttpServletRequest.class);
+    expect(httpServletRequest.getHeader("Authorization")).andReturn("Negotiate 
.....").once();
+
+    AmbariKerberosAuthenticationProperties properties = 
createMock(AmbariKerberosAuthenticationProperties.class);
+    
expect(properties.isKerberosAuthenticationEnabled()).andReturn(true).once();
+
+    Configuration configuration = createMock(Configuration.class);
+    
expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
+
+    AuthenticationManager authenticationManager = 
createMock(AuthenticationManager.class);
+    AuthenticationEntryPoint entryPoint = 
createMock(AuthenticationEntryPoint.class);
+    AuditLogger auditLogger = createMock(AuditLogger.class);
+    PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+
+    replayAll();
+
+    AmbariKerberosAuthenticationFilter filter = new 
AmbariKerberosAuthenticationFilter(
+        authenticationManager,
+        entryPoint,
+        configuration,
+        auditLogger,
+        permissionHelper
+    );
+
+    Assert.assertTrue(filter.shouldApply(httpServletRequest));
+
+    verifyAll();
+  }
+
+  @Test
+  public void shouldApplyFalseMissingHeader() throws Exception {
+    HttpServletRequest httpServletRequest = 
createMock(HttpServletRequest.class);
+    
expect(httpServletRequest.getHeader("Authorization")).andReturn(null).once();
+
+    AmbariKerberosAuthenticationProperties properties = 
createMock(AmbariKerberosAuthenticationProperties.class);
+    
expect(properties.isKerberosAuthenticationEnabled()).andReturn(true).once();
+
+    Configuration configuration = createMock(Configuration.class);
+    
expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
+
+    AuthenticationManager authenticationManager = 
createMock(AuthenticationManager.class);
+    AuthenticationEntryPoint entryPoint = 
createMock(AuthenticationEntryPoint.class);
+    AuditLogger auditLogger = createMock(AuditLogger.class);
+    PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+
+    replayAll();
+
+    AmbariKerberosAuthenticationFilter filter = new 
AmbariKerberosAuthenticationFilter(
+        authenticationManager,
+        entryPoint,
+        configuration,
+        auditLogger,
+        permissionHelper
+    );
+
+    Assert.assertFalse(filter.shouldApply(httpServletRequest));
+
+    verifyAll();
+  }
+
+  @Test
+  public void shouldApplyNotFalseEnabled() throws Exception {
+    HttpServletRequest httpServletRequest = 
createMock(HttpServletRequest.class);
+
+    AmbariKerberosAuthenticationProperties properties = 
createMock(AmbariKerberosAuthenticationProperties.class);
+    
expect(properties.isKerberosAuthenticationEnabled()).andReturn(false).once();
+
+    Configuration configuration = createMock(Configuration.class);
+    
expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
+
+    AuthenticationManager authenticationManager = 
createMock(AuthenticationManager.class);
+    AuthenticationEntryPoint entryPoint = 
createMock(AuthenticationEntryPoint.class);
+    AuditLogger auditLogger = createMock(AuditLogger.class);
+    PermissionHelper permissionHelper = createMock(PermissionHelper.class);
+
+    replayAll();
+
+    AmbariKerberosAuthenticationFilter filter = new 
AmbariKerberosAuthenticationFilter(
+        authenticationManager,
+        entryPoint,
+        configuration,
+        auditLogger,
+        permissionHelper
+    );
+
+    Assert.assertFalse(filter.shouldApply(httpServletRequest));
+
+    verifyAll();
+  }
+
+  @Test
+  public void doFilter() throws Exception {
+    // Skip this test since the real work is being done by 
SpnegoAuthenticationProcessingFilter, which
+    // is a class in the Spring libraries.
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/b4320b5a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidatorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidatorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidatorTest.java
new file mode 100644
index 0000000..9bc87a4
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/security/authentication/kerberos/AmbariKerberosTicketValidatorTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.kerberos;
+
+import org.apache.ambari.server.configuration.Configuration;
+import org.easymock.EasyMockSupport;
+import org.junit.Test;
+
+import static org.easymock.EasyMock.expect;
+
+public class AmbariKerberosTicketValidatorTest extends EasyMockSupport {
+
+  /**
+   * Tests an {@link AmbariKerberosTicketValidator} to ensure that the Spnego 
identity is properly
+   * set in the base class during construction.
+   */
+  @Test
+  public void testConstructor() throws NoSuchMethodException {
+    AmbariKerberosAuthenticationProperties properties = 
createMock(AmbariKerberosAuthenticationProperties.class);
+    
expect(properties.isKerberosAuthenticationEnabled()).andReturn(true).once();
+    
expect(properties.getSpnegoPrincipalName()).andReturn("HTTP/somehost.example.com").times(1);
+    
expect(properties.getSpnegoKeytabFilePath()).andReturn("/etc/security/keytabs/spnego.service.keytab").times(2);
+
+    Configuration configuration = createMock(Configuration.class);
+    
expect(configuration.getKerberosAuthenticationProperties()).andReturn(properties).once();
+
+    replayAll();
+
+    new AmbariKerberosTicketValidator(configuration);
+
+    verifyAll();
+  }
+}
\ No newline at end of file

Reply via email to