github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/observer/audit.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  package observer
     4  
     5  import (
     6  	"fmt"
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/version"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/audit"
    15  	"github.com/juju/juju/rpc"
    16  )
    17  
    18  // Context defines things an Audit observer need know about to operate
    19  // correctly.
    20  type AuditContext struct {
    21  
    22  	// JujuServerVersion is the version of jujud.
    23  	JujuServerVersion version.Number
    24  
    25  	// ModelUUID is the UUID of the model the audit observer is
    26  	// currently running on.
    27  	ModelUUID string
    28  }
    29  
    30  type ErrorHandler func(error)
    31  
    32  // NewAudit creates a new Audit with the information provided via the Context.
    33  func NewAudit(ctx *AuditContext, handleAuditEntry audit.AuditEntrySinkFn, errorHandler ErrorHandler) *Audit {
    34  	return &Audit{
    35  		jujuServerVersion: ctx.JujuServerVersion,
    36  		modelUUID:         ctx.ModelUUID,
    37  		errorHandler:      errorHandler,
    38  		handleAuditEntry:  handleAuditEntry,
    39  	}
    40  }
    41  
    42  // Audit is an observer which will log APIServer requests using the
    43  // function provided.
    44  type Audit struct {
    45  	jujuServerVersion version.Number
    46  	modelUUID         string
    47  	errorHandler      ErrorHandler
    48  	handleAuditEntry  audit.AuditEntrySinkFn
    49  
    50  	// state represents information that's built up as methods on this
    51  	// type are called. We segregate this to ensure it's clear what
    52  	// information is transient in case we want to extract it
    53  	// later. It's an anonymous struct so this doesn't leak outside
    54  	// this type.
    55  	state struct {
    56  		remoteAddress    string
    57  		authenticatedTag string
    58  	}
    59  }
    60  
    61  // Login implements Observer.
    62  func (a *Audit) Login(entity names.Tag, _ names.ModelTag, _ bool, _ string) {
    63  	a.state.authenticatedTag = entity.String()
    64  }
    65  
    66  // Join implements Observer.
    67  func (a *Audit) Join(req *http.Request, _ uint64) {
    68  	a.state.remoteAddress = req.RemoteAddr
    69  }
    70  
    71  // Leave implements Observer.
    72  func (a *Audit) Leave() {
    73  	a.state.remoteAddress = ""
    74  	a.state.authenticatedTag = ""
    75  }
    76  
    77  // RPCObserver implements Observer.
    78  func (a *Audit) RPCObserver() rpc.Observer {
    79  	return &AuditRPCObserver{
    80  		jujuServerVersion: a.jujuServerVersion,
    81  		modelUUID:         a.modelUUID,
    82  		errorHandler:      a.errorHandler,
    83  		handleAuditEntry:  a.handleAuditEntry,
    84  		authenticatedTag:  a.state.authenticatedTag,
    85  		remoteAddress:     a.state.remoteAddress,
    86  	}
    87  }
    88  
    89  // AuditRPCObserver is an observer which will log RPC requests using
    90  // the function provided.
    91  type AuditRPCObserver struct {
    92  	jujuServerVersion version.Number
    93  	modelUUID         string
    94  	errorHandler      ErrorHandler
    95  	handleAuditEntry  audit.AuditEntrySinkFn
    96  	authenticatedTag  string
    97  	remoteAddress     string
    98  }
    99  
   100  // ServerRequest implements Observer.
   101  func (a *AuditRPCObserver) ServerRequest(hdr *rpc.Header, body interface{}) {
   102  	auditEntry := a.boilerplateAuditEntry()
   103  	auditEntry.OriginName = a.authenticatedTag
   104  
   105  	auditEntry.OriginType = "API request"
   106  	auditEntry.Operation = rpcRequestToOperation(hdr.Request)
   107  	auditEntry.Data = map[string]interface{}{"request-body": body}
   108  	err := a.handleAuditEntry(auditEntry)
   109  	if err != nil {
   110  		a.errorHandler(errors.Trace(err))
   111  	}
   112  }
   113  
   114  // ServerReply implements Observer.
   115  func (a *AuditRPCObserver) ServerReply(rpc.Request, *rpc.Header, interface{}) {}
   116  
   117  func (a *AuditRPCObserver) boilerplateAuditEntry() audit.AuditEntry {
   118  	return audit.AuditEntry{
   119  		JujuServerVersion: a.jujuServerVersion,
   120  		ModelUUID:         a.modelUUID,
   121  		Timestamp:         time.Now().UTC(),
   122  		RemoteAddress:     a.remoteAddress,
   123  		OriginName:        a.authenticatedTag,
   124  	}
   125  }
   126  
   127  func rpcRequestToOperation(req rpc.Request) string {
   128  	return fmt.Sprintf("%s:v%d - %s", req.Type, req.Version, req.Action)
   129  }