Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,6 @@ jobs:
./unitcoverage.out
./test/reports/report.xml
./test/reports/coverage.out
./test/diagnostics.tgz
./test/diagnostics.tgz.p7m
overwrite: true

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

test/reports
test/diagnostics.tgz
test/diagnostics.tgz.p7m

test/sempclient/action/*
!test/sempclient/action/go.mod
Expand Down
29 changes: 17 additions & 12 deletions pkg/solace/config/messaging_service_properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,9 @@ const (
// +-----------------+-------------------------------+--------------------+
// | 'AES256-SHA256' | 'ECDHE-RSA-AES256-GCM-SHA384' | 'AES128-SHA256' |
// +-----------------+-------------------------------+--------------------+
// | 'DES-CBC3-SHA' | 'ECDHE-RSA-DES-CBC3-SHA' | |
// +-----------------+-------------------------------+--------------------+
// | 'RC4-SHA' | 'ECDHE-RSA-AES256-SHA384' | 'AES128 |
// +-----------------+-------------------------------+--------------------+
// | 'ECDHE-RSA-AES128-SHA256' | 'AES128-GCM-SHA256'|
// +-----------------+-------------------------------+--------------------+
// | 'RC4-MD5' | 'ECDHE-RSA-AES128-GCM-SHA256' | |
// | 'ECDHE-RSA-AES256-SHA384' | 'ECDHE-RSA-AES128-SHA256' |
// +----------------------------------------+-----------------------------+
// | 'AES128-GCM-SHA256' |'ECDHE-RSA-AES128-GCM-SHA256'| |
// +----------------------------------------+-----------------------------+
// | 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'| 'ECDHE-RSA-AES128-SHA' |
// +----------------------------------------+-----------------------------+
Expand All @@ -318,16 +314,25 @@ const (
// | 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA' | |
// +----------------------------------------+-----------------------------+
// | 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256'| |
// +-----------------------------------+----------------------------------+
// +----------------------------------------+-----------------------------+
// | 'TLS_RSA_WITH_AES_128_GCM_SHA256' | |
// +-----------------------------------+----------------------------------+
// | 'TLS_RSA_WITH_AES_128_CBC_SHA256' |'TLS_RSA_WITH_AES_256_GCM_SHA384' |
// | 'TLS_RSA_WITH_AES_128_CBC_SHA256' |'TLS_RSA_WITH_AES_256_CBC_SHA256' |
// +-----------------------------------+----------------------------------+
// | 'TLS_RSA_WITH_AES_256_CBC_SHA' | 'TLS_RSA_WITH_AES_128_CBC_SHA' |
// +-----------------------------------+----------------------------------+
//
// Unsupported cipher suites (previously supported on older brokers):
// +-----------------------------------+----------------------------------+
// | 'DES-CBC3-SHA' |'ECDHE-RSA-DES-CBC3-SHA' |
// +-----------------------------------+----------------------------------+
// | 'RC4-SHA' | 'AES128' |
// +-----------------------------------+----------------------------------+
// | 'TLS_RSA_WITH_AES_256_CBC_SHA256' | 'TLS_RSA_WITH_AES_256_CBC_SHA' |
// | 'TLS_RSA_WITH_AES_256_GCM_SHA384' | 'RC4-MD5' |
// +-----------------------------------+----------------------------------+
// | 'SSL_RSA_WITH_3DES_EDE_CBC_SHA | 'TLS_RSA_WITH_AES_128_CBC_SHA' |
// | 'SSL_RSA_WITH_3DES_EDE_CBC_SHA' | 'SSL_RSA_WITH_RC4_128_SHA' |
// +-----------------------------------+----------------------------------+
// | 'SSL_RSA_WITH_RC4_128_SHA' | 'SSL_RSA_WITH_RC4_128_MD5' |
// | 'SSL_RSA_WITH_RC4_128_MD5' | |
// +-----------------------------------+----------------------------------+
TransportLayerSecurityPropertyCipherSuites ServiceProperty = "solace.messaging.tls.cipher-suites"

Expand Down
29 changes: 17 additions & 12 deletions pkg/solace/config/messaging_service_strategies.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,9 @@ func (tss TransportSecurityStrategy) WithCertificateValidation(
// +-----------------+-------------------------------+--------------------+
// | 'AES256-SHA256' | 'ECDHE-RSA-AES256-GCM-SHA384' | 'AES128-SHA256' |
// +-----------------+-------------------------------+--------------------+
// | 'DES-CBC3-SHA' | 'ECDHE-RSA-DES-CBC3-SHA' | |
// +-----------------+-------------------------------+--------------------+
// | 'RC4-SHA' | 'ECDHE-RSA-AES256-SHA384' | 'AES128 |
// +-----------------+-------------------------------+--------------------+
// | 'ECDHE-RSA-AES128-SHA256' | 'AES128-GCM-SHA256'|
// +-----------------+-------------------------------+--------------------+
// | 'RC4-MD5' | 'ECDHE-RSA-AES128-GCM-SHA256' | |
// | 'ECDHE-RSA-AES256-SHA384' | 'ECDHE-RSA-AES128-SHA256' |
// +----------------------------------------+-----------------------------+
// | 'AES128-GCM-SHA256' |'ECDHE-RSA-AES128-GCM-SHA256'| |
// +----------------------------------------+-----------------------------+
// | 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'| 'ECDHE-RSA-AES128-SHA' |
// +----------------------------------------+-----------------------------+
Expand All @@ -280,16 +276,25 @@ func (tss TransportSecurityStrategy) WithCertificateValidation(
// | 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA' | |
// +----------------------------------------+-----------------------------+
// | 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256'| |
// +-----------------------------------+----------------------------------+
// +----------------------------------------+-----------------------------+
// | 'TLS_RSA_WITH_AES_128_GCM_SHA256' | |
// +-----------------------------------+----------------------------------+
// | 'TLS_RSA_WITH_AES_128_CBC_SHA256' |'TLS_RSA_WITH_AES_256_GCM_SHA384' |
// | 'TLS_RSA_WITH_AES_128_CBC_SHA256' |'TLS_RSA_WITH_AES_256_CBC_SHA256' |
// +-----------------------------------+----------------------------------+
// | 'TLS_RSA_WITH_AES_256_CBC_SHA' | 'TLS_RSA_WITH_AES_128_CBC_SHA' |
// +-----------------------------------+----------------------------------+
//
// Unsupported cipher suites (previously supported on older brokers):
// +-----------------------------------+----------------------------------+
// | 'DES-CBC3-SHA' |'ECDHE-RSA-DES-CBC3-SHA' |
// +-----------------------------------+----------------------------------+
// | 'RC4-SHA' | 'AES128' |
// +-----------------------------------+----------------------------------+
// | 'TLS_RSA_WITH_AES_256_CBC_SHA256' | 'TLS_RSA_WITH_AES_256_CBC_SHA' |
// | 'TLS_RSA_WITH_AES_256_GCM_SHA384' | 'RC4-MD5' |
// +-----------------------------------+----------------------------------+
// | 'SSL_RSA_WITH_3DES_EDE_CBC_SHA | 'TLS_RSA_WITH_AES_128_CBC_SHA' |
// | 'SSL_RSA_WITH_3DES_EDE_CBC_SHA' | 'SSL_RSA_WITH_RC4_128_SHA' |
// +-----------------------------------+----------------------------------+
// | 'SSL_RSA_WITH_RC4_128_SHA' | 'SSL_RSA_WITH_RC4_128_MD5' |
// | 'SSL_RSA_WITH_RC4_128_MD5' | |
// +-----------------------------------+----------------------------------+
func (tss TransportSecurityStrategy) WithCipherSuites(cipherSuiteList string) TransportSecurityStrategy {
tss.config[TransportLayerSecurityPropertyCipherSuites] = cipherSuiteList
Expand Down
10 changes: 5 additions & 5 deletions test/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3022,7 +3022,7 @@ var _ = Describe("Cache Strategy", func() {
messageReceiver solace.DirectMessageReceiver) {
Expect(messagingService.Disconnect()).To(BeNil())
Expect(messagingService.IsConnected()).To(BeFalse())
Eventually(messageReceiver.IsTerminated(), "5s").Should(BeTrue())
Eventually(messageReceiver.IsTerminated(), "8s").Should(BeTrue())
},
configuration: func() config.ServicePropertyMap {
return helpers.DefaultCacheConfiguration()
Expand All @@ -3035,10 +3035,10 @@ var _ = Describe("Cache Strategy", func() {
terminateFunction: func(messagingService solace.MessagingService,
messageReceiver solace.DirectMessageReceiver) {
var err error
Eventually(messagingService.DisconnectAsync(), "5s").Should(Receive(&err))
Eventually(messagingService.DisconnectAsync(), "8s").Should(Receive(&err))
Expect(err).To(BeNil())
Expect(messagingService.IsConnected()).To(BeFalse())
Eventually(messageReceiver.IsTerminated(), "5s").Should(BeTrue())
Eventually(messageReceiver.IsTerminated(), "8s").Should(BeTrue())
},
configuration: func() config.ServicePropertyMap {
return helpers.DefaultCacheConfiguration()
Expand All @@ -3055,10 +3055,10 @@ var _ = Describe("Cache Strategy", func() {
errorChan <- err
})
var err_holder error
Eventually(errorChan, "5s").Should(Receive(&err_holder))
Eventually(errorChan, "8s").Should(Receive(&err_holder))
Expect(err_holder).To(BeNil())
Expect(messagingService.IsConnected()).To(BeFalse())
Eventually(messageReceiver.IsTerminated(), "5s").Should(BeTrue())
Eventually(messageReceiver.IsTerminated(), "8s").Should(BeTrue())
},
configuration: func() config.ServicePropertyMap {
return helpers.DefaultCacheConfiguration()
Expand Down
2 changes: 1 addition & 1 deletion test/data/compose/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ services:
memlock: -1
nofile:
soft: 2448
hard: 42192
hard: 1048576
Copy link
Author

@oodigie oodigie Jul 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the docs, this hard limit is required for the solace software broker version 1.25.0 to startup successfully.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2025-07-11 at 10 04 09 AM

secrets:
- server.pem
- server_passphrase
Expand Down
2 changes: 1 addition & 1 deletion test/data/config/config_testcontainers.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"testcontainers": {
"broker_hostname": "solbroker",
"broker_tag": "10.4",
"broker_tag": "10.25.0",
"broker_repo": "solace/solace-pubsub",
"broker_edition": "standard",
"toxiproxy_hostname": "toxiproxy",
Expand Down
80 changes: 54 additions & 26 deletions test/helpers/cache_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ import (
"fmt"
"strconv"
"strings"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"solace.dev/go/messaging"
"solace.dev/go/messaging/pkg/solace"
"solace.dev/go/messaging/pkg/solace/config"
"solace.dev/go/messaging/pkg/solace/message"
"solace.dev/go/messaging/pkg/solace/resource"
Expand Down Expand Up @@ -54,49 +57,50 @@ func DefaultCacheConfiguration() config.ServicePropertyMap {
return config
}

func SendMsgsToTopic(topic string, numMessages int) {
builder := messaging.NewMessagingServiceBuilder().FromConfigurationProvider(DefaultCacheConfiguration())
messagingService := buildMessagingService(builder, 2)
defer func() {
err := messagingService.Disconnect()
Expect(err).To(BeNil())
}()
err := messagingService.Connect()
Expect(err).To(BeNil())
receiver, err := messagingService.CreateDirectMessageReceiverBuilder().WithSubscriptions(resource.TopicSubscriptionOf(topic)).Build()
func SendMsgsToTopic(
publisher solace.DirectMessagePublisher,
topic string,
messageBuilder solace.OutboundMessageBuilder,
directMsgReceiverBuilder solace.DirectMessageReceiverBuilder,
numMessages int) {

receivedMsgs := make(chan message.InboundMessage, numMessages)
cacheMessageHandlerCallback := func(msg message.InboundMessage) {
receivedMsgs <- msg
}

receiver, err := directMsgReceiverBuilder.WithSubscriptions(resource.TopicSubscriptionOf(topic)).Build()
Expect(err).To(BeNil())
defer func() {
err := receiver.Terminate(0)
Expect(err).To(BeNil())
}()
err = receiver.Start()
Expect(err).To(BeNil())
publisher, err := messagingService.CreateDirectMessagePublisherBuilder().Build()
Expect(err).To(BeNil())
defer func() {
err := publisher.Terminate(0)
Expect(err).To(BeNil())
}()
err = publisher.Start()
Expect(err).To(BeNil())
receivedMsgs := make(chan message.InboundMessage, numMessages)
cacheMessageHandlerCallback := func(msg message.InboundMessage) {
receivedMsgs <- msg
}

err = receiver.ReceiveAsync(cacheMessageHandlerCallback)
Expect(err).To(BeNil())

counter := 0
messageBuilder := messagingService.MessageBuilder()
for counter < numMessages {
msg, err := messageBuilder.BuildWithStringPayload(fmt.Sprintf("message %d", counter))
Expect(err).To(BeNil())
err = publisher.Publish(msg, resource.TopicOf(topic))
Expect(err).To(BeNil())
counter++
}

// wait for 10 seconds per message to receive all messages
totalMsgWaitTime := time.Duration(10*numMessages) * time.Second
Eventually(receivedMsgs, totalMsgWaitTime).Should(HaveLen(numMessages), fmt.Sprintf("Timed out waiting to receive %d message(s)", numMessages)) // messages should have been sent

var receivedMessage message.InboundMessage
for i := 0; i < numMessages; i++ {
var receivedMessage message.InboundMessage
Eventually(receivedMsgs, "10s").Should(Receive(&receivedMessage), fmt.Sprintf("Timed out waiting to receive message %d of %d", i, numMessages))
select {
case receivedMessage = <-receivedMsgs:
case <-time.After(2 * time.Second):
Fail("Timed out waiting to receive message %d of %d", i, numMessages)
}
Expect(receivedMessage.GetDestinationName()).To(Equal(topic))
}
}
Expand Down Expand Up @@ -130,8 +134,32 @@ func InitCacheWithPreExistingMessages(cacheCluster testcontext.CacheClusterConfi
topics = append(topics, fmt.Sprintf("%s%s%s", splitString[0], vpnName, splitString[1]))
}
}

// Create a single messaging service to use to populate the caches
builder := messaging.NewMessagingServiceBuilder().FromConfigurationProvider(DefaultCacheConfiguration())
messagingService := buildMessagingService(builder, 2)
defer func() {
err := messagingService.Disconnect()
Expect(err).To(BeNil())
}()
err := messagingService.Connect()
Expect(err).To(BeNil())

publisher, err := messagingService.CreateDirectMessagePublisherBuilder().Build()
Expect(err).To(BeNil())
defer func() {
err := publisher.Terminate(0)
Expect(err).To(BeNil())
}()
err = publisher.Start()
Expect(err).To(BeNil())

// used to build the messages being published to the topics
messageBuilder := messagingService.MessageBuilder()
directMsgReceiverBuilder := messagingService.CreateDirectMessageReceiverBuilder()

for _, topic := range topics {
SendMsgsToTopic(topic, numMessages)
SendMsgsToTopic(publisher, topic, messageBuilder, directMsgReceiverBuilder, numMessages)
}
}

Expand Down
26 changes: 14 additions & 12 deletions test/messaging_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,17 +500,19 @@ var _ = Describe("MessagingService Lifecycle", func() {
})
It("should be able to connect with cipher suite", func() {
builder.WithTransportSecurityStrategy(config.NewTransportSecurityStrategy().
WithCipherSuites("AES128-SHA"))
WithMaximumProtocol(config.TransportSecurityProtocolTLSv1_2). // cipher suite selection only available in TLSv1.2
WithCipherSuites("ECDHE-RSA-AES128-GCM-SHA256"))
helpers.TestConnectDisconnectMessagingServiceClientValidation(builder, func(client *monitor.MsgVpnClient) {
Expect(client.TlsCipherDescription).To(HavePrefix("AES128-SHA"))
Expect(client.TlsVersion).To(BeEquivalentTo(config.TransportSecurityProtocolTLSv1_2))
Expect(client.TlsCipherDescription).To(HavePrefix("ECDHE-RSA-AES128-GCM-SHA256"))
})
})
// Originally this explicitly test tls1.1
// on systems with new openssl (3.0 or later) tls1.1 is no longer supported from the client
// As a result this is adapted to explicitly verify tls1.2 in anticipation for tls1.3
// once openssl 1.1 support is deprecated this maybe
// We need to explicitly enable TLS1.2 to test a few cases
Context("when allowing TLS1.2 connections", func() {
Context("when allowing TLS1.2 and TLS1.3 connections", func() {
BeforeEach(func() {
// semp configuration for tls version support
// revist for enabling support for tls 1.2 in the future
Expand All @@ -528,16 +530,16 @@ var _ = Describe("MessagingService Lifecycle", func() {
})
It("should be able to connect with excluded protocols", func() {
builder.WithTransportSecurityStrategy(config.NewTransportSecurityStrategy().
WithExcludedProtocols(config.TransportSecurityProtocolSSLv3, config.TransportSecurityProtocolTLSv1, config.TransportSecurityProtocolTLSv1_1))
WithExcludedProtocols(config.TransportSecurityProtocolSSLv3, config.TransportSecurityProtocolTLSv1_3, config.TransportSecurityProtocolTLSv1, config.TransportSecurityProtocolTLSv1_1))
helpers.TestConnectDisconnectMessagingServiceClientValidation(builder, func(client *monitor.MsgVpnClient) {
Expect(client.TlsVersion).To(BeEquivalentTo(config.TransportSecurityProtocolTLSv1_2))
})
})
It("should be able to connect with minimum protocol", func() {
builder.WithTransportSecurityStrategy(config.NewTransportSecurityStrategy().
WithMinimumProtocol(config.TransportSecurityProtocolTLSv1_2))
WithMinimumProtocol(config.TransportSecurityProtocolTLSv1_3))
helpers.TestConnectDisconnectMessagingServiceClientValidation(builder, func(client *monitor.MsgVpnClient) {
Expect(client.TlsVersion).To(BeEquivalentTo(config.TransportSecurityProtocolTLSv1_2))
Expect(client.TlsVersion).To(BeEquivalentTo(config.TransportSecurityProtocolTLSv1_3))
})
})
It("should be able to connect with maximum protocol", func() {
Expand All @@ -563,22 +565,22 @@ var _ = Describe("MessagingService Lifecycle", func() {
tss := config.NewTransportSecurityStrategy()
tss.WithMinimumProtocol(config.TransportSecurityProtocolTLSv1_2)
tss.WithMaximumProtocol(config.TransportSecurityProtocolTLSv1_2)
tss.WithExcludedProtocols(config.TransportSecurityProtocolSSLv3, config.TransportSecurityProtocolTLSv1, config.TransportSecurityProtocolTLSv1_1)
tss.WithExcludedProtocols(config.TransportSecurityProtocolSSLv3, config.TransportSecurityProtocolTLSv1, config.TransportSecurityProtocolTLSv1, config.TransportSecurityProtocolTLSv1_1)
builder.WithTransportSecurityStrategy(tss)
_, err := builder.Build()
Expect(err).To(HaveOccurred())
Expect(err).To(BeAssignableToTypeOf(&solace.InvalidConfigurationError{}))
Expect(err.Error()).To(ContainSubstring("Attempt to configure both deprecated and new tls version control properties."))
})

// When we upgrade the broker, this will fail by conneccting successfully, but until then, it's useful.
// EBP-511
It("fails to connect with TLSv1.3 because the broker is old", func() {
// This will fail on older broker versions.
It("should connect with TLSv1.3 on newer broker versions", func() {
tss := config.NewTransportSecurityStrategy()
tss.WithMinimumProtocol(config.TransportSecurityProtocolTLSv1_3)
builder.WithTransportSecurityStrategy(tss)
helpers.TestFailedConnectMessagingService(builder, func(err error) {
helpers.ValidateNativeError(err, subcode.CommunicationError)

helpers.TestConnectDisconnectMessagingServiceClientValidation(builder, func(client *monitor.MsgVpnClient) {
Expect(client.TlsVersion).To(BeEquivalentTo(config.TransportSecurityProtocolTLSv1_3))
})
})
})
Expand Down
4 changes: 2 additions & 2 deletions test/testcontext/test_context_testcontainers.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func (context *testContainersTestContext) Teardown() error {
fmt.Println("Encountered error getting working directory for " + pubsubHostname + " diagnostics err:" + err.Error())
}

err = context.gatherBrokerDiagnostics(path.Join(wd, "diagnostics.tgz"))
err = context.gatherBrokerDiagnostics(path.Join(wd, "diagnostics.tgz.p7m"))
if err != nil {
fmt.Println("Encountered error getting " + pubsubHostname + " diagnostics err:" + err.Error())
}
Expand Down Expand Up @@ -245,7 +245,7 @@ func (context *testContainersTestContext) gatherBrokerDiagnostics(destinationPat
fmt.Println("Gathered gather-diagnostics for " + pubsubHostname)
// extract diagnostic to host
// first get absolute path from container
resp, diagnosticPath, err := context.dockerExec(pubsubHostname, []string{"/bin/bash", "-l", "-c", "ls -rt /usr/sw/jail/logs/gather-diagnostics*.tgz | tail -n 1"})
resp, diagnosticPath, err := context.dockerExec(pubsubHostname, []string{"/bin/bash", "-l", "-c", "ls -rt /usr/sw/jail/logs/gather-diagnostics*.tgz.p7m | tail -n 1"})
//resp, diagnosticPath, err := context.dockerExec(pubsubHostname, []string{"/bin/bash", "-l", "-c", " realpath $(ls -rt /usr/sw/jail/logs/gather-diagnostics*.tgz | tail -n 1)"})
if err != nil {
return err
Expand Down
Loading