diff --git a/pkg/authorization/authz.go b/pkg/authorization/authz.go index 04eef64b67..9080249b5e 100644 --- a/pkg/authorization/authz.go +++ b/pkg/authorization/authz.go @@ -52,6 +52,8 @@ type Ctx struct { } // AuthZRequest authorized the request to the docker daemon using authZ plugins +// Side effect: If the authz plugin is invalid, then update ctx.plugins, so that +// the caller(middleware) can update its list and stop retrying with invalid plugins. func (ctx *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error { var body []byte if sendBody(ctx.requestURI, r.Header) && r.ContentLength > 0 && r.ContentLength < maxBodySize { @@ -76,11 +78,14 @@ func (ctx *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error { RequestHeaders: headers(r.Header), } - for _, plugin := range ctx.plugins { + for i, plugin := range ctx.plugins { logrus.Debugf("AuthZ request using plugin %s", plugin.Name()) authRes, err := plugin.AuthZRequest(ctx.authReq) if err != nil { + if err == ErrInvalidPlugin { + ctx.plugins = append(ctx.plugins[:i], ctx.plugins[i+1:]...) + } return fmt.Errorf("plugin %s failed with error: %s", plugin.Name(), err) } @@ -93,6 +98,8 @@ func (ctx *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error { } // AuthZResponse authorized and manipulates the response from docker daemon using authZ plugins +// Side effect: If the authz plugin is invalid, then update ctx.plugins, so that +// the caller(middleware) can update its list and stop retrying with invalid plugins. func (ctx *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { ctx.authReq.ResponseStatusCode = rm.StatusCode() ctx.authReq.ResponseHeaders = headers(rm.Header()) @@ -101,11 +108,14 @@ func (ctx *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { ctx.authReq.ResponseBody = rm.RawBody() } - for _, plugin := range ctx.plugins { + for i, plugin := range ctx.plugins { logrus.Debugf("AuthZ response using plugin %s", plugin.Name()) authRes, err := plugin.AuthZResponse(ctx.authReq) if err != nil { + if err == ErrInvalidPlugin { + ctx.plugins = append(ctx.plugins[:i], ctx.plugins[i+1:]...) + } return fmt.Errorf("plugin %s failed with error: %s", plugin.Name(), err) } diff --git a/pkg/authorization/middleware.go b/pkg/authorization/middleware.go index 52890dd360..ab8e810efc 100644 --- a/pkg/authorization/middleware.go +++ b/pkg/authorization/middleware.go @@ -2,6 +2,7 @@ package authorization import ( "net/http" + "strings" "sync" "github.com/Sirupsen/logrus" @@ -59,6 +60,11 @@ func (m *Middleware) WrapHandler(handler func(ctx context.Context, w http.Respon if err := authCtx.AuthZRequest(w, r); err != nil { logrus.Errorf("AuthZRequest for %s %s returned error: %s", r.Method, r.RequestURI, err) + if strings.Contains(err.Error(), ErrInvalidPlugin.Error()) { + m.mu.Lock() + m.plugins = authCtx.plugins + m.mu.Unlock() + } return err } @@ -72,6 +78,11 @@ func (m *Middleware) WrapHandler(handler func(ctx context.Context, w http.Respon if err := authCtx.AuthZResponse(rw, r); errD == nil && err != nil { logrus.Errorf("AuthZResponse for %s %s returned error: %s", r.Method, r.RequestURI, err) + if strings.Contains(err.Error(), ErrInvalidPlugin.Error()) { + m.mu.Lock() + m.plugins = authCtx.plugins + m.mu.Unlock() + } return err } diff --git a/pkg/authorization/plugin.go b/pkg/authorization/plugin.go index 4b1c71bd4b..5c3431d5cf 100644 --- a/pkg/authorization/plugin.go +++ b/pkg/authorization/plugin.go @@ -1,12 +1,20 @@ package authorization import ( + "errors" "sync" "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugins" ) +var ( + // ErrInvalidPlugin indicates that the plugin cannot be used. This is + // because the plugin was not found or does not implement necessary + // functionality + ErrInvalidPlugin = errors.New("invalid plugin") +) + // Plugin allows third party plugins to authorize requests and responses // in the context of docker API type Plugin interface { @@ -102,7 +110,7 @@ func (a *authorizationPlugin) initPlugin() error { plugin, e = plugins.Get(a.name, AuthZApiImplements) } if e != nil { - err = e + err = ErrInvalidPlugin return } a.plugin = plugin.Client()