f35a0f3210
This patches avoids registering (and calling) the same plugin more than once. Using an helper map which indexes by name guarantees this and keeps the order. The behavior of overriding the same name in a flag is consistent with, for instance, the `docker run -v /test -v /test` flag which register the volume just once. Adds integration tests. Without this patch: ``` Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.080901676+01:00" level=debug msg="Calling GET /v1.22/info" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.081213202+01:00" level=debug msg="AuthZ request using plugin docker-novolume-plugin" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.081268132+01:00" level=debug msg="docker-novolume-plugin implements: authz" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.081699788+01:00" level=debug msg="AuthZ request using plugin docker-novolume-plugin" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.081762507+01:00" level=debug msg="docker-novolume-plugin implements: authz" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.082092480+01:00" level=debug msg="GET /v1.22/info" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.628691038+01:00" level=debug msg="AuthZ response using plugin docker-novolume-plugin" Dec 20 19:34:52 localhost.localdomain docker[9988]: time="2015-12-20T19:34:52.629880930+01:00" level=debug msg="AuthZ response using plugin docker-novolume-plugin" ``` With this patch: ``` Dec 20 19:37:32 localhost.localdomain docker[16620]: time="2015-12-20T19:37:32.376523958+01:00" level=debug msg="Calling GET /v1.22/info" Dec 20 19:37:32 localhost.localdomain docker[16620]: time="2015-12-20T19:37:32.376715483+01:00" level=debug msg="AuthZ request using plugin docker-novolume-plugin" Dec 20 19:37:32 localhost.localdomain docker[16620]: time="2015-12-20T19:37:32.376771230+01:00" level=debug msg="docker-novolume-plugin implements: authz" Dec 20 19:37:32 localhost.localdomain docker[16620]: time="2015-12-20T19:37:32.377698897+01:00" level=debug msg="GET /v1.22/info" Dec 20 19:37:32 localhost.localdomain docker[16620]: time="2015-12-20T19:37:32.951016441+01:00" level=debug msg="AuthZ response using plugin docker-novolume-plugin" ``` Also removes a somehow duplicate debug statement (leaving only the second one as it's a loop of plugin's manifest): ``` Dec 20 19:52:30 localhost.localdomain docker[25767]: time="2015-12-20T19:52:30.544090518+01:00" level=debug msg="docker-novolume-plugin's manifest: &{[authz]}" Dec 20 19:52:30 localhost.localdomain docker[25767]: time="2015-12-20T19:52:30.544170677+01:00" level=debug msg="docker-novolume-plugin implements: authz" ``` Signed-off-by: Antonio Murdaca <runcom@redhat.com>
83 lines
2 KiB
Go
83 lines
2 KiB
Go
package authorization
|
|
|
|
import "github.com/docker/docker/pkg/plugins"
|
|
|
|
// Plugin allows third party plugins to authorize requests and responses
|
|
// in the context of docker API
|
|
type Plugin interface {
|
|
// Name returns the registered plugin name
|
|
Name() string
|
|
|
|
// AuthZRequest authorize the request from the client to the daemon
|
|
AuthZRequest(*Request) (*Response, error)
|
|
|
|
// AuthZResponse authorize the response from the daemon to the client
|
|
AuthZResponse(*Request) (*Response, error)
|
|
}
|
|
|
|
// NewPlugins constructs and initialize the authorization plugins based on plugin names
|
|
func NewPlugins(names []string) []Plugin {
|
|
plugins := []Plugin{}
|
|
pluginsMap := make(map[string]struct{})
|
|
for _, name := range names {
|
|
if _, ok := pluginsMap[name]; ok {
|
|
continue
|
|
}
|
|
pluginsMap[name] = struct{}{}
|
|
plugins = append(plugins, newAuthorizationPlugin(name))
|
|
}
|
|
return plugins
|
|
}
|
|
|
|
// authorizationPlugin is an internal adapter to docker plugin system
|
|
type authorizationPlugin struct {
|
|
plugin *plugins.Plugin
|
|
name string
|
|
}
|
|
|
|
func newAuthorizationPlugin(name string) Plugin {
|
|
return &authorizationPlugin{name: name}
|
|
}
|
|
|
|
func (a *authorizationPlugin) Name() string {
|
|
return a.name
|
|
}
|
|
|
|
func (a *authorizationPlugin) AuthZRequest(authReq *Request) (*Response, error) {
|
|
if err := a.initPlugin(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
authRes := &Response{}
|
|
if err := a.plugin.Client.Call(AuthZApiRequest, authReq, authRes); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return authRes, nil
|
|
}
|
|
|
|
func (a *authorizationPlugin) AuthZResponse(authReq *Request) (*Response, error) {
|
|
if err := a.initPlugin(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
authRes := &Response{}
|
|
if err := a.plugin.Client.Call(AuthZApiResponse, authReq, authRes); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return authRes, nil
|
|
}
|
|
|
|
// initPlugin initialize the authorization plugin if needed
|
|
func (a *authorizationPlugin) initPlugin() error {
|
|
// Lazy loading of plugins
|
|
if a.plugin == nil {
|
|
var err error
|
|
a.plugin, err = plugins.Get(a.name, AuthZApiImplements)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|