Audit unwrapped response (#1950)

This commit is contained in:
Jeff Mitchell 2016-09-29 12:03:47 -07:00 committed by GitHub
parent eb8f449a61
commit 5657789627
5 changed files with 65 additions and 15 deletions

View File

@ -297,15 +297,15 @@ type AuditRequest struct {
type AuditResponse struct {
Auth *AuditAuth `json:"auth,omitempty"`
Secret *AuditSecret `json:"secret,emitempty"`
Data map[string]interface{} `json:"data"`
Redirect string `json:"redirect"`
Secret *AuditSecret `json:"secret,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
Redirect string `json:"redirect,omitempty"`
WrapInfo *AuditWrapInfo `json:"wrap_info,omitempty"`
}
type AuditAuth struct {
ClientToken string `json:"client_token,omitempty"`
Accessor string `json:"accessor,omitempty"`
ClientToken string `json:"client_token"`
Accessor string `json:"accessor"`
DisplayName string `json:"display_name"`
Policies []string `json:"policies"`
Metadata map[string]string `json:"metadata"`

View File

@ -32,7 +32,7 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
},
errors.New("this is an error"),
"",
`<json:object name="auth"><json:string name="display_name"></json:string><json:null name="metadata" /><json:array name="policies"><json:string>root</json:string></json:array></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token"></json:string><json:null name="data" /><json:string name="id"></json:string><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
`<json:object name="auth"><json:string name="accessor"></json:string><json:string name="client_token"></json:string><json:string name="display_name"></json:string><json:null name="metadata" /><json:array name="policies"><json:string>root</json:string></json:array></json:object><json:string name="error">this is an error</json:string><json:object name="request"><json:string name="client_token"></json:string><json:null name="data" /><json:string name="id"></json:string><json:string name="operation">update</json:string><json:string name="path">/foo</json:string><json:string name="remote_address">127.0.0.1</json:string><json:number name="wrap_ttl">60</json:number></json:object><json:string name="type">request</json:string>`,
},
}

View File

@ -175,7 +175,7 @@ func respondLogical(w http.ResponseWriter, r *http.Request, req *logical.Request
},
}
} else {
httpResp = logical.SanitizeResponse(resp)
httpResp = logical.LogicalResponseToHTTPResponse(resp)
httpResp.RequestID = req.ID
}

View File

@ -4,28 +4,29 @@ import (
"bytes"
"encoding/json"
"fmt"
"time"
)
// This logic was pulled from the http package so that it can be used for
// encoding wrapped responses as well. It simply translates the logical request
// to an http response, with the values we want and omitting the values we
// don't.
func SanitizeResponse(input *Response) *HTTPResponse {
logicalResp := &HTTPResponse{
func LogicalResponseToHTTPResponse(input *Response) *HTTPResponse {
httpResp := &HTTPResponse{
Data: input.Data,
Warnings: input.Warnings(),
}
if input.Secret != nil {
logicalResp.LeaseID = input.Secret.LeaseID
logicalResp.Renewable = input.Secret.Renewable
logicalResp.LeaseDuration = int(input.Secret.TTL.Seconds())
httpResp.LeaseID = input.Secret.LeaseID
httpResp.Renewable = input.Secret.Renewable
httpResp.LeaseDuration = int(input.Secret.TTL.Seconds())
}
// If we have authentication information, then
// set up the result structure.
if input.Auth != nil {
logicalResp.Auth = &HTTPAuth{
httpResp.Auth = &HTTPAuth{
ClientToken: input.Auth.ClientToken,
Accessor: input.Auth.Accessor,
Policies: input.Auth.Policies,
@ -35,6 +36,34 @@ func SanitizeResponse(input *Response) *HTTPResponse {
}
}
return httpResp
}
func HTTPResponseToLogicalResponse(input *HTTPResponse) *Response {
logicalResp := &Response{
Data: input.Data,
warnings: input.Warnings,
}
if input.LeaseID != "" {
logicalResp.Secret = &Secret{
LeaseID: input.LeaseID,
}
logicalResp.Secret.Renewable = input.Renewable
logicalResp.Secret.TTL = time.Second * time.Duration(input.LeaseDuration)
}
if input.Auth != nil {
logicalResp.Auth = &Auth{
ClientToken: input.Auth.ClientToken,
Accessor: input.Auth.Accessor,
Policies: input.Auth.Policies,
Metadata: input.Auth.Metadata,
}
logicalResp.Auth.Renewable = input.Auth.Renewable
logicalResp.Auth.TTL = time.Second * time.Duration(input.Auth.LeaseDuration)
}
return logicalResp
}

View File

@ -8,6 +8,7 @@ import (
"github.com/armon/go-metrics"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/vault/helper/jsonutil"
"github.com/hashicorp/vault/helper/policyutil"
"github.com/hashicorp/vault/helper/strutil"
"github.com/hashicorp/vault/logical"
@ -81,8 +82,28 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
}
}
auditResp := resp
// When unwrapping we want to log the actual response that will be written
// out. We still want to return the raw value to avoid automatic updating
// to any of it.
if req.Path == "sys/wrapping/unwrap" &&
resp != nil &&
resp.Data != nil &&
resp.Data[logical.HTTPRawBody] != nil {
// Decode the JSON
httpResp := &logical.HTTPResponse{}
err := jsonutil.DecodeJSON(resp.Data[logical.HTTPRawBody].([]byte), httpResp)
if err != nil {
c.logger.Error("core: failed to unmarshal wrapped HTTP response for audit logging", "error", err)
return nil, ErrInternalError
}
auditResp = logical.HTTPResponseToLogicalResponse(httpResp)
}
// Create an audit trail of the response
if auditErr := c.auditBroker.LogResponse(auth, req, resp, err); auditErr != nil {
if auditErr := c.auditBroker.LogResponse(auth, req, auditResp, err); auditErr != nil {
c.logger.Error("core: failed to audit response", "request_path", req.Path, "error", auditErr)
return nil, ErrInternalError
}
@ -436,7 +457,7 @@ func (c *Core) wrapInCubbyhole(req *logical.Request, resp *logical.Response) (*l
"response": resp.Data["response"],
}
} else {
httpResponse := logical.SanitizeResponse(resp)
httpResponse := logical.LogicalResponseToHTTPResponse(resp)
// Add the unique identifier of the original request to the response
httpResponse.RequestID = req.ID