mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
011bfd666e
Add a unit test for validateManifest which ensures extra data can't be injected by adding data to the JSON object outside the payload area. This also removes validation of legacy signatures at pull time. This starts the path of deprecating legacy signatures, whose presence in the very JSON document they attempt to sign is problematic. These signatures were only checked for official images, and since they only caused a weakly-worded message to be printed, removing the verification should not cause impact. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
114 lines
3.5 KiB
Go
114 lines
3.5 KiB
Go
package graph
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/distribution"
|
|
"github.com/docker/distribution/digest"
|
|
"github.com/docker/distribution/manifest"
|
|
"github.com/docker/distribution/registry/client"
|
|
"github.com/docker/distribution/registry/client/auth"
|
|
"github.com/docker/distribution/registry/client/transport"
|
|
"github.com/docker/docker/cliconfig"
|
|
"github.com/docker/docker/registry"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
type dumbCredentialStore struct {
|
|
auth *cliconfig.AuthConfig
|
|
}
|
|
|
|
func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) {
|
|
return dcs.auth.Username, dcs.auth.Password
|
|
}
|
|
|
|
// NewV2Repository returns a repository (v2 only). It creates a HTTP transport
|
|
// providing timeout settings and authentication support, and also verifies the
|
|
// remote API version.
|
|
func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *cliconfig.AuthConfig, actions ...string) (distribution.Repository, error) {
|
|
ctx := context.Background()
|
|
|
|
repoName := repoInfo.CanonicalName
|
|
// If endpoint does not support CanonicalName, use the RemoteName instead
|
|
if endpoint.TrimHostname {
|
|
repoName = repoInfo.RemoteName
|
|
}
|
|
|
|
// TODO(dmcgowan): Call close idle connections when complete, use keep alive
|
|
base := &http.Transport{
|
|
Proxy: http.ProxyFromEnvironment,
|
|
Dial: (&net.Dialer{
|
|
Timeout: 30 * time.Second,
|
|
KeepAlive: 30 * time.Second,
|
|
DualStack: true,
|
|
}).Dial,
|
|
TLSHandshakeTimeout: 10 * time.Second,
|
|
TLSClientConfig: endpoint.TLSConfig,
|
|
// TODO(dmcgowan): Call close idle connections when complete and use keep alive
|
|
DisableKeepAlives: true,
|
|
}
|
|
|
|
modifiers := registry.DockerHeaders(metaHeaders)
|
|
authTransport := transport.NewTransport(base, modifiers...)
|
|
pingClient := &http.Client{
|
|
Transport: authTransport,
|
|
Timeout: 5 * time.Second,
|
|
}
|
|
endpointStr := endpoint.URL + "/v2/"
|
|
req, err := http.NewRequest("GET", endpointStr, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp, err := pingClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
versions := auth.APIVersions(resp, endpoint.VersionHeader)
|
|
if endpoint.VersionHeader != "" && len(endpoint.Versions) > 0 {
|
|
var foundVersion bool
|
|
for _, version := range endpoint.Versions {
|
|
for _, pingVersion := range versions {
|
|
if version == pingVersion {
|
|
foundVersion = true
|
|
}
|
|
}
|
|
}
|
|
if !foundVersion {
|
|
return nil, errors.New("endpoint does not support v2 API")
|
|
}
|
|
}
|
|
|
|
challengeManager := auth.NewSimpleChallengeManager()
|
|
if err := challengeManager.AddResponse(resp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
creds := dumbCredentialStore{auth: authConfig}
|
|
tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...)
|
|
basicHandler := auth.NewBasicHandler(creds)
|
|
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
|
|
tr := transport.NewTransport(base, modifiers...)
|
|
|
|
return client.NewRepository(ctx, repoName, endpoint.URL, tr)
|
|
}
|
|
|
|
func digestFromManifest(m *manifest.SignedManifest, localName string) (digest.Digest, int, error) {
|
|
payload, err := m.Payload()
|
|
if err != nil {
|
|
// If this failed, the signatures section was corrupted
|
|
// or missing. Treat the entire manifest as the payload.
|
|
payload = m.Raw
|
|
}
|
|
manifestDigest, err := digest.FromBytes(payload)
|
|
if err != nil {
|
|
logrus.Infof("Could not compute manifest digest for %s:%s : %v", localName, m.Tag, err)
|
|
}
|
|
return manifestDigest, len(payload), nil
|
|
}
|