* Part 1 of FIPS Compliance * MQ Web Server FIPSs changes * Remove function param * Updates to FIPS MQ WebServer * Fix build error * Merge latest code from private-master * Rename fips variable * Fix build break * Fix build break * Fix build break * Add new docker tests * First cut of fips metrics * First cut of fips metrics * Second part of metrics fips * Second part of metrics fips * Added NativeHA FIPS * Updated test * Add Native HA tests * Optimze FIPS handling * Update comments * Apply changes from private-master * Undo metrics changes * Merge latest changes * Pull in changes from master * Update copyright year * Resolve merge conflicts
785 lines
25 KiB
Go
785 lines
25 KiB
Go
//go:build mqdev
|
|
// +build mqdev
|
|
|
|
/*
|
|
© 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.
|
|
*/
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
"crypto/tls"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/network"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/go-connections/nat"
|
|
)
|
|
|
|
// TestDevGoldenPath tests using the default values for the default developer config.
|
|
// Note: This test requires a separate container image to be available for the JMS tests.
|
|
func TestDevGoldenPath(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
qm := "qm1"
|
|
containerConfig := container.Config{
|
|
Env: []string{
|
|
"LICENSE=accept",
|
|
"MQ_QMGR_NAME=" + qm,
|
|
"DEBUG=true",
|
|
},
|
|
}
|
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
|
defer cleanContainer(t, cli, id)
|
|
waitForReady(t, cli, id)
|
|
waitForWebReady(t, cli, id, insecureTLSConfig)
|
|
t.Run("JMS", func(t *testing.T) {
|
|
// 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, "")
|
|
})
|
|
t.Run("REST messaging", func(t *testing.T) {
|
|
testRESTMessaging(t, cli, id, insecureTLSConfig, qm, "app", defaultAppPasswordWeb, "")
|
|
})
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, id)
|
|
}
|
|
|
|
// TestDevSecure tests the default developer config using the a custom TLS key store and password.
|
|
// Note: This test requires a separate container image to be available for the JMS tests
|
|
func TestDevSecure(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const tlsPassPhrase string = "passw0rd"
|
|
qm := "qm1"
|
|
appPassword := "differentPassw0rd"
|
|
containerConfig := container.Config{
|
|
Env: []string{
|
|
"LICENSE=accept",
|
|
"MQ_QMGR_NAME=" + qm,
|
|
"MQ_APP_PASSWORD=" + appPassword,
|
|
"DEBUG=1",
|
|
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
|
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
|
|
},
|
|
Image: imageName(),
|
|
}
|
|
hostConfig := container.HostConfig{
|
|
Binds: []string{
|
|
coverageBind(t),
|
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
|
},
|
|
// Assign a random port for the web server on the host
|
|
// TODO: Don't do this for all tests
|
|
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)
|
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
|
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
|
|
|
t.Run("JMS", func(t *testing.T) {
|
|
// 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, "")
|
|
})
|
|
t.Run("REST messaging", func(t *testing.T) {
|
|
testRESTMessaging(t, cli, ctr.ID, insecureTLSConfig, qm, "app", appPassword, "")
|
|
})
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
func TestDevWebDisabled(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 := runContainer(t, cli, &containerConfig)
|
|
defer cleanContainer(t, cli, id)
|
|
waitForReady(t, cli, id)
|
|
t.Run("Web", func(t *testing.T) {
|
|
_, dspmqweb := execContainer(t, cli, id, "", []string{"dspmqweb"})
|
|
if !strings.Contains(dspmqweb, "Server mqweb is not running.") && !strings.Contains(dspmqweb, "MQWB1125I") {
|
|
t.Errorf("Expected dspmqweb to say 'Server is not running' or 'MQWB1125I'; got \"%v\"", dspmqweb)
|
|
}
|
|
})
|
|
t.Run("JMS", func(t *testing.T) {
|
|
// Run the JMS tests, with no password specified
|
|
// 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)
|
|
}
|
|
|
|
func TestDevConfigDisabled(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_DEV=false",
|
|
},
|
|
}
|
|
id := runContainerWithPorts(t, cli, &containerConfig, []int{9443})
|
|
defer cleanContainer(t, cli, id)
|
|
waitForReady(t, cli, id)
|
|
waitForWebReady(t, cli, id, insecureTLSConfig)
|
|
rc, _ := execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'display qlocal(DEV*)' | runmqsc"})
|
|
if rc == 0 {
|
|
t.Errorf("Expected DEV queues to be missing")
|
|
}
|
|
// 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( )") {
|
|
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
|
// Hence wait for a second and retry few times before giving up.
|
|
waitCount := 30
|
|
var i int
|
|
for i = 0; i < waitCount; i++ {
|
|
time.Sleep(1 * time.Second)
|
|
_, sslkeyROutput = execContainer(t, cli, id, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
|
if strings.Contains(sslkeyROutput, "SSLKEYR( )") && strings.Contains(sslkeyROutput, "CERTLABL( )") {
|
|
break
|
|
}
|
|
}
|
|
// Failed to get expected output? dump the contents of mqsc files.
|
|
if i == waitCount {
|
|
_, tls15mqsc := execContainer(t, cli, id, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
|
_, autoMQSC := execContainer(t, cli, id, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
|
t.Errorf("Expected SSLKEYR to be blank but it is not; got \"%v\"\n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
|
}
|
|
}
|
|
|
|
// 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)") {
|
|
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
|
// Hence wait for a second and retry few times before giving up.
|
|
waitCount := 30
|
|
var i int
|
|
for i = 0; i < waitCount; i++ {
|
|
time.Sleep(1 * time.Second)
|
|
_, 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)") {
|
|
break
|
|
}
|
|
}
|
|
// Failed to get expected output? dump the contents of mqsc files.
|
|
if i == waitCount {
|
|
_, tls15mqsc := execContainer(t, cli, ctr.ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
|
_, autoMQSC := execContainer(t, cli, ctr.ID, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\" \n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
|
}
|
|
}
|
|
|
|
// 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)") {
|
|
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
|
// Hence wait for a second and retry few times before giving up.
|
|
waitCount := 30
|
|
var i int
|
|
for i = 0; i < waitCount; i++ {
|
|
time.Sleep(1 * time.Second)
|
|
_, sslkeyROutput = execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
|
if strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
|
break
|
|
}
|
|
}
|
|
// Failed to get expected output? dump the contents of mqsc files.
|
|
if i == waitCount {
|
|
_, tls15mqsc := execContainer(t, cli, ctr.ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
|
_, autoMQSC := execContainer(t, cli, ctr.ID, "", []string{"cat", "/mnt/mqm/data/qmgrs/QM1/autocfg/cached.mqsc"})
|
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"\n AutoConfig MQSC file contents %v\n 15-tls: %v", sslkeyROutput, autoMQSC, tls15mqsc)
|
|
}
|
|
}
|
|
|
|
if !strings.Contains(sslkeyROutput, "CERTLABL(QM1CA)") {
|
|
_, autoMQSC := execContainer(t, cli, ctr.ID, "", []string{"cat", "/etc/mqm/15-tls.mqsc"})
|
|
t.Errorf("Expected CERTLABL to be 'QM1CA' but it is not; got \"%v\" \n MQSC File contents %v", sslkeyROutput, autoMQSC)
|
|
}
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=false
|
|
func TestSSLFIPSNO(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",
|
|
"MQ_ENABLE_FIPS=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, SSLFIPS and CERTLABL attibutes.
|
|
// Search the console output for exepcted values
|
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
|
|
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
|
|
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// Verifies SSLFIPS is set to YES if certificates for queue manager
|
|
// are supplied and MQ_ENABLE_FIPS=true
|
|
func TestSSLFIPSYES(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
appPassword := "differentPassw0rd"
|
|
containerConfig := container.Config{
|
|
Env: []string{
|
|
"LICENSE=accept",
|
|
"MQ_APP_PASSWORD=" + appPassword,
|
|
"MQ_QMGR_NAME=QM1",
|
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
|
"MQ_ENABLE_FIPS=true",
|
|
},
|
|
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)
|
|
|
|
// Check for expected message on container log
|
|
logs := inspectLogs(t, cli, ctr.ID)
|
|
if !strings.Contains(logs, "FIPS cryptography is enabled.") {
|
|
t.Errorf("Expected 'FIPS cryptography is enabled.' but got %v\n", logs)
|
|
}
|
|
|
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
|
// Search the console output for exepcted values
|
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
|
|
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(YES)") {
|
|
t.Errorf("Expected SSLFIPS to be 'YES' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
t.Run("JMS", func(t *testing.T) {
|
|
// Run the JMS tests, with no password specified
|
|
runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
|
})
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// TestDevSecureFIPSYESWeb verifies if the MQ Web Server is running in FIPS mode
|
|
func TestDevSecureFIPSTrueWeb(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const tlsPassPhrase string = "passw0rd"
|
|
qm := "qm1"
|
|
appPassword := "differentPassw0rd"
|
|
containerConfig := container.Config{
|
|
Env: []string{
|
|
"LICENSE=accept",
|
|
"MQ_QMGR_NAME=" + qm,
|
|
"MQ_APP_PASSWORD=" + appPassword,
|
|
"DEBUG=1",
|
|
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
|
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
|
|
"MQ_ENABLE_FIPS=true",
|
|
},
|
|
Image: imageName(),
|
|
}
|
|
hostConfig := container.HostConfig{
|
|
Binds: []string{
|
|
coverageBind(t),
|
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
|
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
|
},
|
|
// Assign a random port for the web server on the host
|
|
// TODO: Don't do this for all tests
|
|
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)
|
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
|
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
|
|
|
// Create a TLS Config with a cipher to use when connecting over HTTPS
|
|
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
|
// Put a message to queue
|
|
t.Run("REST messaging", func(t *testing.T) {
|
|
testRESTMessaging(t, cli, ctr.ID, secureTLSConfig, qm, "app", appPassword, "")
|
|
})
|
|
|
|
// Create a TLS Config with a non-FIPS cipher to use when connecting over HTTPS
|
|
var secureNonFIPSCipherConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA})
|
|
// Put a message to queue - the attempt to put message will fail with a EOF return message.
|
|
t.Run("REST messaging", func(t *testing.T) {
|
|
testRESTMessaging(t, cli, ctr.ID, secureNonFIPSCipherConfig, qm, "app", appPassword, "EOF")
|
|
})
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// TestDevSecureNOFIPSWeb verifies if the MQ Web Server is not running in FIPS mode
|
|
func TestDevSecureFalseFIPSWeb(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
const tlsPassPhrase string = "passw0rd"
|
|
qm := "qm1"
|
|
appPassword := "differentPassw0rd"
|
|
containerConfig := container.Config{
|
|
Env: []string{
|
|
"LICENSE=accept",
|
|
"MQ_QMGR_NAME=" + qm,
|
|
"MQ_APP_PASSWORD=" + appPassword,
|
|
"DEBUG=1",
|
|
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
|
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
|
|
"MQ_ENABLE_FIPS=false",
|
|
},
|
|
Image: imageName(),
|
|
}
|
|
hostConfig := container.HostConfig{
|
|
Binds: []string{
|
|
coverageBind(t),
|
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
|
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
|
},
|
|
// 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)
|
|
|
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
|
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
|
|
|
// As FIPS is not enabled, the MQ WebServer (actually Java) will choose a JSSE provider from the list
|
|
// specified in java.security file. We will need to enable java.net.debug and then parse the web server
|
|
// logs to check what JJSE provider is being used. Hence just check the jvm.options file does not contain
|
|
// -Dcom.ibm.jsse2.usefipsprovider line.
|
|
_, jvmOptionsOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "cat /var/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults/jvm.options"})
|
|
if strings.Contains(jvmOptionsOutput, "-Dcom.ibm.jsse2.usefipsprovider") {
|
|
t.Errorf("Did not expect -Dcom.ibm.jsse2.usefipsprovider but it is not; got \"%v\"", jvmOptionsOutput)
|
|
}
|
|
|
|
// Just do a HTTPS GET as well to query installation details.
|
|
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
|
t.Run("REST admin", func(t *testing.T) {
|
|
testRESTAdmin(t, cli, ctr.ID, secureTLSConfig, "")
|
|
})
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// Verify SSLFIPS is set to NO if no certificates were supplied
|
|
func TestSSLFIPSTrueNoCerts(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
appPassword := "differentPassw0rd"
|
|
containerConfig := container.Config{
|
|
Env: []string{
|
|
"LICENSE=accept",
|
|
"MQ_APP_PASSWORD=" + appPassword,
|
|
"MQ_QMGR_NAME=QM1",
|
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
|
"MQ_ENABLE_FIPS=true",
|
|
},
|
|
Image: imageName(),
|
|
}
|
|
hostConfig := container.HostConfig{
|
|
Binds: []string{
|
|
coverageBind(t),
|
|
},
|
|
}
|
|
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, SSLFIPS and CERTLABL attibutes.
|
|
// Search the console output for exepcted values
|
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR( )") {
|
|
t.Errorf("Expected SSLKEYR to be ' ' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
if !strings.Contains(sslFIPSOutput, "CERTLABL( )") {
|
|
t.Errorf("Expected CERTLABL to be blank but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
|
|
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=tru (invalid value)
|
|
func TestSSLFIPSInvalidValue(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",
|
|
"MQ_ENABLE_FIPS=tru",
|
|
},
|
|
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, SSLFIPS and CERTLABL attibutes.
|
|
// Search the console output for exepcted values
|
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
|
|
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
|
|
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
|
|
}
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|
|
|
|
// Container creation fails when invalid certs are passed and MQ_ENABLE_FIPS set true
|
|
func TestSSLFIPSBadCerts(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",
|
|
"MQ_ENABLE_FIPS=true",
|
|
},
|
|
Image: imageName(),
|
|
}
|
|
hostConfig := container.HostConfig{
|
|
Binds: []string{
|
|
coverageBind(t),
|
|
tlsDirInvalid(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)
|
|
|
|
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
|
// Expect return code 1 if container failed to create.
|
|
if rc == 1 {
|
|
// Get container logs and search for specific message.
|
|
logs := inspectLogs(t, cli, ctr.ID)
|
|
if strings.Contains(logs, "Failed to parse private key") {
|
|
t.Logf("Container creating failed because of invalid certifates")
|
|
}
|
|
} else {
|
|
// Some other error occurred.
|
|
t.Errorf("Expected rc=0, got rc=%v", rc)
|
|
}
|
|
|
|
// Stop the container cleanly
|
|
stopContainer(t, cli, ctr.ID)
|
|
}
|