Signed-off-by: Antonio Murdaca <runcom@redhat.com>
Antonio Murdaca authored on 2015/12/16 20:01:04... | ... |
@@ -26,7 +26,13 @@ import ( |
26 | 26 |
// For response manipulation, the response from each plugin is piped between plugins. Plugin execution order |
27 | 27 |
// is determined according to daemon parameters |
28 | 28 |
func NewCtx(authZPlugins []Plugin, user, userAuthNMethod, requestMethod, requestURI string) *Ctx { |
29 |
- return &Ctx{plugins: authZPlugins, user: user, userAuthNMethod: userAuthNMethod, requestMethod: requestMethod, requestURI: requestURI} |
|
29 |
+ return &Ctx{ |
|
30 |
+ plugins: authZPlugins, |
|
31 |
+ user: user, |
|
32 |
+ userAuthNMethod: userAuthNMethod, |
|
33 |
+ requestMethod: requestMethod, |
|
34 |
+ requestURI: requestURI, |
|
35 |
+ } |
|
30 | 36 |
} |
31 | 37 |
|
32 | 38 |
// Ctx stores a a single request-response interaction context |
... | ... |
@@ -41,27 +47,26 @@ type Ctx struct { |
41 | 41 |
} |
42 | 42 |
|
43 | 43 |
// AuthZRequest authorized the request to the docker daemon using authZ plugins |
44 |
-func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) (err error) { |
|
45 |
- |
|
44 |
+func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error { |
|
46 | 45 |
var body []byte |
47 | 46 |
if sendBody(a.requestURI, r.Header) { |
48 |
- var drainedBody io.ReadCloser |
|
47 |
+ var ( |
|
48 |
+ err error |
|
49 |
+ drainedBody io.ReadCloser |
|
50 |
+ ) |
|
49 | 51 |
drainedBody, r.Body, err = drainBody(r.Body) |
50 | 52 |
if err != nil { |
51 | 53 |
return err |
52 | 54 |
} |
53 |
- body, err = ioutil.ReadAll(drainedBody) |
|
54 | 55 |
defer drainedBody.Close() |
55 |
- |
|
56 |
+ body, err = ioutil.ReadAll(drainedBody) |
|
56 | 57 |
if err != nil { |
57 | 58 |
return err |
58 | 59 |
} |
59 | 60 |
} |
60 | 61 |
|
61 | 62 |
var h bytes.Buffer |
62 |
- err = r.Header.Write(&h) |
|
63 |
- |
|
64 |
- if err != nil { |
|
63 |
+ if err := r.Header.Write(&h); err != nil { |
|
65 | 64 |
return err |
66 | 65 |
} |
67 | 66 |
|
... | ... |
@@ -74,9 +79,7 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) (err error) { |
74 | 74 |
RequestHeaders: headers(r.Header)} |
75 | 75 |
|
76 | 76 |
for _, plugin := range a.plugins { |
77 |
- |
|
78 | 77 |
authRes, err := plugin.AuthZRequest(a.authReq) |
79 |
- |
|
80 | 78 |
if err != nil { |
81 | 79 |
return err |
82 | 80 |
} |
... | ... |
@@ -91,7 +94,6 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) (err error) { |
91 | 91 |
|
92 | 92 |
// AuthZResponse authorized and manipulates the response from docker daemon using authZ plugins |
93 | 93 |
func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { |
94 |
- |
|
95 | 94 |
a.authReq.ResponseStatusCode = rm.StatusCode() |
96 | 95 |
a.authReq.ResponseHeaders = headers(rm.Header()) |
97 | 96 |
|
... | ... |
@@ -100,9 +102,7 @@ func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { |
100 | 100 |
} |
101 | 101 |
|
102 | 102 |
for _, plugin := range a.plugins { |
103 |
- |
|
104 | 103 |
authRes, err := plugin.AuthZResponse(a.authReq) |
105 |
- |
|
106 | 104 |
if err != nil { |
107 | 105 |
return err |
108 | 106 |
} |
... | ... |
@@ -119,12 +119,12 @@ func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error { |
119 | 119 |
|
120 | 120 |
// drainBody dump the body, it reads the body data into memory and |
121 | 121 |
// see go sources /go/src/net/http/httputil/dump.go |
122 |
-func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) { |
|
122 |
+func drainBody(b io.ReadCloser) (io.ReadCloser, io.ReadCloser, error) { |
|
123 | 123 |
var buf bytes.Buffer |
124 |
- if _, err = buf.ReadFrom(b); err != nil { |
|
124 |
+ if _, err := buf.ReadFrom(b); err != nil { |
|
125 | 125 |
return nil, nil, err |
126 | 126 |
} |
127 |
- if err = b.Close(); err != nil { |
|
127 |
+ if err := b.Close(); err != nil { |
|
128 | 128 |
return nil, nil, err |
129 | 129 |
} |
130 | 130 |
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) { |
132 | 132 |
|
133 | 133 |
// sendBody returns true when request/response body should be sent to AuthZPlugin |
134 | 134 |
func sendBody(url string, header http.Header) bool { |
135 |
- |
|
136 | 135 |
// Skip body for auth endpoint |
137 | 136 |
if strings.HasSuffix(url, "/auth") { |
138 | 137 |
return false |
... | ... |
@@ -2,10 +2,6 @@ package authorization |
2 | 2 |
|
3 | 3 |
import ( |
4 | 4 |
"encoding/json" |
5 |
- "fmt" |
|
6 |
- "github.com/docker/docker/pkg/plugins" |
|
7 |
- "github.com/docker/docker/pkg/tlsconfig" |
|
8 |
- "github.com/gorilla/mux" |
|
9 | 5 |
"io/ioutil" |
10 | 6 |
"log" |
11 | 7 |
"net" |
... | ... |
@@ -15,12 +11,15 @@ import ( |
15 | 15 |
"path" |
16 | 16 |
"reflect" |
17 | 17 |
"testing" |
18 |
+ |
|
19 |
+ "github.com/docker/docker/pkg/plugins" |
|
20 |
+ "github.com/docker/docker/pkg/tlsconfig" |
|
21 |
+ "github.com/gorilla/mux" |
|
18 | 22 |
) |
19 | 23 |
|
20 | 24 |
const pluginAddress = "authzplugin.sock" |
21 | 25 |
|
22 | 26 |
func TestAuthZRequestPlugin(t *testing.T) { |
23 |
- |
|
24 | 27 |
server := authZPluginTestServer{t: t} |
25 | 28 |
go server.start() |
26 | 29 |
defer server.stop() |
... | ... |
@@ -40,7 +39,6 @@ func TestAuthZRequestPlugin(t *testing.T) { |
40 | 40 |
} |
41 | 41 |
|
42 | 42 |
actualResponse, err := authZPlugin.AuthZRequest(&request) |
43 |
- |
|
44 | 43 |
if err != nil { |
45 | 44 |
t.Fatalf("Failed to authorize request %v", err) |
46 | 45 |
} |
... | ... |
@@ -54,7 +52,6 @@ func TestAuthZRequestPlugin(t *testing.T) { |
54 | 54 |
} |
55 | 55 |
|
56 | 56 |
func TestAuthZResponsePlugin(t *testing.T) { |
57 |
- |
|
58 | 57 |
server := authZPluginTestServer{t: t} |
59 | 58 |
go server.start() |
60 | 59 |
defer server.stop() |
... | ... |
@@ -71,7 +68,6 @@ func TestAuthZResponsePlugin(t *testing.T) { |
71 | 71 |
} |
72 | 72 |
|
73 | 73 |
actualResponse, err := authZPlugin.AuthZResponse(&request) |
74 |
- |
|
75 | 74 |
if err != nil { |
76 | 75 |
t.Fatalf("Failed to authorize request %v", err) |
77 | 76 |
} |
... | ... |
@@ -85,7 +81,6 @@ func TestAuthZResponsePlugin(t *testing.T) { |
85 | 85 |
} |
86 | 86 |
|
87 | 87 |
func TestResponseModifier(t *testing.T) { |
88 |
- |
|
89 | 88 |
r := httptest.NewRecorder() |
90 | 89 |
m := NewResponseModifier(r) |
91 | 90 |
m.Header().Set("h1", "v1") |
... | ... |
@@ -105,7 +100,6 @@ func TestResponseModifier(t *testing.T) { |
105 | 105 |
} |
106 | 106 |
|
107 | 107 |
func TestResponseModifierOverride(t *testing.T) { |
108 |
- |
|
109 | 108 |
r := httptest.NewRecorder() |
110 | 109 |
m := NewResponseModifier(r) |
111 | 110 |
m.Header().Set("h1", "v1") |
... | ... |
@@ -137,18 +131,12 @@ func TestResponseModifierOverride(t *testing.T) { |
137 | 137 |
// createTestPlugin creates a new sample authorization plugin |
138 | 138 |
func createTestPlugin(t *testing.T) *authorizationPlugin { |
139 | 139 |
plugin := &plugins.Plugin{Name: "authz"} |
140 |
- var err error |
|
141 | 140 |
pwd, err := os.Getwd() |
142 | 141 |
if err != nil { |
143 |
- fmt.Println(err) |
|
144 |
- os.Exit(1) |
|
145 |
- } |
|
146 |
- if err != nil { |
|
147 | 142 |
log.Fatal(err) |
148 | 143 |
} |
149 | 144 |
|
150 | 145 |
plugin.Client, err = plugins.NewClient("unix:///"+path.Join(pwd, pluginAddress), tlsconfig.Options{InsecureSkipVerify: true}) |
151 |
- |
|
152 | 146 |
if err != nil { |
153 | 147 |
t.Fatalf("Failed to create client %v", err) |
154 | 148 |
} |
... | ... |
@@ -186,9 +174,7 @@ func (t *authZPluginTestServer) start() { |
186 | 186 |
|
187 | 187 |
// stop stops the test server that implements the plugin |
188 | 188 |
func (t *authZPluginTestServer) stop() { |
189 |
- |
|
190 | 189 |
os.Remove(pluginAddress) |
191 |
- |
|
192 | 190 |
if t.listener != nil { |
193 | 191 |
t.listener.Close() |
194 | 192 |
} |
... | ... |
@@ -196,9 +182,7 @@ func (t *authZPluginTestServer) stop() { |
196 | 196 |
|
197 | 197 |
// auth is a used to record/replay the authentication api messages |
198 | 198 |
func (t *authZPluginTestServer) auth(w http.ResponseWriter, r *http.Request) { |
199 |
- |
|
200 | 199 |
t.recordedRequest = Request{} |
201 |
- |
|
202 | 200 |
defer r.Body.Close() |
203 | 201 |
body, err := ioutil.ReadAll(r.Body) |
204 | 202 |
json.Unmarshal(body, &t.recordedRequest) |
... | ... |
@@ -207,11 +191,9 @@ func (t *authZPluginTestServer) auth(w http.ResponseWriter, r *http.Request) { |
207 | 207 |
log.Fatal(err) |
208 | 208 |
} |
209 | 209 |
w.Write(b) |
210 |
- |
|
211 | 210 |
} |
212 | 211 |
|
213 | 212 |
func (t *authZPluginTestServer) activate(w http.ResponseWriter, r *http.Request) { |
214 |
- |
|
215 | 213 |
b, err := json.Marshal(plugins.Manifest{Implements: []string{AuthZApiImplements}}) |
216 | 214 |
if err != nil { |
217 | 215 |
log.Fatal(err) |
... | ... |
@@ -8,12 +8,11 @@ import ( |
8 | 8 |
// Plugin allows third party plugins to authorize requests and responses |
9 | 9 |
// in the context of docker API |
10 | 10 |
type Plugin interface { |
11 |
- |
|
12 | 11 |
// AuthZRequest authorize the request from the client to the daemon |
13 |
- AuthZRequest(authReq *Request) (authRes *Response, err error) |
|
12 |
+ AuthZRequest(*Request) (*Response, error) |
|
14 | 13 |
|
15 | 14 |
// AuthZResponse authorize the response from the daemon to the client |
16 |
- AuthZResponse(authReq *Request) (authRes *Response, err error) |
|
15 |
+ AuthZResponse(*Request) (*Response, error) |
|
17 | 16 |
} |
18 | 17 |
|
19 | 18 |
// NewPlugins constructs and initialize the authorization plugins based on plugin names |
... | ... |
@@ -35,38 +34,30 @@ func newAuthorizationPlugin(name string) Plugin { |
35 | 35 |
return &authorizationPlugin{name: name} |
36 | 36 |
} |
37 | 37 |
|
38 |
-func (a *authorizationPlugin) AuthZRequest(authReq *Request) (authRes *Response, err error) { |
|
39 |
- |
|
38 |
+func (a *authorizationPlugin) AuthZRequest(authReq *Request) (*Response, error) { |
|
40 | 39 |
logrus.Debugf("AuthZ requset using plugins %s", a.name) |
41 | 40 |
|
42 |
- err = a.initPlugin() |
|
43 |
- if err != nil { |
|
41 |
+ if err := a.initPlugin(); err != nil { |
|
44 | 42 |
return nil, err |
45 | 43 |
} |
46 | 44 |
|
47 |
- authRes = &Response{} |
|
48 |
- err = a.plugin.Client.Call(AuthZApiRequest, authReq, authRes) |
|
49 |
- |
|
50 |
- if err != nil { |
|
45 |
+ authRes := &Response{} |
|
46 |
+ if err := a.plugin.Client.Call(AuthZApiRequest, authReq, authRes); err != nil { |
|
51 | 47 |
return nil, err |
52 | 48 |
} |
53 | 49 |
|
54 | 50 |
return authRes, nil |
55 | 51 |
} |
56 | 52 |
|
57 |
-func (a *authorizationPlugin) AuthZResponse(authReq *Request) (authRes *Response, err error) { |
|
58 |
- |
|
53 |
+func (a *authorizationPlugin) AuthZResponse(authReq *Request) (*Response, error) { |
|
59 | 54 |
logrus.Debugf("AuthZ response using plugins %s", a.name) |
60 | 55 |
|
61 |
- err = a.initPlugin() |
|
62 |
- if err != nil { |
|
56 |
+ if err := a.initPlugin(); err != nil { |
|
63 | 57 |
return nil, err |
64 | 58 |
} |
65 | 59 |
|
66 |
- authRes = &Response{} |
|
67 |
- err = a.plugin.Client.Call(AuthZApiResponse, authReq, authRes) |
|
68 |
- |
|
69 |
- if err != nil { |
|
60 |
+ authRes := &Response{} |
|
61 |
+ if err := a.plugin.Client.Call(AuthZApiResponse, authReq, authRes); err != nil { |
|
70 | 62 |
return nil, err |
71 | 63 |
} |
72 | 64 |
|
... | ... |
@@ -74,10 +65,10 @@ func (a *authorizationPlugin) AuthZResponse(authReq *Request) (authRes *Response |
74 | 74 |
} |
75 | 75 |
|
76 | 76 |
// initPlugin initialize the authorization plugin if needed |
77 |
-func (a *authorizationPlugin) initPlugin() (err error) { |
|
78 |
- |
|
77 |
+func (a *authorizationPlugin) initPlugin() error { |
|
79 | 78 |
// Lazy loading of plugins |
80 | 79 |
if a.plugin == nil { |
80 |
+ var err error |
|
81 | 81 |
a.plugin, err = plugins.Get(a.name, AuthZApiImplements) |
82 | 82 |
if err != nil { |
83 | 83 |
return err |
... | ... |
@@ -81,9 +81,7 @@ func (rm *responseModifier) OverrideStatusCode(statusCode int) { |
81 | 81 |
// Override replace the headers of the HTTP reply |
82 | 82 |
func (rm *responseModifier) OverrideHeader(b []byte) error { |
83 | 83 |
header := http.Header{} |
84 |
- err := json.Unmarshal(b, &header) |
|
85 |
- |
|
86 |
- if err != nil { |
|
84 |
+ if err := json.Unmarshal(b, &header); err != nil { |
|
87 | 85 |
return err |
88 | 86 |
} |
89 | 87 |
rm.header = header |
... | ... |
@@ -103,8 +101,7 @@ func (rm *responseModifier) RawBody() []byte { |
103 | 103 |
|
104 | 104 |
func (rm *responseModifier) RawHeaders() ([]byte, error) { |
105 | 105 |
var b bytes.Buffer |
106 |
- err := rm.header.Write(&b) |
|
107 |
- if err != nil { |
|
106 |
+ if err := rm.header.Write(&b); err != nil { |
|
108 | 107 |
return nil, err |
109 | 108 |
} |
110 | 109 |
return b.Bytes(), nil |
... | ... |
@@ -121,7 +118,6 @@ func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) { |
121 | 121 |
|
122 | 122 |
// Flush flushes all data to the HTTP response |
123 | 123 |
func (rm *responseModifier) Flush() error { |
124 |
- |
|
125 | 124 |
// Copy the status code |
126 | 125 |
if rm.statusCode > 0 { |
127 | 126 |
rm.rw.WriteHeader(rm.statusCode) |