SitePaths: Convert SSH-related paths to Path

Change-Id: I7dc8fdfcf8fec2bab159e02cab23cd64186913f2
This commit is contained in:
Dave Borowitz
2015-02-23 15:25:51 -08:00
parent b078dd6308
commit 7e55f6bbd8
6 changed files with 108 additions and 83 deletions

View File

@@ -21,6 +21,7 @@ import org.eclipse.jgit.util.IO;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; 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() { private FileUtil() {
} }
} }

View File

@@ -29,10 +29,11 @@ import com.google.gwtjsonrpc.server.SignedToken;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
/** Initialize the {@code httpd} configuration section. */ /** Initialize the {@code httpd} configuration section. */
@Singleton @Singleton
@@ -149,8 +150,9 @@ class InitHttpd implements InitStep {
return; return;
} }
final File store = site.ssl_keystore; Path store = site.ssl_keystore;
if (!ui.yesno(!store.exists(), "Create new self-signed SSL certificate")) { if (!ui.yesno(!Files.exists(store),
"Create new self-signed SSL certificate")) {
return; return;
} }
@@ -167,15 +169,17 @@ class InitHttpd implements InitStep {
final String dname = final String dname =
"CN=" + hostname + ",OU=Gerrit Code Review,O=" + domainOf(hostname); "CN=" + hostname + ",OU=Gerrit Code Review,O=" + domainOf(hostname);
final File tmpdir = new File(site.etc_dir, "tmp.sslcertgen"); Path tmpdir = site.etc_dir.toPath().resolve("tmp.sslcertgen");
if (!tmpdir.mkdir()) { try {
throw die("Cannot create directory " + tmpdir); Files.createDirectory(tmpdir);
} catch (IOException e) {
throw die("Cannot create directory " + tmpdir, e);
} }
chmod(0600, tmpdir); chmod(0600, tmpdir);
final File tmpstore = new File(tmpdir, "keystore"); Path tmpstore = tmpdir.resolve("keystore");
Runtime.getRuntime().exec(new String[] {"keytool", // Runtime.getRuntime().exec(new String[] {"keytool", //
"-keystore", tmpstore.getAbsolutePath(), // "-keystore", tmpstore.toAbsolutePath().toString(), //
"-storepass", ssl_pass, // "-storepass", ssl_pass, //
"-genkeypair", // "-genkeypair", //
"-alias", hostname, // "-alias", hostname, //
@@ -186,11 +190,15 @@ class InitHttpd implements InitStep {
}).waitFor(); }).waitFor();
chmod(0600, tmpstore); chmod(0600, tmpstore);
if (!tmpstore.renameTo(store)) { try {
throw die("Cannot rename " + tmpstore + " to " + store); Files.move(tmpstore, store);
} catch (IOException e) {
throw die("Cannot rename " + tmpstore + " to " + store, e);
} }
if (!tmpdir.delete()) { try {
throw die("Cannot delete " + tmpdir); Files.delete(tmpdir);
} catch (IOException e) {
throw die("Cannot delete " + tmpdir, e);
} }
} }

View File

@@ -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.die;
import static com.google.gerrit.pgm.init.api.InitUtil.hostname; 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.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep; import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.pgm.init.api.Section; 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.common.util.SecurityUtils;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
/** Initialize the {@code sshd} configuration section. */ /** Initialize the {@code sshd} configuration section. */
@Singleton @Singleton
@@ -74,9 +77,9 @@ class InitSshd implements InitStep {
port = ui.readInt(port, "Listen on port"); port = ui.readInt(port, "Listen on port");
sshd.set("listenAddress", SocketUtil.format(hostname, 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(); libraries.bouncyCastleSSL.downloadRequired();
} else if (!site.ssh_key.exists()) { } else if (!exists(site.ssh_key)) {
libraries.bouncyCastleSSL.downloadOptional(); libraries.bouncyCastleSSL.downloadOptional();
} }
@@ -90,9 +93,9 @@ class InitSshd implements InitStep {
} }
private void generateSshHostKeys() throws InterruptedException, IOException { private void generateSshHostKeys() throws InterruptedException, IOException {
if (!site.ssh_key.exists() // if (!exists(site.ssh_key) //
&& !site.ssh_rsa.exists() // && !exists(site.ssh_rsa) //
&& !site.ssh_dsa.exists()) { && !exists(site.ssh_dsa)) {
System.err.print("Generating SSH host key ..."); System.err.print("Generating SSH host key ...");
System.err.flush(); System.err.flush();
@@ -108,7 +111,7 @@ class InitSshd implements InitStep {
"-t", "rsa", // "-t", "rsa", //
"-P", "", // "-P", "", //
"-C", comment, // "-C", comment, //
"-f", site.ssh_rsa.getAbsolutePath() // "-f", site.ssh_rsa.toAbsolutePath().toString() //
}).waitFor(); }).waitFor();
System.err.print(" dsa..."); System.err.print(" dsa...");
@@ -118,7 +121,7 @@ class InitSshd implements InitStep {
"-t", "dsa", // "-t", "dsa", //
"-P", "", // "-P", "", //
"-C", comment, // "-C", comment, //
"-f", site.ssh_dsa.getAbsolutePath() // "-f", site.ssh_dsa.toAbsolutePath().toString() //
}).waitFor(); }).waitFor();
} else { } else {
@@ -128,28 +131,34 @@ class InitSshd implements InitStep {
// short period of time. We try to reduce that risk by creating // short period of time. We try to reduce that risk by creating
// the key within a temporary directory. // the key within a temporary directory.
// //
final File tmpdir = new File(site.etc_dir, "tmp.sshkeygen"); Path tmpdir = site.etc_dir.toPath().resolve("tmp.sshkeygen");
if (!tmpdir.mkdir()) { try {
throw die("Cannot create directory " + tmpdir); Files.createDirectory(tmpdir);
} catch (IOException e) {
throw die("Cannot create directory " + tmpdir, e);
} }
chmod(0600, tmpdir); chmod(0600, tmpdir);
final File tmpkey = new File(tmpdir, site.ssh_key.getName()); Path tmpkey = tmpdir.resolve(site.ssh_key.getFileName().toString());
final SimpleGeneratorHostKeyProvider p; SimpleGeneratorHostKeyProvider p;
System.err.print(" rsa(simple)..."); System.err.print(" rsa(simple)...");
System.err.flush(); System.err.flush();
p = new SimpleGeneratorHostKeyProvider(); p = new SimpleGeneratorHostKeyProvider();
p.setPath(tmpkey.getAbsolutePath()); p.setPath(tmpkey.toAbsolutePath().toString());
p.setAlgorithm("RSA"); p.setAlgorithm("RSA");
p.loadKeys(); // forces the key to generate. p.loadKeys(); // forces the key to generate.
chmod(0600, tmpkey); chmod(0600, tmpkey);
if (!tmpkey.renameTo(site.ssh_key)) { try {
throw die("Cannot rename " + tmpkey + " to " + site.ssh_key); Files.move(tmpkey, site.ssh_key);
} catch (IOException e) {
throw die("Cannot rename " + tmpkey + " to " + site.ssh_key, e);
} }
if (!tmpdir.delete()) { try {
throw die("Cannot delete " + tmpdir); Files.delete(tmpdir);
} catch (IOException e) {
throw die("Cannot delete " + tmpdir, e);
} }
} }
System.err.println(" done"); System.err.println(" done");

View File

@@ -50,11 +50,11 @@ public final class SitePaths {
public final File secure_config; public final File secure_config;
public final File contact_information_pub; public final File contact_information_pub;
public final File ssl_keystore; public final Path ssl_keystore;
public final File ssh_key; public final Path ssh_key;
public final File ssh_rsa; public final Path ssh_rsa;
public final File ssh_dsa; public final Path ssh_dsa;
public final File peer_keys; public final Path peer_keys;
public final Path site_css; public final Path site_css;
public final Path site_header; public final Path site_header;
@@ -90,13 +90,13 @@ public final class SitePaths {
secure_config = new File(etc_dir, "secure.config"); secure_config = new File(etc_dir, "secure.config");
contact_information_pub = new File(etc_dir, "contact_information.pub"); 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(); 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_css = etcDirPath.resolve(CSS_FILENAME);
site_header = etcDirPath.resolve(HEADER_FILENAME); site_header = etcDirPath.resolve(HEADER_FILENAME);
site_footer = etcDirPath.resolve(FOOTER_FILENAME); site_footer = etcDirPath.resolve(FOOTER_FILENAME);

View File

@@ -14,6 +14,9 @@
package com.google.gerrit.sshd; 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.reviewdb.client.AccountSshKey;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PeerDaemonUser; import com.google.gerrit.server.PeerDaemonUser;
@@ -33,10 +36,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Collection; import java.util.Collection;
@@ -170,56 +173,50 @@ class DatabasePubKeyAuth implements PublickeyAuthenticator {
} }
private static class PeerKeyCache { private static class PeerKeyCache {
private final File path; private final Path path;
private final long modified; private final long modified;
final Set<PublicKey> keys; final Set<PublicKey> keys;
PeerKeyCache(final File path) { PeerKeyCache(Path path) {
this.path = path; this.path = path;
this.modified = path.lastModified(); this.modified = FileUtil.lastModified(path);
this.keys = read(path); this.keys = read(path);
} }
private static Set<PublicKey> read(File path) { private static Set<PublicKey> read(Path path) {
try { try (BufferedReader br = Files.newBufferedReader(path, UTF_8)) {
final BufferedReader br = new BufferedReader(new FileReader(path)); final Set<PublicKey> keys = new HashSet<>();
try { String line;
final Set<PublicKey> keys = new HashSet<>(); while ((line = br.readLine()) != null) {
String line; line = line.trim();
while ((line = br.readLine()) != null) { if (line.startsWith("#") || line.isEmpty()) {
line = line.trim(); continue;
if (line.startsWith("#") || line.isEmpty()) { }
continue;
} try {
byte[] bin = Base64.decodeBase64(line.getBytes("ISO-8859-1"));
try { keys.add(new Buffer(bin).getRawPublicKey());
byte[] bin = Base64.decodeBase64(line.getBytes("ISO-8859-1")); } catch (RuntimeException e) {
keys.add(new Buffer(bin).getRawPublicKey()); logBadKey(path, line, e);
} catch (RuntimeException e) { } catch (SshException e) {
logBadKey(path, line, e); logBadKey(path, line, e);
} catch (SshException e) {
logBadKey(path, line, e);
}
} }
return Collections.unmodifiableSet(keys);
} finally {
br.close();
} }
return Collections.unmodifiableSet(keys);
} catch (FileNotFoundException noFile) { } catch (FileNotFoundException noFile) {
return Collections.emptySet(); return Collections.emptySet();
} catch (IOException err) { } catch (IOException err) {
log.error("Cannot read " + path, err); log.error("Cannot read " + path, err);
return Collections.emptySet(); 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); log.warn("Invalid key in " + path + ":\n " + line, e);
} }
boolean isCurrent() { boolean isCurrent() {
return path.lastModified() == modified; return modified == FileUtil.lastModified(path);
} }
PeerKeyCache reload() { PeerKeyCache reload() {

View File

@@ -24,7 +24,8 @@ import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.util.SecurityUtils; import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; 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.ArrayList;
import java.util.List; import java.util.List;
@@ -38,29 +39,29 @@ class HostKeyProvider implements Provider<KeyPairProvider> {
@Override @Override
public KeyPairProvider get() { public KeyPairProvider get() {
final File objKey = site.ssh_key; Path objKey = site.ssh_key;
final File rsaKey = site.ssh_rsa; Path rsaKey = site.ssh_rsa;
final File dsaKey = site.ssh_dsa; Path dsaKey = site.ssh_dsa;
final List<String> stdKeys = new ArrayList<>(2); final List<String> stdKeys = new ArrayList<>(2);
if (rsaKey.exists()) { if (Files.exists(rsaKey)) {
stdKeys.add(rsaKey.getAbsolutePath()); stdKeys.add(rsaKey.toAbsolutePath().toString());
} }
if (dsaKey.exists()) { if (Files.exists(dsaKey)) {
stdKeys.add(dsaKey.getAbsolutePath()); stdKeys.add(dsaKey.toAbsolutePath().toString());
} }
if (objKey.exists()) { if (Files.exists(objKey)) {
if (stdKeys.isEmpty()) { if (stdKeys.isEmpty()) {
SimpleGeneratorHostKeyProvider p = new SimpleGeneratorHostKeyProvider(); SimpleGeneratorHostKeyProvider p = new SimpleGeneratorHostKeyProvider();
p.setPath(objKey.getAbsolutePath()); p.setPath(objKey.toAbsolutePath().toString());
return p; return p;
} else { } else {
// Both formats of host key exist, we don't know which format // Both formats of host key exist, we don't know which format
// should be authoritative. Complain and abort. // should be authoritative. Complain and abort.
// //
stdKeys.add(objKey.getAbsolutePath()); stdKeys.add(objKey.toAbsolutePath().toString());
throw new ProvisionException("Multiple host keys exist: " + stdKeys); throw new ProvisionException("Multiple host keys exist: " + stdKeys);
} }