SitePaths: Convert SSH-related paths to Path
Change-Id: I7dc8fdfcf8fec2bab159e02cab23cd64186913f2
This commit is contained in:
		@@ -21,6 +21,7 @@ import org.eclipse.jgit.util.IO;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
@@ -67,6 +68,15 @@ public class FileUtil {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static long lastModified(Path p) {
 | 
			
		||||
    // Replicate File#lastModified() behavior of returning 0 on errors.
 | 
			
		||||
    try {
 | 
			
		||||
      return Files.getLastModifiedTime(p).toMillis();
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private FileUtil() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,10 +29,11 @@ import com.google.gwtjsonrpc.server.SignedToken;
 | 
			
		||||
import com.google.inject.Inject;
 | 
			
		||||
import com.google.inject.Singleton;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.URI;
 | 
			
		||||
import java.net.URISyntaxException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
 | 
			
		||||
/** Initialize the {@code httpd} configuration section. */
 | 
			
		||||
@Singleton
 | 
			
		||||
@@ -149,8 +150,9 @@ class InitHttpd implements InitStep {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final File store = site.ssl_keystore;
 | 
			
		||||
    if (!ui.yesno(!store.exists(), "Create new self-signed SSL certificate")) {
 | 
			
		||||
    Path store = site.ssl_keystore;
 | 
			
		||||
    if (!ui.yesno(!Files.exists(store),
 | 
			
		||||
        "Create new self-signed SSL certificate")) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -167,15 +169,17 @@ class InitHttpd implements InitStep {
 | 
			
		||||
    final String dname =
 | 
			
		||||
        "CN=" + hostname + ",OU=Gerrit Code Review,O=" + domainOf(hostname);
 | 
			
		||||
 | 
			
		||||
    final File tmpdir = new File(site.etc_dir, "tmp.sslcertgen");
 | 
			
		||||
    if (!tmpdir.mkdir()) {
 | 
			
		||||
      throw die("Cannot create directory " + tmpdir);
 | 
			
		||||
    Path tmpdir = site.etc_dir.toPath().resolve("tmp.sslcertgen");
 | 
			
		||||
    try {
 | 
			
		||||
      Files.createDirectory(tmpdir);
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      throw die("Cannot create directory " + tmpdir, e);
 | 
			
		||||
    }
 | 
			
		||||
    chmod(0600, tmpdir);
 | 
			
		||||
 | 
			
		||||
    final File tmpstore = new File(tmpdir, "keystore");
 | 
			
		||||
    Path tmpstore = tmpdir.resolve("keystore");
 | 
			
		||||
    Runtime.getRuntime().exec(new String[] {"keytool", //
 | 
			
		||||
        "-keystore", tmpstore.getAbsolutePath(), //
 | 
			
		||||
        "-keystore", tmpstore.toAbsolutePath().toString(), //
 | 
			
		||||
        "-storepass", ssl_pass, //
 | 
			
		||||
        "-genkeypair", //
 | 
			
		||||
        "-alias", hostname, //
 | 
			
		||||
@@ -186,11 +190,15 @@ class InitHttpd implements InitStep {
 | 
			
		||||
    }).waitFor();
 | 
			
		||||
    chmod(0600, tmpstore);
 | 
			
		||||
 | 
			
		||||
    if (!tmpstore.renameTo(store)) {
 | 
			
		||||
      throw die("Cannot rename " + tmpstore + " to " + store);
 | 
			
		||||
    try {
 | 
			
		||||
      Files.move(tmpstore, store);
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      throw die("Cannot rename " + tmpstore + " to " + store, e);
 | 
			
		||||
    }
 | 
			
		||||
    if (!tmpdir.delete()) {
 | 
			
		||||
      throw die("Cannot delete " + tmpdir);
 | 
			
		||||
    try {
 | 
			
		||||
      Files.delete(tmpdir);
 | 
			
		||||
    } catch (IOException e) {
 | 
			
		||||
      throw die("Cannot delete " + tmpdir, e);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,8 @@ import static com.google.gerrit.common.FileUtil.chmod;
 | 
			
		||||
import static com.google.gerrit.pgm.init.api.InitUtil.die;
 | 
			
		||||
import static com.google.gerrit.pgm.init.api.InitUtil.hostname;
 | 
			
		||||
 | 
			
		||||
import static java.nio.file.Files.exists;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.pgm.init.api.ConsoleUI;
 | 
			
		||||
import com.google.gerrit.pgm.init.api.InitStep;
 | 
			
		||||
import com.google.gerrit.pgm.init.api.Section;
 | 
			
		||||
@@ -29,9 +31,10 @@ import com.google.inject.Singleton;
 | 
			
		||||
import org.apache.sshd.common.util.SecurityUtils;
 | 
			
		||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.InetSocketAddress;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
 | 
			
		||||
/** Initialize the {@code sshd} configuration section. */
 | 
			
		||||
@Singleton
 | 
			
		||||
@@ -74,9 +77,9 @@ class InitSshd implements InitStep {
 | 
			
		||||
    port = ui.readInt(port, "Listen on port");
 | 
			
		||||
    sshd.set("listenAddress", SocketUtil.format(hostname, port));
 | 
			
		||||
 | 
			
		||||
    if (site.ssh_rsa.exists() || site.ssh_dsa.exists()) {
 | 
			
		||||
    if (exists(site.ssh_rsa) || exists(site.ssh_dsa)) {
 | 
			
		||||
      libraries.bouncyCastleSSL.downloadRequired();
 | 
			
		||||
    } else if (!site.ssh_key.exists()) {
 | 
			
		||||
    } else if (!exists(site.ssh_key)) {
 | 
			
		||||
      libraries.bouncyCastleSSL.downloadOptional();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -90,9 +93,9 @@ class InitSshd implements InitStep {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void generateSshHostKeys() throws InterruptedException, IOException {
 | 
			
		||||
    if (!site.ssh_key.exists() //
 | 
			
		||||
        && !site.ssh_rsa.exists() //
 | 
			
		||||
        && !site.ssh_dsa.exists()) {
 | 
			
		||||
    if (!exists(site.ssh_key) //
 | 
			
		||||
        && !exists(site.ssh_rsa) //
 | 
			
		||||
        && !exists(site.ssh_dsa)) {
 | 
			
		||||
      System.err.print("Generating SSH host key ...");
 | 
			
		||||
      System.err.flush();
 | 
			
		||||
 | 
			
		||||
@@ -108,7 +111,7 @@ class InitSshd implements InitStep {
 | 
			
		||||
            "-t", "rsa", //
 | 
			
		||||
            "-P", "", //
 | 
			
		||||
            "-C", comment, //
 | 
			
		||||
            "-f", site.ssh_rsa.getAbsolutePath() //
 | 
			
		||||
            "-f", site.ssh_rsa.toAbsolutePath().toString() //
 | 
			
		||||
            }).waitFor();
 | 
			
		||||
 | 
			
		||||
        System.err.print(" dsa...");
 | 
			
		||||
@@ -118,7 +121,7 @@ class InitSshd implements InitStep {
 | 
			
		||||
            "-t", "dsa", //
 | 
			
		||||
            "-P", "", //
 | 
			
		||||
            "-C", comment, //
 | 
			
		||||
            "-f", site.ssh_dsa.getAbsolutePath() //
 | 
			
		||||
            "-f", site.ssh_dsa.toAbsolutePath().toString() //
 | 
			
		||||
            }).waitFor();
 | 
			
		||||
 | 
			
		||||
      } else {
 | 
			
		||||
@@ -128,28 +131,34 @@ class InitSshd implements InitStep {
 | 
			
		||||
        // short period of time. We try to reduce that risk by creating
 | 
			
		||||
        // the key within a temporary directory.
 | 
			
		||||
        //
 | 
			
		||||
        final File tmpdir = new File(site.etc_dir, "tmp.sshkeygen");
 | 
			
		||||
        if (!tmpdir.mkdir()) {
 | 
			
		||||
          throw die("Cannot create directory " + tmpdir);
 | 
			
		||||
        Path tmpdir = site.etc_dir.toPath().resolve("tmp.sshkeygen");
 | 
			
		||||
        try {
 | 
			
		||||
          Files.createDirectory(tmpdir);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
          throw die("Cannot create directory " + tmpdir, e);
 | 
			
		||||
        }
 | 
			
		||||
        chmod(0600, tmpdir);
 | 
			
		||||
 | 
			
		||||
        final File tmpkey = new File(tmpdir, site.ssh_key.getName());
 | 
			
		||||
        final SimpleGeneratorHostKeyProvider p;
 | 
			
		||||
        Path tmpkey = tmpdir.resolve(site.ssh_key.getFileName().toString());
 | 
			
		||||
        SimpleGeneratorHostKeyProvider p;
 | 
			
		||||
 | 
			
		||||
        System.err.print(" rsa(simple)...");
 | 
			
		||||
        System.err.flush();
 | 
			
		||||
        p = new SimpleGeneratorHostKeyProvider();
 | 
			
		||||
        p.setPath(tmpkey.getAbsolutePath());
 | 
			
		||||
        p.setPath(tmpkey.toAbsolutePath().toString());
 | 
			
		||||
        p.setAlgorithm("RSA");
 | 
			
		||||
        p.loadKeys(); // forces the key to generate.
 | 
			
		||||
        chmod(0600, tmpkey);
 | 
			
		||||
 | 
			
		||||
        if (!tmpkey.renameTo(site.ssh_key)) {
 | 
			
		||||
          throw die("Cannot rename " + tmpkey + " to " + site.ssh_key);
 | 
			
		||||
        try {
 | 
			
		||||
          Files.move(tmpkey, site.ssh_key);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
          throw die("Cannot rename " + tmpkey + " to " + site.ssh_key, e);
 | 
			
		||||
        }
 | 
			
		||||
        if (!tmpdir.delete()) {
 | 
			
		||||
          throw die("Cannot delete " + tmpdir);
 | 
			
		||||
        try {
 | 
			
		||||
          Files.delete(tmpdir);
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
          throw die("Cannot delete " + tmpdir, e);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      System.err.println(" done");
 | 
			
		||||
 
 | 
			
		||||
@@ -50,11 +50,11 @@ public final class SitePaths {
 | 
			
		||||
  public final File secure_config;
 | 
			
		||||
  public final File contact_information_pub;
 | 
			
		||||
 | 
			
		||||
  public final File ssl_keystore;
 | 
			
		||||
  public final File ssh_key;
 | 
			
		||||
  public final File ssh_rsa;
 | 
			
		||||
  public final File ssh_dsa;
 | 
			
		||||
  public final File peer_keys;
 | 
			
		||||
  public final Path ssl_keystore;
 | 
			
		||||
  public final Path ssh_key;
 | 
			
		||||
  public final Path ssh_rsa;
 | 
			
		||||
  public final Path ssh_dsa;
 | 
			
		||||
  public final Path peer_keys;
 | 
			
		||||
 | 
			
		||||
  public final Path site_css;
 | 
			
		||||
  public final Path site_header;
 | 
			
		||||
@@ -90,13 +90,13 @@ public final class SitePaths {
 | 
			
		||||
    secure_config = new File(etc_dir, "secure.config");
 | 
			
		||||
    contact_information_pub = new File(etc_dir, "contact_information.pub");
 | 
			
		||||
 | 
			
		||||
    ssl_keystore = new File(etc_dir, "keystore");
 | 
			
		||||
    ssh_key = new File(etc_dir, "ssh_host_key");
 | 
			
		||||
    ssh_rsa = new File(etc_dir, "ssh_host_rsa_key");
 | 
			
		||||
    ssh_dsa = new File(etc_dir, "ssh_host_dsa_key");
 | 
			
		||||
    peer_keys = new File(etc_dir, "peer_keys");
 | 
			
		||||
 | 
			
		||||
    Path etcDirPath = etc_dir.toPath();
 | 
			
		||||
    ssl_keystore = etcDirPath.resolve("keystore");
 | 
			
		||||
    ssh_key = etcDirPath.resolve("ssh_host_key");
 | 
			
		||||
    ssh_rsa = etcDirPath.resolve("ssh_host_rsa_key");
 | 
			
		||||
    ssh_dsa = etcDirPath.resolve("ssh_host_dsa_key");
 | 
			
		||||
    peer_keys = etcDirPath.resolve("peer_keys");
 | 
			
		||||
 | 
			
		||||
    site_css = etcDirPath.resolve(CSS_FILENAME);
 | 
			
		||||
    site_header = etcDirPath.resolve(HEADER_FILENAME);
 | 
			
		||||
    site_footer = etcDirPath.resolve(FOOTER_FILENAME);
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,9 @@
 | 
			
		||||
 | 
			
		||||
package com.google.gerrit.sshd;
 | 
			
		||||
 | 
			
		||||
import static java.nio.charset.StandardCharsets.UTF_8;
 | 
			
		||||
 | 
			
		||||
import com.google.gerrit.common.FileUtil;
 | 
			
		||||
import com.google.gerrit.reviewdb.client.AccountSshKey;
 | 
			
		||||
import com.google.gerrit.server.IdentifiedUser;
 | 
			
		||||
import com.google.gerrit.server.PeerDaemonUser;
 | 
			
		||||
@@ -33,10 +36,10 @@ import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileNotFoundException;
 | 
			
		||||
import java.io.FileReader;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.security.KeyPair;
 | 
			
		||||
import java.security.PublicKey;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
@@ -170,20 +173,18 @@ class DatabasePubKeyAuth implements PublickeyAuthenticator {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static class PeerKeyCache {
 | 
			
		||||
    private final File path;
 | 
			
		||||
    private final Path path;
 | 
			
		||||
    private final long modified;
 | 
			
		||||
    final Set<PublicKey> keys;
 | 
			
		||||
 | 
			
		||||
    PeerKeyCache(final File path) {
 | 
			
		||||
    PeerKeyCache(Path path) {
 | 
			
		||||
      this.path = path;
 | 
			
		||||
      this.modified = path.lastModified();
 | 
			
		||||
      this.modified = FileUtil.lastModified(path);
 | 
			
		||||
      this.keys = read(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Set<PublicKey> read(File path) {
 | 
			
		||||
      try {
 | 
			
		||||
        final BufferedReader br = new BufferedReader(new FileReader(path));
 | 
			
		||||
        try {
 | 
			
		||||
    private static Set<PublicKey> read(Path path) {
 | 
			
		||||
      try (BufferedReader br = Files.newBufferedReader(path, UTF_8)) {
 | 
			
		||||
        final Set<PublicKey> keys = new HashSet<>();
 | 
			
		||||
        String line;
 | 
			
		||||
        while ((line = br.readLine()) != null) {
 | 
			
		||||
@@ -202,24 +203,20 @@ class DatabasePubKeyAuth implements PublickeyAuthenticator {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return Collections.unmodifiableSet(keys);
 | 
			
		||||
        } finally {
 | 
			
		||||
          br.close();
 | 
			
		||||
        }
 | 
			
		||||
      } catch (FileNotFoundException noFile) {
 | 
			
		||||
        return Collections.emptySet();
 | 
			
		||||
 | 
			
		||||
      } catch (IOException err) {
 | 
			
		||||
        log.error("Cannot read " + path, err);
 | 
			
		||||
        return Collections.emptySet();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void logBadKey(File path, String line, Exception e) {
 | 
			
		||||
    private static void logBadKey(Path path, String line, Exception e) {
 | 
			
		||||
      log.warn("Invalid key in " + path + ":\n  " + line, e);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean isCurrent() {
 | 
			
		||||
      return path.lastModified() == modified;
 | 
			
		||||
      return modified == FileUtil.lastModified(path);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    PeerKeyCache reload() {
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,8 @@ import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
 | 
			
		||||
import org.apache.sshd.common.util.SecurityUtils;
 | 
			
		||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Path;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@@ -38,29 +39,29 @@ class HostKeyProvider implements Provider<KeyPairProvider> {
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public KeyPairProvider get() {
 | 
			
		||||
    final File objKey = site.ssh_key;
 | 
			
		||||
    final File rsaKey = site.ssh_rsa;
 | 
			
		||||
    final File dsaKey = site.ssh_dsa;
 | 
			
		||||
    Path objKey = site.ssh_key;
 | 
			
		||||
    Path rsaKey = site.ssh_rsa;
 | 
			
		||||
    Path dsaKey = site.ssh_dsa;
 | 
			
		||||
 | 
			
		||||
    final List<String> stdKeys = new ArrayList<>(2);
 | 
			
		||||
    if (rsaKey.exists()) {
 | 
			
		||||
      stdKeys.add(rsaKey.getAbsolutePath());
 | 
			
		||||
    if (Files.exists(rsaKey)) {
 | 
			
		||||
      stdKeys.add(rsaKey.toAbsolutePath().toString());
 | 
			
		||||
    }
 | 
			
		||||
    if (dsaKey.exists()) {
 | 
			
		||||
      stdKeys.add(dsaKey.getAbsolutePath());
 | 
			
		||||
    if (Files.exists(dsaKey)) {
 | 
			
		||||
      stdKeys.add(dsaKey.toAbsolutePath().toString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (objKey.exists()) {
 | 
			
		||||
    if (Files.exists(objKey)) {
 | 
			
		||||
      if (stdKeys.isEmpty()) {
 | 
			
		||||
        SimpleGeneratorHostKeyProvider p = new SimpleGeneratorHostKeyProvider();
 | 
			
		||||
        p.setPath(objKey.getAbsolutePath());
 | 
			
		||||
        p.setPath(objKey.toAbsolutePath().toString());
 | 
			
		||||
        return p;
 | 
			
		||||
 | 
			
		||||
      } else {
 | 
			
		||||
        // Both formats of host key exist, we don't know which format
 | 
			
		||||
        // should be authoritative. Complain and abort.
 | 
			
		||||
        //
 | 
			
		||||
        stdKeys.add(objKey.getAbsolutePath());
 | 
			
		||||
        stdKeys.add(objKey.toAbsolutePath().toString());
 | 
			
		||||
        throw new ProvisionException("Multiple host keys exist: " + stdKeys);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user