httpclient.go 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package httpclient
  2. import (
  3. "crypto/tls"
  4. "crypto/x509"
  5. "io/ioutil"
  6. "net/http"
  7. "path/filepath"
  8. "time"
  9. "github.com/drakkan/sftpgo/logger"
  10. "github.com/drakkan/sftpgo/utils"
  11. )
  12. // Config defines the configuration for HTTP clients.
  13. // HTTP clients are used for executing hooks such as the ones used for
  14. // custom actions, external authentication and pre-login user modifications
  15. type Config struct {
  16. // Timeout specifies a time limit, in seconds, for requests
  17. Timeout int64 `json:"timeout" mapstructure:"timeout"`
  18. // CACertificates defines extra CA certificates to trust.
  19. // The paths can be absolute or relative to the config dir.
  20. // Adding trusted CA certificates is a convenient way to use self-signed
  21. // certificates without defeating the purpose of using TLS
  22. CACertificates []string `json:"ca_certificates" mapstructure:"ca_certificates"`
  23. // if enabled the HTTP client accepts any TLS certificate presented by
  24. // the server and any host name in that certificate.
  25. // In this mode, TLS is susceptible to man-in-the-middle attacks.
  26. // This should be used only for testing.
  27. SkipTLSVerify bool `json:"skip_tls_verify" mapstructure:"skip_tls_verify"`
  28. customTransport *http.Transport
  29. }
  30. const logSender = "httpclient"
  31. var httpConfig Config
  32. // Initialize configures HTTP clients
  33. func (c Config) Initialize(configDir string) {
  34. httpConfig = c
  35. rootCAs := c.loadCACerts(configDir)
  36. customTransport := http.DefaultTransport.(*http.Transport).Clone()
  37. if customTransport.TLSClientConfig != nil {
  38. customTransport.TLSClientConfig.RootCAs = rootCAs
  39. } else {
  40. customTransport.TLSClientConfig = &tls.Config{
  41. RootCAs: rootCAs,
  42. }
  43. }
  44. customTransport.TLSClientConfig.InsecureSkipVerify = c.SkipTLSVerify
  45. httpConfig.customTransport = customTransport
  46. }
  47. // loadCACerts returns system cert pools and try to add the configured
  48. // CA certificates to it
  49. func (c Config) loadCACerts(configDir string) *x509.CertPool {
  50. rootCAs, err := x509.SystemCertPool()
  51. if err != nil {
  52. rootCAs = x509.NewCertPool()
  53. }
  54. for _, ca := range c.CACertificates {
  55. if !utils.IsFileInputValid(ca) {
  56. logger.Warn(logSender, "", "unable to load invalid CA certificate: %#v", ca)
  57. logger.WarnToConsole("unable to load invalid CA certificate: %#v", ca)
  58. continue
  59. }
  60. if !filepath.IsAbs(ca) {
  61. ca = filepath.Join(configDir, ca)
  62. }
  63. certs, err := ioutil.ReadFile(ca)
  64. if err != nil {
  65. logger.Warn(logSender, "", "unable to load CA certificate: %v", err)
  66. logger.WarnToConsole("unable to load CA certificate: %#v", err)
  67. }
  68. if rootCAs.AppendCertsFromPEM(certs) {
  69. logger.Debug(logSender, "", "CA certificate %#v added to the trusted certificates", ca)
  70. } else {
  71. logger.Warn(logSender, "", "unable to add CA certificate %#v to the trusted cetificates", ca)
  72. logger.WarnToConsole("unable to add CA certificate %#v to the trusted cetificates", ca)
  73. }
  74. }
  75. return rootCAs
  76. }
  77. // GetHTTPClient returns an HTTP client with the configured parameters
  78. func GetHTTPClient() *http.Client {
  79. return &http.Client{
  80. Timeout: time.Duration(httpConfig.Timeout) * time.Second,
  81. Transport: httpConfig.customTransport,
  82. }
  83. }