Signed-off-by: Matt Moore <mattmoor@google.com>
| ... | ... |
@@ -482,6 +482,10 @@ func (s *TagStore) pullV2Repository(r *registry.Session, out io.Writer, repoInfo |
| 482 | 482 |
if err != nil {
|
| 483 | 483 |
return fmt.Errorf("error getting authorization: %s", err)
|
| 484 | 484 |
} |
| 485 |
+ if !auth.CanAuthorizeV2() {
|
|
| 486 |
+ return ErrV2RegistryUnavailable |
|
| 487 |
+ } |
|
| 488 |
+ |
|
| 485 | 489 |
var layersDownloaded bool |
| 486 | 490 |
if tag == "" {
|
| 487 | 491 |
logrus.Debugf("Pulling tag list from V2 registry for %s", repoInfo.CanonicalName)
|
| ... | ... |
@@ -322,6 +322,9 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o |
| 322 | 322 |
if err != nil {
|
| 323 | 323 |
return fmt.Errorf("error getting authorization: %s", err)
|
| 324 | 324 |
} |
| 325 |
+ if !auth.CanAuthorizeV2() {
|
|
| 326 |
+ return ErrV2RegistryUnavailable |
|
| 327 |
+ } |
|
| 325 | 328 |
|
| 326 | 329 |
for _, tag := range tags {
|
| 327 | 330 |
logrus.Debugf("Pushing repository: %s:%s", repoInfo.CanonicalName, tag)
|
| ... | ... |
@@ -549,6 +552,7 @@ func (s *TagStore) Push(localName string, imagePushConfig *ImagePushConfig) erro |
| 549 | 549 |
if err != ErrV2RegistryUnavailable {
|
| 550 | 550 |
return fmt.Errorf("Error pushing to registry: %s", err)
|
| 551 | 551 |
} |
| 552 |
+ logrus.Debug("V2 registry is unavailable, falling back on V1")
|
|
| 552 | 553 |
} |
| 553 | 554 |
|
| 554 | 555 |
if err := s.pushRepository(r, imagePushConfig.OutStream, repoInfo, localRepo, imagePushConfig.Tag, sf); err != nil {
|
| ... | ... |
@@ -74,6 +74,19 @@ func (auth *RequestAuthorization) getToken() (string, error) {
|
| 74 | 74 |
return "", nil |
| 75 | 75 |
} |
| 76 | 76 |
|
| 77 |
+// Checks that requests to the v2 registry can be authorized. |
|
| 78 |
+func (auth *RequestAuthorization) CanAuthorizeV2() bool {
|
|
| 79 |
+ if len(auth.registryEndpoint.AuthChallenges) == 0 {
|
|
| 80 |
+ return true |
|
| 81 |
+ } |
|
| 82 |
+ scope := fmt.Sprintf("%s:%s:%s", auth.resource, auth.scope, strings.Join(auth.actions, ","))
|
|
| 83 |
+ if _, err := loginV2(auth.authConfig, auth.registryEndpoint, scope); err != nil {
|
|
| 84 |
+ logrus.Debugf("Cannot authorize against V2 endpoint: %s", auth.registryEndpoint)
|
|
| 85 |
+ return false |
|
| 86 |
+ } |
|
| 87 |
+ return true |
|
| 88 |
+} |
|
| 89 |
+ |
|
| 77 | 90 |
func (auth *RequestAuthorization) Authorize(req *http.Request) error {
|
| 78 | 91 |
token, err := auth.getToken() |
| 79 | 92 |
if err != nil {
|
| ... | ... |
@@ -91,7 +104,7 @@ func (auth *RequestAuthorization) Authorize(req *http.Request) error {
|
| 91 | 91 |
func Login(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (string, error) {
|
| 92 | 92 |
// Separates the v2 registry login logic from the v1 logic. |
| 93 | 93 |
if registryEndpoint.Version == APIVersion2 {
|
| 94 |
- return loginV2(authConfig, registryEndpoint) |
|
| 94 |
+ return loginV2(authConfig, registryEndpoint, "" /* scope */) |
|
| 95 | 95 |
} |
| 96 | 96 |
return loginV1(authConfig, registryEndpoint) |
| 97 | 97 |
} |
| ... | ... |
@@ -209,7 +222,7 @@ func loginV1(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (stri |
| 209 | 209 |
// now, users should create their account through other means like directly from a web page |
| 210 | 210 |
// served by the v2 registry service provider. Whether this will be supported in the future |
| 211 | 211 |
// is to be determined. |
| 212 |
-func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (string, error) {
|
|
| 212 |
+func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint, scope string) (string, error) {
|
|
| 213 | 213 |
logrus.Debugf("attempting v2 login to registry endpoint %s", registryEndpoint)
|
| 214 | 214 |
var ( |
| 215 | 215 |
err error |
| ... | ... |
@@ -217,13 +230,18 @@ func loginV2(authConfig *cliconfig.AuthConfig, registryEndpoint *Endpoint) (stri |
| 217 | 217 |
) |
| 218 | 218 |
|
| 219 | 219 |
for _, challenge := range registryEndpoint.AuthChallenges {
|
| 220 |
- logrus.Debugf("trying %q auth challenge with params %s", challenge.Scheme, challenge.Parameters)
|
|
| 220 |
+ params := make(map[string]string, len(challenge.Parameters)+1) |
|
| 221 |
+ for k, v := range challenge.Parameters {
|
|
| 222 |
+ params[k] = v |
|
| 223 |
+ } |
|
| 224 |
+ params["scope"] = scope |
|
| 225 |
+ logrus.Debugf("trying %q auth challenge with params %v", challenge.Scheme, params)
|
|
| 221 | 226 |
|
| 222 | 227 |
switch strings.ToLower(challenge.Scheme) {
|
| 223 | 228 |
case "basic": |
| 224 |
- err = tryV2BasicAuthLogin(authConfig, challenge.Parameters, registryEndpoint) |
|
| 229 |
+ err = tryV2BasicAuthLogin(authConfig, params, registryEndpoint) |
|
| 225 | 230 |
case "bearer": |
| 226 |
- err = tryV2TokenAuthLogin(authConfig, challenge.Parameters, registryEndpoint) |
|
| 231 |
+ err = tryV2TokenAuthLogin(authConfig, params, registryEndpoint) |
|
| 227 | 232 |
default: |
| 228 | 233 |
// Unsupported challenge types are explicitly skipped. |
| 229 | 234 |
err = fmt.Errorf("unsupported auth scheme: %q", challenge.Scheme)
|