...

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-2024 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 represents SSLv3.
   165  	TransportSecurityProtocolSSLv3 TransportSecurityProtocol = "SSLv3"
   166  	// TransportSecurityProtocolTLSv1 represents TLSv1.
   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  )
   173  
   174  // NewTransportSecurityStrategy creates a transport security strategy with default configuration.
   175  // Properties can be overwritten by calling the various configuration functions on TransportSecurityStrategy.
   176  func NewTransportSecurityStrategy() TransportSecurityStrategy {
   177  	tss := TransportSecurityStrategy{
   178  		config: make(ServicePropertyMap),
   179  	}
   180  	return tss
   181  }
   182  
   183  // Downgradable configures TLS so that the session connection is downgraded to plain-text after client authentication.
   184  // WARNING: Downgrading SSL to plain-text after client authentication exposes a client and the data being sent
   185  // to higher security risks.
   186  func (tss TransportSecurityStrategy) Downgradable() TransportSecurityStrategy {
   187  	tss.config[TransportLayerSecurityPropertyProtocolDowngradeTo] = DowngradeToPlaintext
   188  	return tss
   189  }
   190  
   191  // WithExcludedProtocols specifies the list of SSL or TLS protocols to not use.
   192  func (tss TransportSecurityStrategy) WithExcludedProtocols(protocols ...TransportSecurityProtocol) TransportSecurityStrategy {
   193  	protocolsCS := ""
   194  	for _, protocol := range protocols {
   195  		if protocolsCS != "" {
   196  			protocolsCS += ","
   197  		}
   198  		protocolsCS += string(protocol)
   199  	}
   200  	tss.config[TransportLayerSecurityPropertyExcludedProtocols] = protocolsCS
   201  	return tss
   202  }
   203  
   204  // WithoutCertificateValidation configures TLS to not validate the server certificate
   205  // configured on the remote broker.
   206  // WARNING: Disabling certificate validation exposes clients and data being sent to higher security risks.
   207  func (tss TransportSecurityStrategy) WithoutCertificateValidation() TransportSecurityStrategy {
   208  	tss.config[TransportLayerSecurityPropertyCertValidated] = false
   209  	return tss
   210  }
   211  
   212  // WithCertificateValidation configures TLS validation on certificates. By default, validation is performed.
   213  // WARNING: Disabling certificate validation exposes clients and data being sent to higher security risks.
   214  //
   215  // ignoreExpiration: when set to true, expired certificates are accepted.
   216  //
   217  // validateServerName: When set to true, certificates without the matching host are not accepted.
   218  //
   219  // trustStoreFilePath: The location of the trust store files. If an empty string is passed, no file path will be set.
   220  //
   221  // trustedCommonNameList: A comma-separated list of acceptable common names for matching with server certificates. An empty string will match no names.
   222  func (tss TransportSecurityStrategy) WithCertificateValidation(
   223  	ignoreExpiration bool,
   224  	validateServerName bool,
   225  	trustStoreFilePath string,
   226  	trustedCommonNameList string,
   227  ) TransportSecurityStrategy {
   228  	tss.config[TransportLayerSecurityPropertyCertValidated] = true
   229  	tss.config[TransportLayerSecurityPropertyCertRejectExpired] = !ignoreExpiration
   230  	tss.config[TransportLayerSecurityPropertyCertValidateServername] = validateServerName
   231  	if trustStoreFilePath != "" {
   232  		tss.config[TransportLayerSecurityPropertyTrustStorePath] = trustStoreFilePath
   233  	}
   234  	if trustedCommonNameList != "" {
   235  		tss.config[TransportLayerSecurityPropertyTrustedCommonNameList] = trustedCommonNameList
   236  	}
   237  	return tss
   238  }
   239  
   240  // WithCipherSuites configures cipher suites to use. The cipher suites value is a comma-separated
   241  // list of cipher suites and must be from the following table:
   242  //
   243  //	+-----------------+-------------------------------+--------------------+
   244  //	| 'AES256-SHA'    | 'ECDHE-RSA-AES256-SHA'        | 'AES256-GCM-SHA384'|
   245  //	+-----------------+-------------------------------+--------------------+
   246  //	| 'AES256-SHA256' | 'ECDHE-RSA-AES256-GCM-SHA384' | 'AES128-SHA256'    |
   247  //	+-----------------+-------------------------------+--------------------+
   248  //	| 'DES-CBC3-SHA'  | 'ECDHE-RSA-DES-CBC3-SHA'      |                    |
   249  //	+-----------------+-------------------------------+--------------------+
   250  //	| 'RC4-SHA'       | 'ECDHE-RSA-AES256-SHA384'     | 'AES128            |
   251  //	+-----------------+-------------------------------+--------------------+
   252  //	| 'ECDHE-RSA-AES128-SHA256'                       | 'AES128-GCM-SHA256'|
   253  //	+-----------------+-------------------------------+--------------------+
   254  //	| 'RC4-MD5'       | 'ECDHE-RSA-AES128-GCM-SHA256' |                    |
   255  //	+----------------------------------------+-----------------------------+
   256  //	| 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384'| 'ECDHE-RSA-AES128-SHA'      |
   257  //	+----------------------------------------+-----------------------------+
   258  //	| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384'|                             |
   259  //	+----------------------------------------+-----------------------------+
   260  //	| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA'   |                             |
   261  //	+----------------------------------------+-----------------------------+
   262  //	| 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA'  |                             |
   263  //	+----------------------------------------+-----------------------------+
   264  //	| 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'|                             |
   265  //	+----------------------------------------+-----------------------------+
   266  //	| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA'   |                             |
   267  //	+----------------------------------------+-----------------------------+
   268  //	| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256'|                             |
   269  //	+-----------------------------------+----------------------------------+
   270  //	| 'TLS_RSA_WITH_AES_128_GCM_SHA256' |                                  |
   271  //	+-----------------------------------+----------------------------------+
   272  //	| 'TLS_RSA_WITH_AES_128_CBC_SHA256' |'TLS_RSA_WITH_AES_256_GCM_SHA384' |
   273  //	+-----------------------------------+----------------------------------+
   274  //	| 'TLS_RSA_WITH_AES_256_CBC_SHA256' | 'TLS_RSA_WITH_AES_256_CBC_SHA'   |
   275  //	+-----------------------------------+----------------------------------+
   276  //	| 'SSL_RSA_WITH_3DES_EDE_CBC_SHA    | 'TLS_RSA_WITH_AES_128_CBC_SHA'   |
   277  //	+-----------------------------------+----------------------------------+
   278  //	| 'SSL_RSA_WITH_RC4_128_SHA'        | 'SSL_RSA_WITH_RC4_128_MD5'       |
   279  //	+-----------------------------------+----------------------------------+
   280  func (tss TransportSecurityStrategy) WithCipherSuites(cipherSuiteList string) TransportSecurityStrategy {
   281  	tss.config[TransportLayerSecurityPropertyCipherSuites] = cipherSuiteList
   282  	return tss
   283  }
   284  
   285  // ToProperties returns the configuration in the form of a ServicePropertyMap.
   286  func (tss TransportSecurityStrategy) ToProperties() ServicePropertyMap {
   287  	if tss.config == nil {
   288  		return make(ServicePropertyMap)
   289  	}
   290  	return tss.config.GetConfiguration()
   291  }
   292