/** Generate a local password and save it in the local-password file. */
 public void postConstruct() {
   logger.fine("Generating local password");
   SecureRandom random = new SecureRandom();
   byte[] pwd = new byte[PASSWORD_BYTES];
   random.nextBytes(pwd);
   password = toHex(pwd);
   File localPasswordFile = new File(env.getConfigDirPath(), LOCAL_PASSWORD_FILE);
   PrintWriter w = null;
   try {
     if (!localPasswordFile.exists()) {
       localPasswordFile.createNewFile();
       /*
        * XXX - There's a security hole here.
        * Between the time the file is created and the permissions
        * are changed to prevent others from opening it, someone
        * else could open it and wait for the data to be written.
        * Java needs the ability to create a file that's readable
        * only by the owner; coming in JDK 7.
        */
       localPasswordFile.setWritable(false, false); // take from all
       localPasswordFile.setWritable(true, true); // owner only
       localPasswordFile.setReadable(false, false); // take from all
       localPasswordFile.setReadable(true, true); // owner only
     }
     w = new PrintWriter(localPasswordFile);
     w.println(password);
   } catch (IOException ex) {
     // ignore errors
     logger.log(Level.FINE, "Exception writing local password file", ex);
   } finally {
     if (w != null) w.close();
   }
 }
/**
 * Manage a local password, which is a cryptographically secure random number stored in a file with
 * permissions that only allow the owner to read it. A new local password is generated each time the
 * server starts. The asadmin client can use it to authenticate when executing local commands, such
 * as stop-domain, without the user needing to supply a password.
 *
 * @author Bill Shannon
 */
@Service
@Scoped(Singleton.class) // only want one local password
public class LocalPasswordImpl implements PostConstruct, Init, LocalPassword {

  @Inject ServerEnvironment env;

  private String password;

  private static final String LOCAL_PASSWORD_FILE = "local-password";
  private static final int PASSWORD_BYTES = 20;
  private static final char[] hex = {
    '0', '1', '2', '3', '4', '5', '6', '7',
    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
  };

  private final Logger logger = Logger.getAnonymousLogger();

  /** Generate a local password and save it in the local-password file. */
  public void postConstruct() {
    logger.fine("Generating local password");
    SecureRandom random = new SecureRandom();
    byte[] pwd = new byte[PASSWORD_BYTES];
    random.nextBytes(pwd);
    password = toHex(pwd);
    File localPasswordFile = new File(env.getConfigDirPath(), LOCAL_PASSWORD_FILE);
    PrintWriter w = null;
    try {
      if (!localPasswordFile.exists()) {
        localPasswordFile.createNewFile();
        /*
         * XXX - There's a security hole here.
         * Between the time the file is created and the permissions
         * are changed to prevent others from opening it, someone
         * else could open it and wait for the data to be written.
         * Java needs the ability to create a file that's readable
         * only by the owner; coming in JDK 7.
         */
        localPasswordFile.setWritable(false, false); // take from all
        localPasswordFile.setWritable(true, true); // owner only
        localPasswordFile.setReadable(false, false); // take from all
        localPasswordFile.setReadable(true, true); // owner only
      }
      w = new PrintWriter(localPasswordFile);
      w.println(password);
    } catch (IOException ex) {
      // ignore errors
      logger.log(Level.FINE, "Exception writing local password file", ex);
    } finally {
      if (w != null) w.close();
    }
  }

  /** Is the given password the local password? */
  public boolean isLocalPassword(String p) {
    return password != null && password.equals(p);
  }

  /** Get the local password. */
  public String getLocalPassword() {
    return password;
  }

  /** Convert the byte array to a hex string. */
  private static String toHex(byte[] b) {
    char[] bc = new char[b.length * 2];
    for (int i = 0, j = 0; i < b.length; i++) {
      byte bb = b[i];
      bc[j++] = hex[(bb >> 4) & 0xF];
      bc[j++] = hex[bb & 0xF];
    }
    return new String(bc);
  }
}