Browse code

Respond with 401 when there is an unauthorized error from the registry.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2016/01/27 03:30:58
Showing 3 changed files
... ...
@@ -7,9 +7,11 @@ import (
7 7
 	"fmt"
8 8
 	"io"
9 9
 	"net/http"
10
+	"net/url"
10 11
 	"strings"
11 12
 
12 13
 	"github.com/docker/distribution/digest"
14
+	"github.com/docker/distribution/registry/api/errcode"
13 15
 	"github.com/docker/docker/api/server/httputils"
14 16
 	"github.com/docker/docker/builder/dockerfile"
15 17
 	derr "github.com/docker/docker/errors"
... ...
@@ -137,6 +139,12 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
137 137
 				err = s.daemon.PullImage(ref, metaHeaders, authConfig, output)
138 138
 			}
139 139
 		}
140
+		// Check the error from pulling an image to make sure the request
141
+		// was authorized. Modify the status if the request was
142
+		// unauthorized to respond with 401 rather than 500.
143
+		if err != nil && isAuthorizedError(err) {
144
+			err = errcode.ErrorCodeUnauthorized.WithMessage(fmt.Sprintf("Authentication is required: %s", err))
145
+		}
140 146
 	} else { //import
141 147
 		var newRef reference.Named
142 148
 		if repo != "" {
... ...
@@ -373,3 +381,16 @@ func (s *router) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *
373 373
 	}
374 374
 	return httputils.WriteJSON(w, http.StatusOK, query.Results)
375 375
 }
376
+
377
+func isAuthorizedError(err error) bool {
378
+	if urlError, ok := err.(*url.Error); ok {
379
+		err = urlError.Err
380
+	}
381
+
382
+	if dError, ok := err.(errcode.Error); ok {
383
+		if dError.ErrorCode() == errcode.ErrorCodeUnauthorized {
384
+			return true
385
+		}
386
+	}
387
+	return false
388
+}
... ...
@@ -28,7 +28,6 @@ var (
28 28
 	// ErrAlreadyExists is an error returned if an image being pushed
29 29
 	// already exists on the remote side
30 30
 	ErrAlreadyExists = errors.New("Image already exists")
31
-	errLoginRequired = errors.New("Authentication is required.")
32 31
 )
33 32
 
34 33
 func init() {
... ...
@@ -19,6 +19,7 @@ import (
19 19
 	"strings"
20 20
 
21 21
 	"github.com/Sirupsen/logrus"
22
+	"github.com/docker/distribution/registry/api/errcode"
22 23
 	"github.com/docker/docker/pkg/httputils"
23 24
 	"github.com/docker/docker/pkg/ioutils"
24 25
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -213,7 +214,7 @@ func (r *Session) GetRemoteHistory(imgID, registry string) ([]string, error) {
213 213
 	defer res.Body.Close()
214 214
 	if res.StatusCode != 200 {
215 215
 		if res.StatusCode == 401 {
216
-			return nil, errLoginRequired
216
+			return nil, errcode.ErrorCodeUnauthorized.WithArgs()
217 217
 		}
218 218
 		return nil, httputils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
219 219
 	}
... ...
@@ -427,7 +428,7 @@ func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, erro
427 427
 	}
428 428
 	defer res.Body.Close()
429 429
 	if res.StatusCode == 401 {
430
-		return nil, errLoginRequired
430
+		return nil, errcode.ErrorCodeUnauthorized.WithArgs()
431 431
 	}
432 432
 	// TODO: Right now we're ignoring checksums in the response body.
433 433
 	// In the future, we need to use them to check image validity.
... ...
@@ -661,7 +662,7 @@ func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData,
661 661
 	defer res.Body.Close()
662 662
 
663 663
 	if res.StatusCode == 401 {
664
-		return nil, errLoginRequired
664
+		return nil, errcode.ErrorCodeUnauthorized.WithArgs()
665 665
 	}
666 666
 
667 667
 	var tokens, endpoints []string