authZ: more fixes

- fix naming and formatting
- provide more context when erroring auth
- do not capitalize errors
- fix wrong documentation
- remove ugly remoteError{}

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2015-12-18 12:34:19 +01:00
parent 7051dc2661
commit bc21007445
3 changed files with 40 additions and 50 deletions

View file

@ -7,6 +7,8 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
"github.com/Sirupsen/logrus"
) )
// NewCtx creates new authZ context, it is used to store authorization information related to a specific docker // NewCtx creates new authZ context, it is used to store authorization information related to a specific docker
@ -47,9 +49,9 @@ type Ctx struct {
} }
// AuthZRequest authorized the request to the docker daemon using authZ plugins // AuthZRequest authorized the request to the docker daemon using authZ plugins
func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error { func (ctx *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error {
var body []byte var body []byte
if sendBody(a.requestURI, r.Header) { if sendBody(ctx.requestURI, r.Header) {
var ( var (
err error err error
drainedBody io.ReadCloser drainedBody io.ReadCloser
@ -70,26 +72,25 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error {
return err return err
} }
a.authReq = &Request{ ctx.authReq = &Request{
User: a.user, User: ctx.user,
UserAuthNMethod: a.userAuthNMethod, UserAuthNMethod: ctx.userAuthNMethod,
RequestMethod: a.requestMethod, RequestMethod: ctx.requestMethod,
RequestURI: a.requestURI, RequestURI: ctx.requestURI,
RequestBody: body, RequestBody: body,
RequestHeaders: headers(r.Header)} RequestHeaders: headers(r.Header),
}
for _, plugin := range a.plugins { for _, plugin := range ctx.plugins {
authRes, err := plugin.AuthZRequest(a.authReq) logrus.Debugf("AuthZ request using plugin %s", plugin.Name())
authRes, err := plugin.AuthZRequest(ctx.authReq)
if err != nil { if err != nil {
return err return fmt.Errorf("plugin %s failed with error: %s", plugin.Name(), err)
}
if authRes.Err != "" {
return fmt.Errorf(authRes.Err)
} }
if !authRes.Allow { if !authRes.Allow {
return fmt.Errorf(authRes.Msg) return fmt.Errorf("authorization denied by plugin %s: %s", plugin.Name(), authRes.Msg)
} }
} }
@ -97,26 +98,24 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error {
} }
// AuthZResponse authorized and manipulates the response from docker daemon using authZ plugins // AuthZResponse authorized and manipulates the response from docker daemon using authZ plugins
func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { func (ctx *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
a.authReq.ResponseStatusCode = rm.StatusCode() ctx.authReq.ResponseStatusCode = rm.StatusCode()
a.authReq.ResponseHeaders = headers(rm.Header()) ctx.authReq.ResponseHeaders = headers(rm.Header())
if sendBody(a.requestURI, rm.Header()) { if sendBody(ctx.requestURI, rm.Header()) {
a.authReq.ResponseBody = rm.RawBody() ctx.authReq.ResponseBody = rm.RawBody()
} }
for _, plugin := range a.plugins { for _, plugin := range ctx.plugins {
authRes, err := plugin.AuthZResponse(a.authReq) logrus.Debugf("AuthZ response using plugin %s", plugin.Name())
if err != nil {
return err
}
if authRes.Err != "" { authRes, err := plugin.AuthZResponse(ctx.authReq)
return fmt.Errorf(authRes.Err) if err != nil {
return fmt.Errorf("plugin %s failed with error: %s", plugin.Name(), err)
} }
if !authRes.Allow { if !authRes.Allow {
return fmt.Errorf(authRes.Msg) return fmt.Errorf("authorization denied by plugin %s: %s", plugin.Name(), authRes.Msg)
} }
} }

View file

@ -1,13 +1,13 @@
package authorization package authorization
import ( import "github.com/docker/docker/pkg/plugins"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
)
// Plugin allows third party plugins to authorize requests and responses // Plugin allows third party plugins to authorize requests and responses
// in the context of docker API // in the context of docker API
type Plugin interface { type Plugin interface {
// Name returns the registered plugin name
Name() string
// AuthZRequest authorize the request from the client to the daemon // AuthZRequest authorize the request from the client to the daemon
AuthZRequest(*Request) (*Response, error) AuthZRequest(*Request) (*Response, error)
@ -34,9 +34,11 @@ func newAuthorizationPlugin(name string) Plugin {
return &authorizationPlugin{name: name} return &authorizationPlugin{name: name}
} }
func (a *authorizationPlugin) AuthZRequest(authReq *Request) (*Response, error) { func (a *authorizationPlugin) Name() string {
logrus.Debugf("AuthZ requset using plugins %s", a.name) return a.name
}
func (a *authorizationPlugin) AuthZRequest(authReq *Request) (*Response, error) {
if err := a.initPlugin(); err != nil { if err := a.initPlugin(); err != nil {
return nil, err return nil, err
} }
@ -50,8 +52,6 @@ func (a *authorizationPlugin) AuthZRequest(authReq *Request) (*Response, error)
} }
func (a *authorizationPlugin) AuthZResponse(authReq *Request) (*Response, error) { func (a *authorizationPlugin) AuthZResponse(authReq *Request) (*Response, error) {
logrus.Debugf("AuthZ response using plugins %s", a.name)
if err := a.initPlugin(); err != nil { if err := a.initPlugin(); err != nil {
return nil, err return nil, err
} }

View file

@ -20,15 +20,6 @@ const (
defaultTimeOut = 30 defaultTimeOut = 30
) )
type remoteError struct {
method string
err string
}
func (e *remoteError) Error() string {
return fmt.Sprintf("Plugin Error: %s, %s", e.err, e.method)
}
// NewClient creates a new plugin client (http). // NewClient creates a new plugin client (http).
func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) { func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) {
tr := &http.Transport{} tr := &http.Transport{}
@ -133,7 +124,7 @@ func (c *Client) callWithRetry(serviceMethod string, data io.Reader, retry bool)
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
b, err := ioutil.ReadAll(resp.Body) b, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, &remoteError{method: serviceMethod, err: err.Error()} return nil, fmt.Errorf("%s: %s", serviceMethod, err)
} }
// Plugins' Response(s) should have an Err field indicating what went // Plugins' Response(s) should have an Err field indicating what went
@ -144,13 +135,13 @@ func (c *Client) callWithRetry(serviceMethod string, data io.Reader, retry bool)
} }
remoteErr := responseErr{} remoteErr := responseErr{}
if err := json.Unmarshal(b, &remoteErr); err != nil { if err := json.Unmarshal(b, &remoteErr); err != nil {
return nil, &remoteError{method: serviceMethod, err: err.Error()} return nil, fmt.Errorf("%s: %s", serviceMethod, err)
} }
if remoteErr.Err != "" { if remoteErr.Err != "" {
return nil, &remoteError{method: serviceMethod, err: remoteErr.Err} return nil, fmt.Errorf("%s: %s", serviceMethod, remoteErr.Err)
} }
// old way... // old way...
return nil, &remoteError{method: serviceMethod, err: string(b)} return nil, fmt.Errorf("%s: %s", serviceMethod, string(b))
} }
return resp.Body, nil return resp.Body, nil
} }