Update authz plugin list on failure.

When daemon fails to load an authz plugin, it should be removed from
the plugin list. Else the plugin is retried on every request and
response, resulting in undesired behavior (eg. daemon panic)

Signed-off-by: Anusha Ragunathan <anusha@docker.com>
This commit is contained in:
Anusha Ragunathan 2016-10-26 16:29:48 -07:00
Родитель ff6db320f8
Коммит fae904af02
3 изменённых файлов: 32 добавлений и 3 удалений

Просмотреть файл

@ -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)
}

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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()