...

Source file src/solace.dev/go/messaging/pkg/solace/config/messaging_service_strategies.go

Documentation: solace.dev/go/messaging/pkg/solace/config

     1  // pubsubplus-go-client
     2  //
     3  // Copyright 2021-2025 Solace Corporation. All rights reserved.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  // http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package config
    18  
    19  import (
    20  	"time"
    21  )
    22  
    23  // AuthenticationStrategy represents an authentication strategy.
    24  type AuthenticationStrategy struct {
    25  	config ServicePropertyMap
    26  }
    27  
    28  func (strategy AuthenticationStrategy) String() string {
    29  	return strategy.config.String()
    30  }
    31  
    32  // ToProperties gets the configuration of the authentication strategy in the form of a ServicePropertyMap.
    33  func (strategy AuthenticationStrategy) ToProperties() ServicePropertyMap {
    34  	// return empty map if config is nil
    35  	if strategy.config == nil {
    36  		return make(ServicePropertyMap)
    37  	}
    38  	// duplicate config
    39  	return strategy.config.GetConfiguration()
    40  }
    41  
    42  // BasicUserNamePasswordAuthentication gets a basic authentication strategy with the provided credentials.
    43  func BasicUserNamePasswordAuthentication(username, password string) AuthenticationStrategy {
    44  	authenticationStrategy := AuthenticationStrategy{make(ServicePropertyMap)}
    45  	authenticationStrategy.config[AuthenticationPropertySchemeBasicUserName] = username
    46  	authenticationStrategy.config[AuthenticationPropertySchemeBasicPassword] = password
    47  	authenticationStrategy.config[AuthenticationPropertyScheme] = AuthenticationSchemeBasic
    48  	return authenticationStrategy
    49  }
    50  
    51  // ClientCertificateAuthentication gets a client certificate-based authentication strategy using
    52  // the provided certificate file, key file, and key password if required. If no keyFile or keyPassword is
    53  // required, use an empty string for the  keyFile and keyPassword arguments.
    54  func ClientCertificateAuthentication(certificateFile, keyFile, keyPassword string) AuthenticationStrategy {
    55  	authenticationStrategy := AuthenticationStrategy{make(ServicePropertyMap)}
    56  	authenticationStrategy.config[AuthenticationPropertyScheme] = AuthenticationSchemeClientCertificate
    57  	authenticationStrategy.config[AuthenticationPropertySchemeSSLClientCertFile] = certificateFile
    58  	if keyFile != "" {
    59  		authenticationStrategy.config[AuthenticationPropertySchemeSSLClientPrivateKeyFile] = keyFile
    60  	}
    61  	if keyPassword != "" {
    62  		authenticationStrategy.config[AuthenticationPropertySchemeClientCertPrivateKeyFilePassword] = keyPassword
    63  	}
    64  	return authenticationStrategy
    65  }
    66  
    67  // OAuth2Authentication creates an OAuth2-based authentication strategy using the specified tokens.
    68  // At least one of accessToken or OIDC idToken must be provided. Optionally, issuerIdentifier
    69  // can be provided. If any of the parameters is not required, an empty string can be passed.
    70  func OAuth2Authentication(accessToken, oidcIDToken, issuerIdentifier string) AuthenticationStrategy {
    71  	authenticationStrategy := AuthenticationStrategy{make(ServicePropertyMap)}
    72  	authenticationStrategy.config[AuthenticationPropertyScheme] = AuthenticationSchemeOAuth2
    73  	if len(accessToken) > 0 {
    74  		authenticationStrategy.config[AuthenticationPropertySchemeOAuth2AccessToken] = accessToken
    75  	}
    76  	// Only set the id token or issuer identifier if they are nonempty.
    77  	if len(oidcIDToken) > 0 {
    78  		authenticationStrategy.config[AuthenticationPropertySchemeOAuth2OIDCIDToken] = oidcIDToken
    79  	}
    80  	if len(issuerIdentifier) > 0 {
    81  		authenticationStrategy.config[AuthenticationPropertySchemeOAuth2IssuerIdentifier] = issuerIdentifier
    82  	}
    83  	return authenticationStrategy
    84  }
    85  
    86  // KerberosAuthentication creates a Kerberos-based authentication strategy. Optionally,
    87  // a Kerberos service name can be provided. If the service name is not required, an empty
    88  // string can be passed to the serviceName argument.
    89  //
    90  // To implement Kerberos authentication for clients connecting to a broker, the following
    91  // configuration is required the broker:
    92  //   - A Kerberos Keytab must be loaded on the  broker. See "Event Broker File Management" for more information
    93  //     on the Solace documentation website.
    94  //   - Kerberos authentication must be configured and enabled for any Message VPNs that
    95  //     Kerberos-authenticated clients will connect to.
    96  //   - Optional: On an appliance, a Kerberos Service Principal Name (SPN) can be assigned to the IP address
    97  //     for the message backbone VRF Kerberos‑authenticated clients will use.
    98  //
    99  // Further reference can be found at
   100  //
   101  //	https://docs.solace.com/Configuring-and-Managing/Configuring-Client-Authentication.htm#Config-Kerberos
   102  func KerberosAuthentication(serviceName string) AuthenticationStrategy {
   103  	authenticationStrategy := AuthenticationStrategy{make(ServicePropertyMap)}
   104  	authenticationStrategy.config[AuthenticationPropertyScheme] = AuthenticationSchemeKerberos
   105  	if len(serviceName) > 0 {
   106  		authenticationStrategy.config[AuthenticationPropertySchemeKerberosInstanceName] = serviceName
   107  	}
   108  	return authenticationStrategy
   109  }
   110  
   111  /* Retry Strategy */
   112  
   113  // RetryStrategy represents the strategy to use when reconnecting.
   114  type RetryStrategy struct {
   115  	retries       int
   116  	retryInterval time.Duration
   117  }
   118  
   119  // GetRetries returns the number of retries configured with the retry strategy.
   120  func (strategy RetryStrategy) GetRetries() int {
   121  	return strategy.retries
   122  }
   123  
   124  // GetRetryInterval returns the interval between (re)connection retry attempts.
   125  func (strategy RetryStrategy) GetRetryInterval() time.Duration {
   126  	return strategy.retryInterval
   127  }
   128  
   129  // RetryStrategyForeverRetry creates a retry strategy that runs forever
   130  // with automatic retries and a retry interval of 3000 milliseconds.
   131  func RetryStrategyForeverRetry() RetryStrategy {
   132  	return RetryStrategy{-1, 3000 * time.Millisecond}
   133  }
   134  
   135  // RetryStrategyForeverRetryWithInterval creates a retry strategy that runs forever
   136  // with automatic retries and a retry interval of the specified duration.
   137  func RetryStrategyForeverRetryWithInterval(retryInterval time.Duration) RetryStrategy {
   138  	return RetryStrategy{-1, retryInterval}
   139  }
   140  
   141  // RetryStrategyNeverRetry creates an instance of configuration for disabled automatic retries.
   142  func RetryStrategyNeverRetry() RetryStrategy {
   143  	return RetryStrategy{0, 3000 * time.Millisecond}
   144  }
   145  
   146  // RetryStrategyParameterizedRetry creates an instance of configuration for free configurability.
   147  // retries must be greater than or equal to zero.
   148  func RetryStrategyParameterizedRetry(retries uint, retryInterval time.Duration) RetryStrategy {
   149  	return RetryStrategy{int(retries), retryInterval}
   150  }
   151  
   152  /* Transport Security Strategy */
   153  
   154  // TransportSecurityStrategy represents the strategy to use when connecting to a broker
   155  // via a secure port.
   156  type TransportSecurityStrategy struct {
   157  	config ServicePropertyMap
   158  }
   159  
   160  // TransportSecurityProtocol represents the various security protocols available to the API.
   161  type TransportSecurityProtocol string
   162  
   163  const (
   164  	// TransportSecurityProtocolSSLv3 is deprecated, do not use.
   165  	TransportSecurityProtocolSSLv3 TransportSecurityProtocol = "SSLv3"
   166  	// TransportSecurityProtocolTLSv1 is deprecated, do not use.
   167  	TransportSecurityProtocolTLSv1 TransportSecurityProtocol = "TLSv1"
   168  	// TransportSecurityProtocolTLSv1_1 represents TLSv1.1.
   169  	TransportSecurityProtocolTLSv1_1 TransportSecurityProtocol = "TLSv1.1"
   170  	// TransportSecurityProtocolTLSv1_2 represents TLSv1.2.
   171  	TransportSecurityProtocolTLSv1_2 TransportSecurityProtocol = "TLSv1.2"
   172  	// TransportSecurityProtocolTLSv1_3 represents TLSv1.3.
   173  	TransportSecurityProtocolTLSv1_3 TransportSecurityProtocol = "TLSv1.3"
   174  )
   175  
   176  // NewTransportSecurityStrategy creates a transport security strategy with default configuration.
   177  // Properties can be overwritten by calling the various configuration functions on TransportSecurityStrategy.
   178  func NewTransportSecurityStrategy() TransportSecurityStrategy {
   179  	tss := TransportSecurityStrategy{
   180  		config: make(ServicePropertyMap),
   181  	}
   182  	return tss
   183  }
   184  
   185  // Downgradable configures TLS so that the session connection is downgraded to plain-text after client authentication.
   186  // WARNING: Downgrading SSL to plain-text after client authentication exposes a client and the data being sent
   187  // to higher security risks.
   188  func (tss TransportSecurityStrategy) Downgradable() TransportSecurityStrategy {
   189  	tss.config[TransportLayerSecurityPropertyProtocolDowngradeTo] = DowngradeToPlaintext
   190  	return tss
   191  }
   192  
   193  // WithExcludedProtocols is deprecated, use WithMinimumProtocol and WithMaximumProtocol instead.
   194  func (tss TransportSecurityStrategy) WithExcludedProtocols(protocols ...TransportSecurityProtocol) TransportSecurityStrategy {
   195  	protocolsCS := ""
   196  	for _, protocol := range protocols {
   197  		if protocolsCS != "" {
   198  			protocolsCS += ","
   199  		}
   200  		protocolsCS += string(protocol)
   201  	}
   202  	tss.config[TransportLayerSecurityPropertyExcludedProtocols] = protocolsCS
   203  	return tss
   204  }
   205  
   206  // WithMinimumProtocol specifies the lowest TLS protocol version to allow.
   207  func (tss TransportSecurityStrategy) WithMinimumProtocol(protocol TransportSecurityProtocol) TransportSecurityStrategy {
   208  	tss.config[TransportLayerSecurityPropertyMinimumProtocol] = string(protocol)
   209  	return tss
   210  }
   211  
   212  // WithMaximumProtocol specifies the highest TLS protocol version to negotiate.
   213  func (tss TransportSecurityStrategy) WithMaximumProtocol(protocol TransportSecurityProtocol) TransportSecurityStrategy {
   214  	tss.config[TransportLayerSecurityPropertyMaximumProtocol] = string(protocol)
   215  	return tss
   216  }
   217  
   218  // WithoutCertificateValidation configures TLS to not validate the server certificate
   219  // configured on the remote broker.
   220  // WARNING: Disabling certificate validation exposes clients and data being sent to higher security risks.
   221  func (tss TransportSecurityStrategy) WithoutCertificateValidation() TransportSecurityStrategy {
   222  	tss.config[TransportLayerSecurityPropertyCertValidated] = false
   223  	return tss
   224  }
   225  
   226  // WithCertificateValidation configures TLS validation on certificates. By default, validation is performed.
   227  // WARNING: Disabling certificate validation exposes clients and data being sent to higher security risks.
   228  //
   229  // ignoreExpiration: when set to true, expired certificates are accepted.
   230  //
   231  // validateServerName: When set to true, certificates without the matching host are not accepted.
   232  //
   233  // trustStoreFilePath: The location of the trust store files. If an empty string is passed, no file path will be set.
   234  //
   235  // trustedCommonNameList: A comma-separated list of acceptable common names for matching with server certificates. An empty string will match no names.
   236  func (tss TransportSecurityStrategy) WithCertificateValidation(
   237  	ignoreExpiration bool,
   238  	validateServerName bool,
   239  	trustStoreFilePath string,
   240  	trustedCommonNameList string,
   241  ) TransportSecurityStrategy {
   242  	tss.config[TransportLayerSecurityPropertyCertValidated] = true
   243  	tss.config[TransportLayerSecurityPropertyCertRejectExpired] = !ignoreExpiration
   244  	tss.config[TransportLayerSecurityPropertyCertValidateServername] = validateServerName
   245  	if trustStoreFilePath != "" {
   246  		tss.config[TransportLayerSecurityPropertyTrustStorePath] = trustStoreFilePath
   247  	}
   248  	if trustedCommonNameList != "" {
   249  		tss.config[TransportLayerSecurityPropertyTrustedCommonNameList] = trustedCommonNameList
   250  	}
   251  	return tss
   252  }
   253  
   254  // WithCipherSuites configures cipher suites to use with TLSv1.2 and older. Has no effect when TLSv1.3 is negotiated.
   255  // The cipher suites value is a comma-separated list of cipher suites and must be from the following table:
   256  //
   257  //	+-----------------+-------------------------------+--------------------+
   258  //	| 'AES256-SHA'    | 'ECDHE-RSA-AES256-SHA'        | 'AES256-GCM-SHA384'|
   259  //	+-----------------+-------------------------------+--------------------+
   260  //	| 'AES256-SHA256' | 'ECDHE-RSA-AES256-GCM-SHA384' | 'AES128-SHA256'    |
   261  //	+-----------------+-------------------------------+--------------------+
   262  //	| 'DES-CBC3-SHA'  | 'ECDHE-RSA-DES-CBC3-SHA'      |                    |
   263  //	+-----------------+-------------------------------+--------------------+
   264  //	| 'RC4-SHA'       | 'ECDHE-RSA-AES256-SHA384'     | 'AES128            |
   265  //	+-----------------+-------------------------------+--------------------+
   266  //	| 'ECDHE-RSA-AES128-SHA256'                       | 'AES128-GCM-SHA256'|
   267  //	+-----------------+-------------------------------+--------------------+
   268  //	| 'RC4-MD5'       | 'ECDHE-RSA-AES128-GCM-SHA256' |                    |
   269  //	+----------------------------------------+-----------------------------+
   270  //	| 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'| 'ECDHE-RSA-AES128-SHA'      |
   271  //	+----------------------------------------+-----------------------------+
   272  //	| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384'|                             |
   273  //	+----------------------------------------+-----------------------------+
   274  //	| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA'   |                             |
   275  //	+----------------------------------------+-----------------------------+
   276  //	| 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA'  |                             |
   277  //	+----------------------------------------+-----------------------------+
   278  //	| 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'|                             |
   279  //	+----------------------------------------+-----------------------------+
   280  //	| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA'   |                             |
   281  //	+----------------------------------------+-----------------------------+
   282  //	| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256'|                             |
   283  //	+-----------------------------------+----------------------------------+
   284  //	| 'TLS_RSA_WITH_AES_128_GCM_SHA256' |                                  |
   285  //	+-----------------------------------+----------------------------------+
   286  //	| 'TLS_RSA_WITH_AES_128_CBC_SHA256' |'TLS_RSA_WITH_AES_256_GCM_SHA384' |
   287  //	+-----------------------------------+----------------------------------+
   288  //	| 'TLS_RSA_WITH_AES_256_CBC_SHA256' | 'TLS_RSA_WITH_AES_256_CBC_SHA'   |
   289  //	+-----------------------------------+----------------------------------+
   290  //	| 'SSL_RSA_WITH_3DES_EDE_CBC_SHA    | 'TLS_RSA_WITH_AES_128_CBC_SHA'   |
   291  //	+-----------------------------------+----------------------------------+
   292  //	| 'SSL_RSA_WITH_RC4_128_SHA'        | 'SSL_RSA_WITH_RC4_128_MD5'       |
   293  //	+-----------------------------------+----------------------------------+
   294  func (tss TransportSecurityStrategy) WithCipherSuites(cipherSuiteList string) TransportSecurityStrategy {
   295  	tss.config[TransportLayerSecurityPropertyCipherSuites] = cipherSuiteList
   296  	return tss
   297  }
   298  
   299  // ToProperties returns the configuration in the form of a ServicePropertyMap.
   300  func (tss TransportSecurityStrategy) ToProperties() ServicePropertyMap {
   301  	if tss.config == nil {
   302  		return make(ServicePropertyMap)
   303  	}
   304  	return tss.config.GetConfiguration()
   305  }
   306