blob: efd13231ad6dbd25b17586c5168bae02cace305b [file] [log] [blame]
package audit
import (
"fmt"
"time"
"veyron.io/veyron/veyron2/security"
)
// NewPrincipal returns a security.Principal implementation that logs
// all private key operations of 'wrapped' to 'auditor' (i.e., all calls to
// BlessSelf, Bless, MintDischarge and Sign).
func NewPrincipal(wrapped security.Principal, auditor Auditor) security.Principal {
return &auditingPrincipal{wrapped, auditor}
}
type auditingPrincipal struct {
principal security.Principal
auditor Auditor
}
type args []interface{}
func (p *auditingPrincipal) Bless(key security.PublicKey, with security.Blessings, extension string, caveat security.Caveat, additionalCaveats ...security.Caveat) (security.Blessings, error) {
blessings, err := p.principal.Bless(key, with, extension, caveat, additionalCaveats...)
if err = p.audit(err, "Bless", addCaveats(args{key, with, extension, caveat}, additionalCaveats...), blessings); err != nil {
return nil, err
}
return blessings, nil
}
func (p *auditingPrincipal) BlessSelf(name string, caveats ...security.Caveat) (security.Blessings, error) {
blessings, err := p.principal.BlessSelf(name, caveats...)
if err = p.audit(err, "BlessSelf", addCaveats(args{name}, caveats...), blessings); err != nil {
return nil, err
}
return blessings, nil
}
func (p *auditingPrincipal) Sign(message []byte) (security.Signature, error) {
// Do not save the signature itself.
sig, err := p.principal.Sign(message)
if err = p.audit(err, "Sign", args{message}, nil); err != nil {
return security.Signature{}, err
}
return sig, nil
}
func (p *auditingPrincipal) MintDischarge(tp security.ThirdPartyCaveat, caveat security.Caveat, additionalCaveats ...security.Caveat) (security.Discharge, error) {
d, err := p.principal.MintDischarge(tp, caveat, additionalCaveats...)
// No need to log the discharge
if err = p.audit(err, "MintDischarge", addCaveats(args{tp, caveat}, additionalCaveats...), nil); err != nil {
return nil, err
}
return d, nil
}
func (p *auditingPrincipal) PublicKey() security.PublicKey { return p.principal.PublicKey() }
func (p *auditingPrincipal) Roots() security.BlessingRoots { return p.principal.Roots() }
func (p *auditingPrincipal) BlessingStore() security.BlessingStore { return p.principal.BlessingStore() }
func (p *auditingPrincipal) AddToRoots(b security.Blessings) error { return p.principal.AddToRoots(b) }
func (p *auditingPrincipal) audit(err error, method string, args args, result interface{}) error {
if err != nil {
return err
}
entry := Entry{Method: method, Timestamp: time.Now()}
if len(args) > 0 {
entry.Arguments = []interface{}(args)
}
if result != nil {
entry.Results = []interface{}{result}
}
if err := p.auditor.Audit(entry); err != nil {
return fmt.Errorf("failed to audit call to %q: %v", method, err)
}
return nil
}
func addCaveats(args args, caveats ...security.Caveat) args {
for _, c := range caveats {
// TODO(ashankar,suharshs): Should isUnconstrainedCaveat in veyron2/security be exported and used here?
if len(c.ValidatorVOM) > 0 {
args = append(args, c)
}
}
return args
}