registry.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package distribution
  2. import (
  3. "fmt"
  4. "net"
  5. "net/http"
  6. "time"
  7. "github.com/docker/distribution"
  8. distreference "github.com/docker/distribution/reference"
  9. "github.com/docker/distribution/registry/client"
  10. "github.com/docker/distribution/registry/client/auth"
  11. "github.com/docker/distribution/registry/client/transport"
  12. "github.com/docker/docker/dockerversion"
  13. "github.com/docker/docker/registry"
  14. "github.com/docker/engine-api/types"
  15. "github.com/docker/go-connections/sockets"
  16. "golang.org/x/net/context"
  17. )
  18. // NewV2Repository returns a repository (v2 only). It creates an HTTP transport
  19. // providing timeout settings and authentication support, and also verifies the
  20. // remote API version.
  21. func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) {
  22. repoName := repoInfo.FullName()
  23. // If endpoint does not support CanonicalName, use the RemoteName instead
  24. if endpoint.TrimHostname {
  25. repoName = repoInfo.RemoteName()
  26. }
  27. direct := &net.Dialer{
  28. Timeout: 30 * time.Second,
  29. KeepAlive: 30 * time.Second,
  30. DualStack: true,
  31. }
  32. // TODO(dmcgowan): Call close idle connections when complete, use keep alive
  33. base := &http.Transport{
  34. Proxy: http.ProxyFromEnvironment,
  35. Dial: direct.Dial,
  36. TLSHandshakeTimeout: 10 * time.Second,
  37. TLSClientConfig: endpoint.TLSConfig,
  38. // TODO(dmcgowan): Call close idle connections when complete and use keep alive
  39. DisableKeepAlives: true,
  40. }
  41. proxyDialer, err := sockets.DialerFromEnvironment(direct)
  42. if err == nil {
  43. base.Dial = proxyDialer.Dial
  44. }
  45. modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(ctx), metaHeaders)
  46. authTransport := transport.NewTransport(base, modifiers...)
  47. challengeManager, foundVersion, err := registry.PingV2Registry(endpoint.URL, authTransport)
  48. if err != nil {
  49. transportOK := false
  50. if responseErr, ok := err.(registry.PingResponseError); ok {
  51. transportOK = true
  52. err = responseErr.Err
  53. }
  54. return nil, foundVersion, fallbackError{
  55. err: err,
  56. confirmedV2: foundVersion,
  57. transportOK: transportOK,
  58. }
  59. }
  60. if authConfig.RegistryToken != "" {
  61. passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
  62. modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
  63. } else {
  64. creds := registry.NewStaticCredentialStore(authConfig)
  65. tokenHandlerOptions := auth.TokenHandlerOptions{
  66. Transport: authTransport,
  67. Credentials: creds,
  68. Scopes: []auth.Scope{
  69. auth.RepositoryScope{
  70. Repository: repoName,
  71. Actions: actions,
  72. },
  73. },
  74. ClientID: registry.AuthClientID,
  75. }
  76. tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
  77. basicHandler := auth.NewBasicHandler(creds)
  78. modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
  79. }
  80. tr := transport.NewTransport(base, modifiers...)
  81. repoNameRef, err := distreference.ParseNamed(repoName)
  82. if err != nil {
  83. return nil, foundVersion, fallbackError{
  84. err: err,
  85. confirmedV2: foundVersion,
  86. transportOK: true,
  87. }
  88. }
  89. repo, err = client.NewRepository(ctx, repoNameRef, endpoint.URL.String(), tr)
  90. if err != nil {
  91. err = fallbackError{
  92. err: err,
  93. confirmedV2: foundVersion,
  94. transportOK: true,
  95. }
  96. }
  97. return
  98. }
  99. type existingTokenHandler struct {
  100. token string
  101. }
  102. func (th *existingTokenHandler) Scheme() string {
  103. return "bearer"
  104. }
  105. func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
  106. req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
  107. return nil
  108. }