Logging authentication errors and bad token usage

This commit is contained in:
Nate Brown 2015-06-18 18:30:18 -07:00
parent c55f103c58
commit 4ec685dc1a
9 changed files with 29 additions and 15 deletions

View File

@ -11,7 +11,7 @@ type Backend interface {
// request is authorized but before the request is executed. The arguments // request is authorized but before the request is executed. The arguments
// MUST not be modified in anyway. They should be deep copied if this is // MUST not be modified in anyway. They should be deep copied if this is
// a possibility. // a possibility.
LogRequest(*logical.Auth, *logical.Request) error LogRequest(*logical.Auth, *logical.Request, error) error
// LogResponse is used to syncronously log a response. This is done after // LogResponse is used to syncronously log a response. This is done after
// the request is processed but before the response is sent. The arguments // the request is processed but before the response is sent. The arguments

View File

@ -8,22 +8,29 @@ import (
"errors" "errors"
) )
// FormatJSON is a Formatter implementation that structuteres data into // FormatJSON is a Formatter implementation that structures data into
// a JSON format. // a JSON format.
type FormatJSON struct{} type FormatJSON struct{}
func (f *FormatJSON) FormatRequest( func (f *FormatJSON) FormatRequest(
w io.Writer, w io.Writer,
auth *logical.Auth, req *logical.Request) error { auth *logical.Auth,
req *logical.Request,
err error) error {
// If auth is nil, make an empty one // If auth is nil, make an empty one
if auth == nil { if auth == nil {
auth = new(logical.Auth) auth = new(logical.Auth)
} }
if err == nil {
err = errors.New("")
}
// Encode! // Encode!
enc := json.NewEncoder(w) enc := json.NewEncoder(w)
return enc.Encode(&JSONRequestEntry{ return enc.Encode(&JSONRequestEntry{
Type: "request", Type: "request",
Error: err.Error(),
Auth: JSONAuth{ Auth: JSONAuth{
DisplayName: auth.DisplayName, DisplayName: auth.DisplayName,
@ -106,6 +113,7 @@ type JSONRequestEntry struct {
Type string `json:"type"` Type string `json:"type"`
Auth JSONAuth `json:"auth"` Auth JSONAuth `json:"auth"`
Request JSONRequest `json:"request"` Request JSONRequest `json:"request"`
Error string `json:"error"`
} }
// JSONResponseEntry is the structure of a response audit log entry in JSON. // JSONResponseEntry is the structure of a response audit log entry in JSON.

View File

@ -12,6 +12,6 @@ import (
// //
// It is recommended that you pass data through Hash prior to formatting it. // It is recommended that you pass data through Hash prior to formatting it.
type Formatter interface { type Formatter interface {
FormatRequest(io.Writer, *logical.Auth, *logical.Request) error FormatRequest(io.Writer, *logical.Auth, *logical.Request, error) error
FormatResponse(io.Writer, *logical.Auth, *logical.Request, *logical.Response, error) error FormatResponse(io.Writer, *logical.Auth, *logical.Request, *logical.Response, error) error
} }

View File

@ -48,7 +48,7 @@ type Backend struct {
f *os.File f *os.File
} }
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error { func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
if err := b.open(); err != nil { if err := b.open(); err != nil {
return err return err
} }
@ -76,7 +76,7 @@ func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
} }
var format audit.FormatJSON var format audit.FormatJSON
return format.FormatRequest(b.f, auth, req) return format.FormatRequest(b.f, auth, req, outerErr)
} }
func (b *Backend) LogResponse( func (b *Backend) LogResponse(

View File

@ -52,7 +52,7 @@ type Backend struct {
logRaw bool logRaw bool
} }
func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error { func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
if !b.logRaw { if !b.logRaw {
// Copy the structures // Copy the structures
cp, err := copystructure.Copy(auth) cp, err := copystructure.Copy(auth)
@ -79,7 +79,7 @@ func (b *Backend) LogRequest(auth *logical.Auth, req *logical.Request) error {
// Encode the entry as JSON // Encode the entry as JSON
var buf bytes.Buffer var buf bytes.Buffer
var format audit.FormatJSON var format audit.FormatJSON
if err := format.FormatRequest(&buf, auth, req); err != nil { if err := format.FormatRequest(&buf, auth, req, outerErr); err != nil {
return err return err
} }

View File

@ -261,7 +261,7 @@ func (a *AuditBroker) IsRegistered(name string) bool {
// LogRequest is used to ensure all the audit backends have an opportunity to // LogRequest is used to ensure all the audit backends have an opportunity to
// log the given request and that *at least one* succeeds. // log the given request and that *at least one* succeeds.
func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request) error { func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request, outerErr error) error {
defer metrics.MeasureSince([]string{"audit", "log_request"}, time.Now()) defer metrics.MeasureSince([]string{"audit", "log_request"}, time.Now())
a.l.RLock() a.l.RLock()
defer a.l.RUnlock() defer a.l.RUnlock()
@ -270,7 +270,7 @@ func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request) error
anyLogged := false anyLogged := false
for name, be := range a.backends { for name, be := range a.backends {
start := time.Now() start := time.Now()
err := be.backend.LogRequest(auth, req) err := be.backend.LogRequest(auth, req, outerErr)
metrics.MeasureSince([]string{"audit", name, "log_request"}, start) metrics.MeasureSince([]string{"audit", name, "log_request"}, start)
if err != nil { if err != nil {
a.logger.Printf("[ERR] audit: backend '%s' failed to log request: %v", name, err) a.logger.Printf("[ERR] audit: backend '%s' failed to log request: %v", name, err)

View File

@ -374,6 +374,7 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) { func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
defer metrics.MeasureSince([]string{"core", "handle_request"}, time.Now()) defer metrics.MeasureSince([]string{"core", "handle_request"}, time.Now())
// Validate the token // Validate the token
auth, err := c.checkToken(req.Operation, req.Path, req.ClientToken) auth, err := c.checkToken(req.Operation, req.Path, req.ClientToken)
if err != nil { if err != nil {
@ -387,6 +388,11 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
errType = logical.ErrInvalidRequest errType = logical.ErrInvalidRequest
} }
if err := c.auditBroker.LogRequest(auth, req, err); err != nil {
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
req, err)
}
return logical.ErrorResponse(err.Error()), errType return logical.ErrorResponse(err.Error()), errType
} }
@ -394,7 +400,7 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
req.DisplayName = auth.DisplayName req.DisplayName = auth.DisplayName
// Create an audit trail of the request // Create an audit trail of the request
if err := c.auditBroker.LogRequest(auth, req); err != nil { if err := c.auditBroker.LogRequest(auth, req, errors.New("")); err != nil {
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v", c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
req, err) req, err)
return nil, ErrInternalError return nil, ErrInternalError
@ -473,7 +479,7 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, erro
defer metrics.MeasureSince([]string{"core", "handle_login_request"}, time.Now()) defer metrics.MeasureSince([]string{"core", "handle_login_request"}, time.Now())
// Create an audit trail of the request, auth is not available on login requests // Create an audit trail of the request, auth is not available on login requests
if err := c.auditBroker.LogRequest(nil, req); err != nil { if err := c.auditBroker.LogRequest(nil, req, errors.New("")); err != nil {
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v", c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
req, err) req, err)
return nil, ErrInternalError return nil, ErrInternalError

View File

@ -86,7 +86,7 @@ func TestKeyCopy(key []byte) []byte {
type noopAudit struct{} type noopAudit struct{}
func (n *noopAudit) LogRequest(a *logical.Auth, r *logical.Request) error { func (n *noopAudit) LogRequest(a *logical.Auth, r *logical.Request, e error) error {
return nil return nil
} }

View File

@ -656,13 +656,13 @@ func (ts *TokenStore) handleLookup(
// Lookup the token // Lookup the token
out, err := ts.Lookup(id) out, err := ts.Lookup(id)
if err != nil { if err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
} }
// Fast-path the not found case
if out == nil { if out == nil {
return nil, nil return logical.ErrorResponse("bad token"), logical.ErrPermissionDenied
} }
// Generate a response. We purposely omit the parent reference otherwise // Generate a response. We purposely omit the parent reference otherwise