You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

clientoptions.go 18 kB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  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. package options // import "go.mongodb.org/mongo-driver/mongo/options"
  7. import (
  8. "bytes"
  9. "context"
  10. "crypto/tls"
  11. "crypto/x509"
  12. "encoding/pem"
  13. "errors"
  14. "fmt"
  15. "io/ioutil"
  16. "net"
  17. "strings"
  18. "time"
  19. "go.mongodb.org/mongo-driver/bson/bsoncodec"
  20. "go.mongodb.org/mongo-driver/event"
  21. "go.mongodb.org/mongo-driver/mongo/readconcern"
  22. "go.mongodb.org/mongo-driver/mongo/readpref"
  23. "go.mongodb.org/mongo-driver/mongo/writeconcern"
  24. "go.mongodb.org/mongo-driver/tag"
  25. "go.mongodb.org/mongo-driver/x/mongo/driver/connstring"
  26. )
  27. // ContextDialer makes new network connections
  28. type ContextDialer interface {
  29. DialContext(ctx context.Context, network, address string) (net.Conn, error)
  30. }
  31. // Credential holds auth options.
  32. //
  33. // AuthMechanism indicates the mechanism to use for authentication.
  34. // Supported values include "SCRAM-SHA-256", "SCRAM-SHA-1", "MONGODB-CR", "PLAIN", "GSSAPI", and "MONGODB-X509".
  35. //
  36. // AuthMechanismProperties specifies additional configuration options which may be used by certain
  37. // authentication mechanisms. Supported properties are:
  38. // SERVICE_NAME: Specifies the name of the service. Defaults to mongodb.
  39. // CANONICALIZE_HOST_NAME: If true, tells the driver to canonicalize the given hostname. Defaults to false. This
  40. // property may not be used on Linux and Darwin systems and may not be used at the same time as SERVICE_HOST.
  41. // SERVICE_REALM: Specifies the realm of the service.
  42. // SERVICE_HOST: Specifies a hostname for GSSAPI authentication if it is different from the server's address. For
  43. // authentication mechanisms besides GSSAPI, this property is ignored.
  44. //
  45. // AuthSource specifies the database to authenticate against.
  46. //
  47. // Username specifies the username that will be authenticated.
  48. //
  49. // Password specifies the password used for authentication.
  50. //
  51. // PasswordSet specifies if the password is actually set, since an empty password is a valid password.
  52. type Credential struct {
  53. AuthMechanism string
  54. AuthMechanismProperties map[string]string
  55. AuthSource string
  56. Username string
  57. Password string
  58. PasswordSet bool
  59. }
  60. // ClientOptions represents all possible options to configure a client.
  61. type ClientOptions struct {
  62. AppName *string
  63. Auth *Credential
  64. ConnectTimeout *time.Duration
  65. Compressors []string
  66. Dialer ContextDialer
  67. HeartbeatInterval *time.Duration
  68. Hosts []string
  69. LocalThreshold *time.Duration
  70. MaxConnIdleTime *time.Duration
  71. MaxPoolSize *uint64
  72. MinPoolSize *uint64
  73. PoolMonitor *event.PoolMonitor
  74. Monitor *event.CommandMonitor
  75. ReadConcern *readconcern.ReadConcern
  76. ReadPreference *readpref.ReadPref
  77. Registry *bsoncodec.Registry
  78. ReplicaSet *string
  79. RetryWrites *bool
  80. RetryReads *bool
  81. ServerSelectionTimeout *time.Duration
  82. Direct *bool
  83. SocketTimeout *time.Duration
  84. TLSConfig *tls.Config
  85. WriteConcern *writeconcern.WriteConcern
  86. ZlibLevel *int
  87. err error
  88. // Adds an option for internal use only and should not be set. This option is deprecated and is
  89. // not part of the stability guarantee. It may be removed in the future.
  90. AuthenticateToAnything *bool
  91. }
  92. // Client creates a new ClientOptions instance.
  93. func Client() *ClientOptions {
  94. return new(ClientOptions)
  95. }
  96. // Validate validates the client options. This method will return the first error found.
  97. func (c *ClientOptions) Validate() error { return c.err }
  98. // ApplyURI parses the provided connection string and sets the values and options accordingly.
  99. //
  100. // Errors that occur in this method can be retrieved by calling Validate.
  101. //
  102. // If the URI contains ssl=true this method will overwrite TLSConfig, even if there aren't any other
  103. // tls options specified.
  104. func (c *ClientOptions) ApplyURI(uri string) *ClientOptions {
  105. if c.err != nil {
  106. return c
  107. }
  108. cs, err := connstring.Parse(uri)
  109. if err != nil {
  110. c.err = err
  111. return c
  112. }
  113. if cs.AppName != "" {
  114. c.AppName = &cs.AppName
  115. }
  116. if cs.AuthMechanism != "" || cs.AuthMechanismProperties != nil || cs.AuthSource != "" ||
  117. cs.Username != "" || cs.PasswordSet {
  118. c.Auth = &Credential{
  119. AuthMechanism: cs.AuthMechanism,
  120. AuthMechanismProperties: cs.AuthMechanismProperties,
  121. AuthSource: cs.AuthSource,
  122. Username: cs.Username,
  123. Password: cs.Password,
  124. PasswordSet: cs.PasswordSet,
  125. }
  126. }
  127. if cs.ConnectSet {
  128. direct := cs.Connect == connstring.SingleConnect
  129. c.Direct = &direct
  130. }
  131. if cs.ConnectTimeoutSet {
  132. c.ConnectTimeout = &cs.ConnectTimeout
  133. }
  134. if len(cs.Compressors) > 0 {
  135. c.Compressors = cs.Compressors
  136. }
  137. if cs.HeartbeatIntervalSet {
  138. c.HeartbeatInterval = &cs.HeartbeatInterval
  139. }
  140. c.Hosts = cs.Hosts
  141. if cs.LocalThresholdSet {
  142. c.LocalThreshold = &cs.LocalThreshold
  143. }
  144. if cs.MaxConnIdleTimeSet {
  145. c.MaxConnIdleTime = &cs.MaxConnIdleTime
  146. }
  147. if cs.MaxPoolSizeSet {
  148. c.MaxPoolSize = &cs.MaxPoolSize
  149. }
  150. if cs.MinPoolSizeSet {
  151. c.MinPoolSize = &cs.MinPoolSize
  152. }
  153. if cs.ReadConcernLevel != "" {
  154. c.ReadConcern = readconcern.New(readconcern.Level(cs.ReadConcernLevel))
  155. }
  156. if cs.ReadPreference != "" || len(cs.ReadPreferenceTagSets) > 0 || cs.MaxStalenessSet {
  157. opts := make([]readpref.Option, 0, 1)
  158. tagSets := tag.NewTagSetsFromMaps(cs.ReadPreferenceTagSets)
  159. if len(tagSets) > 0 {
  160. opts = append(opts, readpref.WithTagSets(tagSets...))
  161. }
  162. if cs.MaxStaleness != 0 {
  163. opts = append(opts, readpref.WithMaxStaleness(cs.MaxStaleness))
  164. }
  165. mode, err := readpref.ModeFromString(cs.ReadPreference)
  166. if err != nil {
  167. c.err = err
  168. return c
  169. }
  170. c.ReadPreference, c.err = readpref.New(mode, opts...)
  171. if c.err != nil {
  172. return c
  173. }
  174. }
  175. if cs.RetryWritesSet {
  176. c.RetryWrites = &cs.RetryWrites
  177. }
  178. if cs.ReplicaSet != "" {
  179. c.ReplicaSet = &cs.ReplicaSet
  180. }
  181. if cs.ServerSelectionTimeoutSet {
  182. c.ServerSelectionTimeout = &cs.ServerSelectionTimeout
  183. }
  184. if cs.SocketTimeoutSet {
  185. c.SocketTimeout = &cs.SocketTimeout
  186. }
  187. if cs.SSL {
  188. tlsConfig := new(tls.Config)
  189. if cs.SSLCaFileSet {
  190. c.err = addCACertFromFile(tlsConfig, cs.SSLCaFile)
  191. if c.err != nil {
  192. return c
  193. }
  194. }
  195. if cs.SSLInsecure {
  196. tlsConfig.InsecureSkipVerify = true
  197. }
  198. if cs.SSLClientCertificateKeyFileSet {
  199. var keyPasswd string
  200. if cs.SSLClientCertificateKeyPasswordSet && cs.SSLClientCertificateKeyPassword != nil {
  201. keyPasswd = cs.SSLClientCertificateKeyPassword()
  202. }
  203. s, err := addClientCertFromFile(tlsConfig, cs.SSLClientCertificateKeyFile, keyPasswd)
  204. if err != nil {
  205. c.err = err
  206. return c
  207. }
  208. // If a username wasn't specified, add one from the certificate.
  209. if c.Auth != nil && strings.ToLower(c.Auth.AuthMechanism) == "mongodb-x509" && c.Auth.Username == "" {
  210. // The Go x509 package gives the subject with the pairs in reverse order that we want.
  211. pairs := strings.Split(s, ",")
  212. for left, right := 0, len(pairs)-1; left < right; left, right = left+1, right-1 {
  213. pairs[left], pairs[right] = pairs[right], pairs[left]
  214. }
  215. c.Auth.Username = strings.Join(pairs, ",")
  216. }
  217. }
  218. c.TLSConfig = tlsConfig
  219. }
  220. if cs.JSet || cs.WString != "" || cs.WNumberSet || cs.WTimeoutSet {
  221. opts := make([]writeconcern.Option, 0, 1)
  222. if len(cs.WString) > 0 {
  223. opts = append(opts, writeconcern.WTagSet(cs.WString))
  224. } else if cs.WNumberSet {
  225. opts = append(opts, writeconcern.W(cs.WNumber))
  226. }
  227. if cs.JSet {
  228. opts = append(opts, writeconcern.J(cs.J))
  229. }
  230. if cs.WTimeoutSet {
  231. opts = append(opts, writeconcern.WTimeout(cs.WTimeout))
  232. }
  233. c.WriteConcern = writeconcern.New(opts...)
  234. }
  235. if cs.ZlibLevelSet {
  236. c.ZlibLevel = &cs.ZlibLevel
  237. }
  238. return c
  239. }
  240. // SetAppName specifies the client application name. This value is used by MongoDB when it logs
  241. // connection information and profile information, such as slow queries.
  242. func (c *ClientOptions) SetAppName(s string) *ClientOptions {
  243. c.AppName = &s
  244. return c
  245. }
  246. // SetAuth sets the authentication options.
  247. func (c *ClientOptions) SetAuth(auth Credential) *ClientOptions {
  248. c.Auth = &auth
  249. return c
  250. }
  251. // SetCompressors sets the compressors that can be used when communicating with a server.
  252. func (c *ClientOptions) SetCompressors(comps []string) *ClientOptions {
  253. c.Compressors = comps
  254. return c
  255. }
  256. // SetConnectTimeout specifies the timeout for an initial connection to a server.
  257. // If a custom Dialer is used, this method won't be set and the user is
  258. // responsible for setting the ConnectTimeout for connections on the dialer
  259. // themselves.
  260. func (c *ClientOptions) SetConnectTimeout(d time.Duration) *ClientOptions {
  261. c.ConnectTimeout = &d
  262. return c
  263. }
  264. // SetDialer specifies a custom dialer used to dial new connections to a server.
  265. // If a custom dialer is not set, a net.Dialer with a 300 second keepalive time will be used by default.
  266. func (c *ClientOptions) SetDialer(d ContextDialer) *ClientOptions {
  267. c.Dialer = d
  268. return c
  269. }
  270. // SetDirect specifies whether the driver should connect directly to the server instead of
  271. // auto-discovering other servers in the cluster.
  272. func (c *ClientOptions) SetDirect(b bool) *ClientOptions {
  273. c.Direct = &b
  274. return c
  275. }
  276. // SetHeartbeatInterval specifies the interval to wait between server monitoring checks.
  277. func (c *ClientOptions) SetHeartbeatInterval(d time.Duration) *ClientOptions {
  278. c.HeartbeatInterval = &d
  279. return c
  280. }
  281. // SetHosts specifies the initial list of addresses from which to discover the rest of the cluster.
  282. func (c *ClientOptions) SetHosts(s []string) *ClientOptions {
  283. c.Hosts = s
  284. return c
  285. }
  286. // SetLocalThreshold specifies how far to distribute queries, beyond the server with the fastest
  287. // round-trip time. If a server's roundtrip time is more than LocalThreshold slower than the
  288. // the fastest, the driver will not send queries to that server.
  289. func (c *ClientOptions) SetLocalThreshold(d time.Duration) *ClientOptions {
  290. c.LocalThreshold = &d
  291. return c
  292. }
  293. // SetMaxConnIdleTime specifies the maximum number of milliseconds that a connection can remain idle
  294. // in a connection pool before being removed and closed.
  295. func (c *ClientOptions) SetMaxConnIdleTime(d time.Duration) *ClientOptions {
  296. c.MaxConnIdleTime = &d
  297. return c
  298. }
  299. // SetMaxPoolSize specifies the max size of a server's connection pool.
  300. func (c *ClientOptions) SetMaxPoolSize(u uint64) *ClientOptions {
  301. c.MaxPoolSize = &u
  302. return c
  303. }
  304. // SetMinPoolSize specifies the min size of a server's connection pool.
  305. func (c *ClientOptions) SetMinPoolSize(u uint64) *ClientOptions {
  306. c.MinPoolSize = &u
  307. return c
  308. }
  309. // SetPoolMonitor specifies the PoolMonitor for a server's connection pool.
  310. func (c *ClientOptions) SetPoolMonitor(m *event.PoolMonitor) *ClientOptions {
  311. c.PoolMonitor = m
  312. return c
  313. }
  314. // SetMonitor specifies a command monitor used to see commands for a client.
  315. func (c *ClientOptions) SetMonitor(m *event.CommandMonitor) *ClientOptions {
  316. c.Monitor = m
  317. return c
  318. }
  319. // SetReadConcern specifies the read concern.
  320. func (c *ClientOptions) SetReadConcern(rc *readconcern.ReadConcern) *ClientOptions {
  321. c.ReadConcern = rc
  322. return c
  323. }
  324. // SetReadPreference specifies the read preference.
  325. func (c *ClientOptions) SetReadPreference(rp *readpref.ReadPref) *ClientOptions {
  326. c.ReadPreference = rp
  327. return c
  328. }
  329. // SetRegistry specifies the bsoncodec.Registry.
  330. func (c *ClientOptions) SetRegistry(registry *bsoncodec.Registry) *ClientOptions {
  331. c.Registry = registry
  332. return c
  333. }
  334. // SetReplicaSet specifies the name of the replica set of the cluster.
  335. func (c *ClientOptions) SetReplicaSet(s string) *ClientOptions {
  336. c.ReplicaSet = &s
  337. return c
  338. }
  339. // SetRetryWrites specifies whether the client has retryable writes enabled.
  340. func (c *ClientOptions) SetRetryWrites(b bool) *ClientOptions {
  341. c.RetryWrites = &b
  342. return c
  343. }
  344. // SetServerSelectionTimeout specifies a timeout in milliseconds to block for server selection.
  345. func (c *ClientOptions) SetServerSelectionTimeout(d time.Duration) *ClientOptions {
  346. c.ServerSelectionTimeout = &d
  347. return c
  348. }
  349. // SetSocketTimeout specifies the time in milliseconds to attempt to send or receive on a socket
  350. // before the attempt times out.
  351. func (c *ClientOptions) SetSocketTimeout(d time.Duration) *ClientOptions {
  352. c.SocketTimeout = &d
  353. return c
  354. }
  355. // SetTLSConfig sets the tls.Config.
  356. func (c *ClientOptions) SetTLSConfig(cfg *tls.Config) *ClientOptions {
  357. c.TLSConfig = cfg
  358. return c
  359. }
  360. // SetWriteConcern sets the write concern.
  361. func (c *ClientOptions) SetWriteConcern(wc *writeconcern.WriteConcern) *ClientOptions {
  362. c.WriteConcern = wc
  363. return c
  364. }
  365. // SetZlibLevel sets the level for the zlib compressor.
  366. func (c *ClientOptions) SetZlibLevel(level int) *ClientOptions {
  367. c.ZlibLevel = &level
  368. return c
  369. }
  370. // MergeClientOptions combines the given connstring and *ClientOptions into a single *ClientOptions in a last one wins
  371. // fashion. The given connstring will be used for the default options, which can be overwritten using the given
  372. // *ClientOptions.
  373. func MergeClientOptions(opts ...*ClientOptions) *ClientOptions {
  374. c := Client()
  375. for _, opt := range opts {
  376. if opt == nil {
  377. continue
  378. }
  379. if opt.Dialer != nil {
  380. c.Dialer = opt.Dialer
  381. }
  382. if opt.AppName != nil {
  383. c.AppName = opt.AppName
  384. }
  385. if opt.Auth != nil {
  386. c.Auth = opt.Auth
  387. }
  388. if opt.AuthenticateToAnything != nil {
  389. c.AuthenticateToAnything = opt.AuthenticateToAnything
  390. }
  391. if opt.Compressors != nil {
  392. c.Compressors = opt.Compressors
  393. }
  394. if opt.ConnectTimeout != nil {
  395. c.ConnectTimeout = opt.ConnectTimeout
  396. }
  397. if opt.HeartbeatInterval != nil {
  398. c.HeartbeatInterval = opt.HeartbeatInterval
  399. }
  400. if len(opt.Hosts) > 0 {
  401. c.Hosts = opt.Hosts
  402. }
  403. if opt.LocalThreshold != nil {
  404. c.LocalThreshold = opt.LocalThreshold
  405. }
  406. if opt.MaxConnIdleTime != nil {
  407. c.MaxConnIdleTime = opt.MaxConnIdleTime
  408. }
  409. if opt.MaxPoolSize != nil {
  410. c.MaxPoolSize = opt.MaxPoolSize
  411. }
  412. if opt.MinPoolSize != nil {
  413. c.MinPoolSize = opt.MinPoolSize
  414. }
  415. if opt.PoolMonitor != nil {
  416. c.PoolMonitor = opt.PoolMonitor
  417. }
  418. if opt.Monitor != nil {
  419. c.Monitor = opt.Monitor
  420. }
  421. if opt.ReadConcern != nil {
  422. c.ReadConcern = opt.ReadConcern
  423. }
  424. if opt.ReadPreference != nil {
  425. c.ReadPreference = opt.ReadPreference
  426. }
  427. if opt.Registry != nil {
  428. c.Registry = opt.Registry
  429. }
  430. if opt.ReplicaSet != nil {
  431. c.ReplicaSet = opt.ReplicaSet
  432. }
  433. if opt.RetryWrites != nil {
  434. c.RetryWrites = opt.RetryWrites
  435. }
  436. if opt.RetryReads != nil {
  437. c.RetryReads = opt.RetryReads
  438. }
  439. if opt.ServerSelectionTimeout != nil {
  440. c.ServerSelectionTimeout = opt.ServerSelectionTimeout
  441. }
  442. if opt.Direct != nil {
  443. c.Direct = opt.Direct
  444. }
  445. if opt.SocketTimeout != nil {
  446. c.SocketTimeout = opt.SocketTimeout
  447. }
  448. if opt.TLSConfig != nil {
  449. c.TLSConfig = opt.TLSConfig
  450. }
  451. if opt.WriteConcern != nil {
  452. c.WriteConcern = opt.WriteConcern
  453. }
  454. if opt.ZlibLevel != nil {
  455. c.ZlibLevel = opt.ZlibLevel
  456. }
  457. if opt.err != nil {
  458. c.err = opt.err
  459. }
  460. }
  461. return c
  462. }
  463. // addCACertFromFile adds a root CA certificate to the configuration given a path
  464. // to the containing file.
  465. func addCACertFromFile(cfg *tls.Config, file string) error {
  466. data, err := ioutil.ReadFile(file)
  467. if err != nil {
  468. return err
  469. }
  470. certBytes, err := loadCert(data)
  471. if err != nil {
  472. return err
  473. }
  474. cert, err := x509.ParseCertificate(certBytes)
  475. if err != nil {
  476. return err
  477. }
  478. if cfg.RootCAs == nil {
  479. cfg.RootCAs = x509.NewCertPool()
  480. }
  481. cfg.RootCAs.AddCert(cert)
  482. return nil
  483. }
  484. func loadCert(data []byte) ([]byte, error) {
  485. var certBlock *pem.Block
  486. for certBlock == nil {
  487. if data == nil || len(data) == 0 {
  488. return nil, errors.New(".pem file must have both a CERTIFICATE and an RSA PRIVATE KEY section")
  489. }
  490. block, rest := pem.Decode(data)
  491. if block == nil {
  492. return nil, errors.New("invalid .pem file")
  493. }
  494. switch block.Type {
  495. case "CERTIFICATE":
  496. if certBlock != nil {
  497. return nil, errors.New("multiple CERTIFICATE sections in .pem file")
  498. }
  499. certBlock = block
  500. }
  501. data = rest
  502. }
  503. return certBlock.Bytes, nil
  504. }
  505. // addClientCertFromFile adds a client certificate to the configuration given a path to the
  506. // containing file and returns the certificate's subject name.
  507. func addClientCertFromFile(cfg *tls.Config, clientFile, keyPasswd string) (string, error) {
  508. data, err := ioutil.ReadFile(clientFile)
  509. if err != nil {
  510. return "", err
  511. }
  512. var currentBlock *pem.Block
  513. var certBlock, certDecodedBlock, keyBlock []byte
  514. remaining := data
  515. start := 0
  516. for {
  517. currentBlock, remaining = pem.Decode(remaining)
  518. if currentBlock == nil {
  519. break
  520. }
  521. if currentBlock.Type == "CERTIFICATE" {
  522. certBlock = data[start : len(data)-len(remaining)]
  523. certDecodedBlock = currentBlock.Bytes
  524. start += len(certBlock)
  525. } else if strings.HasSuffix(currentBlock.Type, "PRIVATE KEY") {
  526. if keyPasswd != "" && x509.IsEncryptedPEMBlock(currentBlock) {
  527. var encoded bytes.Buffer
  528. buf, err := x509.DecryptPEMBlock(currentBlock, []byte(keyPasswd))
  529. if err != nil {
  530. return "", err
  531. }
  532. pem.Encode(&encoded, &pem.Block{Type: currentBlock.Type, Bytes: buf})
  533. keyBlock = encoded.Bytes()
  534. start = len(data) - len(remaining)
  535. } else {
  536. keyBlock = data[start : len(data)-len(remaining)]
  537. start += len(keyBlock)
  538. }
  539. }
  540. }
  541. if len(certBlock) == 0 {
  542. return "", fmt.Errorf("failed to find CERTIFICATE")
  543. }
  544. if len(keyBlock) == 0 {
  545. return "", fmt.Errorf("failed to find PRIVATE KEY")
  546. }
  547. cert, err := tls.X509KeyPair(certBlock, keyBlock)
  548. if err != nil {
  549. return "", err
  550. }
  551. cfg.Certificates = append(cfg.Certificates, cert)
  552. // The documentation for the tls.X509KeyPair indicates that the Leaf certificate is not
  553. // retained.
  554. crt, err := x509.ParseCertificate(certDecodedBlock)
  555. if err != nil {
  556. return "", err
  557. }
  558. return x509CertSubject(crt), nil
  559. }