diff --git a/.travis.yml b/.travis.yml index f47d71b..d1c5d35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ env: global: - MAIN_BRANCH=v9.3.1 - TAGCACHE_FILE=tagcache - - RELEASE=r1 + - RELEASE=r2 go_import_path: "github.com/ibm-messaging/mq-container" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a09528..54abdb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change log +## 9.3.1.0-r2 (2022-11) + +* Queue manager attribute SSLKEYR is now set to blank instead of '/run/runmqserver/tls/key' if key and certificate are not supplied. + ## 9.3.1.0 (2022-10) * Updated to MQ version 9.3.1.0 diff --git a/Dockerfile-server b/Dockerfile-server index c2f889c..747ba3d 100644 --- a/Dockerfile-server +++ b/Dockerfile-server @@ -13,9 +13,9 @@ # limitations under the License. ARG BASE_IMAGE=registry.access.redhat.com/ubi8/ubi-minimal -ARG BASE_TAG=8.6-941 +ARG BASE_TAG=8.7-923 ARG BUILDER_IMAGE=registry.access.redhat.com/ubi8/go-toolset -ARG BUILDER_TAG=1.17.12-7 +ARG BUILDER_TAG=1.17.12-11 ARG GO_WORKDIR=/opt/app-root/src/go/src/github.com/ibm-messaging/mq-container ARG MQ_URL="https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/9.3.1.0-IBM-MQ-Advanced-for-Developers-Non-Install-LinuxX64.tar.gz" ############################################################################### diff --git a/Makefile b/Makefile index 96211dd..c8bd0a2 100644 --- a/Makefile +++ b/Makefile @@ -304,7 +304,7 @@ build-devjmstest: test-devserver: test/docker/vendor $(info $(SPACER)$(shell printf $(TITLE)"Test $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) on $(shell $(COMMAND) --version)"$(END))) $(COMMAND) inspect $(MQ_IMAGE_DEVSERVER):$(MQ_TAG) - cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=true DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER) + cd test/docker && TEST_IMAGE=$(MQ_IMAGE_DEVSERVER):$(MQ_TAG) EXPECTED_LICENSE=Developer DEV_JMS_IMAGE=$(DEV_JMS_IMAGE) IBMJRE=false DOCKER_API_VERSION=$(DOCKER_API_VERSION) go test -parallel $(NUM_CPU) -timeout $(TEST_TIMEOUT_DOCKER) -tags mqdev $(TEST_OPTS_DOCKER) .PHONY: coverage coverage: diff --git a/internal/keystore/keystore.go b/internal/keystore/keystore.go index e24856c..591e168 100644 --- a/internal/keystore/keystore.go +++ b/internal/keystore/keystore.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2018, 2020 +© Copyright IBM Corporation 2018, 2022 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -171,8 +171,8 @@ func (ks *KeyStore) GetCertificateLabels() ([]string, error) { var labels []string for scanner.Scan() { s := scanner.Text() - if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") { - s := strings.TrimLeft(s, "-*") + if strings.HasPrefix(s, "-") || strings.HasPrefix(s, "*-") || strings.HasPrefix(s, "!") { + s := strings.TrimLeft(s, "-*!") labels = append(labels, strings.TrimSpace(s)) } } diff --git a/internal/tls/tls.go b/internal/tls/tls.go index 96ca64d..32fb105 100644 --- a/internal/tls/tls.go +++ b/internal/tls/tls.go @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2019, 2021 +© Copyright IBM Corporation 2019, 2022 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -76,18 +76,20 @@ type TLSStore struct { Truststore KeyStoreData } -func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool) (string, KeyStoreData, KeyStoreData, error) { - +func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool, nativeTLSHA bool) (string, KeyStoreData, KeyStoreData, error) { + var keyLabel string // Create the CMS Keystore & PKCS#12 Truststore (if required) - tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired) + tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired, nativeTLSHA) if err != nil { return "", tlsStore.Keystore, tlsStore.Truststore, err } - // Process all keys - add them to the CMS KeyStore - keyLabel, err := processKeys(&tlsStore, keystoreDir, keyDir) - if err != nil { - return "", tlsStore.Keystore, tlsStore.Truststore, err + if tlsStore.Keystore.Keystore != nil { + // Process all keys - add them to the CMS KeyStore + keyLabel, err = processKeys(&tlsStore, keystoreDir, keyDir) + if err != nil { + return "", tlsStore.Keystore, tlsStore.Truststore, err + } } // Process all trust certificates - add them to the CMS KeyStore & PKCS#12 Truststore (if required) @@ -101,13 +103,13 @@ func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRe // ConfigureDefaultTLSKeystores configures the CMS Keystore & PKCS#12 Truststore func ConfigureDefaultTLSKeystores() (string, KeyStoreData, KeyStoreData, error) { - return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true) + return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true, false) } // ConfigureHATLSKeystore configures the CMS Keystore & PKCS#12 Truststore func ConfigureHATLSKeystore() (string, KeyStoreData, KeyStoreData, error) { // *.crt files mounted to the HA TLS dir keyDirHA will be processed as trusted in the CMS keystore - return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false) + return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false, true) } // ConfigureTLS configures TLS for the queue manager @@ -115,9 +117,18 @@ func ConfigureTLS(keyLabel string, cmsKeystore KeyStoreData, devMode bool, log * const mqsc string = "/etc/mqm/15-tls.mqsc" const mqscTemplate string = mqsc + ".tpl" + sslKeyRing := "" + // Don't set SSLKEYR if no keys or crts are not supplied + // Key label will be blank if no certs were added during processing keys and certs. + if cmsKeystore.Keystore != nil { + certList, _ := cmsKeystore.Keystore.ListAllCertificates() + if len(certList) > 0 { + sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb") + } + } err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{ - "SSLKeyR": strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb"), + "SSLKeyR": sslKeyRing, "CertificateLabel": keyLabel, }, log) if err != nil { @@ -159,7 +170,7 @@ func configureTLSDev(log *logger.Logger) error { } // generateAllKeystores creates the CMS Keystore & PKCS#12 Truststore (if required) -func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSStore, error) { +func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool, nativeTLSHA bool) (TLSStore, error) { var cmsKeystore, p12Truststore KeyStoreData @@ -175,11 +186,19 @@ func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSSt return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create Keystore directory: %v", err) } - // Create the CMS Keystore - cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password) - err = cmsKeystore.Keystore.Create() - if err != nil { - return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err) + // Search the default keys directory for any keys/certs. + keysDirectory := keyDirDefault + // Change to default native HA TLS directory if we are configuring nativeHA + if nativeTLSHA { + keysDirectory = keyDirHA + } + // Create the CMS Keystore if we have been provided keys and certificates + if haveKeysAndCerts(keysDirectory) || haveKeysAndCerts(trustDirDefault) { + cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password) + err = cmsKeystore.Keystore.Create() + if err != nil { + return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err) + } } // Create the PKCS#12 Truststore (if required) @@ -203,7 +222,6 @@ func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string, // Process all keys keyList, err := ioutil.ReadDir(keyDir) if err == nil && len(keyList) > 0 { - // Process each set of keys - each set should contain files: *.key & *.crt for _, keySet := range keyList { keys, _ := ioutil.ReadDir(filepath.Join(keyDir, keySet.Name())) @@ -602,3 +620,23 @@ func writeCertificatesToFile(file string, certificates []*pem.Block) error { } return nil } + +// Search the specified directory for .key and .crt files. +// Return true if at least one .key or .crt file is found else false +func haveKeysAndCerts(keyDir string) bool { + fileList, err := os.ReadDir(keyDir) + if err == nil && len(fileList) > 0 { + for _, fileInfo := range fileList { + // Keys and certs will be supplied in an user defined subdirectory. + // Do a listing of the subdirectory and then search for .key and .cert files + keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name())) + for _, key := range keys { + if strings.Contains(key.Name(), ".key") || strings.Contains(key.Name(), ".crt") { + // We found at least one key/crt file. + return true + } + } + } + } + return false +} diff --git a/internal/tls/tls_web.go b/internal/tls/tls_web.go index 2b84af8..3789114 100644 --- a/internal/tls/tls_web.go +++ b/internal/tls/tls_web.go @@ -65,7 +65,6 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin // Check if a new self-signed certificate should be generated genHostName := os.Getenv("MQ_GENERATE_CERTIFICATE_HOSTNAME") if genHostName != "" { - // Create the Web Keystore newWebKeystore := keystore.NewPKCS12KeyStore(webKeystoreFile, p12Truststore.Password) err := newWebKeystore.Create() diff --git a/test/docker/devconfig_test.go b/test/docker/devconfig_test.go index f7a29d5..f754f2e 100644 --- a/test/docker/devconfig_test.go +++ b/test/docker/devconfig_test.go @@ -1,3 +1,4 @@ +//go:build mqdev // +build mqdev /* @@ -51,8 +52,10 @@ func TestDevGoldenPath(t *testing.T) { waitForReady(t, cli, id) waitForWebReady(t, cli, id, insecureTLSConfig) t.Run("JMS", func(t *testing.T) { - // Run the JMS tests, with no password specified - runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS) + // Run the JMS tests, with no password specified. + // Use OpenJDK JRE for running testing, pass false for 7th parameter. + // Last parameter is blank as the test doesn't use TLS. + runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS, "false", "") }) t.Run("REST admin", func(t *testing.T) { testRESTAdmin(t, cli, id, insecureTLSConfig) @@ -115,7 +118,9 @@ func TestDevSecure(t *testing.T) { waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase)) t.Run("JMS", func(t *testing.T) { - runJMSTests(t, cli, ctr.ID, true, "app", appPassword) + // OpenJDK is used for running tests, hence pass "false" for 7th parameter. + // Cipher name specified is compliant with non-IBM JRE naming. + runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256") }) t.Run("REST admin", func(t *testing.T) { testRESTAdmin(t, cli, ctr.ID, insecureTLSConfig) @@ -153,7 +158,9 @@ func TestDevWebDisabled(t *testing.T) { }) t.Run("JMS", func(t *testing.T) { // Run the JMS tests, with no password specified - runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS) + // OpenJDK is used for running tests, hence pass "false" for 7th parameter. + // Last parameter is blank as the test doesn't use TLS. + runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS, "false", "") }) // Stop the container cleanly stopContainer(t, cli, id) @@ -184,3 +191,131 @@ func TestDevConfigDisabled(t *testing.T) { // Stop the container cleanly stopContainer(t, cli, id) } + +// Test if SSLKEYR and CERTLABL attributes are not set when key and certificate +// are not supplied. +func TestSSLKEYRBlank(t *testing.T) { + t.Parallel() + + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + t.Fatal(err) + } + containerConfig := container.Config{ + Env: []string{ + "LICENSE=accept", + "MQ_QMGR_NAME=qm1", + "MQ_ENABLE_EMBEDDED_WEB_SERVER=false", + }, + } + id := runContainerWithPorts(t, cli, &containerConfig, []int{9443}) + defer cleanContainer(t, cli, id) + waitForReady(t, cli, id) + // execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes. + // Search the console output for exepcted values + _, sslkeyROutput := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"}) + if !strings.Contains(sslkeyROutput, "SSLKEYR( )") && !strings.Contains(sslkeyROutput, "CERTLABL( )") { + t.Errorf("Expected SSLKEYR to be blank but it is not; got \"%v\"", sslkeyROutput) + } + + // Stop the container cleanly + stopContainer(t, cli, id) +} + +// Test if SSLKEYR and CERTLABL attributes are set when key and certificate +// are supplied. +func TestSSLKEYRWithSuppliedKeyAndCert(t *testing.T) { + t.Parallel() + + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + t.Fatal(err) + } + + containerConfig := container.Config{ + Env: []string{ + "LICENSE=accept", + "MQ_QMGR_NAME=QM1", + "MQ_ENABLE_EMBEDDED_WEB_SERVER=false", + }, + Image: imageName(), + } + hostConfig := container.HostConfig{ + Binds: []string{ + coverageBind(t), + tlsDir(t, false) + ":/etc/mqm/pki/keys/default", + }, + } + networkingConfig := network.NetworkingConfig{} + ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()) + if err != nil { + t.Fatal(err) + } + defer cleanContainer(t, cli, ctr.ID) + startContainer(t, cli, ctr.ID) + waitForReady(t, cli, ctr.ID) + // execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes. + // Search the console output for exepcted values + _, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"}) + if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") && !strings.Contains(sslkeyROutput, "CERTLABL(default)") { + t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslkeyROutput) + } + + // Stop the container cleanly + stopContainer(t, cli, ctr.ID) +} + +// Test with CA cert +func TestSSLKEYRWithCACert(t *testing.T) { + t.Parallel() + + cli, err := client.NewClientWithOpts(client.FromEnv) + if err != nil { + t.Fatal(err) + } + + containerConfig := container.Config{ + Env: []string{ + "LICENSE=accept", + "MQ_QMGR_NAME=QM1", + "MQ_ENABLE_EMBEDDED_WEB_SERVER=false", + }, + Image: imageName(), + } + hostConfig := container.HostConfig{ + Binds: []string{ + coverageBind(t), + tlsDirWithCA(t, false) + ":/etc/mqm/pki/keys/QM1CA", + }, + // Assign a random port for the web server on the host + PortBindings: nat.PortMap{ + "9443/tcp": []nat.PortBinding{ + { + HostIP: "0.0.0.0", + }, + }, + }, + } + networkingConfig := network.NetworkingConfig{} + ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name()) + if err != nil { + t.Fatal(err) + } + defer cleanContainer(t, cli, ctr.ID) + startContainer(t, cli, ctr.ID) + waitForReady(t, cli, ctr.ID) + + // execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes. + // Search the console output for exepcted values + _, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"}) + if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") { + t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslkeyROutput) + } + + if !strings.Contains(sslkeyROutput, "CERTLABL(QM1CA)") { + t.Errorf("Expected CERTLABL to be 'QM1CA' but it is not; got \"%v\"", sslkeyROutput) + } + + // Stop the container cleanly + stopContainer(t, cli, ctr.ID) +} diff --git a/test/docker/devconfig_test_util.go b/test/docker/devconfig_test_util.go index 45d5a61..f61ddf5 100644 --- a/test/docker/devconfig_test_util.go +++ b/test/docker/devconfig_test_util.go @@ -1,7 +1,8 @@ +//go:build mqdev // +build mqdev /* -© Copyright IBM Corporation 2018, 2021 +© Copyright IBM Corporation 2018, 2022 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,6 +19,7 @@ limitations under the License. package main import ( + "bufio" "bytes" "context" "crypto/tls" @@ -26,8 +28,8 @@ import ( "io/ioutil" "net/http" "net/http/httputil" - "os" "path/filepath" + "strconv" "strings" "testing" "time" @@ -80,15 +82,19 @@ func tlsDir(t *testing.T, unixPath bool) string { return filepath.Join(getCwd(t, unixPath), "../tls") } +func tlsDirWithCA(t *testing.T, unixPath bool) string { + return filepath.Join(getCwd(t, unixPath), "../tlscacert") +} + // runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID -func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string) { +func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string, ibmjre string, cipherName string) { containerConfig := container.Config{ // -e MQ_PORT_1414_TCP_ADDR=9.145.14.173 -e MQ_USERNAME=app -e MQ_PASSWORD=passw0rd -e MQ_CHANNEL=DEV.APP.SVRCONN -e MQ_TLS_TRUSTSTORE=/tls/test.p12 -e MQ_TLS_PASSPHRASE=passw0rd -v /Users/arthurbarr/go/src/github.com/ibm-messaging/mq-container/test/tls:/tls msgtest Env: []string{ "MQ_PORT_1414_TCP_ADDR=" + getIPAddress(t, cli, ID), "MQ_USERNAME=" + user, "MQ_CHANNEL=DEV.APP.SVRCONN", - "IBMJRE=" + os.Getenv("IBMJRE"), + "IBMJRE=" + ibmjre, }, Image: imageNameDevJMS(), } @@ -101,6 +107,7 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa containerConfig.Env = append(containerConfig.Env, []string{ "MQ_TLS_TRUSTSTORE=/var/tls/client-trust.jks", "MQ_TLS_PASSPHRASE=passw0rd", + "MQ_TLS_CIPHER=" + cipherName, }...) } hostConfig := container.HostConfig{ @@ -119,9 +126,57 @@ func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, pa if rc != 0 { t.Errorf("JUnit container failed with rc=%v", rc) } + + // Get console output of the container and process the lines + // to see if we have any failures + scanner := bufio.NewScanner(strings.NewReader(inspectLogs(t, cli, ctr.ID))) + for scanner.Scan() { + s := scanner.Text() + if processJunitLogLine(s) { + t.Errorf("JUnit container tests failed. Reason: %s", s) + } + } + defer cleanContainer(t, cli, ctr.ID) } +// Parse JUnit log line and return true if line contains failed or aborted tests +func processJunitLogLine(outputLine string) bool { + var failedLine bool + // Sample JUnit test run output + //[ 2 containers found ] + //[ 0 containers skipped ] + //[ 2 containers started ] + //[ 0 containers aborted ] + //[ 2 containers successful ] + //[ 0 containers failed ] + //[ 0 tests found ] + //[ 0 tests skipped ] + //[ 0 tests started ] + //[ 0 tests aborted ] + //[ 0 tests successful ] + //[ 0 tests failed ] + + // Consider only those lines that begin with '[' and with ']' + if strings.HasPrefix(outputLine, "[") && strings.HasSuffix(outputLine, "]") { + // Strip off [] and whitespaces + trimmed := strings.Trim(outputLine, "[] ") + if strings.Contains(trimmed, "aborted") || strings.Contains(trimmed, "failed") { + // Tokenize on whitespace + tokens := strings.Split(trimmed, " ") + // Determine the count of aborted or failed tests + count, err := strconv.Atoi(tokens[0]) + if err == nil { + if count > 0 { + failedLine = true + } + } + } + } + + return failedLine +} + // createTLSConfig creates a tls.Config which trusts the specified certificate func createTLSConfig(t *testing.T, certFile, password string) *tls.Config { // Get the SystemCertPool, continue with an empty pool on error diff --git a/test/messaging/Dockerfile b/test/messaging/Dockerfile index 21bb612..c03da28 100644 --- a/test/messaging/Dockerfile +++ b/test/messaging/Dockerfile @@ -16,16 +16,16 @@ # Application build environment (Maven) ############################################################################### FROM registry.access.redhat.com/ubi8/openjdk-8 as builder -COPY pom.xml . +COPY pom.xml ./ #WORKDIR /usr/src/mymaven # Download dependencies separately, so Docker caches them RUN mvn dependency:go-offline install # Copy source -COPY src . +COPY src ./src # Run the main build RUN mvn --offline install # Print a list of all the files (useful for debugging) -RUN find . +RUN find ./ ############################################################################### # Application runtime (JRE only, no build environment) @@ -35,4 +35,4 @@ FROM registry.access.redhat.com/ubi8/openjdk-8-runtime COPY --from=builder /home/jboss/target/*.jar /opt/app/ COPY --from=builder /home/jboss/target/lib/*.jar /opt/app/ USER 1001 -ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"] +ENTRYPOINT ["java", "-classpath", "/opt/app/*", "org.junit.platform.console.ConsoleLauncher", "--fail-if-no-tests", "-p", "com.ibm.mqcontainer.test", "--details", "verbose"] diff --git a/test/messaging/src/main/java/com/ibm/mqcontainer/test/JMSTests.java b/test/messaging/src/main/java/com/ibm/mqcontainer/test/JMSTests.java index 903ff39..24a2001 100644 --- a/test/messaging/src/main/java/com/ibm/mqcontainer/test/JMSTests.java +++ b/test/messaging/src/main/java/com/ibm/mqcontainer/test/JMSTests.java @@ -1,5 +1,5 @@ /* -© Copyright IBM Corporation 2018, 2021 +© Copyright IBM Corporation 2018, 2022 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -82,11 +82,10 @@ class JMSTests { boolean ibmjre = System.getenv("IBMJRE").equals("true"); if (ibmjre){ System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "true"); - factory.setSSLCipherSuite("SSL_RSA_WITH_AES_128_CBC_SHA256"); } else { System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", "false"); - factory.setSSLCipherSuite("TLS_RSA_WITH_AES_128_CBC_SHA256"); } + factory.setSSLCipherSuite(System.getenv("MQ_TLS_CIPHER")); } return factory; } diff --git a/test/tlscacert/cacert.crt b/test/tlscacert/cacert.crt new file mode 100644 index 0000000..1c988f1 --- /dev/null +++ b/test/tlscacert/cacert.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIUc5EKoPi8cg2M2n+SqCPn44LFjoAwDQYJKoZIhvcNAQEL +BQAwcjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9y +azEMMAoGA1UECgwDSUJNMQwwCgYDVQQLDANJQk0xDDAKBgNVBAMMA0lCTTEZMBcG +CSqGSIb3DQEJARYKbXFAaWJtLmNvbTAeFw0yMjEwMDYxMzA2NTVaFw0zMjEwMDMx +MzA2NTVaMHIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTERMA8GA1UEBwwITmV3 +IFlvcmsxDDAKBgNVBAoMA0lCTTEMMAoGA1UECwwDSUJNMQwwCgYDVQQDDANJQk0x +GTAXBgkqhkiG9w0BCQEWCm1xQGlibS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCls3oNIDxzKct0NXVsoz1Hng3BcaDPcBRYCNgAEwDOVe3rEEbZ +d2KFliDgCG3hCHMM1Yaabx3iTVsKklubBxr1JFmyDtgb4z9mJpMVYXS+gsKsZOs/ +vNSmzpt5VlbEadHKJ/aFf/EWxvoOP80UiEeUJt36aWFUTyjjyArd2xS8fD1DATFB +U2bteaWfkpuLeFiTtwftZhsLv1s5T35+Ex087eX1tkm/TArxZsNl/9RrSWsbJh/t +bjiRKn+fCZdirFsurP3Si5Jd9laCW0RBKAKYEh40XYDgjLhvcazDPTBueTHXQPG5 +S0hCOhCJiCWpPCsh8rIOCz0D9YIByZADR1WvAgMBAAGjUzBRMB0GA1UdDgQWBBS5 +OsiPqZXlMwpMqGKczUg3qVvy0zAfBgNVHSMEGDAWgBS5OsiPqZXlMwpMqGKczUg3 +qVvy0zAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBfwYRcckke +/NzDHlFb8TBlUDqERmlT/qTWamVZO2Zuo4Y0BFOYFEA23F5sQU2s2MFSEZcAKe5v +mJroFE2rr4aY4bJ4Z0UXlOAYyqNxVOTI4MIxwbg3GVr8c8oWBnAmgqI9W9OpgZ52 +/bN24XL9s6I3TeOTtYI9z5O70Kl/E3nG8GcfMw0EtNIy0UPUWvJH8FgEsotsRO9v +tPtlZklEK/D+Keozbs2shdNhKgVnDatpdTBqvwLztb1+te5AckuOnJsnG+iIrG2D +Ehoq2O3gktIVdAk4sv2BoONzegLWB+GSxGVZsemfYF4PkN9/w+znz0LK/ATAtabK +rikk0yC+Xg8z +-----END CERTIFICATE----- diff --git a/test/tlscacert/generate-test-cert.sh b/test/tlscacert/generate-test-cert.sh new file mode 100644 index 0000000..5b248ce --- /dev/null +++ b/test/tlscacert/generate-test-cert.sh @@ -0,0 +1,34 @@ +#!/bin/bash -ex +# -*- mode: sh -*- +# © Copyright IBM Corporation 2018, 2022 +# +# Licensed 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. + +KEY=server.key +CERT=server.crt +CACERT=cacert.crt +CAPEM=rootcakey.pem + +# Create a private key and certificate in PEM format, for the server to use +openssl req \ + -newkey rsa:2048 -nodes -keyout ${KEY} \ + -subj "/CN=localhost" \ + -addext "subjectAltName = DNS:localhost" \ + -x509 -days 3650 -out ${CERT} + +# Generate the private key of the root CA +openssl genrsa -out ${CAPEM} 2048 + +#Generate the self-signed root CA certificate. Manual input is required when prompted +openssl req -x509 -sha256 -new -nodes -key ${CAPEM} -days 3650 -out ${CACERT} + diff --git a/test/tlscacert/rootcakey.pem b/test/tlscacert/rootcakey.pem new file mode 100644 index 0000000..658f245 --- /dev/null +++ b/test/tlscacert/rootcakey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEApbN6DSA8cynLdDV1bKM9R54NwXGgz3AUWAjYABMAzlXt6xBG +2XdihZYg4Aht4QhzDNWGmm8d4k1bCpJbmwca9SRZsg7YG+M/ZiaTFWF0voLCrGTr +P7zUps6beVZWxGnRyif2hX/xFsb6Dj/NFIhHlCbd+mlhVE8o48gK3dsUvHw9QwEx +QVNm7Xmln5Kbi3hYk7cH7WYbC79bOU9+fhMdPO3l9bZJv0wK8WbDZf/Ua0lrGyYf +7W44kSp/nwmXYqxbLqz90ouSXfZWgltEQSgCmBIeNF2A4Iy4b3Gswz0wbnkx10Dx +uUtIQjoQiYglqTwrIfKyDgs9A/WCAcmQA0dVrwIDAQABAoIBAQCcL9ZltPMF4mlh ++lnasuu6K+LvafmYTh7+9CcVutPRqfF+1nLR3NRC8sW+JnPb36kCeepMe1yByUR9 +bINoV4QzebYKPi+56bQCx21wg9IVGRACi4WrKISRTsIB1z4mGVCj6pNWNsi7HYbq +E31tUx+VKCWoOdiCLbNvMUn84Npk5npK9P9F86qypSJqJv3HORgOa58x7qZiD2fk +TroLuGHKFWGtSiK1vvgax8gBwMi9JvWoPhwHagINh0WwT820+3/4KbqcsvRNSIu8 +qA+ltk/Vt0ftwPMpxPYnvRFrSvzYIRE04fbWqA3mxhPr/oP3xXrwyd1hnX6GzPIR +KXeX1i7BAoGBANGV6XtL8cq8tu/4emOYDn4tncMRICQ8uMWZqnIQAvX8PBx1w9E2 +Wbkl0oBHJ/gDtU+feDvbHI0JBvXerce2cxj4+793TGLUl980dgq776x2fcxHjvYZ +uZjJd4M95Lh+IhtWGZQ1FviiylDg62w+mrNydX8WiFjLGYPydQqCIAAxAoGBAMpl +m/MDqpgPxiDU1O9DAq8C/0MQUOc/p+67aGsYxmPDdCouBLA/zckQh6Cp9Wo3n7MF +X5UHOqn72q/4ahNEx+3YQoaLqRKTjUHl3r3zj+MsM0hIDp1uOxVzbANxazuLuqqA +C+yJTmRU7uvNPH1AMFJBKRSmhd3MJwoHF/KZAhvfAoGAFaGPU3ZnIjGP//x5RUYw +WL2EhtmBo7vQpjRR7yvP4muCGL3e0/z0DbPloe+2JFbdo7Ylxqe6rqO74Cx3ayFd +h7pK4VwCukCO3C6h8EGtXvNr0GWiT6wgB7DjcNw2ewQpqQCd6zn/gPHsR6SvJ6De +fp7VmaRNtjxgCcpAYjFD9EECgYAhEPaofjnZvAH/jSX4rPb8Rr4TY9AD58d03lNR +4+tNkzogRgJoFRR2u+ecnQfGQa4qnj8eZt7ztHzm8OvLmBodxo4f0yNdMJQMZxS7 +7dXdJHSAY51XpRGsEH5eFaKSSOLHRkIsc8ZF6AZcqdwvDlSWq6SdhhMqyFa8cao8 +7TiF+wKBgADNZ4HoZDfnuH5jUvf7y+YlxDX3jxWR+BUTLCJmt082uT+8Xg5SALec +B8GP5s6VKglD5Wzj8IhxvpQ5yzH9DRHwEeu3vFLBinIUlWdBiXwtnbmY0E9r3PSb +pZQH5RZ5PyrJicIVBJSqdFu2HDl4heeLJE0LGh7SQnFaexxXn397 +-----END RSA PRIVATE KEY----- diff --git a/test/tlscacert/server.crt b/test/tlscacert/server.crt new file mode 100644 index 0000000..998b184 --- /dev/null +++ b/test/tlscacert/server.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDHzCCAgegAwIBAgIUUFCo8fUglrbfDY8ZUDnzAfWeq54wDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMTAwNjEzMDYwMloXDTMyMTAw +MzEzMDYwMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAxcja4TbshPj4tWgbRP73eDs2382j6Km5TNej6To13PJq +Wyezg081ctmgFEMlgbRiowZmecpYOKjDKuVDtfLE6nZMmN+PjXXuOMGIPu67fx/4 +tnaMDYw96WIBEFNVZ7dC/pceaTIRbnjma89o1/mTudTAYPLAvKpeBqpJJFWPMDhz +nK3NKeydTdUYc9jmEJWiFCI4bUdyvyUjp+7QrDbdODXo27/nVAV0Ih+OuU4ZnxT5 +cf1fzVV1ZqHd8jbLm25ZoAmkk+9DSXFNA2hbSepf70mRVD/Qyn8U6b5A2v+mWIfs +B1+iAlPl7IX88W1Q9q1yu0uT8YWGWpeTbeOnJ4WJ8wIDAQABo2kwZzAdBgNVHQ4E +FgQUEjp6AtPmpuLQyBPeiW4pW+VGb2wwHwYDVR0jBBgwFoAUEjp6AtPmpuLQyBPe +iW4pW+VGb2wwDwYDVR0TAQH/BAUwAwEB/zAUBgNVHREEDTALgglsb2NhbGhvc3Qw +DQYJKoZIhvcNAQELBQADggEBAL2bTWfTqxfN0YbBPjG05sR4nO8mhbNSGHDuGeiO +OP0wPxkgAueScTpyhHWEAJmMQOMUM9KhByZj7LnqW8XY9BBS3zPAyzAdia8/o6Vl +7El+M2JCfqz7hSupRK8M+r+XUq3hyEFjPLt+KO6D5VNzXiTM+36UueeQD3aaxxyo +LpHSPeXFBkOrT/wt6FHi4NHvWls95PllncWZVYjxPMUUF/o30tOxSmgXwjUknrI8 +29ADKM1IbFuXd4vKYG9V+ukI6n5F86PYrN2ajPBKIidvTqU8tPzMHuJZ3YiIiv8p +TARE2b5YLWuu+aF2z/V71MmIWr0uyOk6pZVGOCw7fwHx/wg= +-----END CERTIFICATE----- diff --git a/test/tlscacert/server.key b/test/tlscacert/server.key new file mode 100644 index 0000000..d437a49 --- /dev/null +++ b/test/tlscacert/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyNrhNuyE+Pi1 +aBtE/vd4OzbfzaPoqblM16PpOjXc8mpbJ7ODTzVy2aAUQyWBtGKjBmZ5ylg4qMMq +5UO18sTqdkyY34+Nde44wYg+7rt/H/i2dowNjD3pYgEQU1Vnt0L+lx5pMhFueOZr +z2jX+ZO51MBg8sC8ql4GqkkkVY8wOHOcrc0p7J1N1Rhz2OYQlaIUIjhtR3K/JSOn +7tCsNt04Nejbv+dUBXQiH465ThmfFPlx/V/NVXVmod3yNsubblmgCaST70NJcU0D +aFtJ6l/vSZFUP9DKfxTpvkDa/6ZYh+wHX6ICU+XshfzxbVD2rXK7S5PxhYZal5Nt +46cnhYnzAgMBAAECggEBAKLRsZZbf6QLzbqRBHntJ04b+RWOlVOQfRHMJ4x1Nig4 +i+OUsEv1pftxOj3T9QlstRKdzziNociq7VffurkLLJ4TWwUybVu37K9easncABAs +ArQ6rRruC32YB2YoJBOoowcw4oEZDY6TCqVP7nB1be46PVDSJmZqHdOA1YuKv8Ci +FbzLZEKYy6QGmHp9xMzc3usQ+KRNIFcR3NJb0eCbfAXb0tP3F12i4ygnxifkOVQS +hukTJlZVbAO3W9uUEzLh5bkLoPfob6Vrwv1tGQ48uFgzgPXc4bWOUDFXHW5+vQLD +1MKFboozrNhRR+Q5xvbRnaWEv4hMHlUNggc5ErRj6CkCgYEA5m5f1VfhfqSvEF2c +XcIfUDiCzREpllY2ZdBSfUlz/GA6f0QUyFJBCdd4ypipQcggn60de9DoKDcNcq32 +rfVfANpsciJq9s4+xLL8MGtUuoi4HK8LHP3tc8aJaAcCVjBFbz0orKXDUOcue6A5 +Z5riDjiXOE56XSLSSNSRjWh4psUCgYEA27sfaM4J0YkdFuth/Qu+X9PeroUZyC0T +3glMN/7PU4jZg+2v4Psfe61gj8qOt0catuWvsD0wQTy3jt+svY/KfkbspK6/7CEG +fKx1AB1xeMr4JuQp9POFVhKRn4sBUMbHOkbjzlNpGmUI2arlLRTwT8YpuMDjCK4l +ZuUYB/IHOVcCgYAqexqryCHIKTAlAjz7g/gl3+UtTQavsoEg0AEFG++IDW17XN+/ +9noLCHA6WV6KxAxPo6iV1POXxl5yT+P0OhIjpCDuAa5ahbdIp/6aJo9ePCpFD3gr +Bh0qhOV8Ch7CKPAEC/Bds8mINrZ5EBbFJOab3I70UHN6jBrcVmPm/+WOSQKBgQCW +AbBWt1qCnu2qCPWzcAH+n8DFOf645vVKPuS20ZEuwR1l8K2ClU4P+/QRFkLKIpO9 +Sx7e3VcFInNZ6Z+fJfwiqz7AysAhbwZjtMSHWJJv2XkB7AAsxtc/RJv/5ED4qUu3 +oE/DOrRlHZamKwIb/dB1VZ6ED8Ku2VyVW09FlViTLwKBgEU21xqvP1+TXzsrZNGm +/Hj/RAaA8B6tyo5Dj9glV80oakMSaxBsLP9xHkoZjkHaJnoFosKBQSnCcPnEY4gP +22WEyGshu8sujLibLKWhARqjeubatXv+XBxiDdMbgcd/XTwbI4HTjXy5LF0o47UI +W6itMOg9uCfBJM/i2jrAkmQR +-----END PRIVATE KEY-----