pkg: authorization: cleanup

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2015-12-16 12:01:04 +01:00
parent 207e5e455a
commit fb77ffd682
4 changed files with 35 additions and 67 deletions

View file

@ -26,7 +26,13 @@ import (
// For response manipulation, the response from each plugin is piped between plugins. Plugin execution order
// is determined according to daemon parameters
func NewCtx(authZPlugins []Plugin, user, userAuthNMethod, requestMethod, requestURI string) *Ctx {
return &Ctx{plugins: authZPlugins, user: user, userAuthNMethod: userAuthNMethod, requestMethod: requestMethod, requestURI: requestURI}
return &Ctx{
plugins: authZPlugins,
user: user,
userAuthNMethod: userAuthNMethod,
requestMethod: requestMethod,
requestURI: requestURI,
}
}
// Ctx stores a a single request-response interaction context
@ -41,27 +47,26 @@ type Ctx struct {
}
// AuthZRequest authorized the request to the docker daemon using authZ plugins
func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) (err error) {
func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error {
var body []byte
if sendBody(a.requestURI, r.Header) {
var drainedBody io.ReadCloser
var (
err error
drainedBody io.ReadCloser
)
drainedBody, r.Body, err = drainBody(r.Body)
if err != nil {
return err
}
body, err = ioutil.ReadAll(drainedBody)
defer drainedBody.Close()
body, err = ioutil.ReadAll(drainedBody)
if err != nil {
return err
}
}
var h bytes.Buffer
err = r.Header.Write(&h)
if err != nil {
if err := r.Header.Write(&h); err != nil {
return err
}
@ -74,9 +79,7 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) (err error) {
RequestHeaders: headers(r.Header)}
for _, plugin := range a.plugins {
authRes, err := plugin.AuthZRequest(a.authReq)
if err != nil {
return err
}
@ -91,7 +94,6 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) (err error) {
// AuthZResponse authorized and manipulates the response from docker daemon using authZ plugins
func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
a.authReq.ResponseStatusCode = rm.StatusCode()
a.authReq.ResponseHeaders = headers(rm.Header())
@ -100,9 +102,7 @@ func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
}
for _, plugin := range a.plugins {
authRes, err := plugin.AuthZResponse(a.authReq)
if err != nil {
return err
}
@ -119,12 +119,12 @@ func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
// drainBody dump the body, it reads the body data into memory and
// see go sources /go/src/net/http/httputil/dump.go
func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
func drainBody(b io.ReadCloser) (io.ReadCloser, io.ReadCloser, error) {
var buf bytes.Buffer
if _, err = buf.ReadFrom(b); err != nil {
if _, err := buf.ReadFrom(b); err != nil {
return nil, nil, err
}
if err = b.Close(); err != nil {
if err := b.Close(); err != nil {
return nil, nil, err
}
return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
@ -132,7 +132,6 @@ func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
// sendBody returns true when request/response body should be sent to AuthZPlugin
func sendBody(url string, header http.Header) bool {
// Skip body for auth endpoint
if strings.HasSuffix(url, "/auth") {
return false

View file

@ -2,10 +2,6 @@ package authorization
import (
"encoding/json"
"fmt"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/tlsconfig"
"github.com/gorilla/mux"
"io/ioutil"
"log"
"net"
@ -15,12 +11,15 @@ import (
"path"
"reflect"
"testing"
"github.com/docker/docker/pkg/plugins"
"github.com/docker/docker/pkg/tlsconfig"
"github.com/gorilla/mux"
)
const pluginAddress = "authzplugin.sock"
func TestAuthZRequestPlugin(t *testing.T) {
server := authZPluginTestServer{t: t}
go server.start()
defer server.stop()
@ -40,7 +39,6 @@ func TestAuthZRequestPlugin(t *testing.T) {
}
actualResponse, err := authZPlugin.AuthZRequest(&request)
if err != nil {
t.Fatalf("Failed to authorize request %v", err)
}
@ -54,7 +52,6 @@ func TestAuthZRequestPlugin(t *testing.T) {
}
func TestAuthZResponsePlugin(t *testing.T) {
server := authZPluginTestServer{t: t}
go server.start()
defer server.stop()
@ -71,7 +68,6 @@ func TestAuthZResponsePlugin(t *testing.T) {
}
actualResponse, err := authZPlugin.AuthZResponse(&request)
if err != nil {
t.Fatalf("Failed to authorize request %v", err)
}
@ -85,7 +81,6 @@ func TestAuthZResponsePlugin(t *testing.T) {
}
func TestResponseModifier(t *testing.T) {
r := httptest.NewRecorder()
m := NewResponseModifier(r)
m.Header().Set("h1", "v1")
@ -105,7 +100,6 @@ func TestResponseModifier(t *testing.T) {
}
func TestResponseModifierOverride(t *testing.T) {
r := httptest.NewRecorder()
m := NewResponseModifier(r)
m.Header().Set("h1", "v1")
@ -137,18 +131,12 @@ func TestResponseModifierOverride(t *testing.T) {
// createTestPlugin creates a new sample authorization plugin
func createTestPlugin(t *testing.T) *authorizationPlugin {
plugin := &plugins.Plugin{Name: "authz"}
var err error
pwd, err := os.Getwd()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if err != nil {
log.Fatal(err)
}
plugin.Client, err = plugins.NewClient("unix:///"+path.Join(pwd, pluginAddress), tlsconfig.Options{InsecureSkipVerify: true})
if err != nil {
t.Fatalf("Failed to create client %v", err)
}
@ -186,9 +174,7 @@ func (t *authZPluginTestServer) start() {
// stop stops the test server that implements the plugin
func (t *authZPluginTestServer) stop() {
os.Remove(pluginAddress)
if t.listener != nil {
t.listener.Close()
}
@ -196,9 +182,7 @@ func (t *authZPluginTestServer) stop() {
// auth is a used to record/replay the authentication api messages
func (t *authZPluginTestServer) auth(w http.ResponseWriter, r *http.Request) {
t.recordedRequest = Request{}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
json.Unmarshal(body, &t.recordedRequest)
@ -207,11 +191,9 @@ func (t *authZPluginTestServer) auth(w http.ResponseWriter, r *http.Request) {
log.Fatal(err)
}
w.Write(b)
}
func (t *authZPluginTestServer) activate(w http.ResponseWriter, r *http.Request) {
b, err := json.Marshal(plugins.Manifest{Implements: []string{AuthZApiImplements}})
if err != nil {
log.Fatal(err)

View file

@ -8,12 +8,11 @@ import (
// Plugin allows third party plugins to authorize requests and responses
// in the context of docker API
type Plugin interface {
// AuthZRequest authorize the request from the client to the daemon
AuthZRequest(authReq *Request) (authRes *Response, err error)
AuthZRequest(*Request) (*Response, error)
// AuthZResponse authorize the response from the daemon to the client
AuthZResponse(authReq *Request) (authRes *Response, err error)
AuthZResponse(*Request) (*Response, error)
}
// NewPlugins constructs and initialize the authorization plugins based on plugin names
@ -35,38 +34,30 @@ func newAuthorizationPlugin(name string) Plugin {
return &authorizationPlugin{name: name}
}
func (a *authorizationPlugin) AuthZRequest(authReq *Request) (authRes *Response, err error) {
func (a *authorizationPlugin) AuthZRequest(authReq *Request) (*Response, error) {
logrus.Debugf("AuthZ requset using plugins %s", a.name)
err = a.initPlugin()
if err != nil {
if err := a.initPlugin(); err != nil {
return nil, err
}
authRes = &Response{}
err = a.plugin.Client.Call(AuthZApiRequest, authReq, authRes)
if err != nil {
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) (authRes *Response, err error) {
func (a *authorizationPlugin) AuthZResponse(authReq *Request) (*Response, error) {
logrus.Debugf("AuthZ response using plugins %s", a.name)
err = a.initPlugin()
if err != nil {
if err := a.initPlugin(); err != nil {
return nil, err
}
authRes = &Response{}
err = a.plugin.Client.Call(AuthZApiResponse, authReq, authRes)
if err != nil {
authRes := &Response{}
if err := a.plugin.Client.Call(AuthZApiResponse, authReq, authRes); err != nil {
return nil, err
}
@ -74,10 +65,10 @@ func (a *authorizationPlugin) AuthZResponse(authReq *Request) (authRes *Response
}
// initPlugin initialize the authorization plugin if needed
func (a *authorizationPlugin) initPlugin() (err error) {
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

View file

@ -81,9 +81,7 @@ func (rm *responseModifier) OverrideStatusCode(statusCode int) {
// Override replace the headers of the HTTP reply
func (rm *responseModifier) OverrideHeader(b []byte) error {
header := http.Header{}
err := json.Unmarshal(b, &header)
if err != nil {
if err := json.Unmarshal(b, &header); err != nil {
return err
}
rm.header = header
@ -103,8 +101,7 @@ func (rm *responseModifier) RawBody() []byte {
func (rm *responseModifier) RawHeaders() ([]byte, error) {
var b bytes.Buffer
err := rm.header.Write(&b)
if err != nil {
if err := rm.header.Write(&b); err != nil {
return nil, err
}
return b.Bytes(), nil
@ -121,7 +118,6 @@ func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
// Flush flushes all data to the HTTP response
func (rm *responseModifier) Flush() error {
// Copy the status code
if rm.statusCode > 0 {
rm.rw.WriteHeader(rm.statusCode)