Merge pull request #736 from stevvooe/authorization-interface-cleanup
Authorization interface cleanupmaster
						commit
						060465882b
					
				| 
						 | 
					@ -34,7 +34,7 @@ import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
						"github.com/docker/distribution/context"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UserInfo carries information about
 | 
					// UserInfo carries information about
 | 
				
			||||||
| 
						 | 
					@ -61,12 +61,12 @@ type Access struct {
 | 
				
			||||||
// header values based on the error.
 | 
					// header values based on the error.
 | 
				
			||||||
type Challenge interface {
 | 
					type Challenge interface {
 | 
				
			||||||
	error
 | 
						error
 | 
				
			||||||
	// ServeHTTP prepares the request to conduct the appropriate challenge
 | 
					
 | 
				
			||||||
	// response by adding the appropriate HTTP challenge header on the response
 | 
						// SetHeaders prepares the request to conduct a challenge response by
 | 
				
			||||||
	// message. Callers are expected to set the appropriate HTTP status code
 | 
						// adding the an HTTP challenge header on the response message. Callers
 | 
				
			||||||
	// (e.g. 401) themselves. Because no body is written, users may write a
 | 
						// are expected to set the appropriate HTTP status code (e.g. 401)
 | 
				
			||||||
	// custom body after calling ServeHTTP.
 | 
						// themselves.
 | 
				
			||||||
	ServeHTTP(w http.ResponseWriter, r *http.Request)
 | 
						SetHeaders(w http.ResponseWriter)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AccessController controls access to registry resources based on a request
 | 
					// AccessController controls access to registry resources based on a request
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,9 +11,8 @@ import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctxu "github.com/docker/distribution/context"
 | 
						"github.com/docker/distribution/context"
 | 
				
			||||||
	"github.com/docker/distribution/registry/auth"
 | 
						"github.com/docker/distribution/registry/auth"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					var (
 | 
				
			||||||
| 
						 | 
					@ -57,7 +56,7 @@ func newAccessController(options map[string]interface{}) (auth.AccessController,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ac *accessController) Authorized(ctx context.Context, accessRecords ...auth.Access) (context.Context, error) {
 | 
					func (ac *accessController) Authorized(ctx context.Context, accessRecords ...auth.Access) (context.Context, error) {
 | 
				
			||||||
	req, err := ctxu.GetRequest(ctx)
 | 
						req, err := context.GetRequest(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -71,7 +70,7 @@ func (ac *accessController) Authorized(ctx context.Context, accessRecords ...aut
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := ac.htpasswd.authenticateUser(username, password); err != nil {
 | 
						if err := ac.htpasswd.authenticateUser(username, password); err != nil {
 | 
				
			||||||
		ctxu.GetLogger(ctx).Errorf("error authenticating user %q: %v", username, err)
 | 
							context.GetLogger(ctx).Errorf("error authenticating user %q: %v", username, err)
 | 
				
			||||||
		return nil, &challenge{
 | 
							return nil, &challenge{
 | 
				
			||||||
			realm: ac.realm,
 | 
								realm: ac.realm,
 | 
				
			||||||
			err:   ErrAuthenticationFailure,
 | 
								err:   ErrAuthenticationFailure,
 | 
				
			||||||
| 
						 | 
					@ -87,12 +86,14 @@ type challenge struct {
 | 
				
			||||||
	err   error
 | 
						err   error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ch *challenge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
					var _ auth.Challenge = challenge{}
 | 
				
			||||||
	header := fmt.Sprintf("Basic realm=%q", ch.realm)
 | 
					
 | 
				
			||||||
	w.Header().Set("WWW-Authenticate", header)
 | 
					// SetHeaders sets the basic challenge header on the response.
 | 
				
			||||||
 | 
					func (ch challenge) SetHeaders(w http.ResponseWriter) {
 | 
				
			||||||
 | 
						w.Header().Set("WWW-Authenticate", fmt.Sprintf("Basic realm=%q", ch.realm))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ch *challenge) Error() string {
 | 
					func (ch challenge) Error() string {
 | 
				
			||||||
	return fmt.Sprintf("basic authentication challenge: %#v", ch)
 | 
						return fmt.Sprintf("basic authentication challenge: %#v", ch)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ func TestBasicAccessController(t *testing.T) {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			switch err := err.(type) {
 | 
								switch err := err.(type) {
 | 
				
			||||||
			case auth.Challenge:
 | 
								case auth.Challenge:
 | 
				
			||||||
				err.ServeHTTP(w, r)
 | 
									err.SetHeaders(w)
 | 
				
			||||||
				w.WriteHeader(http.StatusUnauthorized)
 | 
									w.WriteHeader(http.StatusUnauthorized)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,9 +12,8 @@ import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctxu "github.com/docker/distribution/context"
 | 
						"github.com/docker/distribution/context"
 | 
				
			||||||
	"github.com/docker/distribution/registry/auth"
 | 
						"github.com/docker/distribution/registry/auth"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// accessController provides a simple implementation of auth.AccessController
 | 
					// accessController provides a simple implementation of auth.AccessController
 | 
				
			||||||
| 
						 | 
					@ -44,7 +43,7 @@ func newAccessController(options map[string]interface{}) (auth.AccessController,
 | 
				
			||||||
// Authorized simply checks for the existence of the authorization header,
 | 
					// Authorized simply checks for the existence of the authorization header,
 | 
				
			||||||
// responding with a bearer challenge if it doesn't exist.
 | 
					// responding with a bearer challenge if it doesn't exist.
 | 
				
			||||||
func (ac *accessController) Authorized(ctx context.Context, accessRecords ...auth.Access) (context.Context, error) {
 | 
					func (ac *accessController) Authorized(ctx context.Context, accessRecords ...auth.Access) (context.Context, error) {
 | 
				
			||||||
	req, err := ctxu.GetRequest(ctx)
 | 
						req, err := context.GetRequest(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -75,7 +74,10 @@ type challenge struct {
 | 
				
			||||||
	scope   string
 | 
						scope   string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ch *challenge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
					var _ auth.Challenge = challenge{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetHeaders sets a simple bearer challenge on the response.
 | 
				
			||||||
 | 
					func (ch challenge) SetHeaders(w http.ResponseWriter) {
 | 
				
			||||||
	header := fmt.Sprintf("Bearer realm=%q,service=%q", ch.realm, ch.service)
 | 
						header := fmt.Sprintf("Bearer realm=%q,service=%q", ch.realm, ch.service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ch.scope != "" {
 | 
						if ch.scope != "" {
 | 
				
			||||||
| 
						 | 
					@ -85,7 +87,7 @@ func (ch *challenge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	w.Header().Set("WWW-Authenticate", header)
 | 
						w.Header().Set("WWW-Authenticate", header)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ch *challenge) Error() string {
 | 
					func (ch challenge) Error() string {
 | 
				
			||||||
	return fmt.Sprintf("silly authentication challenge: %#v", ch)
 | 
						return fmt.Sprintf("silly authentication challenge: %#v", ch)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ func TestSillyAccessController(t *testing.T) {
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			switch err := err.(type) {
 | 
								switch err := err.(type) {
 | 
				
			||||||
			case auth.Challenge:
 | 
								case auth.Challenge:
 | 
				
			||||||
				err.ServeHTTP(w, r)
 | 
									err.SetHeaders(w)
 | 
				
			||||||
				w.WriteHeader(http.StatusUnauthorized)
 | 
									w.WriteHeader(http.StatusUnauthorized)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,10 +11,9 @@ import (
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctxu "github.com/docker/distribution/context"
 | 
						"github.com/docker/distribution/context"
 | 
				
			||||||
	"github.com/docker/distribution/registry/auth"
 | 
						"github.com/docker/distribution/registry/auth"
 | 
				
			||||||
	"github.com/docker/libtrust"
 | 
						"github.com/docker/libtrust"
 | 
				
			||||||
	"golang.org/x/net/context"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// accessSet maps a typed, named resource to
 | 
					// accessSet maps a typed, named resource to
 | 
				
			||||||
| 
						 | 
					@ -82,20 +81,22 @@ type authChallenge struct {
 | 
				
			||||||
	accessSet accessSet
 | 
						accessSet accessSet
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var _ auth.Challenge = authChallenge{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Error returns the internal error string for this authChallenge.
 | 
					// Error returns the internal error string for this authChallenge.
 | 
				
			||||||
func (ac *authChallenge) Error() string {
 | 
					func (ac authChallenge) Error() string {
 | 
				
			||||||
	return ac.err.Error()
 | 
						return ac.err.Error()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Status returns the HTTP Response Status Code for this authChallenge.
 | 
					// Status returns the HTTP Response Status Code for this authChallenge.
 | 
				
			||||||
func (ac *authChallenge) Status() int {
 | 
					func (ac authChallenge) Status() int {
 | 
				
			||||||
	return http.StatusUnauthorized
 | 
						return http.StatusUnauthorized
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// challengeParams constructs the value to be used in
 | 
					// challengeParams constructs the value to be used in
 | 
				
			||||||
// the WWW-Authenticate response challenge header.
 | 
					// the WWW-Authenticate response challenge header.
 | 
				
			||||||
// See https://tools.ietf.org/html/rfc6750#section-3
 | 
					// See https://tools.ietf.org/html/rfc6750#section-3
 | 
				
			||||||
func (ac *authChallenge) challengeParams() string {
 | 
					func (ac authChallenge) challengeParams() string {
 | 
				
			||||||
	str := fmt.Sprintf("Bearer realm=%q,service=%q", ac.realm, ac.service)
 | 
						str := fmt.Sprintf("Bearer realm=%q,service=%q", ac.realm, ac.service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if scope := ac.accessSet.scopeParam(); scope != "" {
 | 
						if scope := ac.accessSet.scopeParam(); scope != "" {
 | 
				
			||||||
| 
						 | 
					@ -111,15 +112,9 @@ func (ac *authChallenge) challengeParams() string {
 | 
				
			||||||
	return str
 | 
						return str
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetHeader sets the WWW-Authenticate value for the given header.
 | 
					// SetChallenge sets the WWW-Authenticate value for the response.
 | 
				
			||||||
func (ac *authChallenge) SetHeader(header http.Header) {
 | 
					func (ac authChallenge) SetHeaders(w http.ResponseWriter) {
 | 
				
			||||||
	header.Add("WWW-Authenticate", ac.challengeParams())
 | 
						w.Header().Add("WWW-Authenticate", ac.challengeParams())
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// ServeHttp handles writing the challenge response
 | 
					 | 
				
			||||||
// by setting the challenge header.
 | 
					 | 
				
			||||||
func (ac *authChallenge) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 | 
					 | 
				
			||||||
	ac.SetHeader(w.Header())
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// accessController implements the auth.AccessController interface.
 | 
					// accessController implements the auth.AccessController interface.
 | 
				
			||||||
| 
						 | 
					@ -224,7 +219,7 @@ func (ac *accessController) Authorized(ctx context.Context, accessItems ...auth.
 | 
				
			||||||
		accessSet: newAccessSet(accessItems...),
 | 
							accessSet: newAccessSet(accessItems...),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req, err := ctxu.GetRequest(ctx)
 | 
						req, err := context.GetRequest(ctx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -518,7 +518,7 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont
 | 
				
			||||||
		switch err := err.(type) {
 | 
							switch err := err.(type) {
 | 
				
			||||||
		case auth.Challenge:
 | 
							case auth.Challenge:
 | 
				
			||||||
			// Add the appropriate WWW-Auth header
 | 
								// Add the appropriate WWW-Auth header
 | 
				
			||||||
			err.ServeHTTP(w, r)
 | 
								err.SetHeaders(w)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if err := errcode.ServeJSON(w, v2.ErrorCodeUnauthorized.WithDetail(accessRecords)); err != nil {
 | 
								if err := errcode.ServeJSON(w, v2.ErrorCodeUnauthorized.WithDetail(accessRecords)); err != nil {
 | 
				
			||||||
				ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors)
 | 
									ctxu.GetLogger(context).Errorf("error serving error json: %v (from %v)", err, context.Errors)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue