mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
pkg: authorization: add Err to tweak response status code
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
905f3336b2
commit
46e3a249a1
5 changed files with 110 additions and 32 deletions
|
@ -147,12 +147,12 @@ should implement the following two methods:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"User": "The user identification"
|
"User": "The user identification",
|
||||||
"UserAuthNMethod": "The authentication method used"
|
"UserAuthNMethod": "The authentication method used",
|
||||||
"RequestMethod": "The HTTP method"
|
"RequestMethod": "The HTTP method",
|
||||||
"RequestUri": "The HTTP request URI"
|
"RequestUri": "The HTTP request URI",
|
||||||
"RequestBody": "Byte array containing the raw HTTP request body"
|
"RequestBody": "Byte array containing the raw HTTP request body",
|
||||||
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string "
|
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string ",
|
||||||
"RequestStatusCode": "Request status code"
|
"RequestStatusCode": "Request status code"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -161,26 +161,26 @@ should implement the following two methods:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"Allow" : "Determined whether the user is allowed or not"
|
"Allow": "Determined whether the user is allowed or not",
|
||||||
"Msg": "The authorization message"
|
"Msg": "The authorization message",
|
||||||
|
"Err": "The error message if things go wrong"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### /AuthzPlugin.AuthZRes
|
#### /AuthzPlugin.AuthZRes
|
||||||
|
|
||||||
**Request**:
|
**Request**:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"User": "The user identification"
|
"User": "The user identification",
|
||||||
"UserAuthNMethod": "The authentication method used"
|
"UserAuthNMethod": "The authentication method used",
|
||||||
"RequestMethod": "The HTTP method"
|
"RequestMethod": "The HTTP method",
|
||||||
"RequestUri": "The HTTP request URI"
|
"RequestUri": "The HTTP request URI",
|
||||||
"RequestBody": "Byte array containing the raw HTTP request body"
|
"RequestBody": "Byte array containing the raw HTTP request body",
|
||||||
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string"
|
"RequestHeader": "Byte array containing the raw HTTP request header as a map[string][]string",
|
||||||
"RequestStatusCode": "Request status code"
|
"RequestStatusCode": "Request status code",
|
||||||
"ResponseBody": "Byte array containing the raw HTTP response body"
|
"ResponseBody": "Byte array containing the raw HTTP response body",
|
||||||
"ResponseHeader": "Byte array containing the raw HTTP response header as a map[string][]string"
|
"ResponseHeader": "Byte array containing the raw HTTP response header as a map[string][]string",
|
||||||
"ResponseStatusCode":"Response status code"
|
"ResponseStatusCode":"Response status code"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -189,10 +189,11 @@ should implement the following two methods:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"Allow" : "Determined whether the user is allowed or not"
|
"Allow": "Determined whether the user is allowed or not",
|
||||||
"Msg": "The authorization message"
|
"Msg": "The authorization message",
|
||||||
"ModifiedBody": "Byte array containing a modified body of the raw HTTP body (or nil if no changes required)"
|
"Err": "The error message if things go wrong",
|
||||||
"ModifiedHeader": "Byte array containing a modified header of the HTTP response (or nil if no changes required)"
|
"ModifiedBody": "Byte array containing a modified body of the raw HTTP body (or nil if no changes required)",
|
||||||
|
"ModifiedHeader": "Byte array containing a modified header of the HTTP response (or nil if no changes required)",
|
||||||
"ModifiedStatusCode": "int containing the modified version of the status code (or 0 if not change is required)"
|
"ModifiedStatusCode": "int containing the modified version of the status code (or 0 if not change is required)"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -222,7 +223,8 @@ Request body | []byte | Raw request body
|
||||||
Name | Type | Description
|
Name | Type | Description
|
||||||
--------|--------|----------------------------------------------------------------------------------
|
--------|--------|----------------------------------------------------------------------------------
|
||||||
Allow | bool | Boolean value indicating whether the request is allowed or denied
|
Allow | bool | Boolean value indicating whether the request is allowed or denied
|
||||||
Message | string | Authorization message (will be returned to the client in case the access is denied)
|
Msg | string | Authorization message (will be returned to the client in case the access is denied)
|
||||||
|
Err | string | Error message (will be returned to the client in case the plugin encounter an error)
|
||||||
|
|
||||||
### Response authorization
|
### Response authorization
|
||||||
|
|
||||||
|
@ -249,4 +251,5 @@ Response body | []byte | Raw docker daemon response body
|
||||||
Name | Type | Description
|
Name | Type | Description
|
||||||
--------|--------|----------------------------------------------------------------------------------
|
--------|--------|----------------------------------------------------------------------------------
|
||||||
Allow | bool | Boolean value indicating whether the response is allowed or denied
|
Allow | bool | Boolean value indicating whether the response is allowed or denied
|
||||||
Message | string | Authorization message (will be returned to the client in case the access is denied)
|
Msg | string | Authorization message (will be returned to the client in case the access is denied)
|
||||||
|
Err | string | Error message (will be returned to the client in case the plugin encounter an error)
|
||||||
|
|
|
@ -17,9 +17,12 @@ import (
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testAuthZPlugin = "authzplugin"
|
const (
|
||||||
const unauthorizedMessage = "User unauthorized authz plugin"
|
testAuthZPlugin = "authzplugin"
|
||||||
const containerListAPI = "/containers/json"
|
unauthorizedMessage = "User unauthorized authz plugin"
|
||||||
|
errorMessage = "something went wrong..."
|
||||||
|
containerListAPI = "/containers/json"
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
check.Suite(&DockerAuthzSuite{
|
check.Suite(&DockerAuthzSuite{
|
||||||
|
@ -66,9 +69,12 @@ func (s *DockerAuthzSuite) SetUpSuite(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.HandleFunc("/AuthZPlugin.AuthZReq", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/AuthZPlugin.AuthZReq", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if s.ctrl.reqRes.Err != "" {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
b, err := json.Marshal(s.ctrl.reqRes)
|
b, err := json.Marshal(s.ctrl.reqRes)
|
||||||
w.Write(b)
|
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
w.Write(b)
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
@ -88,6 +94,9 @@ func (s *DockerAuthzSuite) SetUpSuite(c *check.C) {
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.HandleFunc("/AuthZPlugin.AuthZRes", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/AuthZPlugin.AuthZRes", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if s.ctrl.resRes.Err != "" {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
b, err := json.Marshal(s.ctrl.resRes)
|
b, err := json.Marshal(s.ctrl.resRes)
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
w.Write(b)
|
w.Write(b)
|
||||||
|
@ -214,6 +223,31 @@ func (s *DockerAuthzSuite) TestAuthZPluginDenyResponse(c *check.C) {
|
||||||
c.Assert(res, check.Equals, fmt.Sprintf("Error response from daemon: %s\n", unauthorizedMessage))
|
c.Assert(res, check.Equals, fmt.Sprintf("Error response from daemon: %s\n", unauthorizedMessage))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerAuthzSuite) TestAuthZPluginErrorResponse(c *check.C) {
|
||||||
|
err := s.d.Start("--authz-plugin=" + testAuthZPlugin)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
s.ctrl.reqRes.Allow = true
|
||||||
|
s.ctrl.resRes.Err = errorMessage
|
||||||
|
|
||||||
|
// Ensure command is blocked
|
||||||
|
res, err := s.d.Cmd("ps")
|
||||||
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
|
c.Assert(res, check.Equals, fmt.Sprintf("Error response from daemon: Plugin Error: %s, %s\n", errorMessage, authorization.AuthZApiResponse))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerAuthzSuite) TestAuthZPluginErrorRequest(c *check.C) {
|
||||||
|
err := s.d.Start("--authz-plugin=" + testAuthZPlugin)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
s.ctrl.reqRes.Err = errorMessage
|
||||||
|
|
||||||
|
// Ensure command is blocked
|
||||||
|
res, err := s.d.Cmd("ps")
|
||||||
|
c.Assert(err, check.NotNil)
|
||||||
|
|
||||||
|
c.Assert(res, check.Equals, fmt.Sprintf("Error response from daemon: Plugin Error: %s, %s\n", errorMessage, authorization.AuthZApiRequest))
|
||||||
|
}
|
||||||
|
|
||||||
// assertURIRecorded verifies that the given URI was sent and recorded in the authz plugin
|
// assertURIRecorded verifies that the given URI was sent and recorded in the authz plugin
|
||||||
func assertURIRecorded(c *check.C, uris []string, uri string) {
|
func assertURIRecorded(c *check.C, uris []string, uri string) {
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,12 @@ type Request struct {
|
||||||
|
|
||||||
// Response represents authZ plugin response
|
// Response represents authZ plugin response
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
|
||||||
// Allow indicating whether the user is allowed or not
|
// Allow indicating whether the user is allowed or not
|
||||||
Allow bool `json:"Allow"`
|
Allow bool `json:"Allow"`
|
||||||
|
|
||||||
// Msg stores the authorization message
|
// Msg stores the authorization message
|
||||||
Msg string `json:"Msg,omitempty"`
|
Msg string `json:"Msg,omitempty"`
|
||||||
|
|
||||||
|
// Err stores a message in case there's an error
|
||||||
|
Err string `json:"Err,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,10 @@ func (a *Ctx) AuthZRequest(w http.ResponseWriter, r *http.Request) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if authRes.Err != "" {
|
||||||
|
return fmt.Errorf(authRes.Err)
|
||||||
|
}
|
||||||
|
|
||||||
if !authRes.Allow {
|
if !authRes.Allow {
|
||||||
return fmt.Errorf(authRes.Msg)
|
return fmt.Errorf(authRes.Msg)
|
||||||
}
|
}
|
||||||
|
@ -107,6 +111,10 @@ func (a *Ctx) AuthZResponse(rm ResponseModifier, r *http.Request) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if authRes.Err != "" {
|
||||||
|
return fmt.Errorf(authRes.Err)
|
||||||
|
}
|
||||||
|
|
||||||
if !authRes.Allow {
|
if !authRes.Allow {
|
||||||
return fmt.Errorf(authRes.Msg)
|
return fmt.Errorf(authRes.Msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,37 @@ import (
|
||||||
|
|
||||||
const pluginAddress = "authzplugin.sock"
|
const pluginAddress = "authzplugin.sock"
|
||||||
|
|
||||||
|
func TestAuthZRequestPluginError(t *testing.T) {
|
||||||
|
server := authZPluginTestServer{t: t}
|
||||||
|
go server.start()
|
||||||
|
defer server.stop()
|
||||||
|
|
||||||
|
authZPlugin := createTestPlugin(t)
|
||||||
|
|
||||||
|
request := Request{
|
||||||
|
User: "user",
|
||||||
|
RequestBody: []byte("sample body"),
|
||||||
|
RequestURI: "www.authz.com",
|
||||||
|
RequestMethod: "GET",
|
||||||
|
RequestHeaders: map[string]string{"header": "value"},
|
||||||
|
}
|
||||||
|
server.replayResponse = Response{
|
||||||
|
Err: "an error",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualResponse, err := authZPlugin.AuthZRequest(&request)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to authorize request %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(server.replayResponse, *actualResponse) {
|
||||||
|
t.Fatalf("Response must be equal")
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(request, server.recordedRequest) {
|
||||||
|
t.Fatalf("Requests must be equal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthZRequestPlugin(t *testing.T) {
|
func TestAuthZRequestPlugin(t *testing.T) {
|
||||||
server := authZPluginTestServer{t: t}
|
server := authZPluginTestServer{t: t}
|
||||||
go server.start()
|
go server.start()
|
||||||
|
|
Loading…
Reference in a new issue