ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dmitriu...@apache.org
Subject [1/2] ambari git commit: AMBARI-13498. Passwords for components should not be readable by end-users (echekanskiy via dlysnichenko)
Date Thu, 22 Oct 2015 16:47:19 GMT
Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 03ef6cbe8 -> eb693f80d
  refs/heads/trunk 2ff92a914 -> 1ff22dffe


AMBARI-13498. Passwords for components should not be readable by end-users (echekanskiy via
dlysnichenko)


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

Branch: refs/heads/branch-2.1
Commit: eb693f80d978077ac2cc522a455158d2b7c849b4
Parents: 03ef6cb
Author: Lisnichenko Dmitro <dlysnichenko@hortonworks.com>
Authored: Thu Oct 22 19:46:13 2015 +0300
Committer: Lisnichenko Dmitro <dlysnichenko@hortonworks.com>
Committed: Thu Oct 22 19:46:13 2015 +0300

----------------------------------------------------------------------
 .../AmbariManagementControllerImpl.java         |  48 +++++-
 .../controller/ConfigurationResponse.java       |  43 +++++-
 .../org/apache/ambari/server/state/Cluster.java |  19 ++-
 .../org/apache/ambari/server/state/Config.java  |   4 +
 .../apache/ambari/server/state/ConfigImpl.java  |  24 +++
 .../server/state/cluster/ClusterImpl.java       |  60 +++++++-
 .../ambari/server/utils/SecretReference.java    |  77 ++++++++++
 .../AmbariManagementControllerTest.java         | 145 +++++++++++++++++++
 .../services/HDFS/configuration/hdfs-site.xml   |   6 +
 9 files changed, 419 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/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 d2203fc..60c60cf 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
@@ -160,6 +160,7 @@ import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEve
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStopEvent;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostUpgradeEvent;
+import org.apache.ambari.server.utils.SecretReference;
 import org.apache.ambari.server.utils.StageUtils;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.io.IOUtils;
@@ -718,6 +719,27 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
     Cluster cluster = clusters.getCluster(request.getClusterName());
 
+    Map<String, String> requestProperties = request.getProperties();
+
+    Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = cluster.getConfigPropertiesTypes(request.getType());
+    if(propertiesTypes.containsKey(PropertyType.PASSWORD)) {
+      for(String passwordProperty : propertiesTypes.get(PropertyType.PASSWORD)) {
+        if(requestProperties.containsKey(passwordProperty)) {
+          String passwordPropertyValue = requestProperties.get(passwordProperty);
+          if (!SecretReference.isSecret(passwordPropertyValue))
+            continue;
+          SecretReference ref = new SecretReference(passwordPropertyValue, passwordProperty,
cluster);
+          if (!ref.getClusterName().equals(request.getClusterName()))
+            throw new AmbariException("Can not reference to different cluster in SECRET");
+          String refValue = ref.getValue();
+          requestProperties.put(passwordProperty, refValue);
+        }
+      }
+    }
+
+
+
+
     Map<String, Config> configs = cluster.getConfigsByType(
         request.getType());
     if (null == configs) {
@@ -738,7 +760,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
     handleGlobalsBackwardsCompability(request, propertiesAttributes);
 
-    Config config = createConfig(cluster, request.getType(), request.getProperties(),
+    Config config = createConfig(cluster, request.getType(), requestProperties,
       request.getVersionTag(), propertiesAttributes);
 
     return new ConfigurationResponse(cluster.getClusterName(), config);
@@ -1214,7 +1236,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
                 request.getType(),
                 config.getTag(), entry.getValue().getVersion(),
                 includeProps ? config.getProperties() : new HashMap<String, String>(),
-                includeProps ? config.getPropertiesAttributes() : new HashMap<String,
Map<String,String>>());
+                includeProps ? config.getPropertiesAttributes() : new HashMap<String,
Map<String,String>>(),
+                config.getPropertiesTypes());
             responses.add(response);
           }
         }
@@ -1227,7 +1250,8 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
               cluster.getClusterName(), config.getStackId(), config.getType(),
               config.getTag(), config.getVersion(),
               includeProps ? config.getProperties() : new HashMap<String, String>(),
-              includeProps ? config.getPropertiesAttributes() : new HashMap<String, Map<String,String>>());
+              includeProps ? config.getPropertiesAttributes() : new HashMap<String, Map<String,String>>(),
+              config.getPropertiesTypes());
 
           responses.add(response);
         }
@@ -1364,6 +1388,24 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     if (request.getDesiredConfig() != null) {
       for (ConfigurationRequest desiredConfig : request.getDesiredConfig()) {
         Map<String, String> requestConfigProperties = desiredConfig.getProperties();
+
+        // processing password properties
+        if(requestConfigProperties != null && !requestConfigProperties.isEmpty())
{
+          Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = cluster.getConfigPropertiesTypes(
+              desiredConfig.getType()
+          );
+          for (Entry<String, String> property : requestConfigProperties.entrySet())
{
+            String propertyName = property.getKey();
+            String propertyValue = property.getValue();
+            if (propertiesTypes.containsKey(PropertyType.PASSWORD) &&
+                propertiesTypes.get(PropertyType.PASSWORD).contains(propertyName)) {
+              if (SecretReference.isSecret(propertyValue)) {
+                SecretReference ref = new SecretReference(propertyValue, propertyName, cluster);
+                requestConfigProperties.put(propertyName, ref.getValue());
+              }
+            }
+          }
+        }
         Map<String,Map<String,String>> requestConfigAttributes = desiredConfig.getPropertiesAttributes();
         Config clusterConfig = cluster.getDesiredConfigByType(desiredConfig.getType());
         Map<String, String> clusterConfigProperties = null;

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
index d6b95c8..3ed9306 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ConfigurationResponse.java
@@ -19,9 +19,12 @@ package org.apache.ambari.server.controller;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.PropertyInfo;
 import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.utils.SecretReference;
 
 /**
  * This class encapsulates a configuration update request.
@@ -46,6 +49,8 @@ public class ConfigurationResponse {
 
   private Map<String, Map<String, String>> configAttributes;
 
+  private Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes;
+
   public ConfigurationResponse(String clusterName, StackId stackId,
       String type, String versionTag, Long version,
       Map<String, String> configs,
@@ -60,6 +65,23 @@ public class ConfigurationResponse {
     this.configAttributes = configAttributes;
   }
 
+  public ConfigurationResponse(String clusterName, StackId stackId,
+                               String type, String versionTag, Long version,
+                               Map<String, String> configs,
+                               Map<String, Map<String, String>> configAttributes,
+                               Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes)
{
+    this.clusterName = clusterName;
+    this.stackId = stackId;
+    this.configs = configs;
+    this.type = type;
+    this.versionTag = versionTag;
+    this.version = version;
+    this.configs = configs;
+    this.configAttributes = configAttributes;
+    this.propertiesTypes = propertiesTypes;
+    stubPasswords();
+  }
+
   /**
    * Constructor.
    *
@@ -69,7 +91,7 @@ public class ConfigurationResponse {
   public ConfigurationResponse(String clusterName, Config config) {
     this(clusterName, config.getStackId(), config.getType(), config.getTag(),
         config.getVersion(), config.getProperties(),
-        config.getPropertiesAttributes());
+        config.getPropertiesAttributes(), config.getPropertiesTypes());
   }
 
   /**
@@ -185,4 +207,23 @@ public class ConfigurationResponse {
   public void setServiceConfigVersions(List<Long> serviceConfigVersions) {
     this.serviceConfigVersions = serviceConfigVersions;
   }
+
+  public Map<PropertyInfo.PropertyType, Set<String>> getPropertiesTypes() {
+    return propertiesTypes;
+  }
+
+  public void setPropertiesTypes(Map<PropertyInfo.PropertyType, Set<String>>
propertiesTypes) {
+    this.propertiesTypes = propertiesTypes;
+  }
+
+  private void stubPasswords(){
+    if(propertiesTypes != null && propertiesTypes.containsKey(PropertyInfo.PropertyType.PASSWORD))
{
+      for(String pwdPropertyName: propertiesTypes.get(PropertyInfo.PropertyType.PASSWORD))
{
+        if(configs.containsKey(pwdPropertyName)){
+          String stub = SecretReference.generateStub(clusterName, type, version);
+          configs.put(pwdPropertyName, stub);
+        }
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
index 2f3641d..affd3a8 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Cluster.java
@@ -301,16 +301,33 @@ public interface Cluster {
   Map<String, Config> getConfigsByType(String configType);
 
   /**
+   * Gets all properties types that mach the specified type.
+   * @param configType the config type to return
+   * @return properties types for given config type
+   */
+  Map<PropertyInfo.PropertyType, Set<String>> getConfigPropertiesTypes(String
configType);
+
+  /**
    * Gets the specific config that matches the specified type and tag.  This not
    * necessarily a DESIRED configuration that applies to a cluster.
    * @param configType  the config type to find
-   * @param versionTag  the config version to find
+   * @param versionTag  the config version tag to find
    * @return  a {@link Config} object, or <code>null</code> if the specific type
    *          and version have not been set.
    */
   Config getConfig(String configType, String versionTag);
 
   /**
+   * Gets the specific config that matches the specified type and version.  This not
+   * necessarily a DESIRED configuration that applies to a cluster.
+   * @param configType  the config type to find
+   * @param configVersion  the config version to find
+   * @return  a {@link Config} object, or <code>null</code> if the specific type
+   *          and version have not been set.
+   */
+  Config getConfigByVersion(String configType, Long configVersion);
+
+  /**
    * Sets a specific config.  NOTE:  This is not a DESIRED configuration that
    * applies to a cluster.
    * @param config  the config instance to add

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java b/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
index e18505a..b35aad9 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/Config.java
@@ -20,11 +20,15 @@ package org.apache.ambari.server.state;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Represents a single instance of a 'Config Type'
  */
 public interface Config {
+  Map<PropertyInfo.PropertyType, Set<String>> getPropertiesTypes();
+
+  void setPropertiesTypes(Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes);
 
   void setStackId(StackId stackId);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
index ea6aecd..2cc3d00 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigImpl.java
@@ -23,6 +23,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -58,6 +59,7 @@ public class ConfigImpl implements Config {
   private volatile Map<String, String> properties;
   private volatile Map<String, Map<String, String>> propertiesAttributes;
   private ClusterConfigEntity entity;
+  private volatile Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes;
 
   @Inject
   private ClusterDAO clusterDAO;
@@ -81,6 +83,7 @@ public class ConfigImpl implements Config {
     stackId = cluster.getDesiredStackVersion();
 
     injector.injectMembers(this);
+    propertiesTypes = cluster.getConfigPropertiesTypes(type);
   }
 
 
@@ -96,6 +99,7 @@ public class ConfigImpl implements Config {
 
     this.entity = entity;
     injector.injectMembers(this);
+    propertiesTypes = cluster.getConfigPropertiesTypes(type);
   }
 
   /**
@@ -120,6 +124,26 @@ public class ConfigImpl implements Config {
   }
 
   @Override
+  public Map<PropertyInfo.PropertyType, Set<String>> getPropertiesTypes() {
+    readWriteLock.readLock().lock();
+    try {
+      return propertiesTypes;
+    } finally {
+      readWriteLock.readLock().unlock();
+    }
+  }
+
+  @Override
+  public void setPropertiesTypes(Map<PropertyInfo.PropertyType, Set<String>>
propertiesTypes) {
+    readWriteLock.writeLock().lock();
+    try {
+      this.propertiesTypes = propertiesTypes;
+    } finally {
+      readWriteLock.writeLock().unlock();
+    }
+  }
+
+  @Override
   public void setStackId(StackId stackId) {
     readWriteLock.writeLock().lock();
     try {

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
index 45369ee..4e37e14 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/cluster/ClusterImpl.java
@@ -109,6 +109,8 @@ import org.apache.ambari.server.state.ServiceFactory;
 import org.apache.ambari.server.state.ServiceInfo;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.State;
+import org.apache.ambari.server.state.PropertyInfo;
+import org.apache.ambari.server.state.StackInfo;
 import org.apache.ambari.server.state.configgroup.ConfigGroup;
 import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
 import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
@@ -253,6 +255,8 @@ public class ClusterImpl implements Cluster {
 
   private volatile Multimap<String, String> serviceConfigTypes;
 
+  private Map<String, Map<PropertyInfo.PropertyType, Set<String>>> configProperiesTypesCache;
+
   @Inject
   public ClusterImpl(@Assisted ClusterEntity clusterEntity,
                      Injector injector) throws AmbariException {
@@ -267,6 +271,8 @@ public class ClusterImpl implements Cluster {
 
     desiredStackVersion = new StackId(clusterEntity.getDesiredStack());
 
+    configProperiesTypesCache = new HashMap<>();
+
     cacheConfigurations();
 
     if (desiredStackVersion != null && !StringUtils.isEmpty(desiredStackVersion.getStackName())
&& !
@@ -1251,7 +1257,7 @@ public class ClusterImpl implements Cluster {
 
     // Also returns when have a mix of CURRENT and INSTALLING|INSTALLED|UPGRADING|UPGRADED
     LOG.warn("have a mix of CURRENT and INSTALLING|INSTALLED|UPGRADING|UPGRADED host versions,
" +
-            "returning OUT_OF_SYNC as cluster version. Host version states: " + stateToHosts.toString());
+        "returning OUT_OF_SYNC as cluster version. Host version states: " + stateToHosts.toString());
     return RepositoryVersionState.OUT_OF_SYNC;
   }
 
@@ -1779,6 +1785,23 @@ public class ClusterImpl implements Cluster {
   }
 
   @Override
+  public Config getConfigByVersion(String configType, Long configVersion) {
+    clusterGlobalLock.readLock().lock();
+    try {
+      if (!allConfigs.containsKey(configType)) {
+        return null;
+      }
+      for(Map.Entry<String, Config> entry: allConfigs.get(configType).entrySet()) {
+        if(entry.getValue().getVersion().equals(configVersion))
+          return entry.getValue();
+      }
+      return null;
+    } finally {
+      clusterGlobalLock.readLock().unlock();
+    }
+  }
+
+  @Override
   public void addConfig(Config config) {
     clusterGlobalLock.writeLock().lock();
     try {
@@ -2205,7 +2228,7 @@ public class ClusterImpl implements Cluster {
           serviceConfigVersionResponse.getConfigurations().add(
               new ConfigurationResponse(getClusterName(), config.getStackId(),
                   config.getType(), config.getTag(), config.getVersion(),
-                  config.getProperties(), config.getPropertiesAttributes()));
+                  config.getProperties(), config.getPropertiesAttributes(), config.getPropertiesTypes()));
         }
 
         serviceConfigVersionResponses.add(serviceConfigVersionResponse);
@@ -2889,6 +2912,39 @@ public class ClusterImpl implements Cluster {
    * {@inheritDoc}
    */
   @Override
+  public synchronized Map<PropertyInfo.PropertyType, Set<String>> getConfigPropertiesTypes(String
configType){
+    if(configProperiesTypesCache.containsKey(configType)) {
+      return configProperiesTypesCache.get(configType);
+    } else {
+      Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes = new HashMap<>();
+      try {
+        StackId stackId = this.getCurrentStackVersion();
+        StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
+        Collection<ServiceInfo> services = stackInfo.getServices();
+        for (ServiceInfo serviceInfo : services) {
+          for (PropertyInfo propertyInfo : serviceInfo.getProperties()) {
+            if (propertyInfo.getFilename().contains(configType) && !propertyInfo.getPropertyTypes().isEmpty())
{
+              Set<PropertyInfo.PropertyType> types = propertyInfo.getPropertyTypes();
+              for (PropertyInfo.PropertyType propertyType : types) {
+                if (!propertiesTypes.containsKey(propertyType))
+                  propertiesTypes.put(propertyType, new HashSet<String>());
+                propertiesTypes.get(propertyType).add(propertyInfo.getName());
+              }
+            }
+          }
+        }
+      } catch (Exception e) {
+
+      }
+      configProperiesTypesCache.put(configType, propertiesTypes);
+      return propertiesTypes;
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
   @Transactional
   public void removeConfigurations(StackId stackId) {
     clusterGlobalLock.writeLock().lock();

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
new file mode 100644
index 0000000..2b1aeae
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/SecretReference.java
@@ -0,0 +1,77 @@
+/**
+ * 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.utils;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Config;
+
+import java.util.Map;
+
+public class SecretReference {
+  private String clusterName;
+  private String configType;
+  private Long version;
+  private String value;
+  private String reference;
+
+  public SecretReference(String reference, String propertyName, Cluster cluster) throws AmbariException{
+    String[] values = reference.split(":");
+    clusterName = values[1];
+    configType = values[2];
+    version = Long.valueOf(values[3]);
+    Config refConfig = cluster.getConfigByVersion(configType, version);
+
+    if(refConfig == null)
+      throw new AmbariException(String.format("Cluster: %s does not contain ConfigType: %s
ConfigVersion: %s",
+          cluster.getClusterName(), configType, version));
+    Map<String, String> refProperties = refConfig.getProperties();
+    if(!refProperties.containsKey(propertyName))
+      throw new AmbariException(String.format("Cluster: %s ConfigType: %s ConfigVersion:
%s does not contain property '%s'",
+          cluster.getClusterName(), configType, version, propertyName));
+    this.value = refProperties.get(propertyName);
+
+    this.reference = reference;
+  }
+
+  public String getClusterName() {
+    return clusterName;
+  }
+
+  public void setConfigType(String configType) {
+    this.configType = configType;
+  }
+
+  public Long getVersion() {
+    return version;
+  }
+
+  public String getValue() {
+    return value;
+  }
+
+  public static boolean isSecret(String value) {
+    String[] values = value.split(":");
+    return values.length == 4 && values[0].equals("SECRET");
+  }
+
+  public static String generateStub(String clusterName, String configType, Long configVersion)
{
+    return "SECRET:" + clusterName + ":" + configType + ":" + configVersion.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 204b865..1aa1a6f 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -10542,6 +10542,151 @@ public class AmbariManagementControllerTest {
   }
 
   @Test
+  public void testSecretReferences() throws AmbariException {
+
+    final String host1 = "h1";
+    final String host2 = "h2";
+    Long clusterId = 1L;
+    String clusterName = "foo1";
+    Cluster cl = setupClusterWithHosts(clusterName, "HDP-2.0.5", new ArrayList<String>()
{
+      {
+        add(host1);
+        add(host2);
+      }
+    }, "centos5");
+    String serviceName = "HDFS";
+    createService(clusterName, serviceName, null);
+    String componentName1 = "NAMENODE";
+    String componentName2 = "DATANODE";
+    String componentName3 = "HDFS_CLIENT";
+
+    createServiceComponent(clusterName, serviceName, componentName1, State.INIT);
+    createServiceComponent(clusterName, serviceName, componentName2, State.INIT);
+    createServiceComponent(clusterName, serviceName, componentName3, State.INIT);
+
+    createServiceComponentHost(clusterName, serviceName, componentName1, host1, null);
+    createServiceComponentHost(clusterName, serviceName, componentName2, host1, null);
+    createServiceComponentHost(clusterName, serviceName, componentName3, host1, null);
+    createServiceComponentHost(clusterName, serviceName, componentName2, host2, null);
+    createServiceComponentHost(clusterName, serviceName, componentName3, host2, null);
+
+    // Install
+    installService(clusterName, serviceName, false, false);
+
+    ClusterRequest crReq;
+    ConfigurationRequest cr;
+
+    cr = new ConfigurationRequest(clusterName,
+        "hdfs-site",
+        "version1",
+        new HashMap<String, String>(){{
+          put("test.password", "first");
+        }},
+        new HashMap<String, Map<String, String>>()
+    );
+    crReq = new ClusterRequest(clusterId, clusterName, null, null);
+    crReq.setDesiredConfig(Collections.singletonList(cr));
+    controller.updateClusters(Collections.singleton(crReq), null);
+    // update config with secret reference
+    cr = new ConfigurationRequest(clusterName,
+        "hdfs-site",
+        "version2",
+        new HashMap<String, String>(){{
+          put("test.password", "SECRET:c1:hdfs-site:1");
+          put("new", "new");//need this to mark config as "changed"
+        }},
+        new HashMap<String, Map<String, String>>()
+    );
+    crReq = new ClusterRequest(clusterId, clusterName, null, null);
+    crReq.setDesiredConfig(Collections.singletonList(cr));
+    controller.updateClusters(Collections.singleton(crReq), null);
+    // change password to new value
+    cr = new ConfigurationRequest(clusterName,
+        "hdfs-site",
+        "version3",
+        new HashMap<String, String>(){{
+          put("test.password", "brandNewPassword");
+        }},
+        new HashMap<String, Map<String, String>>()
+    );
+    crReq = new ClusterRequest(clusterId, clusterName, null, null);
+    crReq.setDesiredConfig(Collections.singletonList(cr));
+    controller.updateClusters(Collections.singleton(crReq), null);
+    // wrong secret reference
+    cr = new ConfigurationRequest(clusterName,
+        "hdfs-site",
+        "version3",
+        new HashMap<String, String>(){{
+          put("test.password", "SECRET:c1:hdfs-site:666");
+        }},
+        new HashMap<String, Map<String, String>>()
+    );
+    crReq = new ClusterRequest(clusterId, clusterName, null, null);
+    crReq.setDesiredConfig(Collections.singletonList(cr));
+    try {
+      controller.updateClusters(Collections.singleton(crReq), null);
+      fail("Request need to be failed with wrong secret reference");
+    } catch (AmbariException e){
+
+    }
+    // reference to config which does not contain requested property
+    cr = new ConfigurationRequest(clusterName,
+        "hdfs-site",
+        "version4",
+        new HashMap<String, String>(){{
+          put("foo", "bar");
+        }},
+        new HashMap<String, Map<String, String>>()
+    );
+    crReq = new ClusterRequest(clusterId, clusterName, null, null);
+    crReq.setDesiredConfig(Collections.singletonList(cr));
+    controller.updateClusters(Collections.singleton(crReq), null);
+    cr = new ConfigurationRequest(clusterName,
+        "hdfs-site",
+        "version5",
+        new HashMap<String, String>(){{
+          put("test.password", "SECRET:c1:hdfs-site:4");
+          put("new", "new");
+        }},
+        new HashMap<String, Map<String, String>>()
+    );
+    crReq = new ClusterRequest(clusterId, clusterName, null, null);
+    crReq.setDesiredConfig(Collections.singletonList(cr));
+    try {
+      controller.updateClusters(Collections.singleton(crReq), null);
+      fail("Request need to be failed with wrong secret reference");
+    } catch (AmbariException e) {
+      assertEquals("Cluster: foo1 ConfigType: hdfs-site ConfigVersion: 4 does not contain
property 'test.password'",
+          e.getMessage());
+    }
+    cl.getAllConfigs();
+    assertEquals(cl.getAllConfigs().size(), 4);
+
+    Config v1 = cl.getConfigByVersion("hdfs-site", 1l);
+    Config v2 = cl.getConfigByVersion("hdfs-site", 2l);
+    Config v3 = cl.getConfigByVersion("hdfs-site", 3l);
+    Config v4 = cl.getConfigByVersion("hdfs-site", 4l);
+
+    assertEquals(v1.getProperties().get("test.password"), "first");
+    assertEquals(v2.getProperties().get("test.password"), "first");
+    assertEquals(v3.getProperties().get("test.password"), "brandNewPassword");
+    assertFalse(v4.getProperties().containsKey("test.password"));
+
+    // check if we have masked secret in responce
+    final ConfigurationRequest configRequest = new ConfigurationRequest(clusterName, "hdfs-site",
null, null, null);
+    configRequest.setIncludeProperties(true);
+    Set<ConfigurationResponse> requestedConfigs = controller.getConfigurations(new
HashSet<ConfigurationRequest>() {{
+      add(configRequest);
+    }});
+    for(ConfigurationResponse resp : requestedConfigs) {
+      String secretName = "SECRET:foo1:hdfs-site:"+resp.getVersion().toString();
+      if(resp.getConfigs().containsKey("test.password")) {
+        assertEquals(resp.getConfigs().get("test.password"), secretName);
+      }
+    }
+  }
+
+  @Test
   public void testTargetedProcessCommand() throws Exception {
     final String host1 = "h1";
     String clusterName = "c1";

http://git-wip-us.apache.org/repos/asf/ambari/blob/eb693f80/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml
b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml
index 246b2f9..f53c667 100644
--- a/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml
+++ b/ambari-server/src/test/resources/stacks/HDP/2.0.5/services/HDFS/configuration/hdfs-site.xml
@@ -23,6 +23,12 @@
 <configuration>
 
 <!-- file system properties -->
+  <property>
+    <name>test.password</name>
+    <property-type>PASSWORD</property-type>
+    <value>test</value>
+    <description>1</description>
+  </property>
 
   <property>
     <name>dfs.namenode.name.dir</name>


Mime
View raw message