veyron2/security: Get rid of FakePublicID and FakePrivateID.
Addresses one of the oldest TODOs in the codebase :)
In the process, also removes some types/libraries that will be rendered
useless once the switch to the new security model is complete anyway.
Change-Id: I5bfa5ef380832ce4b8c4370a83ea4f8a07507559
diff --git a/runtimes/google/security/publicid_store.go b/runtimes/google/security/publicid_store.go
index 0f5c855..5df9874 100644
--- a/runtimes/google/security/publicid_store.go
+++ b/runtimes/google/security/publicid_store.go
@@ -64,8 +64,6 @@
updatedIDs = append(updatedIDs, ids...)
}
default:
- // TODO(ataly): Once we get rid of FakePublicID, force this case to be exactly
- // *chainPublicID.
for _, pattern := range s.state.Store[id] {
if pattern == peerPattern {
return updatedIDs, nil
diff --git a/runtimes/google/security/util_test.go b/runtimes/google/security/util_test.go
index 92f1362..294c552 100644
--- a/runtimes/google/security/util_test.go
+++ b/runtimes/google/security/util_test.go
@@ -142,8 +142,6 @@
cSomebody1 = derive(bless(cSelf.PublicID(), cProvider1, "somebody1"), cSelf)
cSomebody2 = derive(bless(cSelf.PublicID(), cProvider2, "somebody2"), cSelf)
setID = newSetPrivateID(cSomebody1, cSomebody2)
-
- fake = security.FakePrivateID("fake")
)
// Initially nobody is trusted
m := map[security.PrivateID]bool{
@@ -182,7 +180,5 @@
TrustIdentityProviders(setID)
m[cProvider1] = true
m[cProvider2] = true
- // Trusting a fake identity should be a no-op
- TrustIdentityProviders(fake)
test()
}
diff --git a/security/audit/id.go b/security/audit/id.go
deleted file mode 100644
index b251ecc..0000000
--- a/security/audit/id.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package audit
-
-import (
- "fmt"
- "time"
-
- "veyron.io/veyron/veyron2/security"
-)
-
-type auditingID struct {
- id security.PrivateID
- auditor Auditor
-}
-
-// NewPrivateID returns a security.PrivateID implementation that wraps over 'wrapped' but
-// logs all operations that use the private key of wrapped to the auditor.
-func NewPrivateID(wrapped security.PrivateID, auditor Auditor) security.PrivateID {
- return &auditingID{wrapped, auditor}
-}
-
-func (id *auditingID) Sign(message []byte) (security.Signature, error) {
- sig, err := id.id.Sign(message)
- // Do not save the signature itself.
- if err = id.audit(err, "Sign", args{message}, nil); err != nil {
- return security.Signature{}, err
- }
- return sig, nil
-}
-
-func (id *auditingID) PublicKey() security.PublicKey {
- return id.id.PublicKey()
-}
-
-func (id *auditingID) PublicID() security.PublicID {
- return id.id.PublicID()
-}
-
-func (id *auditingID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.Caveat) (security.PublicID, error) {
- blessed, err := id.id.Bless(blessee, blessingName, duration, caveats)
- if err = id.audit(err, "Bless", args{blessee, blessingName, duration, caveats}, blessed); err != nil {
- return nil, err
- }
- return blessed, nil
-}
-
-func (id *auditingID) Derive(publicID security.PublicID) (security.PrivateID, error) {
- // No auditing for Derive. Two reasons:
- // (1) This method is expected to go away (ataly@)
- // (2) There is no operation on the private key here.
- // However, operations on the Derived id do need to be audited.
- derived, err := id.id.Derive(publicID)
- if err != nil {
- return nil, err
- }
- return NewPrivateID(derived, id.auditor), nil
-}
-
-func (id *auditingID) MintDischarge(caveat security.ThirdPartyCaveat, context security.Context, duration time.Duration, caveats []security.Caveat) (security.Discharge, error) {
- d, err := id.id.MintDischarge(caveat, context, duration, caveats)
- if err = id.audit(err, "MintDischarge", args{caveat, context, duration, caveats}, nil); err != nil {
- return nil, err
- }
- return d, nil
-}
-
-func (id *auditingID) 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 := id.auditor.Audit(entry); err != nil {
- return fmt.Errorf("failed to audit call to %q: %v", method, err)
- }
- return nil
-}
diff --git a/security/audit/id_test.go b/security/audit/id_test.go
deleted file mode 100644
index e655b01..0000000
--- a/security/audit/id_test.go
+++ /dev/null
@@ -1,240 +0,0 @@
-package audit_test
-
-import (
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "errors"
- "reflect"
- "strings"
- "testing"
- "time"
-
- "veyron.io/veyron/veyron/security/audit"
- "veyron.io/veyron/veyron2/naming"
- "veyron.io/veyron/veyron2/security"
-)
-
-func TestAuditingID(t *testing.T) {
- var (
- // A bunch of values that will be used as arguments to method calls.
- byteSlice []byte
- publicID = security.FakePublicID("publicid")
- str string
- duration time.Duration
- caveats []security.Caveat
- thirdPartyCaveat thirdPartyCaveat
- context context
-
- // A bunch of values that will be returned as results
- rSignature = security.Signature{R: []byte{1}, S: []byte{1}}
- rBlessing = security.FakePublicID("blessed")
- rDischarge = new(discharge)
-
- // The error returned by call calls to mockID operations
- wantErr = errors.New("call failed")
-
- // The PrivateID to wrap over
- mockID = new(mockID)
- mockAuditor = new(mockAuditor)
- )
- id := audit.NewPrivateID(mockID, mockAuditor)
- tests := []struct {
- Method string
- Args V
- Result interface{} // Result returned by the Method call.
- AuditedResult interface{} // Result written to the audit entry.
- }{
- {"Sign", V{byteSlice}, rSignature, nil},
- {"Bless", V{publicID, str, duration, caveats}, rBlessing, rBlessing},
- {"MintDischarge", V{thirdPartyCaveat, context, duration, caveats}, rDischarge, nil},
- }
- for _, test := range tests {
- // Test1: Nothing is written to the audit log if the underlying operation fails.
- mockID.NextError = wantErr
- results, err := call(id, test.Method, test.Args)
- if err != nil {
- t.Errorf("failed to invoke id.%v(%#v): %v", test.Method, test.Args, err)
- continue
- }
- got, ok := results[len(results)-1].(error)
- if !ok || got != wantErr {
- t.Errorf("id.%v(%#v) returned (..., %v), want (..., %v)", test.Method, test.Args, got, wantErr)
- }
- // Nothing should be audited
- if audited := mockAuditor.Release(); !reflect.DeepEqual(audited, audit.Entry{}) {
- t.Errorf("id.%v(%#v) resulted in [%+v] being written to the audit log, nothing should have been", test.Method, test.Args, audited)
- }
-
- // Test2: If the auditing fails then the operation should fail too.
- mockAuditor.NextError = errors.New("auditor failed")
- results, err = call(id, test.Method, test.Args)
- if err != nil {
- t.Errorf("failed to invoke id.%v(%#v): %v", test.Method, test.Args, err)
- continue
- }
- got, ok = results[len(results)-1].(error)
- if !ok || !strings.HasSuffix(got.Error(), "auditor failed") {
- t.Errorf("id.%v(%#v) returned (..., %v) when auditor failed, wanted (..., %v)", test.Method, test.Args, got, "... auditor failed")
- }
-
- // Test3: Should audit the call and return the same value as the underlying operation.
- now := time.Now()
- mockID.NextResult = test.Result
- results, err = call(id, test.Method, test.Args)
- audited := mockAuditor.Release()
- if err != nil {
- t.Errorf("failed to invoke id.%v(%#v): %v", test.Method, test.Args, err)
- continue
- }
- if got := results[len(results)-1]; got != nil {
- t.Errorf("id.%v(%#v) returned an error: %v", test.Method, test.Args, got)
- }
- if got := results[0]; !reflect.DeepEqual(got, test.Result) {
- t.Errorf("id.%v(%#v) returned %v(%T) want %v(%T)", test.Method, test.Args, got, got, test.Result, test.Result)
- }
- if audited.Timestamp.Before(now) || audited.Timestamp.IsZero() {
- t.Errorf("id.%v(%#v) audited the time as %v, should have been a time after %v", test.Method, test.Args, audited.Timestamp, now)
- }
- if want := (audit.Entry{
- Method: test.Method,
- Arguments: []interface{}(test.Args),
- Results: sliceOrNil(true, test.AuditedResult),
- Timestamp: audited.Timestamp, // Hard to come up with the expected timestamp, relying on sanity check above.
- }); !reflect.DeepEqual(audited, want) {
- t.Errorf("id.%v(%#v) resulted in [%#v] being audited, wanted [%#v]", test.Method, test.Args, audited, want)
- }
- }
-}
-
-func TestUnauditedMethodsOnPrivateID(t *testing.T) {
- var (
- mockID = new(mockID)
- mockAuditor = new(mockAuditor)
- id = audit.NewPrivateID(mockID, mockAuditor)
- key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- pubkey = security.NewECDSAPublicKey(&key.PublicKey)
- emptyEntry audit.Entry
- )
- if err != nil {
- t.Fatal(err)
- }
- mockID.NextResult = pubkey
- if got, want := id.PublicKey(), pubkey; got != want {
- t.Errorf("Got %v want %v", got, want)
- }
- if entry := mockAuditor.Release(); !reflect.DeepEqual(entry, emptyEntry) {
- t.Errorf("Unexpected audit: %v", entry)
- }
-
- var pubID security.PublicID
- mockID.NextResult = pubID
- if got, want := id.PublicID(), pubID; got != want {
- t.Errorf("Got %v want %v", got, want)
- }
- if entry := mockAuditor.Release(); !reflect.DeepEqual(entry, emptyEntry) {
- t.Errorf("Unexpected audit: %v", entry)
- }
-}
-
-func TestDerive(t *testing.T) {
- var (
- mockID = new(mockID)
- mockAuditor = new(mockAuditor)
- id = audit.NewPrivateID(mockID, mockAuditor)
- publicID = security.FakePublicID("publicid")
- rSignature = security.Signature{R: []byte{2}, S: []byte{2}}
- msg = []byte{1, 2, 3}
- )
- mockID.NextResult = mockID
- derived, err := id.Derive(publicID)
- if err != nil {
- t.Fatal(err)
- }
-
- mockID.NextResult = rSignature
- if got, err := derived.Sign(msg); err != nil || !reflect.DeepEqual(got, rSignature) {
- t.Fatalf("Got (%v, %v) want (%v, nil)", got, err, rSignature)
- }
- got := mockAuditor.Release()
- if want := (audit.Entry{Method: "Sign", Arguments: []interface{}{msg}, Timestamp: got.Timestamp}); !reflect.DeepEqual(got, want) {
- t.Fatalf("Audit log shows [%v] want [%v]", got, want)
- }
-}
-
-type mockID struct {
- NextError error
- NextResult interface{}
-}
-
-func (id *mockID) Sign(message []byte) (security.Signature, error) {
- defer id.reset()
- ret, ok := id.NextResult.(security.Signature)
- if ok {
- return ret, id.NextError
- }
- return security.Signature{}, id.NextError
-}
-
-func (id *mockID) PublicID() security.PublicID {
- defer id.reset()
- if id.NextResult == nil {
- return nil
- }
- return id.NextResult.(security.PublicID)
-}
-func (id *mockID) Bless(blessee security.PublicID, blessingName string, duration time.Duration, caveats []security.Caveat) (security.PublicID, error) {
- defer id.reset()
- result, _ := id.NextResult.(security.PublicID)
- return result, id.NextError
-}
-func (id *mockID) Derive(publicID security.PublicID) (security.PrivateID, error) {
- defer id.reset()
- result, _ := id.NextResult.(security.PrivateID)
- return result, id.NextError
-}
-func (id *mockID) MintDischarge(caveat security.ThirdPartyCaveat, context security.Context, duration time.Duration, caveats []security.Caveat) (security.Discharge, error) {
- defer id.reset()
- result, _ := id.NextResult.(security.Discharge)
- return result, id.NextError
-}
-
-func (id *mockID) reset() {
- id.NextError = nil
- id.NextResult = nil
-}
-
-func (id *mockID) PublicKey() security.PublicKey { return id.NextResult.(security.PublicKey) }
-
-// thirdPartyCaveat implements security.ThirdPartyCaveat
-type thirdPartyCaveat struct{}
-
-func (thirdPartyCaveat) Validate(security.Context) error { return nil }
-func (thirdPartyCaveat) ID() string { return "thirdPartyCaveatID" }
-func (thirdPartyCaveat) Location() string { return "thirdPartyCaveatLocation" }
-func (thirdPartyCaveat) Requirements() security.ThirdPartyRequirements {
- return security.ThirdPartyRequirements{}
-}
-func (thirdPartyCaveat) Dischargeable(security.Context) error { return nil }
-
-// discharge implements the security.Discharge interface
-type discharge struct{}
-
-func (*discharge) ID() string { return "thirdPartyCaveatID" }
-func (*discharge) ThirdPartyCaveats() []security.ThirdPartyCaveat { return nil }
-
-// context implements security.Context
-type context struct{}
-
-func (context) Method() string { return "method" }
-func (context) Name() string { return "name" }
-func (context) Suffix() string { return "suffix" }
-func (context) Label() security.Label { return security.ReadLabel }
-func (context) Discharges() map[string]security.Discharge { return nil }
-func (context) LocalPrincipal() security.Principal { return nil }
-func (context) LocalBlessings() security.Blessings { return nil }
-func (context) RemoteBlessings() security.Blessings { return nil }
-func (context) LocalID() security.PublicID { return nil }
-func (context) RemoteID() security.PublicID { return nil }
-func (context) LocalEndpoint() naming.Endpoint { return nil }
-func (context) RemoteEndpoint() naming.Endpoint { return nil }
diff --git a/security/util_test.go b/security/util_test.go
index 9d098a6..daf4fc1 100644
--- a/security/util_test.go
+++ b/security/util_test.go
@@ -66,23 +66,6 @@
}
}
-func TestLoadSaveIdentity(t *testing.T) {
- id := security.FakePrivateID("test")
-
- var buf bytes.Buffer
- if err := SaveIdentity(&buf, id); err != nil {
- t.Fatalf("Failed to save PrivateID %q: %v", id, err)
- }
-
- loadedID, err := LoadIdentity(&buf)
- if err != nil {
- t.Fatalf("Failed to load PrivateID: %v", err)
- }
- if !reflect.DeepEqual(loadedID, id) {
- t.Fatalf("Got Identity %v, but want %v", loadedID, id)
- }
-}
-
func TestLoadSaveACL(t *testing.T) {
acl := security.ACL{}
acl.In = map[security.BlessingPattern]security.LabelSet{
diff --git a/services/identity/auditor/file.go b/services/identity/auditor/file.go
deleted file mode 100644
index 5850370..0000000
--- a/services/identity/auditor/file.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package auditor
-
-import (
- "fmt"
- "io"
- "os"
- "path/filepath"
- "sync"
- "time"
-
- "veyron.io/veyron/veyron/security/audit"
- "veyron.io/veyron/veyron2/security/wire"
- "veyron.io/veyron/veyron2/vlog"
- "veyron.io/veyron/veyron2/vom"
-)
-
-type fileAuditor struct {
- mu sync.Mutex
- file *os.File
- enc *vom.Encoder
-}
-
-// NewFileAuditor returns a security.Auditor implementation that synchronously writes
-// audit log entries to files on disk.
-//
-// The file on disk is named with the provided prefix and a timestamp appended to it.
-//
-// TODO(ashankar,ataly): Should we be using something more query-able, like sqllite or
-// something? Do we need integrity protection (NewSigningWriter)?
-func NewFileAuditor(prefix string) (audit.Auditor, error) {
- var file *os.File
- for file == nil {
- fname := fmt.Sprintf("%s.%s", prefix, time.Now().Format(time.RFC3339))
- var err error
- if file, err = os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600); err != nil && !os.IsExist(err) {
- return nil, err
- }
- }
- return &fileAuditor{
- file: file,
- enc: vom.NewEncoder(file),
- }, nil
-}
-
-func (a *fileAuditor) Audit(entry audit.Entry) error {
- a.mu.Lock()
- defer a.mu.Unlock()
- if err := a.enc.Encode(entry); err != nil {
- return fmt.Errorf("failed to write audit entry: %v", err)
- }
- // Ensure that any log entries are not lost in case the machine on which this process is running reboots.
- if err := a.file.Sync(); err != nil {
- return fmt.Errorf("failed to commit audit entry to persistent storage: %v", err)
- }
- return nil
-}
-
-// ReadAuditLog reads audit entries written using NewFileAuditor and produces them on the returned channel.
-//
-// The returned channel is closed when all committed entries have been sent on the channel.
-// If blessingFilter is non-empty, only audit entries for method invocations matching:
-// security.PrivateID.Bless(<*>, blessingFilter, ...)
-// will be printed on the channel.
-//
-// TODO(ashankar): This custom "query" language is another reason why I think of a more sophisticated store.
-func ReadAuditLog(prefix, blessingFilter string) (<-chan audit.Entry, error) {
- files, err := filepath.Glob(prefix + "*")
- if err != nil {
- return nil, err
- }
- c := make(chan audit.Entry)
- go sendAuditEvents(c, files, blessingFilter)
- return c, nil
-}
-
-func sendAuditEvents(dst chan<- audit.Entry, src []string, blessingFilter string) {
- defer close(dst)
- for _, fname := range src {
- file, err := os.Open(fname)
- if err != nil {
- vlog.VI(3).Infof("Unable to open %q: %v", fname, err)
- continue
- }
- decoder := vom.NewDecoder(file)
- fileloop:
- for {
- var entry audit.Entry
- switch err := decoder.Decode(&entry); err {
- case nil:
- filterAndSend(&entry, blessingFilter, dst)
- case io.EOF:
- break fileloop
- default:
- vlog.Errorf("Corrupt audit log? %q: %v", fname, err)
- break fileloop
- }
- }
- file.Close()
- }
-}
-
-func filterAndSend(entry *audit.Entry, filter string, dst chan<- audit.Entry) {
- if err := wire.ValidateBlessingName(filter); err != nil {
- // If the filter is invalid, send all events.
- // This allows for a means to ask for all events without defining a new
- // special character.
- dst <- *entry
- return
- }
- if entry.Method != "Bless" || len(entry.Arguments) < 2 {
- return
- }
- if name, ok := entry.Arguments[1].(string); ok && name == filter {
- dst <- *entry
- }
-}
diff --git a/services/identity/auditor/file_test.go b/services/identity/auditor/file_test.go
deleted file mode 100644
index 2a89aad..0000000
--- a/services/identity/auditor/file_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package auditor
-
-import (
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "reflect"
- "testing"
- "time"
-
- "veyron.io/veyron/veyron2/rt"
- "veyron.io/veyron/veyron2/security"
-
- _ "veyron.io/veyron/veyron/profiles"
- "veyron.io/veyron/veyron/security/audit"
-)
-
-func TestFileAuditor(t *testing.T) {
- r := rt.Init()
- defer r.Cleanup()
-
- // Setup a directory where the audit logs will be stored.
- dir, err := ioutil.TempDir("", "TestFileAuditor")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(dir)
-
- prefix := path.Join(dir, "log")
- auditor, err := NewFileAuditor(prefix)
- if err != nil {
- t.Fatal(err)
- }
- provider, _ := r.NewIdentity("provider")
- provider = audit.NewPrivateID(provider, auditor)
- blessee := func() security.PublicID {
- priv, _ := r.NewIdentity("blessee")
- return priv.PublicID()
- }()
-
- // Bless a bunch of names
- for idx, name := range []string{"brucewayne", "batman", "bugsbunny", "daffyduck", "batman", "bugsbunny", "brucewayne"} {
- if _, err := provider.Bless(blessee, name, time.Hour, nil); err != nil {
- t.Fatalf("Bless(#%d, %v, ...) failed: %v", idx, name, err)
- }
- }
-
- tests := []struct {
- Filter string
- Want []string
- }{
- {"", []string{"brucewayne", "batman", "bugsbunny", "daffyduck", "batman", "bugsbunny", "brucewayne"}},
- {"/", []string{"brucewayne", "batman", "bugsbunny", "daffyduck", "batman", "bugsbunny", "brucewayne"}},
- {"batman", []string{"batman", "batman"}},
- {"daffyduck", []string{"daffyduck"}},
- {"elmerfudd", []string{}},
- }
- for _, test := range tests {
- ch, err := ReadAuditLog(prefix, test.Filter)
- if err != nil {
- t.Errorf("ReadAuditLog(%q, %q) failed: %v", prefix, test.Filter, err)
- continue
- }
- channelloop:
- for i, want := range test.Want {
- got := <-ch
- testinfo := fmt.Sprintf("in test %+v (%d/%d)", test, i, len(want))
- if got.Method != "Bless" {
- t.Errorf("Got %q, wanted the Bless method %s", got, testinfo)
- break channelloop
- }
- if arg := got.Arguments[0]; !reflect.DeepEqual(arg, blessee) {
- t.Errorf("First argument was %v, wanted %v", arg, blessee, testinfo)
- break channelloop
- }
- if arg := got.Arguments[1].(string); arg != want {
- t.Errorf("Second argument was %v, wanted %v %s", arg, want, testinfo)
- break channelloop
- }
- }
- select {
- case entry, open := <-ch:
- if open {
- for _ = range ch {
- // Drain the channel to prevent the producer goroutines from being leaked.
- }
- t.Errorf("Got more entries that expected (such as %v) for test %+v", entry, test)
- }
- default:
- }
- }
-}
diff --git a/services/identity/identityd/main.go b/services/identity/identityd/main.go
index 4e2d8d8..252362f 100644
--- a/services/identity/identityd/main.go
+++ b/services/identity/identityd/main.go
@@ -22,7 +22,6 @@
"veyron.io/veyron/veyron2/vlog"
"veyron.io/veyron/veyron/lib/signals"
- "veyron.io/veyron/veyron/services/identity/auditor"
"veyron.io/veyron/veyron/services/identity/blesser"
"veyron.io/veyron/veyron/services/identity/googleoauth"
"veyron.io/veyron/veyron/services/identity/handlers"
@@ -296,7 +295,6 @@
defer r.Cleanup()
p := r.Principal()
// TODO(ashankar): Hook this up with Suharsh's new auditor implementation.
- // DO NOT SUBMIT
if len(*auditprefix) == 0 {
return options.RuntimePrincipal{p}
}
@@ -336,15 +334,7 @@
if len(*auditprefix) == 0 {
vlog.Fatalf("Must set --audit")
}
- ch, err := auditor.ReadAuditLog(*auditprefix, *auditfilter)
- if err != nil {
- vlog.Fatal(err)
- }
- idx := 0
- for entry := range ch {
- fmt.Printf("%6d) %v\n", idx, entry)
- idx++
- }
+ vlog.Fatalf("Auditing support disabled. Please contact ashankar@ or suharshs@ for restoration timeline")
}
var tmpl = template.Must(template.New("main").Parse(`<!doctype html>