| /* |
| * 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.io.File; |
| import java.io.IOException; |
| import java.nio.charset.Charset; |
| import java.util.concurrent.locks.Lock; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| import org.apache.ambari.server.AmbariException; |
| import org.apache.ambari.server.configuration.Configuration; |
| import org.apache.ambari.server.security.encryption.CredentialProvider; |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.lang.StringUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.google.inject.Inject; |
| |
| /** |
| * Utility class to read passwords from files or the Credential Store |
| */ |
| public class PasswordUtils { |
| |
| private static final Logger LOG = LoggerFactory.getLogger(PasswordUtils.class); |
| private static final Lock LOCK = new ReentrantLock(); |
| private static final PasswordUtils INSTANCE = new PasswordUtils(); |
| |
| /** |
| * The constructor we need for creating a singleton instance |
| */ |
| private PasswordUtils() { |
| } |
| |
| @Inject |
| private static Configuration configuration; |
| |
| private volatile CredentialProvider credentialProvider = null; |
| |
| public static PasswordUtils getInstance() { |
| return INSTANCE; |
| } |
| |
| /** |
| * Reading the password belong to the given password property |
| * |
| * @param passwordProperty |
| * this is either the Credential Store alias or the password file name |
| * you want to read the password for/from |
| * @param defaultPassword |
| * the default password this function returns in case the given |
| * <code>passwordProperty</code> is <blank> or the password file cannot |
| * be read for any reason |
| * @return in case <code>passwordProperty</code> belongs to a Credential Store |
| * alias this function returns the password of the given Credential |
| * Store alias or <code>null</code> (if the given alias is |
| * <code>blank</code> or there is no password found in CS); otherwise |
| * either the password found in the given password file is returned or |
| * <code>defaultPassword</code> if the given path is <code>blank</code> |
| * or cannot be read for any reason |
| * @throws RuntimeException |
| * if any error occurred while reading the password file |
| */ |
| public String readPassword(String passwordProperty, String defaultPassword) { |
| if (StringUtils.isNotBlank(passwordProperty)) { |
| if (CredentialProvider.isAliasString(passwordProperty)) { |
| return readPasswordFromStore(passwordProperty); |
| } else { |
| return readPasswordFromFile(passwordProperty, defaultPassword); |
| } |
| } |
| return defaultPassword; |
| } |
| |
| /** |
| * Reading password from the given password file |
| * |
| * @param filePath |
| * the path of the file to read the password from |
| * @param defaultPassword |
| * the default password this function returns in case the given |
| * <code>filePath</code> is <code>blank</code> or the password file |
| * cannot be read for any reason |
| * @return the password found in the given password file or |
| * <code>defaultPassword</code> if the given path is <code>blank</code> |
| * or cannot be read for any reason |
| * @throws RuntimeException |
| * when any error occurred while reading the password file |
| */ |
| public String readPasswordFromFile(String filePath, String defaultPassword) { |
| if (StringUtils.isBlank(filePath) || !fileExistsAndCanBeRead(filePath)) { |
| LOG.debug("DB password file not specified or does not exist/can not be read - using default"); |
| return defaultPassword; |
| } else { |
| LOG.debug("Reading password from file {}", filePath); |
| String password = null; |
| try { |
| password = FileUtils.readFileToString(new File(filePath), Charset.defaultCharset()); |
| return StringUtils.chomp(password); |
| } catch (IOException e) { |
| throw new RuntimeException("Unable to read password from file [" + filePath + "]", e); |
| } |
| } |
| } |
| |
| private boolean fileExistsAndCanBeRead(String filePath) { |
| final File passwordFile = new File(filePath); |
| return passwordFile.exists() && passwordFile.canRead() && passwordFile.isFile(); |
| } |
| |
| private String readPasswordFromStore(String aliasStr) { |
| return readPasswordFromStore(aliasStr, configuration.getMasterKeyLocation(), configuration.isMasterKeyPersisted(), configuration.getMasterKeyStoreLocation()); |
| } |
| |
| /** |
| * Reading the password from Credential Store for the given alias |
| * |
| * @param aliasStr |
| * the Credential Store alias you want to read the password for |
| * @param masterKeyLocation |
| * the master key location file |
| * @param isMasterKeyPersisted |
| * a flag indicating whether the master key is persisted |
| * @param masterKeyStoreLocation |
| * the master key-store location file |
| * @return the password of the given alias if it is not <code>blank</code> and |
| * there is password stored for this alias in Credential Store; |
| * <code>null</code> otherwise |
| */ |
| public String readPasswordFromStore(String aliasStr, File masterKeyLocation, boolean isMasterKeyPersisted, File masterKeyStoreLocation) { |
| String password = null; |
| loadCredentialProvider(masterKeyLocation, isMasterKeyPersisted, masterKeyStoreLocation); |
| if (credentialProvider != null) { |
| char[] result = null; |
| try { |
| result = credentialProvider.getPasswordForAlias(aliasStr); |
| } catch (AmbariException e) { |
| LOG.error("Error reading from credential store.", e); |
| } |
| if (result != null) { |
| password = new String(result); |
| } else { |
| if (CredentialProvider.isAliasString(aliasStr)) { |
| LOG.error("Cannot read password for alias = " + aliasStr); |
| } else { |
| LOG.warn("Raw password provided, not an alias. It cannot be read from credential store."); |
| } |
| } |
| } |
| return password; |
| } |
| |
| private void loadCredentialProvider(File masterKeyLocation, boolean isMasterKeyPersisted, File masterKeyStoreLocation) { |
| if (credentialProvider == null) { |
| try { |
| LOCK.lock(); |
| credentialProvider = new CredentialProvider(null, masterKeyLocation, isMasterKeyPersisted, masterKeyStoreLocation); |
| } catch (Exception e) { |
| LOG.info("Credential provider creation failed", e); |
| credentialProvider = null; |
| } finally { |
| LOCK.unlock(); |
| } |
| } |
| } |
| |
| } |