audit: separate hashing from formatting to facilitate raw
This commit is contained in:
parent
dd3a6bf37f
commit
1b34aae7f1
|
@ -2,7 +2,6 @@ package audit
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/hashicorp/vault/logical"
|
||||
|
@ -20,16 +19,6 @@ func (f *FormatJSON) FormatRequest(
|
|||
auth = new(logical.Auth)
|
||||
}
|
||||
|
||||
// Hash the data
|
||||
dataRaw, err := HashStructure(req.Data, f.hashFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, ok := dataRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("data came back as not map")
|
||||
}
|
||||
|
||||
// Encode!
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(&JSONRequestEntry{
|
||||
|
@ -43,7 +32,7 @@ func (f *FormatJSON) FormatRequest(
|
|||
Request: JSONRequest{
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: data,
|
||||
Data: req.Data,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -54,8 +43,6 @@ func (f *FormatJSON) FormatResponse(
|
|||
req *logical.Request,
|
||||
resp *logical.Response,
|
||||
err error) error {
|
||||
hashFunc := f.hashFunc()
|
||||
|
||||
// If things are nil, make empty to avoid panics
|
||||
if auth == nil {
|
||||
auth = new(logical.Auth)
|
||||
|
@ -66,13 +53,8 @@ func (f *FormatJSON) FormatResponse(
|
|||
|
||||
var respAuth JSONAuth
|
||||
if resp.Auth != nil {
|
||||
token, err := hashFunc(resp.Auth.ClientToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respAuth = JSONAuth{
|
||||
ClientToken: token,
|
||||
ClientToken: resp.Auth.ClientToken,
|
||||
Policies: resp.Auth.Policies,
|
||||
Metadata: resp.Auth.Metadata,
|
||||
}
|
||||
|
@ -85,25 +67,6 @@ func (f *FormatJSON) FormatResponse(
|
|||
}
|
||||
}
|
||||
|
||||
// Hash the data
|
||||
dataRaw, err := HashStructure(req.Data, f.hashFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reqData, ok := dataRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("data came back as not map")
|
||||
}
|
||||
|
||||
dataRaw, err = HashStructure(resp.Data, f.hashFunc())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
respData, ok := dataRaw.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("data came back as not map")
|
||||
}
|
||||
|
||||
// Encode!
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(&JSONResponseEntry{
|
||||
|
@ -117,22 +80,18 @@ func (f *FormatJSON) FormatResponse(
|
|||
Request: JSONRequest{
|
||||
Operation: req.Operation,
|
||||
Path: req.Path,
|
||||
Data: reqData,
|
||||
Data: req.Data,
|
||||
},
|
||||
|
||||
Response: JSONResponse{
|
||||
Auth: respAuth,
|
||||
Secret: respSecret,
|
||||
Data: respData,
|
||||
Data: resp.Data,
|
||||
Redirect: resp.Redirect,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (f *FormatJSON) hashFunc() HashCallback {
|
||||
return HashSHA1("")
|
||||
}
|
||||
|
||||
// JSONRequest is the structure of a request audit log entry in JSON.
|
||||
type JSONRequestEntry struct {
|
||||
Type string `json:"type"`
|
||||
|
|
|
@ -38,5 +38,5 @@ func TestFormatJSON_formatRequest(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
const testFormatJSONReqBasicStr = `{"type":"request","auth":{"policies":["root"],"metadata":null},"request":{"operation":"write","path":"/foo","data":{}}}
|
||||
const testFormatJSONReqBasicStr = `{"type":"request","auth":{"policies":["root"],"metadata":null},"request":{"operation":"write","path":"/foo","data":null}}
|
||||
`
|
||||
|
|
|
@ -7,11 +7,61 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/mitchellh/copystructure"
|
||||
"github.com/mitchellh/reflectwalk"
|
||||
)
|
||||
|
||||
// HashStructures takes an interface and hashes all the values within
|
||||
// Hash will hash the given type. This has built-in support for auth,
|
||||
// requests, and responses. If it is a type that isn't recognized, then
|
||||
// it will be passed through.
|
||||
//
|
||||
// The structure is modified in-place.
|
||||
func Hash(raw interface{}) error {
|
||||
fn := HashSHA1("")
|
||||
|
||||
switch s := raw.(type) {
|
||||
case *logical.Auth:
|
||||
if s.ClientToken != "" {
|
||||
token, err := fn(s.ClientToken)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.ClientToken = token
|
||||
}
|
||||
case *logical.Request:
|
||||
if s.Auth != nil {
|
||||
if err := Hash(s.Auth); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
data, err := HashStructure(s.Data, fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Data = data.(map[string]interface{})
|
||||
case *logical.Response:
|
||||
if s.Auth != nil {
|
||||
if err := Hash(s.Auth); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
data, err := HashStructure(s.Data, fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.Data = data.(map[string]interface{})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HashStructure takes an interface and hashes all the values within
|
||||
// the structure. Only _values_ are hashed: keys of objects are not.
|
||||
//
|
||||
// For the HashCallback, see the built-in HashCallbacks below.
|
||||
|
|
|
@ -1,10 +1,59 @@
|
|||
package audit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
func TestHash(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input interface{}
|
||||
Output interface{}
|
||||
}{
|
||||
{
|
||||
&logical.Auth{ClientToken: "foo"},
|
||||
&logical.Auth{ClientToken: "sha1:0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"},
|
||||
},
|
||||
{
|
||||
&logical.Request{
|
||||
Data: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
&logical.Request{
|
||||
Data: map[string]interface{}{
|
||||
"foo": "sha1:62cdb7020ff920e5aa642c3d4066950dd1f01f4d",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
&logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
&logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"foo": "sha1:62cdb7020ff920e5aa642c3d4066950dd1f01f4d",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
input := fmt.Sprintf("%#v", tc.Input)
|
||||
if err := Hash(tc.Input); err != nil {
|
||||
t.Fatalf("err: %s\n\n%s", err, input)
|
||||
}
|
||||
if !reflect.DeepEqual(tc.Input, tc.Output) {
|
||||
t.Fatalf("bad:\n\n%s\n\n%#v\n\n%#v", input, tc.Input, tc.Output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashWalker(t *testing.T) {
|
||||
replaceText := "foo"
|
||||
|
||||
|
|
Loading…
Reference in New Issue