commit
ebb1d56ecb
10 changed files with 49 additions and 77 deletions
|
@ -70,7 +70,7 @@ func (cli *Client) postHijacked(path string, query url.Values, body interface{},
|
|||
|
||||
rwc, br := clientconn.Hijack()
|
||||
|
||||
return types.HijackedResponse{rwc, br}, nil
|
||||
return types.HijackedResponse{Conn: rwc, Reader: br}, nil
|
||||
}
|
||||
|
||||
func tlsDial(network, addr string, config *tls.Config) (net.Conn, error) {
|
||||
|
|
|
@ -29,7 +29,7 @@ func (cli *Client) NetworkRemove(networkID string) error {
|
|||
|
||||
// NetworkConnect connects a container to an existent network in the docker host.
|
||||
func (cli *Client) NetworkConnect(networkID, containerID string) error {
|
||||
nc := types.NetworkConnect{containerID}
|
||||
nc := types.NetworkConnect{Container: containerID}
|
||||
resp, err := cli.post("/networks/"+networkID+"/connect", nil, nc, nil)
|
||||
ensureReaderClosed(resp)
|
||||
return err
|
||||
|
@ -37,7 +37,7 @@ func (cli *Client) NetworkConnect(networkID, containerID string) error {
|
|||
|
||||
// NetworkDisconnect disconnects a container from an existent network in the docker host.
|
||||
func (cli *Client) NetworkDisconnect(networkID, containerID string) error {
|
||||
nc := types.NetworkConnect{containerID}
|
||||
nc := types.NetworkConnect{Container: containerID}
|
||||
resp, err := cli.post("/networks/"+networkID+"/disconnect", nil, nc, nil)
|
||||
ensureReaderClosed(resp)
|
||||
return err
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/daemon/graphdriver/graphtest"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/daemon/graphdriver/graphtest"
|
||||
)
|
||||
|
||||
// This avoids creating a new driver for each test if all tests are run
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
package zfs
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/daemon/graphdriver/graphtest"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/daemon/graphdriver/graphtest"
|
||||
)
|
||||
|
||||
// This avoids creating a new driver for each test if all tests are run
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"github.com/docker/docker/volume"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/volume"
|
||||
)
|
||||
|
||||
func TestParseVolumesFrom(t *testing.T) {
|
||||
|
|
|
@ -5,15 +5,16 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/docker/docker/pkg/authorization"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/go-check/check"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/authorization"
|
||||
"github.com/docker/docker/pkg/integration/checker"
|
||||
"github.com/docker/docker/pkg/plugins"
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
const testAuthZPlugin = "authzplugin"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue