AMBARI-14905. Add API directive to force toggling Kerberos if the cluster's security type has not changed (rlevas)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/eb3f9959 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/eb3f9959 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/eb3f9959 Branch: refs/heads/branch-dev-patch-upgrade Commit: eb3f995965b2749910ceae9e5cc8f8bc043e6862 Parents: ab06c68 Author: Robert Levas <rle...@hortonworks.com> Authored: Thu Feb 4 15:46:18 2016 -0500 Committer: Robert Levas <rle...@hortonworks.com> Committed: Thu Feb 4 15:46:23 2016 -0500 ---------------------------------------------------------------------- .../resources/ClusterResourceDefinition.java | 3 +- .../AmbariManagementControllerImpl.java | 44 +++++++------ .../server/controller/KerberosHelper.java | 26 +++++++- .../server/controller/KerberosHelperImpl.java | 5 ++ .../AmbariManagementControllerImplTest.java | 12 ++++ .../server/controller/KerberosHelperTest.java | 66 +++++++++++++++++++- 6 files changed, 133 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/eb3f9959/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java index b2be291..e57364f 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/resources/ClusterResourceDefinition.java @@ -81,8 +81,9 @@ public class ClusterResourceDefinition extends BaseResourceDefinition { @Override public Collection<String> getUpdateDirectives() { Collection<String> directives = super.getUpdateDirectives(); - directives.add("regenerate_keytabs"); + directives.add(KerberosHelper.DIRECTIVE_REGENERATE_KEYTABS); directives.add(KerberosHelper.DIRECTIVE_MANAGE_KERBEROS_IDENTITIES); + directives.add(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS); return directives; } http://git-wip-us.apache.org/repos/asf/ambari/blob/eb3f9959/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java index 5010311..69b3348 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java @@ -1708,29 +1708,35 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle } catch (KerberosOperationException e) { throw new IllegalArgumentException(e.getMessage(), e); } - } else if (cluster.getSecurityType() != securityType) { - LOG.info("Received cluster security type change request from {} to {}", - cluster.getSecurityType().name(), securityType.name()); + } else { + // If force_toggle_kerberos is not specified, null will be returned. Therefore, perform an + // equals check to yield true if the result is Boolean.TRUE, otherwise false. + boolean forceToggleKerberos = kerberosHelper.getForceToggleKerberosDirective(requestProperties); - if ((securityType == SecurityType.KERBEROS) || (securityType == SecurityType.NONE)) { - if(!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(), EnumSet.of(RoleAuthorization.CLUSTER_TOGGLE_KERBEROS))) { - throw new AuthorizationException("The authenticated user does not have authorization to enable or disable Kerberos"); - } + if (forceToggleKerberos || (cluster.getSecurityType() != securityType)) { + LOG.info("Received cluster security type change request from {} to {} (forced: {})", + cluster.getSecurityType().name(), securityType.name(), forceToggleKerberos); - // Since the security state of the cluster has changed, invoke toggleKerberos to handle - // adding or removing Kerberos from the cluster. This may generate multiple stages - // or not depending the current state of the cluster. - try { - requestStageContainer = kerberosHelper.toggleKerberos(cluster, securityType, requestStageContainer, - kerberosHelper.getManageIdentitiesDirective(requestProperties)); - } catch (KerberosOperationException e) { - throw new IllegalArgumentException(e.getMessage(), e); + if ((securityType == SecurityType.KERBEROS) || (securityType == SecurityType.NONE)) { + if (!AuthorizationHelper.isAuthorized(ResourceType.CLUSTER, cluster.getResourceId(), EnumSet.of(RoleAuthorization.CLUSTER_TOGGLE_KERBEROS))) { + throw new AuthorizationException("The authenticated user does not have authorization to enable or disable Kerberos"); + } + + // Since the security state of the cluster has changed, invoke toggleKerberos to handle + // adding or removing Kerberos from the cluster. This may generate multiple stages + // or not depending the current state of the cluster. + try { + requestStageContainer = kerberosHelper.toggleKerberos(cluster, securityType, requestStageContainer, + kerberosHelper.getManageIdentitiesDirective(requestProperties)); + } catch (KerberosOperationException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } else { + throw new IllegalArgumentException(String.format("Unexpected security type encountered: %s", securityType.name())); } - } else { - throw new IllegalArgumentException(String.format("Unexpected security type encountered: %s", securityType.name())); - } - cluster.setSecurityType(securityType); + cluster.setSecurityType(securityType); + } } } http://git-wip-us.apache.org/repos/asf/ambari/blob/eb3f9959/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 5008d60..39f55cd 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 @@ -45,6 +45,15 @@ public interface KerberosHelper { */ String DIRECTIVE_MANAGE_KERBEROS_IDENTITIES = "manage_kerberos_identities"; /** + * directive used to indicate that the enable Kerberos operation is only to regenerate keytab files + */ + String DIRECTIVE_REGENERATE_KEYTABS = "regenerate_keytabs"; + /** + * directive used to indicate that the enable Kerberos operation should proceed even if the + * cluster's security type is not changing + */ + String DIRECTIVE_FORCE_TOGGLE_KERBEROS = "force_toggle_kerberos"; + /** * config type which contains the property used to determine if Kerberos is enabled */ String SECURITY_ENABLED_CONFIG_TYPE = "cluster-env"; @@ -472,13 +481,28 @@ public interface KerberosHelper { * If manage_kerberos_identities does exists in the map of request properties, a Boolean value * is returned indicating whether its value is "false" (Boolean.FALSE) or not (Boolean.TRUE). * - * @param requestProperties a map of the requst property name/value pairs + * @param requestProperties a map of the request property name/value pairs * @return Boolean.TRUE or Boolean.FALSE if the manage_kerberos_identities property exists in the map; * otherwise false */ Boolean getManageIdentitiesDirective(Map<String, String> requestProperties); /** + * Retrieves the value of the force_toggle_kerberos directive from the request properties, + * if it exists. + * <p/> + * If force_toggle_kerberos does not exist in the map of request properties, <code>false</code> is + * returned. + * <p/> + * If force_toggle_kerberos does exists in the map of request properties and is equal to "true", + * then <code>true</code> is returned; otherwise <code>false</code> is returned. + * + * @param requestProperties a map of the request property name/value pairs + * @return true if force_toggle_kerberos is "true"; otherwise false + */ + boolean getForceToggleKerberosDirective(Map<String, String> requestProperties); + + /** * Given a list of KerberosIdentityDescriptors, returns a Map fo configuration types to property * names and values. * <p/> http://git-wip-us.apache.org/repos/asf/ambari/blob/eb3f9959/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 63aa92d..556bed8 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 @@ -2078,6 +2078,11 @@ public class KerberosHelperImpl implements KerberosHelper { } @Override + public boolean getForceToggleKerberosDirective(Map<String, String> requestProperties) { + return (requestProperties != null) && "true".equalsIgnoreCase(requestProperties.get(DIRECTIVE_FORCE_TOGGLE_KERBEROS)); + } + + @Override public Map<String, Map<String, String>> getIdentityConfigurations(List<KerberosIdentityDescriptor> identityDescriptors) { Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>(); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb3f9959/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java index 5838001..6069ba6 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java @@ -728,6 +728,9 @@ public class AmbariManagementControllerImplTest { expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.KERBEROS, null)) .andReturn(false) .once(); + expect(kerberosHelper.getForceToggleKerberosDirective(anyObject(Map.class))) + .andReturn(false) + .once(); // Note: kerberosHelper.toggleKerberos is not called // replay mocks @@ -775,6 +778,9 @@ public class AmbariManagementControllerImplTest { expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.KERBEROS, null)) .andReturn(false) .once(); + expect(kerberosHelper.getForceToggleKerberosDirective(null)) + .andReturn(false) + .once(); expect(kerberosHelper.getManageIdentitiesDirective(null)) .andReturn(null) .once(); @@ -856,6 +862,9 @@ public class AmbariManagementControllerImplTest { expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.NONE, null)) .andReturn(false) .once(); + expect(kerberosHelper.getForceToggleKerberosDirective(anyObject(Map.class))) + .andReturn(false) + .once(); expect(kerberosHelper.getManageIdentitiesDirective(anyObject(Map.class))) .andReturn(manageIdentities) .once(); @@ -920,6 +929,9 @@ public class AmbariManagementControllerImplTest { expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.NONE, null)) .andReturn(false) .once(); + expect(kerberosHelper.getForceToggleKerberosDirective(anyObject(Map.class))) + .andReturn(false) + .once(); expect(kerberosHelper.getManageIdentitiesDirective(anyObject(Map.class))) .andReturn(null) .once(); http://git-wip-us.apache.org/repos/asf/ambari/blob/eb3f9959/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 869d187..2dcde00 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 @@ -420,7 +420,7 @@ public class KerberosHelperTest extends EasyMockSupport { final Cluster cluster = createNiceMock(Cluster.class); kerberosHelper.executeCustomOperations(cluster, - Collections.singletonMap("regenerate_keytabs", "false"), null, true); + Collections.singletonMap(KerberosHelper.DIRECTIVE_REGENERATE_KEYTABS, "false"), null, true); Assert.fail("AmbariException should have failed"); } @@ -1751,7 +1751,7 @@ public class KerberosHelperTest extends EasyMockSupport { credentialStoreService.setCredential(cluster.getClusterName(), KerberosHelper.KDC_ADMINISTRATOR_CREDENTIAL_ALIAS, PrincipalKeyCredential, CredentialStoreType.TEMPORARY); - Assert.assertNotNull(kerberosHelper.executeCustomOperations(cluster, Collections.singletonMap("regenerate_keytabs", "true"), requestStageContainer, true)); + Assert.assertNotNull(kerberosHelper.executeCustomOperations(cluster, Collections.singletonMap(KerberosHelper.DIRECTIVE_REGENERATE_KEYTABS, "true"), requestStageContainer, true)); verifyAll(); } @@ -1845,6 +1845,68 @@ public class KerberosHelperTest extends EasyMockSupport { } @Test + public void testGetForceToggleKerberosDirective_NotSet() throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective(null)); + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective(Collections.<String, String>emptyMap())); + + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective( + new HashMap<String, String>() { + { + put(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS, null); + put("some_directive_0", "false"); + put("some_directive_1", null); + } + } + )); + + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective( + new HashMap<String, String>() { + { + put("some_directive_0", "false"); + put("some_directive_1", null); + } + } + )); + } + + @Test + public void testGetForceToggleKerberosDirective_True() throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + + assertEquals(true, kerberosHelper.getForceToggleKerberosDirective(Collections.singletonMap(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS, "true"))); + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective(Collections.singletonMap(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS, "not_true"))); + + assertEquals(true, kerberosHelper.getForceToggleKerberosDirective( + new HashMap<String, String>() { + { + put(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS, "true"); + put("some_directive_0", "false"); + put("some_directive_1", null); + } + } + )); + } + + @Test + public void testGetForceToggleKerberosDirective_False() throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective(Collections.singletonMap(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS, "false"))); + + assertEquals(false, kerberosHelper.getForceToggleKerberosDirective( + new HashMap<String, String>() { + { + put(KerberosHelper.DIRECTIVE_FORCE_TOGGLE_KERBEROS, "false"); + put("some_directive_0", "false"); + put("some_directive_1", null); + } + } + )); + } + + @Test public void testSetAuthToLocalRules() throws Exception { KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);