github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/mongo/options/clientoptions.go (about) 1 // Copyright (C) MongoDB, Inc. 2017-present. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may 4 // not use this file except in compliance with the License. You may obtain 5 // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7 package options // import "go.mongodb.org/mongo-driver/mongo/options" 8 9 import ( 10 "bytes" 11 "context" 12 "crypto/tls" 13 "crypto/x509" 14 "encoding/pem" 15 "errors" 16 "fmt" 17 "io/ioutil" 18 "net" 19 "net/http" 20 "strings" 21 "time" 22 23 "github.com/youmark/pkcs8" 24 "go.mongodb.org/mongo-driver/bson/bsoncodec" 25 "go.mongodb.org/mongo-driver/event" 26 "go.mongodb.org/mongo-driver/internal" 27 "go.mongodb.org/mongo-driver/mongo/readconcern" 28 "go.mongodb.org/mongo-driver/mongo/readpref" 29 "go.mongodb.org/mongo-driver/mongo/writeconcern" 30 "go.mongodb.org/mongo-driver/tag" 31 "go.mongodb.org/mongo-driver/x/mongo/driver" 32 "go.mongodb.org/mongo-driver/x/mongo/driver/connstring" 33 "go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage" 34 ) 35 36 // ContextDialer is an interface that can be implemented by types that can create connections. It should be used to 37 // provide a custom dialer when configuring a Client. 38 // 39 // DialContext should return a connection to the provided address on the given network. 40 type ContextDialer interface { 41 DialContext(ctx context.Context, network, address string) (net.Conn, error) 42 } 43 44 // Credential can be used to provide authentication options when configuring a Client. 45 // 46 // AuthMechanism: the mechanism to use for authentication. Supported values include "SCRAM-SHA-256", "SCRAM-SHA-1", 47 // "MONGODB-CR", "PLAIN", "GSSAPI", "MONGODB-X509", and "MONGODB-AWS". This can also be set through the "authMechanism" 48 // URI option. (e.g. "authMechanism=PLAIN"). For more information, see 49 // https://www.mongodb.com/docs/manual/core/authentication-mechanisms/. 50 // 51 // AuthMechanismProperties can be used to specify additional configuration options for certain mechanisms. They can also 52 // be set through the "authMechanismProperites" URI option 53 // (e.g. "authMechanismProperties=SERVICE_NAME:service,CANONICALIZE_HOST_NAME:true"). Supported properties are: 54 // 55 // 1. SERVICE_NAME: The service name to use for GSSAPI authentication. The default is "mongodb". 56 // 57 // 2. CANONICALIZE_HOST_NAME: If "true", the driver will canonicalize the host name for GSSAPI authentication. The default 58 // is "false". 59 // 60 // 3. SERVICE_REALM: The service realm for GSSAPI authentication. 61 // 62 // 4. SERVICE_HOST: The host name to use for GSSAPI authentication. This should be specified if the host name to use for 63 // authentication is different than the one given for Client construction. 64 // 65 // 4. AWS_SESSION_TOKEN: The AWS token for MONGODB-AWS authentication. This is optional and used for authentication with 66 // temporary credentials. 67 // 68 // The SERVICE_HOST and CANONICALIZE_HOST_NAME properties must not be used at the same time on Linux and Darwin 69 // systems. 70 // 71 // AuthSource: the name of the database to use for authentication. This defaults to "$external" for MONGODB-X509, 72 // GSSAPI, and PLAIN and "admin" for all other mechanisms. This can also be set through the "authSource" URI option 73 // (e.g. "authSource=otherDb"). 74 // 75 // Username: the username for authentication. This can also be set through the URI as a username:password pair before 76 // the first @ character. For example, a URI for user "user", password "pwd", and host "localhost:27017" would be 77 // "mongodb://user:pwd@localhost:27017". This is optional for X509 authentication and will be extracted from the 78 // client certificate if not specified. 79 // 80 // Password: the password for authentication. This must not be specified for X509 and is optional for GSSAPI 81 // authentication. 82 // 83 // PasswordSet: For GSSAPI, this must be true if a password is specified, even if the password is the empty string, and 84 // false if no password is specified, indicating that the password should be taken from the context of the running 85 // process. For other mechanisms, this field is ignored. 86 type Credential struct { 87 AuthMechanism string 88 AuthMechanismProperties map[string]string 89 AuthSource string 90 Username string 91 Password string 92 PasswordSet bool 93 } 94 95 // BSONOptions are optional BSON marshaling and unmarshaling behaviors. 96 type BSONOptions struct { 97 // UseJSONStructTags causes the driver to fall back to using the "json" 98 // struct tag if a "bson" struct tag is not specified. 99 UseJSONStructTags bool 100 101 // ErrorOnInlineDuplicates causes the driver to return an error if there is 102 // a duplicate field in the marshaled BSON when the "inline" struct tag 103 // option is set. 104 ErrorOnInlineDuplicates bool 105 106 // IntMinSize causes the driver to marshal Go integer values (int, int8, 107 // int16, int32, int64, uint, uint8, uint16, uint32, or uint64) as the 108 // minimum BSON int size (either 32 or 64 bits) that can represent the 109 // integer value. 110 IntMinSize bool 111 112 // NilMapAsEmpty causes the driver to marshal nil Go maps as empty BSON 113 // documents instead of BSON null. 114 // 115 // Empty BSON documents take up slightly more space than BSON null, but 116 // preserve the ability to use document update operations like "$set" that 117 // do not work on BSON null. 118 NilMapAsEmpty bool 119 120 // NilSliceAsEmpty causes the driver to marshal nil Go slices as empty BSON 121 // arrays instead of BSON null. 122 // 123 // Empty BSON arrays take up slightly more space than BSON null, but 124 // preserve the ability to use array update operations like "$push" or 125 // "$addToSet" that do not work on BSON null. 126 NilSliceAsEmpty bool 127 128 // NilByteSliceAsEmpty causes the driver to marshal nil Go byte slices as 129 // empty BSON binary values instead of BSON null. 130 NilByteSliceAsEmpty bool 131 132 // OmitZeroStruct causes the driver to consider the zero value for a struct 133 // (e.g. MyStruct{}) as empty and omit it from the marshaled BSON when the 134 // "omitempty" struct tag option is set. 135 OmitZeroStruct bool 136 137 // StringifyMapKeysWithFmt causes the driver to convert Go map keys to BSON 138 // document field name strings using fmt.Sprint instead of the default 139 // string conversion logic. 140 StringifyMapKeysWithFmt bool 141 142 // AllowTruncatingDoubles causes the driver to truncate the fractional part 143 // of BSON "double" values when attempting to unmarshal them into a Go 144 // integer (int, int8, int16, int32, or int64) struct field. The truncation 145 // logic does not apply to BSON "decimal128" values. 146 AllowTruncatingDoubles bool 147 148 // BinaryAsSlice causes the driver to unmarshal BSON binary field values 149 // that are the "Generic" or "Old" BSON binary subtype as a Go byte slice 150 // instead of a primitive.Binary. 151 BinaryAsSlice bool 152 153 // DefaultDocumentD causes the driver to always unmarshal documents into the 154 // primitive.D type. This behavior is restricted to data typed as 155 // "interface{}" or "map[string]interface{}". 156 DefaultDocumentD bool 157 158 // DefaultDocumentM causes the driver to always unmarshal documents into the 159 // primitive.M type. This behavior is restricted to data typed as 160 // "interface{}" or "map[string]interface{}". 161 DefaultDocumentM bool 162 163 // UseLocalTimeZone causes the driver to unmarshal time.Time values in the 164 // local timezone instead of the UTC timezone. 165 UseLocalTimeZone bool 166 167 // ZeroMaps causes the driver to delete any existing values from Go maps in 168 // the destination value before unmarshaling BSON documents into them. 169 ZeroMaps bool 170 171 // ZeroStructs causes the driver to delete any existing values from Go 172 // structs in the destination value before unmarshaling BSON documents into 173 // them. 174 ZeroStructs bool 175 } 176 177 // ClientOptions contains options to configure a Client instance. Each option can be set through setter functions. See 178 // documentation for each setter function for an explanation of the option. 179 type ClientOptions struct { 180 AppName *string 181 Auth *Credential 182 AutoEncryptionOptions *AutoEncryptionOptions 183 ConnectTimeout *time.Duration 184 Compressors []string 185 Dialer ContextDialer 186 Direct *bool 187 DisableOCSPEndpointCheck *bool 188 HeartbeatInterval *time.Duration 189 Hosts []string 190 HTTPClient *http.Client 191 LoadBalanced *bool 192 LocalThreshold *time.Duration 193 LoggerOptions *LoggerOptions 194 MaxConnIdleTime *time.Duration 195 MaxPoolSize *uint64 196 MinPoolSize *uint64 197 MaxConnecting *uint64 198 PoolMonitor *event.PoolMonitor 199 Monitor *event.CommandMonitor 200 ServerMonitor *event.ServerMonitor 201 ReadConcern *readconcern.ReadConcern 202 ReadPreference *readpref.ReadPref 203 BSONOptions *BSONOptions 204 Registry *bsoncodec.Registry 205 ReplicaSet *string 206 RetryReads *bool 207 RetryWrites *bool 208 ServerAPIOptions *ServerAPIOptions 209 ServerSelectionTimeout *time.Duration 210 SRVMaxHosts *int 211 SRVServiceName *string 212 Timeout *time.Duration 213 TLSConfig *tls.Config 214 WriteConcern *writeconcern.WriteConcern 215 ZlibLevel *int 216 ZstdLevel *int 217 218 err error 219 uri string 220 cs *connstring.ConnString 221 222 // AuthenticateToAnything skips server type checks when deciding if authentication is possible. 223 // 224 // Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any 225 // release. 226 AuthenticateToAnything *bool 227 228 // Crypt specifies a custom driver.Crypt to be used to encrypt and decrypt documents. The default is no 229 // encryption. 230 // 231 // Deprecated: This option is for internal use only and should not be set (see GODRIVER-2149). It may be 232 // changed or removed in any release. 233 Crypt driver.Crypt 234 235 // Deployment specifies a custom deployment to use for the new Client. 236 // 237 // Deprecated: This option is for internal use only and should not be set. It may be changed or removed in any 238 // release. 239 Deployment driver.Deployment 240 241 // SocketTimeout specifies the timeout to be used for the Client's socket reads and writes. 242 // 243 // NOTE(benjirewis): SocketTimeout will be deprecated in a future release. The more general Timeout option 244 // may be used in its place to control the amount of time that a single operation can run before returning 245 // an error. Setting SocketTimeout and Timeout on a single client will result in undefined behavior. 246 SocketTimeout *time.Duration 247 } 248 249 // Client creates a new ClientOptions instance. 250 func Client() *ClientOptions { 251 return &ClientOptions{ 252 HTTPClient: internal.DefaultHTTPClient, 253 } 254 } 255 256 // Validate validates the client options. This method will return the first error found. 257 func (c *ClientOptions) Validate() error { 258 if c.err != nil { 259 return c.err 260 } 261 c.err = c.validate() 262 return c.err 263 } 264 265 func (c *ClientOptions) validate() error { 266 // Direct connections cannot be made if multiple hosts are specified or an SRV URI is used. 267 if c.Direct != nil && *c.Direct { 268 if len(c.Hosts) > 1 { 269 return errors.New("a direct connection cannot be made if multiple hosts are specified") 270 } 271 if c.cs != nil && c.cs.Scheme == connstring.SchemeMongoDBSRV { 272 return errors.New("a direct connection cannot be made if an SRV URI is used") 273 } 274 } 275 276 if c.MaxPoolSize != nil && c.MinPoolSize != nil && *c.MaxPoolSize != 0 && *c.MinPoolSize > *c.MaxPoolSize { 277 return fmt.Errorf("minPoolSize must be less than or equal to maxPoolSize, got minPoolSize=%d maxPoolSize=%d", *c.MinPoolSize, *c.MaxPoolSize) 278 } 279 280 // verify server API version if ServerAPIOptions are passed in. 281 if c.ServerAPIOptions != nil { 282 if err := c.ServerAPIOptions.ServerAPIVersion.Validate(); err != nil { 283 return err 284 } 285 } 286 287 // Validation for load-balanced mode. 288 if c.LoadBalanced != nil && *c.LoadBalanced { 289 if len(c.Hosts) > 1 { 290 return internal.ErrLoadBalancedWithMultipleHosts 291 } 292 if c.ReplicaSet != nil { 293 return internal.ErrLoadBalancedWithReplicaSet 294 } 295 if c.Direct != nil && *c.Direct { 296 return internal.ErrLoadBalancedWithDirectConnection 297 } 298 } 299 300 // Validation for srvMaxHosts. 301 if c.SRVMaxHosts != nil && *c.SRVMaxHosts > 0 { 302 if c.ReplicaSet != nil { 303 return internal.ErrSRVMaxHostsWithReplicaSet 304 } 305 if c.LoadBalanced != nil && *c.LoadBalanced { 306 return internal.ErrSRVMaxHostsWithLoadBalanced 307 } 308 } 309 return nil 310 } 311 312 // GetURI returns the original URI used to configure the ClientOptions instance. If ApplyURI was not called during 313 // construction, this returns "". 314 func (c *ClientOptions) GetURI() string { 315 return c.uri 316 } 317 318 // ApplyURI parses the given URI and sets options accordingly. The URI can contain host names, IPv4/IPv6 literals, or 319 // an SRV record that will be resolved when the Client is created. When using an SRV record, TLS support is 320 // implictly enabled. Specify the "tls=false" URI option to override this. 321 // 322 // If the connection string contains any options that have previously been set, it will overwrite them. Options that 323 // correspond to multiple URI parameters, such as WriteConcern, will be completely overwritten if any of the query 324 // parameters are specified. If an option is set on ClientOptions after this method is called, that option will override 325 // any option applied via the connection string. 326 // 327 // If the URI format is incorrect or there are conflicting options specified in the URI an error will be recorded and 328 // can be retrieved by calling Validate. 329 // 330 // For more information about the URI format, see https://www.mongodb.com/docs/manual/reference/connection-string/. See 331 // mongo.Connect documentation for examples of using URIs for different Client configurations. 332 func (c *ClientOptions) ApplyURI(uri string) *ClientOptions { 333 if c.err != nil { 334 return c 335 } 336 337 c.uri = uri 338 cs, err := connstring.ParseAndValidate(uri) 339 if err != nil { 340 c.err = err 341 return c 342 } 343 c.cs = &cs 344 345 if cs.AppName != "" { 346 c.AppName = &cs.AppName 347 } 348 349 // Only create a Credential if there is a request for authentication via non-empty credentials in the URI. 350 if cs.HasAuthParameters() { 351 c.Auth = &Credential{ 352 AuthMechanism: cs.AuthMechanism, 353 AuthMechanismProperties: cs.AuthMechanismProperties, 354 AuthSource: cs.AuthSource, 355 Username: cs.Username, 356 Password: cs.Password, 357 PasswordSet: cs.PasswordSet, 358 } 359 } 360 361 if cs.ConnectSet { 362 direct := cs.Connect == connstring.SingleConnect 363 c.Direct = &direct 364 } 365 366 if cs.DirectConnectionSet { 367 c.Direct = &cs.DirectConnection 368 } 369 370 if cs.ConnectTimeoutSet { 371 c.ConnectTimeout = &cs.ConnectTimeout 372 } 373 374 if len(cs.Compressors) > 0 { 375 c.Compressors = cs.Compressors 376 if stringSliceContains(c.Compressors, "zlib") { 377 defaultLevel := wiremessage.DefaultZlibLevel 378 c.ZlibLevel = &defaultLevel 379 } 380 if stringSliceContains(c.Compressors, "zstd") { 381 defaultLevel := wiremessage.DefaultZstdLevel 382 c.ZstdLevel = &defaultLevel 383 } 384 } 385 386 if cs.HeartbeatIntervalSet { 387 c.HeartbeatInterval = &cs.HeartbeatInterval 388 } 389 390 c.Hosts = cs.Hosts 391 392 if cs.LoadBalancedSet { 393 c.LoadBalanced = &cs.LoadBalanced 394 } 395 396 if cs.LocalThresholdSet { 397 c.LocalThreshold = &cs.LocalThreshold 398 } 399 400 if cs.MaxConnIdleTimeSet { 401 c.MaxConnIdleTime = &cs.MaxConnIdleTime 402 } 403 404 if cs.MaxPoolSizeSet { 405 c.MaxPoolSize = &cs.MaxPoolSize 406 } 407 408 if cs.MinPoolSizeSet { 409 c.MinPoolSize = &cs.MinPoolSize 410 } 411 412 if cs.MaxConnectingSet { 413 c.MaxConnecting = &cs.MaxConnecting 414 } 415 416 if cs.ReadConcernLevel != "" { 417 c.ReadConcern = readconcern.New(readconcern.Level(cs.ReadConcernLevel)) 418 } 419 420 if cs.ReadPreference != "" || len(cs.ReadPreferenceTagSets) > 0 || cs.MaxStalenessSet { 421 opts := make([]readpref.Option, 0, 1) 422 423 tagSets := tag.NewTagSetsFromMaps(cs.ReadPreferenceTagSets) 424 if len(tagSets) > 0 { 425 opts = append(opts, readpref.WithTagSets(tagSets...)) 426 } 427 428 if cs.MaxStaleness != 0 { 429 opts = append(opts, readpref.WithMaxStaleness(cs.MaxStaleness)) 430 } 431 432 mode, err := readpref.ModeFromString(cs.ReadPreference) 433 if err != nil { 434 c.err = err 435 return c 436 } 437 438 c.ReadPreference, c.err = readpref.New(mode, opts...) 439 if c.err != nil { 440 return c 441 } 442 } 443 444 if cs.RetryWritesSet { 445 c.RetryWrites = &cs.RetryWrites 446 } 447 448 if cs.RetryReadsSet { 449 c.RetryReads = &cs.RetryReads 450 } 451 452 if cs.ReplicaSet != "" { 453 c.ReplicaSet = &cs.ReplicaSet 454 } 455 456 if cs.ServerSelectionTimeoutSet { 457 c.ServerSelectionTimeout = &cs.ServerSelectionTimeout 458 } 459 460 if cs.SocketTimeoutSet { 461 c.SocketTimeout = &cs.SocketTimeout 462 } 463 464 if cs.SRVMaxHosts != 0 { 465 c.SRVMaxHosts = &cs.SRVMaxHosts 466 } 467 468 if cs.SRVServiceName != "" { 469 c.SRVServiceName = &cs.SRVServiceName 470 } 471 472 if cs.SSL { 473 tlsConfig := new(tls.Config) 474 475 if cs.SSLCaFileSet { 476 c.err = addCACertFromFile(tlsConfig, cs.SSLCaFile) 477 if c.err != nil { 478 return c 479 } 480 } 481 482 if cs.SSLInsecure { 483 tlsConfig.InsecureSkipVerify = true 484 } 485 486 var x509Subject string 487 var keyPasswd string 488 if cs.SSLClientCertificateKeyPasswordSet && cs.SSLClientCertificateKeyPassword != nil { 489 keyPasswd = cs.SSLClientCertificateKeyPassword() 490 } 491 if cs.SSLClientCertificateKeyFileSet { 492 x509Subject, err = addClientCertFromConcatenatedFile(tlsConfig, cs.SSLClientCertificateKeyFile, keyPasswd) 493 } else if cs.SSLCertificateFileSet || cs.SSLPrivateKeyFileSet { 494 x509Subject, err = addClientCertFromSeparateFiles(tlsConfig, cs.SSLCertificateFile, 495 cs.SSLPrivateKeyFile, keyPasswd) 496 } 497 if err != nil { 498 c.err = err 499 return c 500 } 501 502 // If a username wasn't specified fork x509, add one from the certificate. 503 if c.Auth != nil && strings.ToLower(c.Auth.AuthMechanism) == "mongodb-x509" && 504 c.Auth.Username == "" { 505 506 // The Go x509 package gives the subject with the pairs in reverse order that we want. 507 c.Auth.Username = extractX509UsernameFromSubject(x509Subject) 508 } 509 510 c.TLSConfig = tlsConfig 511 } 512 513 if cs.JSet || cs.WString != "" || cs.WNumberSet || cs.WTimeoutSet { 514 opts := make([]writeconcern.Option, 0, 1) 515 516 if len(cs.WString) > 0 { 517 opts = append(opts, writeconcern.WTagSet(cs.WString)) 518 } else if cs.WNumberSet { 519 opts = append(opts, writeconcern.W(cs.WNumber)) 520 } 521 522 if cs.JSet { 523 opts = append(opts, writeconcern.J(cs.J)) 524 } 525 526 if cs.WTimeoutSet { 527 opts = append(opts, writeconcern.WTimeout(cs.WTimeout)) 528 } 529 530 c.WriteConcern = writeconcern.New(opts...) 531 } 532 533 if cs.ZlibLevelSet { 534 c.ZlibLevel = &cs.ZlibLevel 535 } 536 if cs.ZstdLevelSet { 537 c.ZstdLevel = &cs.ZstdLevel 538 } 539 540 if cs.SSLDisableOCSPEndpointCheckSet { 541 c.DisableOCSPEndpointCheck = &cs.SSLDisableOCSPEndpointCheck 542 } 543 544 if cs.TimeoutSet { 545 c.Timeout = &cs.Timeout 546 } 547 548 return c 549 } 550 551 // SetAppName specifies an application name that is sent to the server when creating new connections. It is used by the 552 // server to log connection and profiling information (e.g. slow query logs). This can also be set through the "appName" 553 // URI option (e.g "appName=example_application"). The default is empty, meaning no app name will be sent. 554 func (c *ClientOptions) SetAppName(s string) *ClientOptions { 555 c.AppName = &s 556 return c 557 } 558 559 // SetAuth specifies a Credential containing options for configuring authentication. See the options.Credential 560 // documentation for more information about Credential fields. The default is an empty Credential, meaning no 561 // authentication will be configured. 562 func (c *ClientOptions) SetAuth(auth Credential) *ClientOptions { 563 c.Auth = &auth 564 return c 565 } 566 567 // SetCompressors sets the compressors that can be used when communicating with a server. Valid values are: 568 // 569 // 1. "snappy" - requires server version >= 3.4 570 // 571 // 2. "zlib" - requires server version >= 3.6 572 // 573 // 3. "zstd" - requires server version >= 4.2, and driver version >= 1.2.0 with cgo support enabled or driver 574 // version >= 1.3.0 without cgo. 575 // 576 // If this option is specified, the driver will perform a negotiation with the server to determine a common list of of 577 // compressors and will use the first one in that list when performing operations. See 578 // https://www.mongodb.com/docs/manual/reference/program/mongod/#cmdoption-mongod-networkmessagecompressors for more 579 // information about configuring compression on the server and the server-side defaults. 580 // 581 // This can also be set through the "compressors" URI option (e.g. "compressors=zstd,zlib,snappy"). The default is 582 // an empty slice, meaning no compression will be enabled. 583 func (c *ClientOptions) SetCompressors(comps []string) *ClientOptions { 584 c.Compressors = comps 585 586 return c 587 } 588 589 // SetConnectTimeout specifies a timeout that is used for creating connections to the server. If a custom Dialer is 590 // specified through SetDialer, this option must not be used. This can be set through ApplyURI with the 591 // "connectTimeoutMS" (e.g "connectTimeoutMS=30") option. If set to 0, no timeout will be used. The default is 30 592 // seconds. 593 func (c *ClientOptions) SetConnectTimeout(d time.Duration) *ClientOptions { 594 c.ConnectTimeout = &d 595 return c 596 } 597 598 // SetDialer specifies a custom ContextDialer to be used to create new connections to the server. The default is a 599 // net.Dialer with the Timeout field set to ConnectTimeout. See https://golang.org/pkg/net/#Dialer for more information 600 // about the net.Dialer type. 601 func (c *ClientOptions) SetDialer(d ContextDialer) *ClientOptions { 602 c.Dialer = d 603 return c 604 } 605 606 // SetDirect specifies whether or not a direct connect should be made. If set to true, the driver will only connect to 607 // the host provided in the URI and will not discover other hosts in the cluster. This can also be set through the 608 // "directConnection" URI option. This option cannot be set to true if multiple hosts are specified, either through 609 // ApplyURI or SetHosts, or an SRV URI is used. 610 // 611 // As of driver version 1.4, the "connect" URI option has been deprecated and replaced with "directConnection". The 612 // "connect" URI option has two values: 613 // 614 // 1. "connect=direct" for direct connections. This corresponds to "directConnection=true". 615 // 616 // 2. "connect=automatic" for automatic discovery. This corresponds to "directConnection=false" 617 // 618 // If the "connect" and "directConnection" URI options are both specified in the connection string, their values must 619 // not conflict. Direct connections are not valid if multiple hosts are specified or an SRV URI is used. The default 620 // value for this option is false. 621 func (c *ClientOptions) SetDirect(b bool) *ClientOptions { 622 c.Direct = &b 623 return c 624 } 625 626 // SetHeartbeatInterval specifies the amount of time to wait between periodic background server checks. This can also be 627 // set through the "heartbeatIntervalMS" URI option (e.g. "heartbeatIntervalMS=10000"). The default is 10 seconds. 628 func (c *ClientOptions) SetHeartbeatInterval(d time.Duration) *ClientOptions { 629 c.HeartbeatInterval = &d 630 return c 631 } 632 633 // SetHosts specifies a list of host names or IP addresses for servers in a cluster. Both IPv4 and IPv6 addresses are 634 // supported. IPv6 literals must be enclosed in '[]' following RFC-2732 syntax. 635 // 636 // Hosts can also be specified as a comma-separated list in a URI. For example, to include "localhost:27017" and 637 // "localhost:27018", a URI could be "mongodb://localhost:27017,localhost:27018". The default is ["localhost:27017"] 638 func (c *ClientOptions) SetHosts(s []string) *ClientOptions { 639 c.Hosts = s 640 return c 641 } 642 643 // SetLoadBalanced specifies whether or not the MongoDB deployment is hosted behind a load balancer. This can also be 644 // set through the "loadBalanced" URI option. The driver will error during Client configuration if this option is set 645 // to true and one of the following conditions are met: 646 // 647 // 1. Multiple hosts are specified, either via the ApplyURI or SetHosts methods. This includes the case where an SRV 648 // URI is used and the SRV record resolves to multiple hostnames. 649 // 2. A replica set name is specified, either via the URI or the SetReplicaSet method. 650 // 3. The options specify whether or not a direct connection should be made, either via the URI or the SetDirect method. 651 // 652 // The default value is false. 653 func (c *ClientOptions) SetLoadBalanced(lb bool) *ClientOptions { 654 c.LoadBalanced = &lb 655 return c 656 } 657 658 // SetLocalThreshold specifies the width of the 'latency window': when choosing between multiple suitable servers for an 659 // operation, this is the acceptable non-negative delta between shortest and longest average round-trip times. A server 660 // within the latency window is selected randomly. This can also be set through the "localThresholdMS" URI option (e.g. 661 // "localThresholdMS=15000"). The default is 15 milliseconds. 662 func (c *ClientOptions) SetLocalThreshold(d time.Duration) *ClientOptions { 663 c.LocalThreshold = &d 664 return c 665 } 666 667 // SetLoggerOptions specifies a LoggerOptions containing options for 668 // configuring a logger. 669 func (c *ClientOptions) SetLoggerOptions(opts *LoggerOptions) *ClientOptions { 670 c.LoggerOptions = opts 671 672 return c 673 } 674 675 // SetMaxConnIdleTime specifies the maximum amount of time that a connection will remain idle in a connection pool 676 // before it is removed from the pool and closed. This can also be set through the "maxIdleTimeMS" URI option (e.g. 677 // "maxIdleTimeMS=10000"). The default is 0, meaning a connection can remain unused indefinitely. 678 func (c *ClientOptions) SetMaxConnIdleTime(d time.Duration) *ClientOptions { 679 c.MaxConnIdleTime = &d 680 return c 681 } 682 683 // SetMaxPoolSize specifies that maximum number of connections allowed in the driver's connection pool to each server. 684 // Requests to a server will block if this maximum is reached. This can also be set through the "maxPoolSize" URI option 685 // (e.g. "maxPoolSize=100"). If this is 0, maximum connection pool size is not limited. The default is 100. 686 func (c *ClientOptions) SetMaxPoolSize(u uint64) *ClientOptions { 687 c.MaxPoolSize = &u 688 return c 689 } 690 691 // SetMinPoolSize specifies the minimum number of connections allowed in the driver's connection pool to each server. If 692 // this is non-zero, each server's pool will be maintained in the background to ensure that the size does not fall below 693 // the minimum. This can also be set through the "minPoolSize" URI option (e.g. "minPoolSize=100"). The default is 0. 694 func (c *ClientOptions) SetMinPoolSize(u uint64) *ClientOptions { 695 c.MinPoolSize = &u 696 return c 697 } 698 699 // SetMaxConnecting specifies the maximum number of connections a connection pool may establish simultaneously. This can 700 // also be set through the "maxConnecting" URI option (e.g. "maxConnecting=2"). If this is 0, the default is used. The 701 // default is 2. Values greater than 100 are not recommended. 702 func (c *ClientOptions) SetMaxConnecting(u uint64) *ClientOptions { 703 c.MaxConnecting = &u 704 return c 705 } 706 707 // SetPoolMonitor specifies a PoolMonitor to receive connection pool events. See the event.PoolMonitor documentation 708 // for more information about the structure of the monitor and events that can be received. 709 func (c *ClientOptions) SetPoolMonitor(m *event.PoolMonitor) *ClientOptions { 710 c.PoolMonitor = m 711 return c 712 } 713 714 // SetMonitor specifies a CommandMonitor to receive command events. See the event.CommandMonitor documentation for more 715 // information about the structure of the monitor and events that can be received. 716 func (c *ClientOptions) SetMonitor(m *event.CommandMonitor) *ClientOptions { 717 c.Monitor = m 718 return c 719 } 720 721 // SetServerMonitor specifies an SDAM monitor used to monitor SDAM events. 722 func (c *ClientOptions) SetServerMonitor(m *event.ServerMonitor) *ClientOptions { 723 c.ServerMonitor = m 724 return c 725 } 726 727 // SetReadConcern specifies the read concern to use for read operations. A read concern level can also be set through 728 // the "readConcernLevel" URI option (e.g. "readConcernLevel=majority"). The default is nil, meaning the server will use 729 // its configured default. 730 func (c *ClientOptions) SetReadConcern(rc *readconcern.ReadConcern) *ClientOptions { 731 c.ReadConcern = rc 732 733 return c 734 } 735 736 // SetReadPreference specifies the read preference to use for read operations. This can also be set through the 737 // following URI options: 738 // 739 // 1. "readPreference" - Specify the read preference mode (e.g. "readPreference=primary"). 740 // 741 // 2. "readPreferenceTags": Specify one or more read preference tags 742 // (e.g. "readPreferenceTags=region:south,datacenter:A"). 743 // 744 // 3. "maxStalenessSeconds" (or "maxStaleness"): Specify a maximum replication lag for reads from secondaries in a 745 // replica set (e.g. "maxStalenessSeconds=10"). 746 // 747 // The default is readpref.Primary(). See https://www.mongodb.com/docs/manual/core/read-preference/#read-preference for 748 // more information about read preferences. 749 func (c *ClientOptions) SetReadPreference(rp *readpref.ReadPref) *ClientOptions { 750 c.ReadPreference = rp 751 752 return c 753 } 754 755 // SetBSONOptions configures optional BSON marshaling and unmarshaling behavior. 756 func (c *ClientOptions) SetBSONOptions(opts *BSONOptions) *ClientOptions { 757 c.BSONOptions = opts 758 return c 759 } 760 761 // SetRegistry specifies the BSON registry to use for BSON marshalling/unmarshalling operations. The default is 762 // bson.DefaultRegistry. 763 func (c *ClientOptions) SetRegistry(registry *bsoncodec.Registry) *ClientOptions { 764 c.Registry = registry 765 return c 766 } 767 768 // SetReplicaSet specifies the replica set name for the cluster. If specified, the cluster will be treated as a replica 769 // set and the driver will automatically discover all servers in the set, starting with the nodes specified through 770 // ApplyURI or SetHosts. All nodes in the replica set must have the same replica set name, or they will not be 771 // considered as part of the set by the Client. This can also be set through the "replicaSet" URI option (e.g. 772 // "replicaSet=replset"). The default is empty. 773 func (c *ClientOptions) SetReplicaSet(s string) *ClientOptions { 774 c.ReplicaSet = &s 775 return c 776 } 777 778 // SetRetryWrites specifies whether supported write operations should be retried once on certain errors, such as network 779 // errors. 780 // 781 // Supported operations are InsertOne, UpdateOne, ReplaceOne, DeleteOne, FindOneAndDelete, FindOneAndReplace, 782 // FindOneAndDelete, InsertMany, and BulkWrite. Note that BulkWrite requests must not include UpdateManyModel or 783 // DeleteManyModel instances to be considered retryable. Unacknowledged writes will not be retried, even if this option 784 // is set to true. 785 // 786 // This option requires server version >= 3.6 and a replica set or sharded cluster and will be ignored for any other 787 // cluster type. This can also be set through the "retryWrites" URI option (e.g. "retryWrites=true"). The default is 788 // true. 789 func (c *ClientOptions) SetRetryWrites(b bool) *ClientOptions { 790 c.RetryWrites = &b 791 792 return c 793 } 794 795 // SetRetryReads specifies whether supported read operations should be retried once on certain errors, such as network 796 // errors. 797 // 798 // Supported operations are Find, FindOne, Aggregate without a $out stage, Distinct, CountDocuments, 799 // EstimatedDocumentCount, Watch (for Client, Database, and Collection), ListCollections, and ListDatabases. Note that 800 // operations run through RunCommand are not retried. 801 // 802 // This option requires server version >= 3.6 and driver version >= 1.1.0. The default is true. 803 func (c *ClientOptions) SetRetryReads(b bool) *ClientOptions { 804 c.RetryReads = &b 805 return c 806 } 807 808 // SetServerSelectionTimeout specifies how long the driver will wait to find an available, suitable server to execute an 809 // operation. This can also be set through the "serverSelectionTimeoutMS" URI option (e.g. 810 // "serverSelectionTimeoutMS=30000"). The default value is 30 seconds. 811 func (c *ClientOptions) SetServerSelectionTimeout(d time.Duration) *ClientOptions { 812 c.ServerSelectionTimeout = &d 813 return c 814 } 815 816 // SetSocketTimeout specifies how long the driver will wait for a socket read or write to return before returning a 817 // network error. This can also be set through the "socketTimeoutMS" URI option (e.g. "socketTimeoutMS=1000"). The 818 // default value is 0, meaning no timeout is used and socket operations can block indefinitely. 819 // 820 // NOTE(benjirewis): SocketTimeout will be deprecated in a future release. The more general Timeout option may be used 821 // in its place to control the amount of time that a single operation can run before returning an error. Setting 822 // SocketTimeout and Timeout on a single client will result in undefined behavior. 823 func (c *ClientOptions) SetSocketTimeout(d time.Duration) *ClientOptions { 824 c.SocketTimeout = &d 825 return c 826 } 827 828 // SetTimeout specifies the amount of time that a single operation run on this Client can execute before returning an error. 829 // The deadline of any operation run through the Client will be honored above any Timeout set on the Client; Timeout will only 830 // be honored if there is no deadline on the operation Context. Timeout can also be set through the "timeoutMS" URI option 831 // (e.g. "timeoutMS=1000"). The default value is nil, meaning operations do not inherit a timeout from the Client. 832 // 833 // If any Timeout is set (even 0) on the Client, the values of MaxTime on operation options, TransactionOptions.MaxCommitTime and 834 // SessionOptions.DefaultMaxCommitTime will be ignored. Setting Timeout and SocketTimeout or WriteConcern.wTimeout will result 835 // in undefined behavior. 836 // 837 // NOTE(benjirewis): SetTimeout represents unstable, provisional API. The behavior of the driver when a Timeout is specified is 838 // subject to change. 839 func (c *ClientOptions) SetTimeout(d time.Duration) *ClientOptions { 840 c.Timeout = &d 841 return c 842 } 843 844 // SetTLSConfig specifies a tls.Config instance to use use to configure TLS on all connections created to the cluster. 845 // This can also be set through the following URI options: 846 // 847 // 1. "tls" (or "ssl"): Specify if TLS should be used (e.g. "tls=true"). 848 // 849 // 2. Either "tlsCertificateKeyFile" (or "sslClientCertificateKeyFile") or a combination of "tlsCertificateFile" and 850 // "tlsPrivateKeyFile". The "tlsCertificateKeyFile" option specifies a path to the client certificate and private key, 851 // which must be concatenated into one file. The "tlsCertificateFile" and "tlsPrivateKey" combination specifies separate 852 // paths to the client certificate and private key, respectively. Note that if "tlsCertificateKeyFile" is used, the 853 // other two options must not be specified. Only the subject name of the first certificate is honored as the username 854 // for X509 auth in a file with multiple certs. 855 // 856 // 3. "tlsCertificateKeyFilePassword" (or "sslClientCertificateKeyPassword"): Specify the password to decrypt the client 857 // private key file (e.g. "tlsCertificateKeyFilePassword=password"). 858 // 859 // 4. "tlsCaFile" (or "sslCertificateAuthorityFile"): Specify the path to a single or bundle of certificate authorities 860 // to be considered trusted when making a TLS connection (e.g. "tlsCaFile=/path/to/caFile"). 861 // 862 // 5. "tlsInsecure" (or "sslInsecure"): Specifies whether or not certificates and hostnames received from the server 863 // should be validated. If true (e.g. "tlsInsecure=true"), the TLS library will accept any certificate presented by the 864 // server and any host name in that certificate. Note that setting this to true makes TLS susceptible to 865 // man-in-the-middle attacks and should only be done for testing. 866 // 867 // The default is nil, meaning no TLS will be enabled. 868 func (c *ClientOptions) SetTLSConfig(cfg *tls.Config) *ClientOptions { 869 c.TLSConfig = cfg 870 return c 871 } 872 873 // SetHTTPClient specifies the http.Client to be used for any HTTP requests. 874 // 875 // This should only be used to set custom HTTP client configurations. By default, the connection will use an internal.DefaultHTTPClient. 876 func (c *ClientOptions) SetHTTPClient(client *http.Client) *ClientOptions { 877 c.HTTPClient = client 878 return c 879 } 880 881 // SetWriteConcern specifies the write concern to use to for write operations. This can also be set through the following 882 // URI options: 883 // 884 // 1. "w": Specify the number of nodes in the cluster that must acknowledge write operations before the operation 885 // returns or "majority" to specify that a majority of the nodes must acknowledge writes. This can either be an integer 886 // (e.g. "w=10") or the string "majority" (e.g. "w=majority"). 887 // 888 // 2. "wTimeoutMS": Specify how long write operations should wait for the correct number of nodes to acknowledge the 889 // operation (e.g. "wTimeoutMS=1000"). 890 // 891 // 3. "journal": Specifies whether or not write operations should be written to an on-disk journal on the server before 892 // returning (e.g. "journal=true"). 893 // 894 // The default is nil, meaning the server will use its configured default. 895 func (c *ClientOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *ClientOptions { 896 c.WriteConcern = wc 897 898 return c 899 } 900 901 // SetZlibLevel specifies the level for the zlib compressor. This option is ignored if zlib is not specified as a 902 // compressor through ApplyURI or SetCompressors. Supported values are -1 through 9, inclusive. -1 tells the zlib 903 // library to use its default, 0 means no compression, 1 means best speed, and 9 means best compression. 904 // This can also be set through the "zlibCompressionLevel" URI option (e.g. "zlibCompressionLevel=-1"). Defaults to -1. 905 func (c *ClientOptions) SetZlibLevel(level int) *ClientOptions { 906 c.ZlibLevel = &level 907 908 return c 909 } 910 911 // SetZstdLevel sets the level for the zstd compressor. This option is ignored if zstd is not specified as a compressor 912 // through ApplyURI or SetCompressors. Supported values are 1 through 20, inclusive. 1 means best speed and 20 means 913 // best compression. This can also be set through the "zstdCompressionLevel" URI option. Defaults to 6. 914 func (c *ClientOptions) SetZstdLevel(level int) *ClientOptions { 915 c.ZstdLevel = &level 916 return c 917 } 918 919 // SetAutoEncryptionOptions specifies an AutoEncryptionOptions instance to automatically encrypt and decrypt commands 920 // and their results. See the options.AutoEncryptionOptions documentation for more information about the supported 921 // options. 922 func (c *ClientOptions) SetAutoEncryptionOptions(opts *AutoEncryptionOptions) *ClientOptions { 923 c.AutoEncryptionOptions = opts 924 return c 925 } 926 927 // SetDisableOCSPEndpointCheck specifies whether or not the driver should reach out to OCSP responders to verify the 928 // certificate status for certificates presented by the server that contain a list of OCSP responders. 929 // 930 // If set to true, the driver will verify the status of the certificate using a response stapled by the server, if there 931 // is one, but will not send an HTTP request to any responders if there is no staple. In this case, the driver will 932 // continue the connection even though the certificate status is not known. 933 // 934 // This can also be set through the tlsDisableOCSPEndpointCheck URI option. Both this URI option and tlsInsecure must 935 // not be set at the same time and will error if they are. The default value is false. 936 func (c *ClientOptions) SetDisableOCSPEndpointCheck(disableCheck bool) *ClientOptions { 937 c.DisableOCSPEndpointCheck = &disableCheck 938 return c 939 } 940 941 // SetServerAPIOptions specifies a ServerAPIOptions instance used to configure the API version sent to the server 942 // when running commands. See the options.ServerAPIOptions documentation for more information about the supported 943 // options. 944 func (c *ClientOptions) SetServerAPIOptions(opts *ServerAPIOptions) *ClientOptions { 945 c.ServerAPIOptions = opts 946 return c 947 } 948 949 // SetSRVMaxHosts specifies the maximum number of SRV results to randomly select during polling. To limit the number 950 // of hosts selected in SRV discovery, this function must be called before ApplyURI. This can also be set through 951 // the "srvMaxHosts" URI option. 952 func (c *ClientOptions) SetSRVMaxHosts(srvMaxHosts int) *ClientOptions { 953 c.SRVMaxHosts = &srvMaxHosts 954 return c 955 } 956 957 // SetSRVServiceName specifies a custom SRV service name to use in SRV polling. To use a custom SRV service name 958 // in SRV discovery, this function must be called before ApplyURI. This can also be set through the "srvServiceName" 959 // URI option. 960 func (c *ClientOptions) SetSRVServiceName(srvName string) *ClientOptions { 961 c.SRVServiceName = &srvName 962 return c 963 } 964 965 // MergeClientOptions combines the given *ClientOptions into a single *ClientOptions in a last one wins fashion. 966 // The specified options are merged with the existing options on the client, with the specified options taking 967 // precedence. 968 // 969 // Deprecated: Merging options structs will not be supported in Go Driver 2.0. Users should create a 970 // single options struct instead. 971 func MergeClientOptions(opts ...*ClientOptions) *ClientOptions { 972 c := Client() 973 974 for _, opt := range opts { 975 if opt == nil { 976 continue 977 } 978 979 if opt.Dialer != nil { 980 c.Dialer = opt.Dialer 981 } 982 if opt.AppName != nil { 983 c.AppName = opt.AppName 984 } 985 if opt.Auth != nil { 986 c.Auth = opt.Auth 987 } 988 if opt.AuthenticateToAnything != nil { 989 c.AuthenticateToAnything = opt.AuthenticateToAnything 990 } 991 if opt.Compressors != nil { 992 c.Compressors = opt.Compressors 993 } 994 if opt.ConnectTimeout != nil { 995 c.ConnectTimeout = opt.ConnectTimeout 996 } 997 if opt.Crypt != nil { 998 c.Crypt = opt.Crypt 999 } 1000 if opt.HeartbeatInterval != nil { 1001 c.HeartbeatInterval = opt.HeartbeatInterval 1002 } 1003 if len(opt.Hosts) > 0 { 1004 c.Hosts = opt.Hosts 1005 } 1006 if opt.HTTPClient != nil { 1007 c.HTTPClient = opt.HTTPClient 1008 } 1009 if opt.LoadBalanced != nil { 1010 c.LoadBalanced = opt.LoadBalanced 1011 } 1012 if opt.LocalThreshold != nil { 1013 c.LocalThreshold = opt.LocalThreshold 1014 } 1015 if opt.MaxConnIdleTime != nil { 1016 c.MaxConnIdleTime = opt.MaxConnIdleTime 1017 } 1018 if opt.MaxPoolSize != nil { 1019 c.MaxPoolSize = opt.MaxPoolSize 1020 } 1021 if opt.MinPoolSize != nil { 1022 c.MinPoolSize = opt.MinPoolSize 1023 } 1024 if opt.MaxConnecting != nil { 1025 c.MaxConnecting = opt.MaxConnecting 1026 } 1027 if opt.PoolMonitor != nil { 1028 c.PoolMonitor = opt.PoolMonitor 1029 } 1030 if opt.Monitor != nil { 1031 c.Monitor = opt.Monitor 1032 } 1033 if opt.ServerAPIOptions != nil { 1034 c.ServerAPIOptions = opt.ServerAPIOptions 1035 } 1036 if opt.ServerMonitor != nil { 1037 c.ServerMonitor = opt.ServerMonitor 1038 } 1039 if opt.ReadConcern != nil { 1040 c.ReadConcern = opt.ReadConcern 1041 } 1042 if opt.ReadPreference != nil { 1043 c.ReadPreference = opt.ReadPreference 1044 } 1045 if opt.BSONOptions != nil { 1046 c.BSONOptions = opt.BSONOptions 1047 } 1048 if opt.Registry != nil { 1049 c.Registry = opt.Registry 1050 } 1051 if opt.ReplicaSet != nil { 1052 c.ReplicaSet = opt.ReplicaSet 1053 } 1054 if opt.RetryWrites != nil { 1055 c.RetryWrites = opt.RetryWrites 1056 } 1057 if opt.RetryReads != nil { 1058 c.RetryReads = opt.RetryReads 1059 } 1060 if opt.ServerSelectionTimeout != nil { 1061 c.ServerSelectionTimeout = opt.ServerSelectionTimeout 1062 } 1063 if opt.Direct != nil { 1064 c.Direct = opt.Direct 1065 } 1066 if opt.SocketTimeout != nil { 1067 c.SocketTimeout = opt.SocketTimeout 1068 } 1069 if opt.SRVMaxHosts != nil { 1070 c.SRVMaxHosts = opt.SRVMaxHosts 1071 } 1072 if opt.SRVServiceName != nil { 1073 c.SRVServiceName = opt.SRVServiceName 1074 } 1075 if opt.Timeout != nil { 1076 c.Timeout = opt.Timeout 1077 } 1078 if opt.TLSConfig != nil { 1079 c.TLSConfig = opt.TLSConfig 1080 } 1081 if opt.WriteConcern != nil { 1082 c.WriteConcern = opt.WriteConcern 1083 } 1084 if opt.ZlibLevel != nil { 1085 c.ZlibLevel = opt.ZlibLevel 1086 } 1087 if opt.ZstdLevel != nil { 1088 c.ZstdLevel = opt.ZstdLevel 1089 } 1090 if opt.AutoEncryptionOptions != nil { 1091 c.AutoEncryptionOptions = opt.AutoEncryptionOptions 1092 } 1093 if opt.Deployment != nil { 1094 c.Deployment = opt.Deployment 1095 } 1096 if opt.DisableOCSPEndpointCheck != nil { 1097 c.DisableOCSPEndpointCheck = opt.DisableOCSPEndpointCheck 1098 } 1099 if opt.err != nil { 1100 c.err = opt.err 1101 } 1102 if opt.uri != "" { 1103 c.uri = opt.uri 1104 } 1105 if opt.cs != nil { 1106 c.cs = opt.cs 1107 } 1108 if opt.LoggerOptions != nil { 1109 c.LoggerOptions = opt.LoggerOptions 1110 } 1111 } 1112 1113 return c 1114 } 1115 1116 // addCACertFromFile adds a root CA certificate to the configuration given a path 1117 // to the containing file. 1118 func addCACertFromFile(cfg *tls.Config, file string) error { 1119 data, err := ioutil.ReadFile(file) 1120 if err != nil { 1121 return err 1122 } 1123 1124 if cfg.RootCAs == nil { 1125 cfg.RootCAs = x509.NewCertPool() 1126 } 1127 if !cfg.RootCAs.AppendCertsFromPEM(data) { 1128 return errors.New("the specified CA file does not contain any valid certificates") 1129 } 1130 1131 return nil 1132 } 1133 1134 func addClientCertFromSeparateFiles(cfg *tls.Config, keyFile, certFile, keyPassword string) (string, error) { 1135 keyData, err := ioutil.ReadFile(keyFile) 1136 if err != nil { 1137 return "", err 1138 } 1139 certData, err := ioutil.ReadFile(certFile) 1140 if err != nil { 1141 return "", err 1142 } 1143 1144 data := make([]byte, 0, len(keyData)+len(certData)+1) 1145 data = append(data, keyData...) 1146 data = append(data, '\n') 1147 data = append(data, certData...) 1148 return addClientCertFromBytes(cfg, data, keyPassword) 1149 } 1150 1151 func addClientCertFromConcatenatedFile(cfg *tls.Config, certKeyFile, keyPassword string) (string, error) { 1152 data, err := ioutil.ReadFile(certKeyFile) 1153 if err != nil { 1154 return "", err 1155 } 1156 1157 return addClientCertFromBytes(cfg, data, keyPassword) 1158 } 1159 1160 // addClientCertFromBytes adds client certificates to the configuration given a path to the 1161 // containing file and returns the subject name in the first certificate. 1162 func addClientCertFromBytes(cfg *tls.Config, data []byte, keyPasswd string) (string, error) { 1163 var currentBlock *pem.Block 1164 var certDecodedBlock []byte 1165 var certBlocks, keyBlocks [][]byte 1166 1167 remaining := data 1168 start := 0 1169 for { 1170 currentBlock, remaining = pem.Decode(remaining) 1171 if currentBlock == nil { 1172 break 1173 } 1174 1175 if currentBlock.Type == "CERTIFICATE" { 1176 certBlock := data[start : len(data)-len(remaining)] 1177 certBlocks = append(certBlocks, certBlock) 1178 // Assign the certDecodedBlock when it is never set, 1179 // so only the first certificate is honored in a file with multiple certs. 1180 if certDecodedBlock == nil { 1181 certDecodedBlock = currentBlock.Bytes 1182 } 1183 start += len(certBlock) 1184 } else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") { 1185 isEncrypted := x509.IsEncryptedPEMBlock(currentBlock) || strings.Contains(currentBlock.Type, "ENCRYPTED PRIVATE KEY") 1186 if isEncrypted { 1187 if keyPasswd == "" { 1188 return "", fmt.Errorf("no password provided to decrypt private key") 1189 } 1190 1191 var keyBytes []byte 1192 var err error 1193 // Process the X.509-encrypted or PKCS-encrypted PEM block. 1194 if x509.IsEncryptedPEMBlock(currentBlock) { 1195 // Only covers encrypted PEM data with a DEK-Info header. 1196 keyBytes, err = x509.DecryptPEMBlock(currentBlock, []byte(keyPasswd)) 1197 if err != nil { 1198 return "", err 1199 } 1200 } else if strings.Contains(currentBlock.Type, "ENCRYPTED") { 1201 // The pkcs8 package only handles the PKCS #5 v2.0 scheme. 1202 decrypted, err := pkcs8.ParsePKCS8PrivateKey(currentBlock.Bytes, []byte(keyPasswd)) 1203 if err != nil { 1204 return "", err 1205 } 1206 keyBytes, err = x509.MarshalPKCS8PrivateKey(decrypted) 1207 if err != nil { 1208 return "", err 1209 } 1210 } 1211 var encoded bytes.Buffer 1212 pem.Encode(&encoded, &pem.Block{Type: currentBlock.Type, Bytes: keyBytes}) 1213 keyBlock := encoded.Bytes() 1214 keyBlocks = append(keyBlocks, keyBlock) 1215 start = len(data) - len(remaining) 1216 } else { 1217 keyBlock := data[start : len(data)-len(remaining)] 1218 keyBlocks = append(keyBlocks, keyBlock) 1219 start += len(keyBlock) 1220 } 1221 } 1222 } 1223 if len(certBlocks) == 0 { 1224 return "", fmt.Errorf("failed to find CERTIFICATE") 1225 } 1226 if len(keyBlocks) == 0 { 1227 return "", fmt.Errorf("failed to find PRIVATE KEY") 1228 } 1229 1230 cert, err := tls.X509KeyPair(bytes.Join(certBlocks, []byte("\n")), bytes.Join(keyBlocks, []byte("\n"))) 1231 if err != nil { 1232 return "", err 1233 } 1234 1235 cfg.Certificates = append(cfg.Certificates, cert) 1236 1237 // The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not 1238 // retained. 1239 crt, err := x509.ParseCertificate(certDecodedBlock) 1240 if err != nil { 1241 return "", err 1242 } 1243 1244 return crt.Subject.String(), nil 1245 } 1246 1247 func stringSliceContains(source []string, target string) bool { 1248 for _, str := range source { 1249 if str == target { 1250 return true 1251 } 1252 } 1253 return false 1254 } 1255 1256 // create a username for x509 authentication from an x509 certificate subject. 1257 func extractX509UsernameFromSubject(subject string) string { 1258 // the Go x509 package gives the subject with the pairs in the reverse order from what we want. 1259 pairs := strings.Split(subject, ",") 1260 for left, right := 0, len(pairs)-1; left < right; left, right = left+1, right-1 { 1261 pairs[left], pairs[right] = pairs[right], pairs[left] 1262 } 1263 1264 return strings.Join(pairs, ",") 1265 }