Audit unwrapped response (#1950)
This commit is contained in:
parent
eb8f449a61
commit
5657789627
|
@ -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"`
|
||||
|
|
|
@ -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>`,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue