<commit_before>/*
 * OpenRemote, the Home of the Digital Home.
 * Copyright 2008-2014, OpenRemote Inc.
 *
 * See the contributors.txt file in the distribution for a
 * full listing of individual contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.openremote.security;

import org.openremote.exception.OpenRemoteException;

import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.net.URI;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;


/**
 * This is a password storage implementation using Java's keystore mechanism. It can
 * be used in cases where an asymmetric key challenge (normally preferred) based on
 * private key is not an option. <p>
 *
 * Where a password based credentials to access, for example a remote web service is
 * required, this implementation allows storing password credentials in an encrypted
 * format in a keystore implementation. This prevents locating stored passwords via a
 * simple filesystem scan for example. However, it doesn't offer password security
 * beyond hiding the password (obscurity) unless the keystore itself is protected by
 * a master password. For non-interactive applications this creates a chicken-egg
 * problem of storing the master password to access a securely stored passwords unless
 * an external key storage (e.g. smart card, biometric hardware or similar) is present.
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class PasswordManager extends KeyManager
{


  // Private Instance Fields ----------------------------------------------------------------------

  /**
   * Location of the keystore, if persisted.
   */
  private URI keystoreLocation = null;

  /**
   * The backing keystore instance.
   */
  private KeyStore keystore = null;


  // Constructors ---------------------------------------------------------------------------------

  /**
   * Constructs an in-memory password manager backed by {@link StorageType#BKS} storage format. <p>
   *
   * Requires BouncyCastle security provider to be available on the classpath and installed
   * as a security provider to the JVM.
   *
   * @see java.security.Security#addProvider(java.security.Provider)
   * @see org.bouncycastle.jce.provider.BouncyCastleProvider
   *
   * @param masterPassword
   *            The master password to access the password storage. Note that the character
   *            array will be cleared when this constructor completes.
   *
   * @throws ConfigurationException
   *            if the configured security provider(s) do not support {@link StorageType#BKS}
   *            keystore type
   *
   * @throws  KeyManagerException
   *            if creating a new keystore instance fails
   */
  public PasswordManager(char[] masterPassword) throws ConfigurationException, KeyManagerException
  {
    try
    {
      init(StorageType.BKS, SecurityProvider.BC.getProviderInstance());

      this.keystore = createKeyStore(masterPassword);
    }

    finally
    {
      clearPassword(masterPassword);
    }
  }


  /**
   * Constructs a persistent password manager backed by {@link StorageType#BKS} storage format.
   * If no password storage exists at the given URI, a new file will be created when passwords
   * are added to this password manager. <p>
   *
   * Requires BouncyCastle security provider to be available on the classpath and installed
   * as a security provider to the JVM.
   *
   * @see java.security.Security#addProvider(java.security.Provider)
   * @see org.bouncycastle.jce.provider.BouncyCastleProvider
   *
   * @param keystoreLocation
   *            location of the persisted password storage
   *
   * @param masterPassword
   *            The master password to access the password storage. Note that the character
   *            array will be cleared when this constructor completes.
   *
   * @throws ConfigurationException
   *            if the configured security provider(s) do not support {@link StorageType#BKS}
   *            keystore type
   *
   * @throws  KeyManagerException
   *            if loading an existing keystore fails, or creating a new keystore instance
   *            fails
   */
  public PasswordManager(URI keystoreLocation, char[] masterPassword)
      throws ConfigurationException, KeyManagerException
  {
    try
    {
      init(StorageType.BKS, SecurityProvider.BC.getProviderInstance());

      if (keystoreLocation == null)
      {
        throw new KeyManagerException("Implementation error: keystore location URI is null.");
      }

      this.keystoreLocation = keystoreLocation;

      if (exists(new File(keystoreLocation)))
      {
        this.keystore = load(new File(keystoreLocation), masterPassword);
      }

      else
      {
        this.keystore = createKeyStore(masterPassword);
      }
    }

    finally
    {
      clearPassword(masterPassword);
    }
  }

  // Public Instance Methods ----------------------------------------------------------------------

  /**
   * Adds a new password to this password manager.
   *
   * @param alias
   *            A named alias for the password used to look it up.
   *
   * @param password<commit_msg>Signature change of exists() method.<commit_after>/*
 * OpenRemote, the Home of the Digital Home.
 * Copyright 2008-2014, OpenRemote Inc.
 *
 * See the contributors.txt file in the distribution for a
 * full listing of individual contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.openremote.security;

import org.openremote.exception.OpenRemoteException;

import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.net.URI;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;


/**
 * This is a password storage implementation using Java's keystore mechanism. It can
 * be used in cases where an asymmetric key challenge (normally preferred) based on
 * private key is not an option. <p>
 *
 * Where a password based credentials to access, for example a remote web service is
 * required, this implementation allows storing password credentials in an encrypted
 * format in a keystore implementation. This prevents locating stored passwords via a
 * simple filesystem scan for example. However, it doesn't offer password security
 * beyond hiding the password (obscurity) unless the keystore itself is protected by
 * a master password. For non-interactive applications this creates a chicken-egg
 * problem of storing the master password to access a securely stored passwords unless
 * an external key storage (e.g. smart card, biometric hardware or similar) is present.
 *
 * @author <a href="mailto:<EMAIL>"><NAME></a>
 */
public class PasswordManager extends KeyManager
{


  // Private Instance Fields ----------------------------------------------------------------------

  /**
   * Location of the keystore, if persisted.
   */
  private URI keystoreLocation = null;

  /**
   * The backing keystore instance.
   */
  private KeyStore keystore = null;


  // Constructors ---------------------------------------------------------------------------------

  /**
   * Constructs an in-memory password manager backed by {@link StorageType#BKS} storage format. <p>
   *
   * Requires BouncyCastle security provider to be available on the classpath and installed
   * as a security provider to the JVM.
   *
   * @see java.security.Security#addProvider(java.security.Provider)
   * @see org.bouncycastle.jce.provider.BouncyCastleProvider
   *
   * @param masterPassword
   *            The master password to access the password storage. Note that the character
   *            array will be cleared when this constructor completes.
   *
   * @throws ConfigurationException
   *            if the configured security provider(s) do not support {@link StorageType#BKS}
   *            keystore type
   *
   * @throws  KeyManagerException
   *            if creating a new keystore instance fails
   */
  public PasswordManager(char[] masterPassword) throws ConfigurationException, KeyManagerException
  {
    try
    {
      init(StorageType.BKS, SecurityProvider.BC.getProviderInstance());

      this.keystore = createKeyStore(masterPassword);
    }

    finally
    {
      clearPassword(masterPassword);
    }
  }


  /**
   * Constructs a persistent password manager backed by {@link StorageType#BKS} storage format.
   * If no password storage exists at the given URI, a new file will be created when passwords
   * are added to this password manager. <p>
   *
   * Requires BouncyCastle security provider to be available on the classpath and installed
   * as a security provider to the JVM.
   *
   * @see java.security.Security#addProvider(java.security.Provider)
   * @see org.bouncycastle.jce.provider.BouncyCastleProvider
   *
   * @param keystoreLocation
   *            location of the persisted password storage
   *
   * @param masterPassword
   *            The master password to access the password storage. Note that the character
   *            array will be cleared when this constructor completes.
   *
   * @throws ConfigurationException
   *            if the configured security provider(s) do not support {@link StorageType#BKS}
   *            keystore type
   *
   * @throws  KeyManagerException
   *            if loading an existing keystore fails, or creating a new keystore instance
   *            fails
   */
  public PasswordManager(URI keystoreLocation, char[] masterPassword)
      throws ConfigurationException, KeyManagerException
  {
    try
    {
      init(StorageType.BKS, SecurityProvider.BC.getProviderInstance());

      if (keystoreLocation == null)
      {
        throw new KeyManagerException("Implementation error: keystore location URI is null.");
      }

      this.keystoreLocation = keystoreLocation;

      if (exists(keystoreLocation))
      {
        this.keystore = load(new File(keystoreLocation), masterPassword);
      }

      else
      {
        this.keystore = createKeyStore(masterPassword);
      }
    }

    finally
    {
      clearPassword(masterPassword);
    }
  }

  // Public Instance Methods ----------------------------------------------------------------------

  /**
   * Adds a new password to this password manager.
   *
   * @param alias
   *            A named alias for the password used to look it up.
   *
   * @param password
{'fraction_non_alphanumeric': 0.10383157894736843, 'fraction_numerical': 0.0015157894736842106, 'mean_word_length': 2.7124101281650517, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3017103', 'n_tokens_mistral': 3015, 'n_tokens_neox': 2878, 'n_words': 1158}