You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2020/10/17 14:42:14 UTC

[shiro] branch tls-for-its created (now b68739b)

This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a change to branch tls-for-its
in repository https://gitbox.apache.org/repos/asf/shiro.git.


      at b68739b  Update AbstractContainerIT to allow for HTTPS connections

This branch includes the following new commits:

     new b68739b  Update AbstractContainerIT to allow for HTTPS connections

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[shiro] 01/01: Update AbstractContainerIT to allow for HTTPS connections

Posted by bd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bdemers pushed a commit to branch tls-for-its
in repository https://gitbox.apache.org/repos/asf/shiro.git

commit b68739bf0ceeaa0282e665b59c0bf861cf1fab4a
Author: Brian Demers <bd...@apache.org>
AuthorDate: Thu Oct 15 11:33:21 2020 -0400

    Update AbstractContainerIT to allow for HTTPS connections
    
    Using a pre-generated keystore
---
 .../shiro/testing/web/AbstractContainerIT.java     |  69 +++++++++++++++++++++
 .../support/src/main/resources/createKeyStore.sh   |  65 +++++++++++++++++++
 .../support/src/main/resources/test-keystore.jks   | Bin 0 -> 2272 bytes
 .../support/src/main/resources/test-keystore.pem   |  22 +++++++
 pom.xml                                            |   2 +
 ...onIT.java => WebAppContainerIntegrationIT.java} |   6 +-
 6 files changed, 161 insertions(+), 3 deletions(-)

diff --git a/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java b/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java
index 9c08423..fe54c0e 100644
--- a/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java
+++ b/integration-tests/support/src/main/java/org/apache/shiro/testing/web/AbstractContainerIT.java
@@ -24,8 +24,15 @@ import com.gargoylesoftware.htmlunit.WebClient;
 import com.github.mjeanroy.junit.servers.jetty.EmbeddedJetty;
 import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration;
 import org.eclipse.jetty.annotations.AnnotationConfiguration;
+import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
 import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
 import org.eclipse.jetty.util.resource.FileResource;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.eclipse.jetty.webapp.Configuration;
 import org.eclipse.jetty.webapp.FragmentConfiguration;
 import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
@@ -39,7 +46,13 @@ import org.junit.BeforeClass;
 
 import java.io.File;
 import java.io.FilenameFilter;
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
 
 import static com.github.mjeanroy.junit.servers.commons.Strings.isNotBlank;
 import static org.eclipse.jetty.util.resource.Resource.newResource;
@@ -50,8 +63,13 @@ public abstract class AbstractContainerIT {
 
     protected static EmbeddedJetty jetty;
 
+    protected static int tlsPort;
+
     protected final WebClient webClient = new WebClient();
 
+    protected static final File TEST_KEYSTORE_PATH = setupKeyStore();
+    protected static final String TEST_KEYSTORE_PASSWORD = "password";
+
     @BeforeClass
     public static void startContainer() throws Exception {
 
@@ -98,6 +116,7 @@ public abstract class AbstractContainerIT {
 
                 Server server = getDelegate();
 
+                // web app
                 ctx.setParentLoaderPriority(true);
                 ctx.setWar(webapp);
                 ctx.setServer(server);
@@ -109,6 +128,26 @@ public abstract class AbstractContainerIT {
             }
         };
 
+        Server server = jetty.getDelegate();
+
+        // TLS
+        tlsPort = getFreePort();
+
+        final SslContextFactory sslContextFactory = new SslContextFactory.Server();
+        sslContextFactory.setKeyStorePath(TEST_KEYSTORE_PATH.getAbsolutePath());
+        sslContextFactory.setKeyStorePassword(TEST_KEYSTORE_PASSWORD);
+        sslContextFactory.setKeyManagerPassword(TEST_KEYSTORE_PASSWORD);
+
+        HttpConfiguration https = new HttpConfiguration();
+        https.addCustomizer(new SecureRequestCustomizer());
+
+        final ServerConnector httpsConnector = new ServerConnector(
+                server,
+                new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
+                new HttpConnectionFactory(https));
+        httpsConnector.setPort(tlsPort);
+        server.addConnector(httpsConnector);
+
         jetty.start();
 
         assertTrue(jetty.isStarted());
@@ -118,6 +157,10 @@ public abstract class AbstractContainerIT {
         return "http://localhost:" + jetty.getPort() + "/";
     }
 
+    protected static String getTlsBaseUri() {
+        return "https://localhost:" + tlsPort + "/";
+    }
+
     protected static String getWarDir() {
         File[] warFiles = new File("target").listFiles(new FilenameFilter() {
             @Override
@@ -150,4 +193,30 @@ public abstract class AbstractContainerIT {
             jetty.stop();
         }
     }
+
+    private static int getFreePort() {
+        try (ServerSocket socket = new ServerSocket(0)) {
+            return socket.getLocalPort();
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to allocate free port", e);
+        }
+    }
+
+    // Dealing with a keystore is NOT fun, it's easier to script one with the keytool
+    // see src/main/resources/createKeyStore.sh for more info
+    private static File setupKeyStore() {
+        try {
+            Path outKeyStoreFile = File.createTempFile("test-keystore", "jks").toPath();
+            URL keyStoreResource = Thread.currentThread().getContextClassLoader().getResource("test-keystore.jks");
+            Files.copy(keyStoreResource.openStream(), outKeyStoreFile, StandardCopyOption.REPLACE_EXISTING);
+            File keyStoreFile = outKeyStoreFile.toFile();
+
+            // clients will pick up the ssl keystore this way, so just set SSL properties
+            System.setProperty("javax.net.ssl.trustStore", keyStoreFile.getAbsolutePath());
+            System.setProperty("javax.net.ssl.trustStorePassword", TEST_KEYSTORE_PASSWORD);
+            return keyStoreFile;
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to create test keystore", e);
+        }
+    }
 }
diff --git a/integration-tests/support/src/main/resources/createKeyStore.sh b/integration-tests/support/src/main/resources/createKeyStore.sh
new file mode 100755
index 0000000..bf71085
--- /dev/null
+++ b/integration-tests/support/src/main/resources/createKeyStore.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+set -e
+
+# This script will generate a self signed certificate, store it in a Java keystore and PEM format.
+# The generated certificate is good for 10 years, and should NOT need to be recreated until then (unless
+# changes to the certificate are needed).
+# Last run with Java 1.8.0_252
+#
+# Usage: For JVM based applications, the resulting keystore MUST be configured to in order for clients to accept TLS
+# connections.  Typical usage requires setting of the Java system property 'javax.net.ssl.trustStore' to the file path
+# of the keystore. Either by adding a command line parameter: `-Djavax.net.ssl.trustStore=/path/to/keystore` or
+# programmatically: `System.setProperty("javax.net.ssl.trustStore", "/path/to/keystore")`
+
+dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+keystore_file="${dir}/test-keystore.jks"
+file_prefix="${dir}/test-keystore"
+rm -f ${file_prefix}*
+
+echo "generate new keystore"
+keytool -genkey \
+        -keystore "${file_prefix}.jks" \
+        -alias "localhost" \
+        -keyalg RSA \
+        -keysize 2048 \
+        -validity 3650 \
+        -dname "C=US; ST=Unknown; L=Springfield; O=Unknown; OU=Unknown; CN=localhost" \
+        -ext SAN=dns:localhost \
+        -keypass password \
+        -storepass password \
+        -noprompt
+
+echo "self sign"
+keytool -selfcert \
+        -alias "localhost" \
+        -keystore "${file_prefix}.jks" \
+        -validity 3650 \
+        -storepass password \
+        -noprompt
+
+echo "export to pem"
+keytool -export \
+        -alias "localhost" \
+        -keystore "${file_prefix}.jks" \
+        -rfc \
+        -file "${file_prefix}.pem" \
+        -storepass password \
+        -noprompt
diff --git a/integration-tests/support/src/main/resources/test-keystore.jks b/integration-tests/support/src/main/resources/test-keystore.jks
new file mode 100644
index 0000000..0cea846
Binary files /dev/null and b/integration-tests/support/src/main/resources/test-keystore.jks differ
diff --git a/integration-tests/support/src/main/resources/test-keystore.pem b/integration-tests/support/src/main/resources/test-keystore.pem
new file mode 100644
index 0000000..bbbad01
--- /dev/null
+++ b/integration-tests/support/src/main/resources/test-keystore.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDjzCCAnegAwIBAgIEDGro0DANBgkqhkiG9w0BAQsFADBtMRIwEAYDVQQDEwls
+b2NhbGhvc3QxEDAOBgNVBAsTB1Vua25vd24xEDAOBgNVBAoTB1Vua25vd24xFDAS
+BgNVBAcTC1NwcmluZ2ZpZWxkMRAwDgYDVQQIEwdVbmtub3duMQswCQYDVQQGEwJV
+UzAeFw0yMDEwMTUxNTE4MThaFw0zMDEwMTMxNTE4MThaMG0xEjAQBgNVBAMTCWxv
+Y2FsaG9zdDEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEChMHVW5rbm93bjEUMBIG
+A1UEBxMLU3ByaW5nZmllbGQxEDAOBgNVBAgTB1Vua25vd24xCzAJBgNVBAYTAlVT
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmlRyaRblUwPFtvMR+NZa
+hW27UEidgyOIXeXS+iwOXbc49B9ADA6utnQybiaKWG5IXMCD1dsPd3Pqx/5Bqmhd
+1QQJCQxjx1McieEhXuhON7wqpYlmt+sIVUvPNHFldyuv/CqqZLBLWYj1uaba15E7
+oLPVT+XBRY/uvWR4q6HtweNcBU0m183eaFSzYwpUuhHCgI5V3+qC40eDoCPd6jrA
+S6BGldvR+Ysbe5fGQUmL7IUks6YO/AGMRZjmR5pKGE5dmoCPsuusnmHvm8iKfkh0
+KzMDcxpY0ZlwNXIsNfIuIBBBAkGZG2RVmJeOJG6Bv6DCSt3ypOLbb0vHiEm7wLrL
+YwIDAQABozcwNTAUBgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYEFNDDMtIb
+fscg7DRkbQV6ZuKNG7YlMA0GCSqGSIb3DQEBCwUAA4IBAQCLJ6743hPQNx1Sop0v
+0Fm+2dm66Xj77aGfB9Xq64/BsQP+imWYuAv0oQq2tgCtXSMBhyfBKQKfEbQcd+m5
+WsiSfkxpvcCWR7Ttc7GuElG6Bb+CqLxLDZuEogIOsVM7MgEfqC5zp94vLhSrLmrl
+HzZzisVL/PH0wMpAuD0IRWgdYyPWavBipVHCJYWJRehQon9D+qi1EuwSOZYvq9af
+YSfZtkndXrVfpmnO9+xrszO5Yu9qgZfvRLhpal/cmsBpRVyZIWdUj4B1wfPtKT3/
+x+85LN5wNyiRkROf1M0S6mb2Ac7zMJrNI5hKfKM2OOLC/g/ec3NOWH8/7k9FlcRv
+alPL
+-----END CERTIFICATE-----
diff --git a/pom.xml b/pom.xml
index fe76cb0..02aedfb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -292,6 +292,7 @@
                             <exclude>**/*.json</exclude>
                             <exclude>**/spring.factories</exclude>
                             <exclude>**/spring.provides</exclude>
+                            <exclude>**/*.iml</exclude>
                         </excludes>
                     </configuration>
                 </plugin>
@@ -1299,6 +1300,7 @@
                         <exclude>**/*.json</exclude>
                         <exclude>**/spring.factories</exclude>
                         <exclude>**/spring.provides</exclude>
+                        <exclude>**/*.iml</exclude>
                     </excludes>
                 </configuration>
             </plugin>
diff --git a/samples/web/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java b/samples/web/src/test/java/org/apache/shiro/test/WebAppContainerIntegrationIT.java
similarity index 91%
rename from samples/web/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java
rename to samples/web/src/test/java/org/apache/shiro/test/WebAppContainerIntegrationIT.java
index 3b8e5b8..3f724f3 100644
--- a/samples/web/src/test/java/org/apache/shiro/test/ContainerIntegrationIT.java
+++ b/samples/web/src/test/java/org/apache/shiro/test/WebAppContainerIntegrationIT.java
@@ -31,14 +31,14 @@ import org.junit.Test;
 import java.io.IOException;
 import java.net.MalformedURLException;
 
-public class ContainerIntegrationIT extends AbstractContainerIT {
+public class WebAppContainerIntegrationIT extends AbstractContainerIT {
 
     protected final WebClient webClient = new WebClient();
 
     @Before
     public void logOut() throws IOException {
         // Make sure we are logged out
-        final HtmlPage homePage = webClient.getPage(getBaseUri());
+        final HtmlPage homePage = webClient.getPage(getTlsBaseUri());
         try {
             homePage.getAnchorByHref("/logout").click();
         }
@@ -50,7 +50,7 @@ public class ContainerIntegrationIT extends AbstractContainerIT {
     @Test
     public void logIn() throws FailingHttpStatusCodeException, MalformedURLException, IOException, InterruptedException {
 
-        HtmlPage page = webClient.getPage(getBaseUri() + "login.jsp");
+        HtmlPage page = webClient.getPage(getTlsBaseUri() + "login.jsp");
         HtmlForm form = page.getFormByName("loginform");
         form.<HtmlInput>getInputByName("username").setValueAttribute("root");
         form.<HtmlInput>getInputByName("password").setValueAttribute("secret");