From de8c3af3958482efc0df040575211122e7f9f86f Mon Sep 17 00:00:00 2001 From: Robbie McKinstry Date: Fri, 27 Apr 2018 13:05:12 -0400 Subject: [PATCH] Remove defer (#3) --- api/client.go | 11 +-- builtin/audit/advisor/backend.go | 155 +++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 builtin/audit/advisor/backend.go diff --git a/api/client.go b/api/client.go index 0f4385f871dc..a36803a37789 100644 --- a/api/client.go +++ b/api/client.go @@ -364,12 +364,6 @@ func NewClient(c *Config) (*Client, error) { c = def } - // Check to see if the Limiter has been set. - // If is has not been set, then set it to have no limit. - if c.Limiter == nil { - c.Limiter = rate.NewLimiter(rate.Inf, 0) - } - c.modifyLock.Lock() defer c.modifyLock.Unlock() @@ -596,7 +590,10 @@ func (c *Client) NewRequest(method, requestPath string) *Request { // a Vault server not configured with this client. This is an advanced operation // that generally won't need to be called externally. func (c *Client) RawRequest(r *Request) (*Response, error) { - defer c.config.Limiter.Wait(context.Background()) + if c.config.Limiter != nil { + c.config.Limiter.Wait(context.Background()) + } + c.modifyLock.RLock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() diff --git a/builtin/audit/advisor/backend.go b/builtin/audit/advisor/backend.go new file mode 100644 index 000000000000..f13862917230 --- /dev/null +++ b/builtin/audit/advisor/backend.go @@ -0,0 +1,155 @@ +package advisor + +import ( + "bytes" + "context" + "errors" + "net/http" + "sync" + + "github.com/hashicorp/vault/audit" + "github.com/hashicorp/vault/helper/salt" +) + +// An Backend is an audit backend designed to +// communicate with an Advisor server over HTTP +type Backend struct { + address string + formatter *audit.AuditFormatter + config audit.FormatterConfig + salt *salt.Salt + saltMutex sync.RWMutex +} + +var _ audit.Backend = &Backend{} + +// LogRequest will serialize a Vault *Request into a JSON object +// and send that payload to Advisor over HTTP +func (backend *Backend) LogRequest(ctx context.Context, in *audit.LogInput) error { + + var reqBody bytes.Buffer + + err := backend.formatter.FormatRequest(ctx, &reqBody, backend.config, in) + if err != nil { + return err + } + + httpResp, err := http.Post(backend.address, "application/json", &reqBody) + if err != nil { + return err + } + if httpResp.StatusCode < 200 || httpResp.StatusCode > 300 { + return errors.New("request to backend failed") + } + return nil +} + +// LogResponse will serialize a Vault *Request into a JSON object +// and send that payload to Advisor over HTTP +func (backend *Backend) LogResponse(ctx context.Context, in *audit.LogInput) error { + + var reqBody bytes.Buffer + + err := backend.formatter.FormatResponse(ctx, &reqBody, backend.config, in) + if err != nil { + return err + } + + httpResp, err := http.Post(backend.address, "application/json", &reqBody) + if err != nil { + return err + } + if httpResp.StatusCode < 200 || httpResp.StatusCode > 300 { + return errors.New("request to backend failed") + } + return nil +} + +func (backend *Backend) setDefaultConfig() { + backend.config = audit.FormatterConfig{} +} + +func (backend *Backend) setDefaultFormatter() { + backend.formatter = &audit.AuditFormatter{ + AuditFormatWriter: &audit.JSONFormatWriter{ + Prefix: "", + SaltFunc: backend.Salt, + }, + } +} + +// Pulls the address out of the configuration +func addressFromConfig(conf *audit.BackendConfig) (string, error) { + if addr, ok := conf.Config["address"]; ok { + return addr, nil + } + + if addr, ok := conf.Config["a"]; ok { + return addr, nil + } + + return "", errors.New("no address provided") +} + +// Factory returns a new Advisor audit backend +func Factory(ctx context.Context, a *audit.BackendConfig) (audit.Backend, error) { + // First, create a new formatter for serializing + // requests and responses into JSON + advisor := &Backend{} + advisor.setDefaultFormatter() + advisor.setDefaultConfig() + + // Next, collect the address from the configuration + addr, err := addressFromConfig(a) + if err != nil { + return nil, err + } + + // Store the address on the new Backend struct. + advisor.address = addr + + return advisor, nil +} + +// Salt returns the salt singleton for this +// backend instance +func (backend *Backend) Salt(ctx context.Context) (*salt.Salt, error) { + backend.saltMutex.RLock() + if backend.salt != nil { + defer backend.saltMutex.RUnlock() + return backend.salt, nil + } + backend.saltMutex.RUnlock() + backend.saltMutex.Lock() + defer backend.saltMutex.Unlock() + if backend.salt != nil { + return backend.salt, nil + } + salt, err := salt.NewSalt(context.Background(), nil, nil) + if err != nil { + return nil, err + } + backend.salt = salt + return salt, nil +} + +// GetHash is needed to implement the AuditBackend interface +func (backend *Backend) GetHash(ctx context.Context, data string) (string, error) { + salt, err := backend.Salt(ctx) + if err != nil { + return "", err + } + return salt.GetIdentifiedHMAC(data), nil +} + +// Reload is required to implement the AuditBackend interface +func (backend *Backend) Reload(ctx context.Context) error { + return nil +} + +// Invalidate is needed to implement the AuditBackend interface +func (backend *Backend) Invalidate(ctx context.Context) { + backend.saltMutex.Lock() + defer backend.saltMutex.Unlock() + backend.salt = nil +}