diff options
Diffstat (limited to 'org.eclipse.jgit.junit.http/src')
-rw-r--r-- | org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java | 136 | ||||
-rw-r--r-- | org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java | 51 |
2 files changed, 175 insertions, 12 deletions
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java index 28c0f21111..69e2cd5957 100644 --- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2012 Google Inc. + * Copyright (C) 2010, 2017 Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -46,15 +46,19 @@ package org.eclipse.jgit.junit.http; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.io.IOException; import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.security.AbstractLoginService; import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.ConstraintMapping; @@ -65,10 +69,12 @@ import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jgit.transport.URIish; /** @@ -88,6 +94,9 @@ public class AppServer { /** Password for {@link #username} in secured access areas. */ public static final String password = "letmein"; + /** SSL keystore password; must have at least 6 characters. */ + private static final String keyPassword = "mykeys"; + static { // Install a logger that throws warning messages. // @@ -97,48 +106,141 @@ public class AppServer { private final Server server; + private final HttpConfiguration config; + private final ServerConnector connector; + private final HttpConfiguration secureConfig; + + private final ServerConnector secureConnector; + private final ContextHandlerCollection contexts; private final TestRequestLog log; + private List<File> filesToDelete = new ArrayList<>(); + public AppServer() { - this(0); + this(0, -1); } /** * @param port - * the http port number + * the http port number; may be zero to allocate a port + * dynamically * @since 4.2 */ public AppServer(int port) { + this(port, -1); + } + + /** + * @param port + * for https, may be zero to allocate a port dynamically + * @param sslPort + * for https,may be zero to allocate a port dynamically. If + * negative, the server will be set up without https support.. + * @since 4.9 + */ + public AppServer(int port, int sslPort) { server = new Server(); - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - http_config.setSecurePort(8443); - http_config.setOutputBufferSize(32768); + config = new HttpConfiguration(); + config.setSecureScheme("https"); + config.setSecurePort(0); + config.setOutputBufferSize(32768); connector = new ServerConnector(server, - new HttpConnectionFactory(http_config)); + new HttpConnectionFactory(config)); connector.setPort(port); + String ip; + String hostName; try { final InetAddress me = InetAddress.getByName("localhost"); - connector.setHost(me.getHostAddress()); + ip = me.getHostAddress(); + connector.setHost(ip); + hostName = InetAddress.getLocalHost().getCanonicalHostName(); } catch (UnknownHostException e) { throw new RuntimeException("Cannot find localhost", e); } + if (sslPort >= 0) { + SslContextFactory sslContextFactory = createTestSslContextFactory( + hostName); + secureConfig = new HttpConfiguration(config); + secureConnector = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, + HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(secureConfig)); + secureConnector.setPort(sslPort); + secureConnector.setHost(ip); + } else { + secureConfig = null; + secureConnector = null; + } + contexts = new ContextHandlerCollection(); log = new TestRequestLog(); log.setHandler(contexts); - server.setConnectors(new Connector[] { connector }); + if (secureConnector == null) { + server.setConnectors(new Connector[] { connector }); + } else { + server.setConnectors( + new Connector[] { connector, secureConnector }); + } server.setHandler(log); } + private SslContextFactory createTestSslContextFactory(String hostName) { + SslContextFactory factory = new SslContextFactory(true); + + String dName = "CN=,OU=,O=,ST=,L=,C="; + + try { + File tmpDir = Files.createTempDirectory("jks").toFile(); + tmpDir.deleteOnExit(); + makePrivate(tmpDir); + File keyStore = new File(tmpDir, "keystore.jks"); + Runtime.getRuntime().exec( + new String[] { + "keytool", // + "-keystore", keyStore.getAbsolutePath(), // + "-storepass", keyPassword, + "-alias", hostName, // + "-genkeypair", // + "-keyalg", "RSA", // + "-keypass", keyPassword, // + "-dname", dName, // + "-validity", "2" // + }).waitFor(); + keyStore.deleteOnExit(); + makePrivate(keyStore); + filesToDelete.add(keyStore); + filesToDelete.add(tmpDir); + factory.setKeyStorePath(keyStore.getAbsolutePath()); + factory.setKeyStorePassword(keyPassword); + factory.setKeyManagerPassword(keyPassword); + factory.setTrustStorePath(keyStore.getAbsolutePath()); + factory.setTrustStorePassword(keyPassword); + } catch (InterruptedException | IOException e) { + throw new RuntimeException("Cannot create ssl key/certificate", e); + } + return factory; + } + + private void makePrivate(File file) { + file.setReadable(false); + file.setWritable(false); + file.setExecutable(false); + file.setReadable(true, true); + file.setWritable(true, true); + if (file.isDirectory()) { + file.setExecutable(true, true); + } + } + /** * Create a new servlet context within the server. * <p> @@ -231,6 +333,10 @@ public class AppServer { RecordingLogger.clear(); log.clear(); server.start(); + config.setSecurePort(getSecurePort()); + if (secureConfig != null) { + secureConfig.setSecurePort(getSecurePort()); + } } /** @@ -243,6 +349,10 @@ public class AppServer { RecordingLogger.clear(); log.clear(); server.stop(); + for (File f : filesToDelete) { + f.delete(); + } + filesToDelete.clear(); } /** @@ -272,6 +382,12 @@ public class AppServer { return connector.getLocalPort(); } + /** @return the HTTPS port or -1 if not configured. */ + public int getSecurePort() { + assertAlreadySetUp(); + return secureConnector != null ? secureConnector.getLocalPort() : -1; + } + /** @return all requests since the server was started. */ public List<AccessEvent> getRequests() { return new ArrayList<>(log.getEvents()); diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java index 1b94e02fa4..eabb0f2256 100644 --- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java +++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/HttpTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2010, Google Inc. + * Copyright (C) 2009-2017, Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -77,7 +77,7 @@ public abstract class HttpTestCase extends LocalDiskRepositoryTestCase { @Override public void setUp() throws Exception { super.setUp(); - server = new AppServer(); + server = createServer(); } @Override @@ -86,6 +86,20 @@ public abstract class HttpTestCase extends LocalDiskRepositoryTestCase { super.tearDown(); } + /** + * Creates the {@linkAppServer}.This default implementation creates a server + * without SSLsupport listening for HTTP connections on a dynamically chosen + * port, which can be gotten once the server has been started via its + * {@link AppServer#getPort()} method. Subclasses may override if they need + * a more specialized server. + * + * @return the {@link AppServer}. + * @since 4.9 + */ + protected AppServer createServer() { + return new AppServer(); + } + protected TestRepository<Repository> createTestRepository() throws IOException { return new TestRepository<>(createBareRepository()); @@ -165,4 +179,37 @@ public abstract class HttpTestCase extends LocalDiskRepositoryTestCase { dir += "/"; return dir + path; } + + protected static String rewriteUrl(String url, String newProtocol, + int newPort) { + String newUrl = url; + if (newProtocol != null && !newProtocol.isEmpty()) { + int schemeEnd = newUrl.indexOf("://"); + if (schemeEnd >= 0) { + newUrl = newProtocol + newUrl.substring(schemeEnd); + } + } + if (newPort > 0) { + newUrl = newUrl.replaceFirst(":\\d+/", ":" + newPort + "/"); + } else { + // Remove the port, if any + newUrl = newUrl.replaceFirst(":\\d+/", "/"); + } + return newUrl; + } + + protected static URIish extendPath(URIish uri, String pathComponents) + throws URISyntaxException { + String raw = uri.toString(); + String newComponents = pathComponents; + if (!newComponents.startsWith("/")) { + newComponents = '/' + newComponents; + } + if (!newComponents.endsWith("/")) { + newComponents += '/'; + } + int i = raw.lastIndexOf('/'); + raw = raw.substring(0, i) + newComponents + raw.substring(i + 1); + return new URIish(raw); + } } |