forked from TrueCloudLab/distribution
registry: unexport auth-related context utilities
The specifics of how the authorization for a request is propagated through the registry app are private implementation details. Hide those details from outsiders so they can be changed as needed without fear of breaking third-party code. Move the utilities for attaching a request's authorization status to its context and retrieving it from the context into the registry/handlers package as unexported symbols. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
parent
bd80d7590d
commit
868faeec67
4 changed files with 73 additions and 75 deletions
|
@ -32,22 +32,11 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
// UserKey is used to get the user object from
|
|
||||||
// a user context
|
|
||||||
UserKey = "auth.user"
|
|
||||||
|
|
||||||
// UserNameKey is used to get the user name from
|
|
||||||
// a user context
|
|
||||||
UserNameKey = "auth.user.name"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrInvalidCredential is returned when the auth token does not authenticate correctly.
|
// ErrInvalidCredential is returned when the auth token does not authenticate correctly.
|
||||||
ErrInvalidCredential = errors.New("invalid authorization credential")
|
ErrInvalidCredential = errors.New("invalid authorization credential")
|
||||||
|
@ -115,63 +104,6 @@ type CredentialAuthenticator interface {
|
||||||
AuthenticateUser(username, password string) error
|
AuthenticateUser(username, password string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithUser returns a context with the authorized user info.
|
|
||||||
func WithUser(ctx context.Context, user UserInfo) context.Context {
|
|
||||||
return userInfoContext{
|
|
||||||
Context: ctx,
|
|
||||||
user: user,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type userInfoContext struct {
|
|
||||||
context.Context
|
|
||||||
user UserInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (uic userInfoContext) Value(key interface{}) interface{} {
|
|
||||||
switch key {
|
|
||||||
case UserKey:
|
|
||||||
return uic.user
|
|
||||||
case UserNameKey:
|
|
||||||
return uic.user.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
return uic.Context.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithResources returns a context with the authorized resources.
|
|
||||||
func WithResources(ctx context.Context, resources []Resource) context.Context {
|
|
||||||
return resourceContext{
|
|
||||||
Context: ctx,
|
|
||||||
resources: resources,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type resourceContext struct {
|
|
||||||
context.Context
|
|
||||||
resources []Resource
|
|
||||||
}
|
|
||||||
|
|
||||||
type resourceKey struct{}
|
|
||||||
|
|
||||||
func (rc resourceContext) Value(key interface{}) interface{} {
|
|
||||||
if key == (resourceKey{}) {
|
|
||||||
return rc.resources
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc.Context.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthorizedResources returns the list of resources which have
|
|
||||||
// been authorized for this request.
|
|
||||||
func AuthorizedResources(ctx context.Context) []Resource {
|
|
||||||
if resources, ok := ctx.Value(resourceKey{}).([]Resource); ok {
|
|
||||||
return resources
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitFunc is the type of an AccessController factory function and is used
|
// InitFunc is the type of an AccessController factory function and is used
|
||||||
// to register the constructor for different AccesController backends.
|
// to register the constructor for different AccesController backends.
|
||||||
type InitFunc func(options map[string]interface{}) (AccessController, error)
|
type InitFunc func(options map[string]interface{}) (AccessController, error)
|
||||||
|
|
|
@ -635,7 +635,7 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add username to request logging
|
// Add username to request logging
|
||||||
context.Context = dcontext.WithLogger(context.Context, dcontext.GetLogger(context.Context, auth.UserNameKey))
|
context.Context = dcontext.WithLogger(context.Context, dcontext.GetLogger(context.Context, userNameKey))
|
||||||
|
|
||||||
// sync up context on the request.
|
// sync up context on the request.
|
||||||
r = r.WithContext(context)
|
r = r.WithContext(context)
|
||||||
|
@ -822,10 +822,10 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont
|
||||||
return fmt.Errorf("access controller returned neither an access grant nor an error")
|
return fmt.Errorf("access controller returned neither an access grant nor an error")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := auth.WithUser(context.Context, grant.User)
|
ctx := withUser(context.Context, grant.User)
|
||||||
ctx = auth.WithResources(ctx, grant.Resources)
|
ctx = withResources(ctx, grant.Resources)
|
||||||
|
|
||||||
dcontext.GetLogger(ctx, auth.UserNameKey).Info("authorized request")
|
dcontext.GetLogger(ctx, userNameKey).Info("authorized request")
|
||||||
// TODO(stevvooe): This pattern needs to be cleaned up a bit. One context
|
// TODO(stevvooe): This pattern needs to be cleaned up a bit. One context
|
||||||
// should be replaced by another, rather than replacing the context on a
|
// should be replaced by another, rather than replacing the context on a
|
||||||
// mutable object.
|
// mutable object.
|
||||||
|
|
|
@ -77,10 +77,20 @@ func getUploadUUID(ctx context.Context) (uuid string) {
|
||||||
return dcontext.GetStringValue(ctx, "vars.uuid")
|
return dcontext.GetStringValue(ctx, "vars.uuid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// userKey is used to get the user object from
|
||||||
|
// a user context
|
||||||
|
userKey = "auth.user"
|
||||||
|
|
||||||
|
// userNameKey is used to get the user name from
|
||||||
|
// a user context
|
||||||
|
userNameKey = "auth.user.name"
|
||||||
|
)
|
||||||
|
|
||||||
// getUserName attempts to resolve a username from the context and request. If
|
// getUserName attempts to resolve a username from the context and request. If
|
||||||
// a username cannot be resolved, the empty string is returned.
|
// a username cannot be resolved, the empty string is returned.
|
||||||
func getUserName(ctx context.Context, r *http.Request) string {
|
func getUserName(ctx context.Context, r *http.Request) string {
|
||||||
username := dcontext.GetStringValue(ctx, auth.UserNameKey)
|
username := dcontext.GetStringValue(ctx, userNameKey)
|
||||||
|
|
||||||
// Fallback to request user with basic auth
|
// Fallback to request user with basic auth
|
||||||
if username == "" {
|
if username == "" {
|
||||||
|
@ -93,3 +103,60 @@ func getUserName(ctx context.Context, r *http.Request) string {
|
||||||
|
|
||||||
return username
|
return username
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// withUser returns a context with the authorized user info.
|
||||||
|
func withUser(ctx context.Context, user auth.UserInfo) context.Context {
|
||||||
|
return userInfoContext{
|
||||||
|
Context: ctx,
|
||||||
|
user: user,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type userInfoContext struct {
|
||||||
|
context.Context
|
||||||
|
user auth.UserInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func (uic userInfoContext) Value(key interface{}) interface{} {
|
||||||
|
switch key {
|
||||||
|
case userKey:
|
||||||
|
return uic.user
|
||||||
|
case userNameKey:
|
||||||
|
return uic.user.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
return uic.Context.Value(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// withResources returns a context with the authorized resources.
|
||||||
|
func withResources(ctx context.Context, resources []auth.Resource) context.Context {
|
||||||
|
return resourceContext{
|
||||||
|
Context: ctx,
|
||||||
|
resources: resources,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type resourceContext struct {
|
||||||
|
context.Context
|
||||||
|
resources []auth.Resource
|
||||||
|
}
|
||||||
|
|
||||||
|
type resourceKey struct{}
|
||||||
|
|
||||||
|
func (rc resourceContext) Value(key interface{}) interface{} {
|
||||||
|
if key == (resourceKey{}) {
|
||||||
|
return rc.resources
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc.Context.Value(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// authorizedResources returns the list of resources which have
|
||||||
|
// been authorized for this request.
|
||||||
|
func authorizedResources(ctx context.Context) []auth.Resource {
|
||||||
|
if resources, ok := ctx.Value(resourceKey{}).([]auth.Resource); ok {
|
||||||
|
return resources
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/distribution/distribution/v3/manifest/ocischema"
|
"github.com/distribution/distribution/v3/manifest/ocischema"
|
||||||
"github.com/distribution/distribution/v3/manifest/schema2"
|
"github.com/distribution/distribution/v3/manifest/schema2"
|
||||||
"github.com/distribution/distribution/v3/registry/api/errcode"
|
"github.com/distribution/distribution/v3/registry/api/errcode"
|
||||||
"github.com/distribution/distribution/v3/registry/auth"
|
|
||||||
"github.com/distribution/distribution/v3/registry/storage/driver"
|
"github.com/distribution/distribution/v3/registry/storage/driver"
|
||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
|
@ -394,7 +393,7 @@ func (imh *manifestHandler) applyResourcePolicy(manifest distribution.Manifest)
|
||||||
return errcode.ErrorCodeDenied.WithMessage(fmt.Sprintf("registry does not allow %s manifest", class))
|
return errcode.ErrorCodeDenied.WithMessage(fmt.Sprintf("registry does not allow %s manifest", class))
|
||||||
}
|
}
|
||||||
|
|
||||||
resources := auth.AuthorizedResources(imh)
|
resources := authorizedResources(imh)
|
||||||
n := imh.Repository.Named().Name()
|
n := imh.Repository.Named().Name()
|
||||||
|
|
||||||
var foundResource bool
|
var foundResource bool
|
||||||
|
|
Loading…
Reference in a new issue