This is an automated email from the ASF dual-hosted git repository.
smolnar pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git
The following commit(s) were added to refs/heads/trunk by this push:
new 9c61584 AMBARI-24742. Encrypting/decrypting PASSWORD type properties
when inserting them into the DB/using them (#2458)
9c61584 is described below
commit 9c61584bba46820f506b8cecd480da912df2fa90
Author: Sandor Molnar <[email protected]>
AuthorDate: Fri Oct 19 17:52:36 2018 +0200
AMBARI-24742. Encrypting/decrypting PASSWORD type properties when inserting
them into the DB/using them (#2458)
---
.../ambari/server/configuration/Configuration.java | 11 ++
.../ambari/server/controller/ControllerModule.java | 5 +
.../security/encryption/AESEncryptionService.java | 19 ++-
.../encryption/ConfigPropertiesEncryptor.java | 127 +++++++++++++++++++++
.../server/security/encryption/Encryptor.java | 43 +++++++
.../org/apache/ambari/server/state/Cluster.java | 10 +-
.../org/apache/ambari/server/state/Config.java | 5 +
.../org/apache/ambari/server/state/ConfigImpl.java | 30 +++--
.../ambari/server/state/cluster/ClusterImpl.java | 9 +-
.../ambari/server/agent/AgentResourceTest.java | 7 ++
.../KerberosAdminPersistedCredentialCheckTest.java | 2 +-
.../server/controller/KerberosHelperTest.java | 2 +-
.../internal/HostResourceProviderTest.java | 2 +-
.../server/testutils/PartialNiceMockBinder.java | 12 ++
.../ambari/server/update/HostUpdateHelperTest.java | 3 +-
.../server/upgrade/UpgradeCatalog251Test.java | 3 +-
.../server/upgrade/UpgradeCatalog252Test.java | 3 +-
.../server/upgrade/UpgradeCatalog260Test.java | 4 +-
.../server/upgrade/UpgradeCatalog270Test.java | 2 +-
19 files changed, 279 insertions(+), 20 deletions(-)
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 d644c08..63c1777 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
@@ -2572,6 +2572,9 @@ public class Configuration {
@Markdown(description = "Whether security password encryption is enabled or
not. In case it is we store passwords in their own file(s); otherwise we store
passwords in the Ambari credential store.")
public static final ConfigurationProperty<Boolean>
SECURITY_PASSWORD_ENCRYPTON_ENABLED = new
ConfigurationProperty<>("security.passwords.encryption.enabled", false);
+ @Markdown(description="Whether to encrypt sensitive data (at rest) on
service level configuration.")
+ public static final ConfigurationProperty<Boolean>
SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED = new
ConfigurationProperty<>("security.server.encrypt_sensitive_data", false);
+
/**
* The maximum number of authentication attempts permitted to a local user.
Once the number of failures reaches this limit the user will be locked out. 0
indicates unlimited failures
*/
@@ -5518,6 +5521,14 @@ public class Configuration {
return
Boolean.parseBoolean(getProperty(SECURITY_PASSWORD_ENCRYPTON_ENABLED));
}
+ public boolean isSensitiveDataEncryptionEnabled() {
+ return
Boolean.parseBoolean(getProperty(SECURITY_SENSITIVE_DATA_ENCRYPTON_ENABLED));
+ }
+
+ public boolean shouldEncryptSensitiveData() {
+ return isSecurityPasswordEncryptionEnabled() &&
isSensitiveDataEncryptionEnabled();
+ }
+
/**
* @return default value of number of tasks to run in parallel during
upgrades
*/
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
index 176e709..2e60deb 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/controller/ControllerModule.java
@@ -115,9 +115,11 @@ import
org.apache.ambari.server.security.authorization.AuthorizationHelper;
import
org.apache.ambari.server.security.authorization.internal.InternalAuthenticationInterceptor;
import
org.apache.ambari.server.security.authorization.internal.RunWithInternalSecurityContext;
import org.apache.ambari.server.security.encryption.AESEncryptionService;
+import org.apache.ambari.server.security.encryption.ConfigPropertiesEncryptor;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
import org.apache.ambari.server.security.encryption.CredentialStoreServiceImpl;
import org.apache.ambari.server.security.encryption.EncryptionService;
+import org.apache.ambari.server.security.encryption.Encryptor;
import
org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandlerFactory;
import org.apache.ambari.server.serveraction.users.CollectionPersisterService;
import
org.apache.ambari.server.serveraction.users.CollectionPersisterServiceFactory;
@@ -179,6 +181,7 @@ import com.google.gson.GsonBuilder;
import com.google.inject.AbstractModule;
import com.google.inject.Scopes;
import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
import com.google.inject.persist.PersistModule;
@@ -332,6 +335,8 @@ public class ControllerModule extends AbstractModule {
bind(CredentialStoreService.class).to(CredentialStoreServiceImpl.class);
bind(EncryptionService.class).to(AESEncryptionService.class);
+ //to support different Encryptor implementation we have to annotate them
by their name and use them as @Named injects
+ bind(new TypeLiteral<Encryptor<Config>>()
{}).annotatedWith(Names.named("ConfigPropertiesEncryptor")).to(ConfigPropertiesEncryptor.class);
bind(Configuration.class).toInstance(configuration);
bind(OsFamily.class).toInstance(os_family);
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/AESEncryptionService.java
b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/AESEncryptionService.java
index ffb92ba..25b3fc7 100644
---
a/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/AESEncryptionService.java
+++
b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/AESEncryptionService.java
@@ -24,6 +24,8 @@ import org.apache.ambari.server.utils.TextEncoding;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
import com.google.inject.Singleton;
@Singleton
@@ -32,6 +34,8 @@ public class AESEncryptionService implements
EncryptionService {
private static final String ENCODED_TEXT_FIELD_DELIMITER = "::";
private static final String UTF_8_CHARSET = StandardCharsets.UTF_8.name();
+ private final Cache<String, AESEncryptor> aesEncryptorCache =
CacheBuilder.newBuilder().build();
+
private MasterKeyService environmentMasterKeyService;
@Override
@@ -51,11 +55,20 @@ public class AESEncryptionService implements
EncryptionService {
@Override
public String encrypt(String toBeEncrypted, String key, TextEncoding
textEncoding) throws Exception {
- final AESEncryptor aes = new AESEncryptor(key);
- final EncryptionResult encryptionResult = aes.encrypt(toBeEncrypted);
+ final EncryptionResult encryptionResult =
getAesEncryptor(key).encrypt(toBeEncrypted);
return TextEncoding.BASE_64 == textEncoding ?
encodeEncryptionResultBase64(encryptionResult) :
encodeEncryptionResultBinHex(encryptionResult);
}
+ private AESEncryptor getAesEncryptor(String key) {
+ AESEncryptor aesEncryptor = aesEncryptorCache.getIfPresent(key);
+ if (aesEncryptor == null) {
+ aesEncryptor = new AESEncryptor(key);
+ aesEncryptorCache.put(key, aesEncryptor);
+ }
+
+ return aesEncryptor;
+ }
+
private final String getAmbariMasterKey() {
initEnvironmentMasterKeyService();
return String.valueOf(environmentMasterKeyService.getMasterSecret());
@@ -100,7 +113,7 @@ public class AESEncryptionService implements
EncryptionService {
final byte[] decodedValue = TextEncoding.BASE_64 == textEncoding ?
Base64.decodeBase64(toBeDecrypted) : Hex.decodeHex(toBeDecrypted.toCharArray());
final String decodedText = new String(decodedValue, UTF_8_CHARSET);
final String[] decodedParts =
decodedText.split(ENCODED_TEXT_FIELD_DELIMITER);
- final AESEncryptor aes = new AESEncryptor(key);
+ final AESEncryptor aes = getAesEncryptor(key);
if (TextEncoding.BASE_64 == textEncoding) {
return new String(aes.decrypt(Base64.decodeBase64(decodedParts[0]),
Base64.decodeBase64(decodedParts[1]), Base64.decodeBase64(decodedParts[2])),
UTF_8_CHARSET);
} else {
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/ConfigPropertiesEncryptor.java
b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/ConfigPropertiesEncryptor.java
new file mode 100644
index 0000000..68710f4
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/ConfigPropertiesEncryptor.java
@@ -0,0 +1,127 @@
+/*
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.encryption;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.AmbariRuntimeException;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.PropertyInfo.PropertyType;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.utils.TextEncoding;
+import org.apache.commons.collections.CollectionUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * {@link Encryptor} implementation for encrypting/decrypting PASSWORD type
+ * properties in {@link Config}'s properties
+ */
+
+@Singleton
+public class ConfigPropertiesEncryptor implements Encryptor<Config> {
+
+ private static final String ENCRYPTED_PROPERTY_PREFIX = "${enc=aes256_hex,
value=";
+ private static final String ENCRYPTED_PROPERTY_SCHEME =
ENCRYPTED_PROPERTY_PREFIX + "%s}";
+
+ private final EncryptionService encryptionService;
+ private final Map<Long, Map<StackId, Map<String, Set<String>>>>
clusterPasswordProperties = new ConcurrentHashMap<>(); //Map<clusterId,
<Map<stackId, Map<configType, Set<passwordPropertyKeys>>>>;
+
+ @Inject
+ public ConfigPropertiesEncryptor(EncryptionService encryptionService) {
+ this.encryptionService = encryptionService;
+ }
+
+ @Override
+ public void encryptSensitiveData(Config config) {
+ try {
+ final Map<String, String> configProperties = config.getProperties();
+ if (configProperties != null) {
+ final Set<String> passwordProperties =
getPasswordProperties(config.getCluster(), config.getType());
+ if (CollectionUtils.isNotEmpty(passwordProperties)) {
+ final Map<String, String> encryptedProperties = new
HashMap<>(configProperties);
+ for (Map.Entry<String, String> property :
configProperties.entrySet()) {
+ if (passwordProperties.contains(property.getKey()) &&
!isEncryptedPassword(property.getValue())) {
+ encryptedProperties.put(property.getKey(),
encryptAndDecoratePropertyValue(property.getValue()));
+ }
+ }
+ config.setProperties(encryptedProperties);
+ }
+ }
+ } catch (Exception e) {
+ throw new AmbariRuntimeException("Error while encrypting sensitive
data", e);
+ }
+ }
+
+ private boolean isEncryptedPassword(String password) {
+ return password != null && password.startsWith(ENCRYPTED_PROPERTY_PREFIX);
// assuming previous encryption by this class
+ }
+
+ private Set<String> getPasswordProperties(Cluster cluster, String
configType) throws AmbariException {
+ //in case of normal configuration change on the UI - or via the API - the
current and desired stacks are equal
+ //in case of an upgrade they are different; in this case we want to get
password properties from the desired stack
+ if
(cluster.getCurrentStackVersion().equals(cluster.getDesiredStackVersion())) {
+ return getPasswordProperties(cluster, cluster.getCurrentStackVersion(),
configType);
+ } else {
+ return getPasswordProperties(cluster, cluster.getDesiredStackVersion(),
configType);
+ }
+ }
+
+ private Set<String> getPasswordProperties(Cluster cluster, StackId stackId,
String configType) {
+ final long clusterId = cluster.getClusterId();
+ clusterPasswordProperties.computeIfAbsent(clusterId, v -> new
ConcurrentHashMap<>()).computeIfAbsent(stackId, v -> new ConcurrentHashMap<>())
+ .computeIfAbsent(configType, v ->
cluster.getConfigPropertiesTypes(configType,
stackId).getOrDefault(PropertyType.PASSWORD, new HashSet<>()));
+ return
clusterPasswordProperties.get(clusterId).get(stackId).getOrDefault(configType,
new HashSet<>());
+ }
+
+ private String encryptAndDecoratePropertyValue(String propertyValue) throws
Exception {
+ final String encrypted = encryptionService.encrypt(propertyValue,
TextEncoding.BIN_HEX);
+ return String.format(ENCRYPTED_PROPERTY_SCHEME, encrypted);
+ }
+
+ @Override
+ public void decryptSensitiveData(Config config) {
+ final Map<String, String> configProperties = config.getProperties();
+ if (configProperties != null) {
+ final Map<String, String> decryptedProperties = new
HashMap<>(configProperties);
+ for (Map.Entry<String, String> property : configProperties.entrySet()) {
+ if (isEncryptedPassword(property.getValue())) {
+ decryptedProperties.put(property.getKey(),
decryptProperty(property.getValue()));
+ }
+ }
+ config.setProperties(decryptedProperties);
+ }
+ }
+
+ private String decryptProperty(String property) {
+ try {
+ // sample value: ${enc=aes256_hex, value=5248...303d}
+ final String encrypted =
property.substring(ENCRYPTED_PROPERTY_PREFIX.length(), property.indexOf('}'));
+ return encryptionService.decrypt(encrypted, TextEncoding.BIN_HEX);
+ } catch (Exception e) {
+ throw new AmbariRuntimeException("Error while decrypting property", e);
+ }
+ }
+}
diff --git
a/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/Encryptor.java
b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/Encryptor.java
new file mode 100644
index 0000000..4fad723
--- /dev/null
+++
b/ambari-server/src/main/java/org/apache/ambari/server/security/encryption/Encryptor.java
@@ -0,0 +1,43 @@
+/*
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.encryption;
+
+/**
+ * Defines a generic contract on encrypting/decrypting sensitive data
+ */
+public interface Encryptor<T> {
+
+ /**
+ * Encrypts the given encryptible object
+ *
+ * @param encryptible
+ * to be encrypted
+ * @return the encrypted value
+ */
+ void encryptSensitiveData(T encryptible);
+
+ /**
+ * Decrypts the given decryptible object
+ *
+ * @param decryptible
+ * to be decrypted
+ * @return the decrypted value
+ */
+ void decryptSensitiveData(T decryptible);
+
+}
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 c201310..a150796 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
@@ -268,13 +268,21 @@ public interface Cluster {
Map<String, Config> getConfigsByType(String configType);
/**
- * Gets all properties types that mach the specified type.
+ * Gets all properties types that matches the specified type for the current
stack.
* @param configType the config type to return
* @return properties types for given config type
*/
Map<PropertyInfo.PropertyType, Set<String>> getConfigPropertiesTypes(String
configType);
/**
+ * Gets all properties types that matches the specified type for the given
stack.
+ * @param configType the config type to return
+ * @param stackId the stack to scan properties for
+ * @return properties types for given config type
+ */
+ Map<PropertyInfo.PropertyType, Set<String>> getConfigPropertiesTypes(String
configType, StackId stackId);
+
+ /**
* 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
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 c1a8dc1..d687e84 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
@@ -97,4 +97,9 @@ public interface Config {
* Persist the configuration.
*/
void save();
+
+ /**
+ * @return the cluster where this config belongs to
+ */
+ Cluster getCluster();
}
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 b3ff843..e04a6bb 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
@@ -27,7 +27,9 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReadWriteLock;
import javax.annotation.Nullable;
+import javax.inject.Named;
+import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.events.ClusterConfigChangedEvent;
import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
import org.apache.ambari.server.logging.LockFactory;
@@ -37,11 +39,13 @@ import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.orm.entities.ClusterConfigEntity;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.StackEntity;
+import org.apache.ambari.server.security.encryption.Encryptor;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -104,9 +108,10 @@ public class ConfigImpl implements Config {
@Assisted Map<String, String> properties,
@Assisted @Nullable Map<String, Map<String, String>>
propertiesAttributes,
ClusterDAO clusterDAO, StackDAO stackDAO,
- Gson gson, AmbariEventPublisher eventPublisher, LockFactory lockFactory)
{
+ Gson gson, AmbariEventPublisher eventPublisher, LockFactory lockFactory,
+ Configuration serverConfiguration, @Named("ConfigPropertiesEncryptor")
Encryptor<Config> configPropertiesEncryptor) {
this(cluster.getDesiredStackVersion(), cluster, type, tag, properties,
propertiesAttributes,
- clusterDAO, stackDAO, gson, eventPublisher, lockFactory);
+ clusterDAO, stackDAO, gson, eventPublisher, lockFactory,
serverConfiguration, configPropertiesEncryptor);
}
@@ -116,20 +121,24 @@ public class ConfigImpl implements Config {
@Assisted Map<String, String> properties,
@Assisted @Nullable Map<String, Map<String, String>>
propertiesAttributes,
ClusterDAO clusterDAO, StackDAO stackDAO,
- Gson gson, AmbariEventPublisher eventPublisher, LockFactory lockFactory)
{
+ Gson gson, AmbariEventPublisher eventPublisher, LockFactory lockFactory,
+ Configuration serverConfiguration, @Named("ConfigPropertiesEncryptor")
Encryptor<Config> configPropertiesEncryptor) {
propertyLock = lockFactory.newReadWriteLock(PROPERTY_LOCK_LABEL);
this.cluster = cluster;
this.type = type;
this.properties = properties;
+ if (serverConfiguration.shouldEncryptSensitiveData()) {
+ configPropertiesEncryptor.encryptSensitiveData(this);
+ }
// only set this if it's non-null
this.propertiesAttributes = null == propertiesAttributes ? null
: new HashMap<>(propertiesAttributes);
this.clusterDAO = clusterDAO;
- this.gson = gson;
+ this.gson = new GsonBuilder().disableHtmlEscaping().create();
this.eventPublisher = eventPublisher;
version = cluster.getNextConfigVersion(type);
@@ -148,10 +157,10 @@ public class ConfigImpl implements Config {
entity.setTag(this.tag);
entity.setTimestamp(System.currentTimeMillis());
entity.setStack(stackEntity);
- entity.setData(gson.toJson(properties));
+ entity.setData(this.gson.toJson(this.properties));
if (null != propertiesAttributes) {
- entity.setAttributes(gson.toJson(propertiesAttributes));
+ entity.setAttributes(this.gson.toJson(propertiesAttributes));
}
// when creating a brand new config without a backing entity, use the
@@ -161,12 +170,13 @@ public class ConfigImpl implements Config {
persist(entity);
configId = entity.getConfigId();
+ configPropertiesEncryptor.decryptSensitiveData(this);
}
@AssistedInject
ConfigImpl(@Assisted Cluster cluster, @Assisted ClusterConfigEntity entity,
ClusterDAO clusterDAO, Gson gson, AmbariEventPublisher eventPublisher,
- LockFactory lockFactory) {
+ LockFactory lockFactory, @Named("ConfigPropertiesEncryptor")
Encryptor<Config> configPropertiesEncryptor) {
propertyLock = lockFactory.newReadWriteLock(PROPERTY_LOCK_LABEL);
this.cluster = cluster;
@@ -194,6 +204,7 @@ public class ConfigImpl implements Config {
}
properties = deserializedProperties;
+ configPropertiesEncryptor.decryptSensitiveData(this);
} catch (JsonSyntaxException e) {
LOG.error("Malformed configuration JSON stored in the database for
{}/{}", entity.getType(),
entity.getTag());
@@ -324,6 +335,11 @@ public class ConfigImpl implements Config {
}
@Override
+ public Cluster getCluster() {
+ return cluster;
+ }
+
+ @Override
public List<Long> getServiceConfigVersions() {
return
serviceConfigDAO.getServiceConfigVersionsByConfig(cluster.getClusterId(), type,
version);
}
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 eb1176e..4ca2caf 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
@@ -2548,8 +2548,15 @@ public class ClusterImpl implements Cluster {
*/
@Override
public Map<PropertyInfo.PropertyType, Set<String>>
getConfigPropertiesTypes(String configType){
+ return getConfigPropertiesTypes(configType, getCurrentStackVersion());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<PropertyInfo.PropertyType, Set<String>>
getConfigPropertiesTypes(String configType, StackId stackId) {
try {
- StackId stackId = getCurrentStackVersion();
StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(),
stackId.getStackVersion());
return stackInfo.getConfigPropertiesTypes(configType);
} catch (AmbariException ignored) {
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentResourceTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentResourceTest.java
index 37d5166..d992d4a 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentResourceTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/agent/AgentResourceTest.java
@@ -59,8 +59,12 @@ import org.apache.ambari.server.scheduler.ExecutionScheduler;
import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
import org.apache.ambari.server.security.SecurityHelper;
import org.apache.ambari.server.security.SecurityHelperImpl;
+import org.apache.ambari.server.security.encryption.AESEncryptionService;
+import org.apache.ambari.server.security.encryption.ConfigPropertiesEncryptor;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
import org.apache.ambari.server.security.encryption.CredentialStoreServiceImpl;
+import org.apache.ambari.server.security.encryption.EncryptionService;
+import org.apache.ambari.server.security.encryption.Encryptor;
import org.apache.ambari.server.stack.StackManagerFactory;
import
org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeContextFactory;
import org.apache.ambari.server.stageplanner.RoleGraphFactory;
@@ -107,6 +111,7 @@ import com.google.gson.GsonBuilder;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
+import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
import com.sun.jersey.api.client.Client;
@@ -352,6 +357,8 @@ public class AgentResourceTest extends RandomPortJerseyTest
{
bind(AmbariManagementController.class).toInstance(createNiceMock(AmbariManagementController.class));
bind(KerberosHelper.class).toInstance(createNiceMock(KerberosHelper.class));
bind(MpackManagerFactory.class).toInstance(createNiceMock(MpackManagerFactory.class));
+ bind(EncryptionService.class).to(AESEncryptionService.class);
+ bind(new TypeLiteral<Encryptor<Config>>()
{}).annotatedWith(Names.named("ConfigPropertiesEncryptor")).to(ConfigPropertiesEncryptor.class);
}
private void installDependencies() {
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java
index edea0a7..ff3be49 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/checks/KerberosAdminPersistedCredentialCheckTest.java
@@ -217,7 +217,7 @@ public class KerberosAdminPersistedCredentialCheckTest
extends EasyMockSupport {
@Override
protected void configure() {
PartialNiceMockBinder.newBuilder().addActionDBAccessorConfigsBindings().addFactoriesInstallBinding()
- .build().configure(binder());
+ .addPasswordEncryptorBindings().build().configure(binder());
bind(ExecutionScheduler.class).toInstance(createNiceMock(ExecutionSchedulerImpl.class));
bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
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 584eff9..c229eb2 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
@@ -238,7 +238,7 @@ public class KerberosHelperTest extends EasyMockSupport {
@Override
protected void configure() {
PartialNiceMockBinder.newBuilder().addActionDBAccessorConfigsBindings().addFactoriesInstallBinding()
- .build().configure(binder());
+ .addPasswordEncryptorBindings().build().configure(binder());
bind(ActionDBAccessor.class).to(ActionDBAccessorImpl.class);
bind(ExecutionScheduler.class).to(ExecutionSchedulerImpl.class);
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
index 3659019..125a9e9 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
@@ -1403,7 +1403,7 @@ public class HostResourceProviderTest extends
EasyMockSupport {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
-
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().build().configure(binder());
+
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().addPasswordEncryptorBindings().build().configure(binder());
bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/testutils/PartialNiceMockBinder.java
b/ambari-server/src/test/java/org/apache/ambari/server/testutils/PartialNiceMockBinder.java
index d87a335..94d64ac 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/testutils/PartialNiceMockBinder.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/testutils/PartialNiceMockBinder.java
@@ -55,6 +55,8 @@ import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
import org.apache.ambari.server.scheduler.ExecutionScheduler;
import org.apache.ambari.server.scheduler.ExecutionSchedulerImpl;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
+import org.apache.ambari.server.security.encryption.EncryptionService;
+import org.apache.ambari.server.security.encryption.Encryptor;
import org.apache.ambari.server.stack.StackManagerFactory;
import
org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeContextFactory;
import org.apache.ambari.server.stageplanner.RoleGraphFactory;
@@ -90,6 +92,7 @@ import
org.springframework.security.crypto.password.StandardPasswordEncoder;
import com.google.inject.Binder;
import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
import com.google.inject.persist.UnitOfWork;
@@ -153,6 +156,7 @@ public class PartialNiceMockBinder implements Module {
});
addConfigsBindings();
addFactoriesInstallBinding();
+ addPasswordEncryptorBindings();
return this;
}
@@ -206,6 +210,14 @@ public class PartialNiceMockBinder implements Module {
return this;
}
+ public Builder addPasswordEncryptorBindings() {
+ configurers.add((Binder binder) -> {
+
binder.bind(EncryptionService.class).toInstance(easyMockSupport.createNiceMock(EncryptionService.class));
+ binder.bind(new TypeLiteral<Encryptor<Config>>()
{}).annotatedWith(Names.named("ConfigPropertiesEncryptor")).toInstance(easyMockSupport.createNiceMock(Encryptor.class));
+ });
+ return this;
+ }
+
public Builder addHostRoleCommandsConfigsBindings() {
configurers.add((Binder binder) -> {
binder.bindConstant().annotatedWith(Names.named(HostRoleCommandDAO.HRC_STATUS_SUMMARY_CACHE_ENABLED)).to(true);
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/update/HostUpdateHelperTest.java
b/ambari-server/src/test/java/org/apache/ambari/server/update/HostUpdateHelperTest.java
index 9c438c9..028f888 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/update/HostUpdateHelperTest.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/update/HostUpdateHelperTest.java
@@ -495,7 +495,8 @@ public class HostUpdateHelperTest {
@Override
protected void configure() {
-
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().build().configure(binder());
+
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().addPasswordEncryptorBindings()
+ .build().configure(binder());
bind(DBAccessor.class).toInstance(dbAccessor);
bind(EntityManager.class).toInstance(entityManager);
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog251Test.java
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog251Test.java
index 6ecea16..03437fa 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog251Test.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog251Test.java
@@ -292,7 +292,8 @@ public class UpgradeCatalog251Test {
Module module = new Module() {
@Override
public void configure(Binder binder) {
-
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().build().configure(binder);
+
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding()
+ .addPasswordEncryptorBindings().build().configure(binder);
binder.bind(DBAccessor.class).toInstance(dbAccessor);
binder.bind(OsFamily.class).toInstance(osFamily);
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog252Test.java
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog252Test.java
index 1d5168c..7dfee87 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog252Test.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog252Test.java
@@ -440,7 +440,8 @@ public class UpgradeCatalog252Test {
Module module = new Module() {
@Override
public void configure(Binder binder) {
-
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().build().configure(binder);
+
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding()
+ .addPasswordEncryptorBindings().build().configure(binder);
binder.bind(DBAccessor.class).toInstance(dbAccessor);
binder.bind(OsFamily.class).toInstance(osFamily);
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
index ba09e97..02a45c2 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog260Test.java
@@ -1025,7 +1025,8 @@ public class UpgradeCatalog260Test {
final Injector mockInjector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
-
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().build().configure(binder());
+
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding()
+ .addPasswordEncryptorBindings().build().configure(binder());
bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
bind(AmbariManagementController.class).toInstance(controller);
@@ -1083,6 +1084,7 @@ public class UpgradeCatalog260Test {
return Guice.createInjector(new Module() {
@Override
public void configure(Binder binder) {
+
PartialNiceMockBinder.newBuilder().addPasswordEncryptorBindings().build().configure(binder);
binder.bindConstant().annotatedWith(Names.named("actionTimeout")).to(600000L);
binder.bindConstant().annotatedWith(Names.named("schedulerSleeptime")).to(1L);
binder.bindConstant().annotatedWith(Names.named(HostRoleCommandDAO.HRC_STATUS_SUMMARY_CACHE_ENABLED)).to(true);
diff --git
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
index c2096d5..6fa317b 100644
---
a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
+++
b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog270Test.java
@@ -600,7 +600,7 @@ public class UpgradeCatalog270Test {
Module module = new AbstractModule() {
@Override
public void configure() {
-
PartialNiceMockBinder.newBuilder().addConfigsBindings().addFactoriesInstallBinding().build().configure(binder());
+
PartialNiceMockBinder.newBuilder().addConfigsBindings().addPasswordEncryptorBindings().addFactoriesInstallBinding().build().configure(binder());
bind(DBAccessor.class).toInstance(dbAccessor);
bind(OsFamily.class).toInstance(osFamily);