You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2016/09/21 13:29:33 UTC
[11/21] ambari git commit: AMBARI-18406. Create authentication filter
to perform Kerberos authentication for Ambari (rlevas)
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 <rl...@hortonworks.com>
Authored: Tue Sep 20 14:45:23 2016 -0400
Committer: Robert Levas <rl...@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("user1@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("user1@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