commit
						9665f836a7
					
				
							
								
								
									
										86
									
								
								docs/auth.go
								
								
								
								
							
							
						
						
									
										86
									
								
								docs/auth.go
								
								
								
								
							| 
						 | 
					@ -91,6 +91,35 @@ func (lcs loginCredentialStore) SetRefreshToken(u *url.URL, service, token strin
 | 
				
			||||||
	lcs.authConfig.IdentityToken = token
 | 
						lcs.authConfig.IdentityToken = token
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type staticCredentialStore struct {
 | 
				
			||||||
 | 
						auth *types.AuthConfig
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewStaticCredentialStore returns a credential store
 | 
				
			||||||
 | 
					// which always returns the same credential values.
 | 
				
			||||||
 | 
					func NewStaticCredentialStore(auth *types.AuthConfig) auth.CredentialStore {
 | 
				
			||||||
 | 
						return staticCredentialStore{
 | 
				
			||||||
 | 
							auth: auth,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (scs staticCredentialStore) Basic(*url.URL) (string, string) {
 | 
				
			||||||
 | 
						if scs.auth == nil {
 | 
				
			||||||
 | 
							return "", ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return scs.auth.Username, scs.auth.Password
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (scs staticCredentialStore) RefreshToken(*url.URL, string) string {
 | 
				
			||||||
 | 
						if scs.auth == nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return scs.auth.IdentityToken
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (scs staticCredentialStore) SetRefreshToken(*url.URL, string, string) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type fallbackError struct {
 | 
					type fallbackError struct {
 | 
				
			||||||
	err error
 | 
						err error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -108,33 +137,14 @@ func loginV2(authConfig *types.AuthConfig, endpoint APIEndpoint, userAgent strin
 | 
				
			||||||
	modifiers := DockerHeaders(userAgent, nil)
 | 
						modifiers := DockerHeaders(userAgent, nil)
 | 
				
			||||||
	authTransport := transport.NewTransport(NewTransport(endpoint.TLSConfig), modifiers...)
 | 
						authTransport := transport.NewTransport(NewTransport(endpoint.TLSConfig), modifiers...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	challengeManager, foundV2, err := PingV2Registry(endpoint, authTransport)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if !foundV2 {
 | 
					 | 
				
			||||||
			err = fallbackError{err: err}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return "", "", err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	credentialAuthConfig := *authConfig
 | 
						credentialAuthConfig := *authConfig
 | 
				
			||||||
	creds := loginCredentialStore{
 | 
						creds := loginCredentialStore{
 | 
				
			||||||
		authConfig: &credentialAuthConfig,
 | 
							authConfig: &credentialAuthConfig,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tokenHandlerOptions := auth.TokenHandlerOptions{
 | 
						loginClient, foundV2, err := v2AuthHTTPClient(endpoint.URL, authTransport, modifiers, creds, nil)
 | 
				
			||||||
		Transport:     authTransport,
 | 
						if err != nil {
 | 
				
			||||||
		Credentials:   creds,
 | 
							return "", "", err
 | 
				
			||||||
		OfflineAccess: true,
 | 
					 | 
				
			||||||
		ClientID:      AuthClientID,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
 | 
					 | 
				
			||||||
	basicHandler := auth.NewBasicHandler(creds)
 | 
					 | 
				
			||||||
	modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
 | 
					 | 
				
			||||||
	tr := transport.NewTransport(authTransport, modifiers...)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	loginClient := &http.Client{
 | 
					 | 
				
			||||||
		Transport: tr,
 | 
					 | 
				
			||||||
		Timeout:   15 * time.Second,
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 | 
						endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 | 
				
			||||||
| 
						 | 
					@ -168,6 +178,34 @@ func loginV2(authConfig *types.AuthConfig, endpoint APIEndpoint, userAgent strin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func v2AuthHTTPClient(endpoint *url.URL, authTransport http.RoundTripper, modifiers []transport.RequestModifier, creds auth.CredentialStore, scopes []auth.Scope) (*http.Client, bool, error) {
 | 
				
			||||||
 | 
						challengeManager, foundV2, err := PingV2Registry(endpoint, authTransport)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if !foundV2 {
 | 
				
			||||||
 | 
								err = fallbackError{err: err}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil, foundV2, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tokenHandlerOptions := auth.TokenHandlerOptions{
 | 
				
			||||||
 | 
							Transport:     authTransport,
 | 
				
			||||||
 | 
							Credentials:   creds,
 | 
				
			||||||
 | 
							OfflineAccess: true,
 | 
				
			||||||
 | 
							ClientID:      AuthClientID,
 | 
				
			||||||
 | 
							Scopes:        scopes,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
 | 
				
			||||||
 | 
						basicHandler := auth.NewBasicHandler(creds)
 | 
				
			||||||
 | 
						modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
 | 
				
			||||||
 | 
						tr := transport.NewTransport(authTransport, modifiers...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &http.Client{
 | 
				
			||||||
 | 
							Transport: tr,
 | 
				
			||||||
 | 
							Timeout:   15 * time.Second,
 | 
				
			||||||
 | 
						}, foundV2, nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResolveAuthConfig matches an auth configuration to a server address or a URL
 | 
					// ResolveAuthConfig matches an auth configuration to a server address or a URL
 | 
				
			||||||
func ResolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
 | 
					func ResolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
 | 
				
			||||||
	configKey := GetAuthConfigKey(index)
 | 
						configKey := GetAuthConfigKey(index)
 | 
				
			||||||
| 
						 | 
					@ -215,7 +253,7 @@ func (err PingResponseError) Error() string {
 | 
				
			||||||
// challenge manager for the supported authentication types and
 | 
					// challenge manager for the supported authentication types and
 | 
				
			||||||
// whether v2 was confirmed by the response. If a response is received but
 | 
					// whether v2 was confirmed by the response. If a response is received but
 | 
				
			||||||
// cannot be interpreted a PingResponseError will be returned.
 | 
					// cannot be interpreted a PingResponseError will be returned.
 | 
				
			||||||
func PingV2Registry(endpoint APIEndpoint, transport http.RoundTripper) (auth.ChallengeManager, bool, error) {
 | 
					func PingV2Registry(endpoint *url.URL, transport http.RoundTripper) (auth.ChallengeManager, bool, error) {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		foundV2   = false
 | 
							foundV2   = false
 | 
				
			||||||
		v2Version = auth.APIVersion{
 | 
							v2Version = auth.APIVersion{
 | 
				
			||||||
| 
						 | 
					@ -228,7 +266,7 @@ func PingV2Registry(endpoint APIEndpoint, transport http.RoundTripper) (auth.Cha
 | 
				
			||||||
		Transport: transport,
 | 
							Transport: transport,
 | 
				
			||||||
		Timeout:   15 * time.Second,
 | 
							Timeout:   15 * time.Second,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	endpointStr := strings.TrimRight(endpoint.URL.String(), "/") + "/v2/"
 | 
						endpointStr := strings.TrimRight(endpoint.String(), "/") + "/v2/"
 | 
				
			||||||
	req, err := http.NewRequest("GET", endpointStr, nil)
 | 
						req, err := http.NewRequest("GET", endpointStr, nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, false, err
 | 
							return nil, false, err
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@ func (options *ServiceOptions) InstallCliFlags(cmd *flag.FlagSet, usageFn func(s
 | 
				
			||||||
	insecureRegistries := opts.NewNamedListOptsRef("insecure-registries", &options.InsecureRegistries, ValidateIndexName)
 | 
						insecureRegistries := opts.NewNamedListOptsRef("insecure-registries", &options.InsecureRegistries, ValidateIndexName)
 | 
				
			||||||
	cmd.Var(insecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
 | 
						cmd.Var(insecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd.BoolVar(&options.V2Only, []string{"-disable-legacy-registry"}, false, usageFn("Do not contact legacy registries"))
 | 
						cmd.BoolVar(&options.V2Only, []string{"-disable-legacy-registry"}, false, usageFn("Disable contacting legacy registries"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// newServiceConfig returns a new instance of ServiceConfig
 | 
					// newServiceConfig returns a new instance of ServiceConfig
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ import (
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
						"golang.org/x/net/context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Sirupsen/logrus"
 | 
						"github.com/Sirupsen/logrus"
 | 
				
			||||||
 | 
						"github.com/docker/distribution/registry/client/auth"
 | 
				
			||||||
	"github.com/docker/docker/reference"
 | 
						"github.com/docker/docker/reference"
 | 
				
			||||||
	"github.com/docker/engine-api/types"
 | 
						"github.com/docker/engine-api/types"
 | 
				
			||||||
	registrytypes "github.com/docker/engine-api/types/registry"
 | 
						registrytypes "github.com/docker/engine-api/types/registry"
 | 
				
			||||||
| 
						 | 
					@ -132,11 +133,44 @@ func (s *DefaultService) Search(ctx context.Context, term string, limit int, aut
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r, err := NewSession(endpoint.client, authConfig, endpoint)
 | 
						var client *http.Client
 | 
				
			||||||
	if err != nil {
 | 
						if authConfig != nil && authConfig.IdentityToken != "" && authConfig.Username != "" {
 | 
				
			||||||
		return nil, err
 | 
							creds := NewStaticCredentialStore(authConfig)
 | 
				
			||||||
 | 
							scopes := []auth.Scope{
 | 
				
			||||||
 | 
								auth.RegistryScope{
 | 
				
			||||||
 | 
									Name:    "catalog",
 | 
				
			||||||
 | 
									Actions: []string{"search"},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							modifiers := DockerHeaders(userAgent, nil)
 | 
				
			||||||
 | 
							v2Client, foundV2, err := v2AuthHTTPClient(endpoint.URL, endpoint.client.Transport, modifiers, creds, scopes)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if fErr, ok := err.(fallbackError); ok {
 | 
				
			||||||
 | 
									logrus.Errorf("Cannot use identity token for search, v2 auth not supported: %v", fErr.err)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if foundV2 {
 | 
				
			||||||
 | 
								// Copy non transport http client features
 | 
				
			||||||
 | 
								v2Client.Timeout = endpoint.client.Timeout
 | 
				
			||||||
 | 
								v2Client.CheckRedirect = endpoint.client.CheckRedirect
 | 
				
			||||||
 | 
								v2Client.Jar = endpoint.client.Jar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								logrus.Debugf("using v2 client for search to %s", endpoint.URL)
 | 
				
			||||||
 | 
								client = v2Client
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if client == nil {
 | 
				
			||||||
 | 
							client = endpoint.client
 | 
				
			||||||
 | 
							if err := authorizeClient(client, authConfig, endpoint); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r := newSession(client, authConfig, endpoint)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if index.Official {
 | 
						if index.Official {
 | 
				
			||||||
		localName := remoteName
 | 
							localName := remoteName
 | 
				
			||||||
		if strings.HasPrefix(localName, "library/") {
 | 
							if strings.HasPrefix(localName, "library/") {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,16 +161,7 @@ func (tr *authTransport) CancelRequest(req *http.Request) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewSession creates a new session
 | 
					func authorizeClient(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) error {
 | 
				
			||||||
// TODO(tiborvass): remove authConfig param once registry client v2 is vendored
 | 
					 | 
				
			||||||
func NewSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) (r *Session, err error) {
 | 
					 | 
				
			||||||
	r = &Session{
 | 
					 | 
				
			||||||
		authConfig:    authConfig,
 | 
					 | 
				
			||||||
		client:        client,
 | 
					 | 
				
			||||||
		indexEndpoint: endpoint,
 | 
					 | 
				
			||||||
		id:            stringid.GenerateRandomID(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var alwaysSetBasicAuth bool
 | 
						var alwaysSetBasicAuth bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If we're working with a standalone private registry over HTTPS, send Basic Auth headers
 | 
						// If we're working with a standalone private registry over HTTPS, send Basic Auth headers
 | 
				
			||||||
| 
						 | 
					@ -178,7 +169,7 @@ func NewSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1E
 | 
				
			||||||
	if endpoint.String() != IndexServer && endpoint.URL.Scheme == "https" {
 | 
						if endpoint.String() != IndexServer && endpoint.URL.Scheme == "https" {
 | 
				
			||||||
		info, err := endpoint.Ping()
 | 
							info, err := endpoint.Ping()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if info.Standalone && authConfig != nil {
 | 
							if info.Standalone && authConfig != nil {
 | 
				
			||||||
			logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", endpoint.String())
 | 
								logrus.Debugf("Endpoint %s is eligible for private registry. Enabling decorator.", endpoint.String())
 | 
				
			||||||
| 
						 | 
					@ -192,11 +183,30 @@ func NewSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1E
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	jar, err := cookiejar.New(nil)
 | 
						jar, err := cookiejar.New(nil)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, errors.New("cookiejar.New is not supposed to return an error")
 | 
							return errors.New("cookiejar.New is not supposed to return an error")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	client.Jar = jar
 | 
						client.Jar = jar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return r, nil
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) *Session {
 | 
				
			||||||
 | 
						return &Session{
 | 
				
			||||||
 | 
							authConfig:    authConfig,
 | 
				
			||||||
 | 
							client:        client,
 | 
				
			||||||
 | 
							indexEndpoint: endpoint,
 | 
				
			||||||
 | 
							id:            stringid.GenerateRandomID(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewSession creates a new session
 | 
				
			||||||
 | 
					// TODO(tiborvass): remove authConfig param once registry client v2 is vendored
 | 
				
			||||||
 | 
					func NewSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1Endpoint) (*Session, error) {
 | 
				
			||||||
 | 
						if err := authorizeClient(client, authConfig, endpoint); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return newSession(client, authConfig, endpoint), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ID returns this registry session's ID.
 | 
					// ID returns this registry session's ID.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue