blob: dfd925dd02ab83558d36b70e1651e63bde96b72a [file] [log] [blame]
/*
* 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 java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.StaticallyInject;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.PropertyInfo;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.inject.Inject;
@StaticallyInject
public class SecretReference {
private static final String secretPrefix = "SECRET";
private String configType;
private Long version;
private String value;
private final static String PASSWORD_TEXT = "password";
private final static String PASSWD_TEXT = "passwd";
@Inject
private static Gson gson;
public SecretReference(String reference, Cluster cluster) throws AmbariException{
String[] values = reference.split(":");
configType = values[1];
version = Long.valueOf(values[2]);
String propertyName = values[3];
String clusterName = cluster.getClusterName();
Config refConfig = cluster.getConfigByVersion(configType, version);
if(refConfig == null)
throw new AmbariException(String.format("Error when parsing secret reference. Cluster: %s does not contain ConfigType: %s ConfigVersion: %s",
clusterName, configType, version));
Map<String, String> refProperties = refConfig.getProperties();
if(!refProperties.containsKey(propertyName))
throw new AmbariException(String.format("Error when parsing secret reference. Cluster: %s ConfigType: %s ConfigVersion: %s does not contain property '%s'",
clusterName, configType, version, propertyName));
this.value = refProperties.get(propertyName);
}
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(secretPrefix);
}
public static String generateStub(String configType, Long configVersion, String propertyName) {
return secretPrefix + ":" + configType + ":" + configVersion + ":" + propertyName;
}
/**
* Helper function to mask a string of property bags that may contain a property with a password.
* @param propertyMap Property map to mask by replacing any passwords with the text "SECRET"
* @return New string with the passwords masked, or null if the property map is null.
*/
public static String maskPasswordInPropertyMap(String propertyMap) {
if (null == propertyMap) return null;
Map<String, String> maskedMap = new HashMap<>();
Map<String, String> map = gson.fromJson(propertyMap, new TypeToken<Map<String, String>>() {}.getType());
for (Map.Entry<String, String> e : map.entrySet()) {
String value = e.getValue();
if (e.getKey().toLowerCase().contains(PASSWORD_TEXT) || e.getKey().toLowerCase().contains(PASSWD_TEXT)) {
value = secretPrefix;
}
maskedMap.put(e.getKey(), value);
}
return gson.toJson(maskedMap);
}
/**
* Replace secret references with appropriate real passwords.
* @param targetMap map in which replacement will be performed
* @param cluster current cluster
* @throws AmbariException
*/
public static void replaceReferencesWithPasswords(Map<String, String> targetMap, Cluster cluster)
throws AmbariException {
if(cluster != null) {
for (Map.Entry<String, String> propertyValueEntry : targetMap.entrySet()) {
String key = propertyValueEntry.getKey();
String value = propertyValueEntry.getValue();
if (value != null && SecretReference.isSecret(value)) {
SecretReference ref = new SecretReference(value, cluster);
targetMap.put(key, ref.getValue());
}
}
}
}
/**
* Replace real passwords with secret references
* @param propertiesTypes map with properties types
* @param propertiesMap map with properties in which replacement will be performed
* @param configType configuration type
* @param configVersion configuration version
*/
public static void replacePasswordsWithReferences(Map<PropertyInfo.PropertyType, Set<String>> propertiesTypes,
Map<String, String> propertiesMap,
String configType,
Long configVersion){
if(propertiesTypes != null && propertiesTypes.containsKey(PropertyInfo.PropertyType.PASSWORD)) {
for(String pwdPropertyName: propertiesTypes.get(PropertyInfo.PropertyType.PASSWORD)) {
if(propertiesMap.containsKey(pwdPropertyName)){
if(!propertiesMap.get(pwdPropertyName).equals("")) {
String stub = SecretReference.generateStub(configType, configVersion, pwdPropertyName);
propertiesMap.put(pwdPropertyName, stub);
}
}
}
}
}
/**
* Replace real passwords with secret references
* @param configAttributes map with config attributes containing properties types as part of their content
* @param propertiesMap map with properties in which replacement will be performed
* @param configType configuration type
* @param configVersion configuration version
*/
public static void replacePasswordsWithReferencesForCustomProperties(Map<String, Map<String, String>> configAttributes,
Map<String, String> propertiesMap,
String configType,
Long configVersion){
if(configAttributes != null && configAttributes.containsKey("password")) {
for(String pwdPropertyName: configAttributes.get("password").keySet()) {
if(propertiesMap.containsKey(pwdPropertyName)){
if(!propertiesMap.get(pwdPropertyName).equals("")) {
String stub = SecretReference.generateStub(configType, configVersion, pwdPropertyName);
propertiesMap.put(pwdPropertyName, stub);
}
}
}
}
}
}