pkg/authorization/response.go
Liron Levin ccdb366aa5 Docker authorization plug-in infrastructure enables extending the functionality of the Docker daemon with respect to user authorization. The infrastructure enables registering a set of external authorization plug-in. Each plug-in receives information about the user and the request and decides whether to allow or deny the request. Only in case all plug-ins allow accessing the resource the access is granted.
Each plug-in operates as a separate service, and registers with Docker
through general (plug-ins API)
[https://blog.docker.com/2015/06/extending-docker-with-plugins/]. No
Docker daemon recompilation is required in order to add / remove an
authentication plug-in. Each plug-in is notified twice for each
operation: 1) before the operation is performed and, 2) before the
response is returned to the client. The plug-ins can modify the response
that is returned to the client.

The authorization depends on the authorization effort that takes place
in parallel [https://github.com/docker/docker/issues/13697].

This is the official issue of the authorization effort:
https://github.com/docker/docker/issues/14674

(Here)[https://github.com/rhatdan/docker-rbac] you can find an open
document that discusses a default RBAC plug-in for Docker.

Signed-off-by: Liron Levin <liron@twistlock.com>
Added container create flow test and extended the verification for ps
2015-12-08 17:34:15 +02:00

140 lines
3.3 KiB
Go

package authorization
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net"
"net/http"
)
// ResponseModifier allows authorization plugins to read and modify the content of the http.response
type ResponseModifier interface {
http.ResponseWriter
// RawBody returns the current http content
RawBody() []byte
// RawHeaders returns the current content of the http headers
RawHeaders() ([]byte, error)
// StatusCode returns the current status code
StatusCode() int
// OverrideBody replace the body of the HTTP reply
OverrideBody(b []byte)
// OverrideHeader replace the headers of the HTTP reply
OverrideHeader(b []byte) error
// OverrideStatusCode replaces the status code of the HTTP reply
OverrideStatusCode(statusCode int)
// Flush flushes all data to the HTTP response
Flush() error
}
// NewResponseModifier creates a wrapper to an http.ResponseWriter to allow inspecting and modifying the content
func NewResponseModifier(rw http.ResponseWriter) ResponseModifier {
return &responseModifier{rw: rw, header: make(http.Header)}
}
// responseModifier is used as an adapter to http.ResponseWriter in order to manipulate and explore
// the http request/response from docker daemon
type responseModifier struct {
// The original response writer
rw http.ResponseWriter
status int
// body holds the response body
body []byte
// header holds the response header
header http.Header
// statusCode holds the response status code
statusCode int
}
// WriterHeader stores the http status code
func (rm *responseModifier) WriteHeader(s int) {
rm.statusCode = s
}
// Header returns the internal http header
func (rm *responseModifier) Header() http.Header {
return rm.header
}
// Header returns the internal http header
func (rm *responseModifier) StatusCode() int {
return rm.statusCode
}
// Override replace the body of the HTTP reply
func (rm *responseModifier) OverrideBody(b []byte) {
rm.body = b
}
func (rm *responseModifier) OverrideStatusCode(statusCode int) {
rm.statusCode = statusCode
}
// 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 {
return err
}
rm.header = header
return nil
}
// Write stores the byte array inside content
func (rm *responseModifier) Write(b []byte) (int, error) {
rm.body = append(rm.body, b...)
return len(b), nil
}
// Body returns the response body
func (rm *responseModifier) RawBody() []byte {
return rm.body
}
func (rm *responseModifier) RawHeaders() ([]byte, error) {
var b bytes.Buffer
err := rm.header.Write(&b)
if err != nil {
return nil, err
}
return b.Bytes(), nil
}
// Hijack returns the internal connection of the wrapped http.ResponseWriter
func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := rm.rw.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("Internal reponse writer doesn't support the Hijacker interface")
}
return hijacker.Hijack()
}
// 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)
}
// Copy the header
for k, vv := range rm.header {
for _, v := range vv {
rm.rw.Header().Add(k, v)
}
}
// Write body
_, err := rm.rw.Write(rm.body)
return err
}