Revoker implements the revoker service using a directory and files to store.
Change-Id: Ia22c65f5d810bc09681f8542e628e86240e2ebc3
diff --git a/services/security/discharger/discharger.go b/services/security/discharger/discharger.go
index 9bcb9ae..47aaf6f 100644
--- a/services/security/discharger/discharger.go
+++ b/services/security/discharger/discharger.go
@@ -25,7 +25,7 @@
return d.id.MintDischarge(caveat, ctx, time.Minute, nil)
}
-// New returns a Discharger server that can be passed to a dispatcher
-func New(id security.PrivateID) interface{} {
- return ssecurity.NewServerDischarger(&dischargerd{id})
+// NewDischarger returns a discharger service implementation that grants discharges using id.MintDischarge.
+func NewDischarger(id security.PrivateID) ssecurity.DischargerService {
+ return dischargerd{id}
}
diff --git a/services/security/discharger/revoker.go b/services/security/discharger/revoker.go
index a87043e..7f325ed 100644
--- a/services/security/discharger/revoker.go
+++ b/services/security/discharger/revoker.go
@@ -5,46 +5,53 @@
"crypto/sha256"
"encoding/hex"
"fmt"
+ "io/ioutil"
+ "os"
"path/filepath"
- "strings"
"sync"
- "time"
"veyron/security/caveat"
ssecurity "veyron/services/security"
"veyron2/ipc"
- "veyron2/naming"
- "veyron2/rt"
"veyron2/security"
- "veyron2/storage"
- "veyron2/storage/vstore"
- "veyron2/vlog"
"veyron2/vom"
)
-// TODO(ataly, andreser) This package uses a global variable to store the
-// revoker state to make it accessible to caveat.Validate. Ideally, we would
-// pass this in through the context (or something equivalent).
+// The revocation caveats will be stored in a directory with a file for each.
+type revocationDir string
-type revocationServiceT struct {
- store storage.Store
- pathInStore string
+// Returns whether the caveat exists in the recovation file.
+func (dir revocationDir) exists(cav string) (bool, error) {
+ if len(dir) == 0 {
+ return false, fmt.Errorf("missing call to NewRecocationCaveat")
+ }
+ _, err := os.Stat(filepath.Join(string(dir), cav))
+ return !os.IsNotExist(err), nil
+}
+
+func (dir revocationDir) put(caveatNonce string, caveatPreimage []byte) error {
+ if len(dir) == 0 {
+ return fmt.Errorf("missing call to NewRecocationCaveat")
+ }
+ return ioutil.WriteFile(filepath.Join(string(dir), caveatNonce), caveatPreimage, 0777)
+}
+
+func (dir revocationDir) Revoke(ctx ipc.ServerContext, caveatPreimage ssecurity.RevocationToken) error {
+ if len(dir) == 0 {
+ return fmt.Errorf("missing call to NewRecocationCaveat")
+ }
+ caveatNonce := sha256.Sum256(caveatPreimage[:])
+ return revocationService.put(hex.EncodeToString(caveatNonce[:]), caveatPreimage[:])
}
var revocationService struct {
- *revocationServiceT
+ revocationDir
sync.Mutex
}
type revocationCaveat [32]byte
func (cav revocationCaveat) Validate(security.Context) error {
- // TODO(ashankar,mattr): Figure out how to get the context of an existing RPC here
- rctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
- defer cancel()
-
- revocation := revocationService.store.BindObject(
- naming.Join(revocationService.pathInStore, hex.EncodeToString(cav[:])))
- exists, err := revocation.Exists(rctx)
+ exists, err := revocationService.exists(hex.EncodeToString(cav[:]))
if err != nil {
return err
}
@@ -67,59 +74,20 @@
return revocation, cav, err
}
-func (revoceationService *revocationServiceT) Revoke(ctx ipc.ServerContext, caveatPreimage ssecurity.RevocationToken) error {
- caveatNonce := sha256.Sum256(caveatPreimage[:])
- revocation := revocationService.store.BindObject(naming.Join(revocationService.pathInStore, hex.EncodeToString(caveatNonce[:])))
- if _, err := revocation.Put(ctx, caveatPreimage[:]); err != nil {
- return err
- }
- return nil
-}
-
-// NewRevoker returns a new revoker service that can be passed to a dispatcher.
-// Currently, due to the use of global variables, this function can be called only once.
-func NewRevoker(storeName, pathInStore string) (interface{}, error) {
+// NewRevoker returns a revoker service implementation that persists information about revocations on the filesystem in dir.
+// Can only be called once due to global variables.
+func NewRevoker(dir string) (ssecurity.RevokerService, error) {
revocationService.Lock()
defer revocationService.Unlock()
- if revocationService.revocationServiceT != nil {
- return nil, fmt.Errorf("revoker.Revoker called more than once")
+ if len(revocationService.revocationDir) > 0 {
+ return nil, fmt.Errorf("revoker.Revoker called more than once.")
}
- var err error
- revocationService.revocationServiceT = &revocationServiceT{pathInStore: pathInStore}
- revocationService.store, err = vstore.New(storeName)
- if err != nil {
- return nil, err
- }
+ revocationService.revocationDir = revocationDir(dir)
- rctx, cancel := rt.R().NewContext().WithTimeout(time.Minute)
- defer cancel()
+ // create the directory if not already there.
+ os.MkdirAll(dir, 0700)
- // Transaction is rooted at "", so tname == tid.
- tname, err := revocationService.store.BindTransactionRoot("").CreateTransaction(rctx)
- if err != nil {
- return nil, err
- }
-
- // Create parent directories for the revoker root, if necessary
- // TODO(tilaks,andreser): provide a `mkdir -p` equivalent in store
- l := strings.Split(pathInStore, "/")
- fmt.Println(l)
- for i := 0; i <= len(l); i++ {
- fmt.Println(i, filepath.Join(l[:i]...))
- prefix := filepath.Join(l[:i]...)
- o := revocationService.store.BindObject(naming.Join(tname, prefix))
- if exist, err := o.Exists(rctx); err != nil {
- vlog.Infof("Error checking existence at %q: %s", prefix, err)
- } else if !exist {
- if _, err := o.Put(rctx, &Dir{}); err != nil {
- vlog.Infof("Error creating directory %q: %s", prefix, err)
- }
- }
- }
- if err := revocationService.store.BindTransaction(tname).Commit(rctx); err != nil {
- vlog.Fatalf("Failed to commit creation of revoker root at %s: %s", pathInStore, err)
- }
- return ssecurity.NewServerRevoker(revocationService.revocationServiceT), nil
+ return revocationService.revocationDir, nil
}
func init() {
diff --git a/services/security/discharger/revoker_test.go b/services/security/discharger/revoker_test.go
index acb89e9..8dc971a 100644
--- a/services/security/discharger/revoker_test.go
+++ b/services/security/discharger/revoker_test.go
@@ -1,29 +1,22 @@
package discharger
import (
+ "os"
+ "path/filepath"
"testing"
ssecurity "veyron/services/security"
- teststore "veyron/services/store/testutil"
+ "veyron2"
"veyron2/ipc"
"veyron2/naming"
"veyron2/rt"
"veyron2/security"
)
-func init() {
- rt.Init()
-}
-
-func setup(t *testing.T) (dischargerID security.PublicID, dischargerEndpoint, revokerEndpoint string, closeFunc func()) {
- // Create and start the store instance that the revoker will use
- storeServer, err := rt.R().NewServer()
- if err != nil {
- t.Fatalf("rt.R().NewServer: %s", err)
- }
- storeVeyronName, closeStore := teststore.NewStore(t, storeServer, rt.R().Identity().PublicID())
-
+func revokerSetup(t *testing.T) (dischargerID security.PublicID, dischargerEndpoint, revokerEndpoint string, closeFunc func(), runtime veyron2.Runtime) {
+ var revokerDirPath = filepath.Join(os.TempDir(), "revoker_dir")
+ r := rt.Init()
// Create and start revoker and revocation discharge service
- revokerServer, err := rt.R().NewServer()
+ revokerServer, err := r.NewServer()
if err != nil {
t.Fatalf("rt.R().NewServer: %s", err)
}
@@ -31,11 +24,12 @@
if err != nil {
t.Fatalf("revokerServer.Listen failed: %v", err)
}
- revokerService, err := NewRevoker(storeVeyronName, "/testrevoker")
+ revokerService, err := NewRevoker(revokerDirPath)
if err != nil {
- t.Fatalf("setup revoker service: %s", err)
+ t.Fatalf("NewRevoker failed: $v", err)
}
- err = revokerServer.Serve("", ipc.SoloDispatcher(revokerService, nil))
+ revokerServiceStub := ssecurity.NewServerRevoker(revokerService)
+ err = revokerServer.Serve("", ipc.SoloDispatcher(revokerServiceStub, nil))
if err != nil {
t.Fatalf("revokerServer.Serve discharger: %s", err)
}
@@ -48,22 +42,23 @@
if err != nil {
t.Fatalf("revokerServer.Listen failed: %v", err)
}
- err = dischargerServer.Serve("", ipc.SoloDispatcher(New(rt.R().Identity()), nil))
- if err != nil {
+ dischargerServiceStub := ssecurity.NewServerDischarger(NewDischarger(r.Identity()))
+ if err := dischargerServer.Serve("", ipc.SoloDispatcher(dischargerServiceStub, nil)); err != nil {
t.Fatalf("revokerServer.Serve revoker: %s", err)
}
- return rt.R().Identity().PublicID(),
+ return r.Identity().PublicID(),
naming.JoinAddressName(dischargerEP.String(), ""),
naming.JoinAddressName(revokerEP.String(), ""),
func() {
+ defer os.RemoveAll(revokerDirPath)
revokerServer.Stop()
dischargerServer.Stop()
- closeStore()
- }
+ },
+ r
}
func TestDischargeRevokeDischargeRevokeDischarge(t *testing.T) {
- dcID, dc, rv, closeFunc := setup(t)
+ dcID, dc, rv, closeFunc, r := revokerSetup(t)
defer closeFunc()
revoker, err := ssecurity.BindRevoker(rv)
if err != nil {
@@ -78,20 +73,19 @@
if err != nil {
t.Fatalf("failed to create public key caveat: %s", err)
}
-
- if _, err = discharger.Discharge(rt.R().NewContext(), cav); err != nil {
+ if _, err = discharger.Discharge(r.NewContext(), cav); err != nil {
t.Fatalf("failed to get discharge: %s", err)
}
- if err = revoker.Revoke(rt.R().NewContext(), preimage); err != nil {
+ if err = revoker.Revoke(r.NewContext(), preimage); err != nil {
t.Fatalf("failed to revoke: %s", err)
}
- if discharge, err := discharger.Discharge(rt.R().NewContext(), cav); err == nil || discharge != nil {
+ if discharge, err := discharger.Discharge(r.NewContext(), cav); err == nil || discharge != nil {
t.Fatalf("got a discharge for a revoked caveat: %s", err)
}
- if err = revoker.Revoke(rt.R().NewContext(), preimage); err != nil {
+ if err = revoker.Revoke(r.NewContext(), preimage); err != nil {
t.Fatalf("failed to revoke again: %s", err)
}
- if discharge, err := discharger.Discharge(rt.R().NewContext(), cav); err == nil || discharge != nil {
+ if discharge, err := discharger.Discharge(r.NewContext(), cav); err == nil || discharge != nil {
t.Fatalf("got a discharge for a doubly revoked caveat: %s", err)
}
}
diff --git a/services/security/dischargerd/main.go b/services/security/dischargerd/main.go
deleted file mode 100644
index 6afb52b..0000000
--- a/services/security/dischargerd/main.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package main
-
-import (
- "flag"
-
- "veyron/lib/signals"
- vsecurity "veyron/security"
- "veyron/services/security/discharger"
-
- "veyron2/ipc"
- "veyron2/rt"
- "veyron2/security"
- "veyron2/vlog"
-)
-
-var (
- // TODO(rthellend): Remove the protocol and address flags when the config
- // manager is working.
- protocol = flag.String("protocol", "tcp", "protocol to listen on")
- address = flag.String("address", ":0", "address to listen on")
-
- aclFile = flag.String("discharger-acl", "", "ACL to use for the discharge service")
- publish = flag.String("publish", "discharger", "the Object Name under which to publish this service")
-
- storeName = flag.String("revocation-store", "", "Object Name of the Veyron store to be used for revocation. Omit to disable revocation functionality.")
- publishRevoker = flag.String("publish-revoker", "revoker", "the Object Name under which to publish this service")
- pathInStore = flag.String("path-in-store", "/revoker", "the location in store where the revoker keeps its state")
- revokerAclFile = flag.String("revoker-acl", "", "ACL to use for the revocation service")
-)
-
-func authorizer(file string) security.Authorizer {
- if file == "" {
- return vsecurity.NewACLAuthorizer(security.NewWhitelistACL(
- map[security.PrincipalPattern]security.LabelSet{
- security.AllPrincipals: security.AllLabels,
- }))
- }
- return vsecurity.NewFileACLAuthorizer(file)
-}
-
-func main() {
- r := rt.Init()
- defer r.Cleanup()
-
- dischargerServer, err := r.NewServer()
- if err != nil {
- vlog.Fatal(err)
- }
- defer dischargerServer.Stop()
- dischargerEndpoint, err := dischargerServer.Listen(*protocol, *address)
- if err != nil {
- vlog.Fatal(err)
- }
- if err = dischargerServer.Serve(*publish, ipc.SoloDispatcher(discharger.New(r.Identity()), authorizer(*aclFile))); err != nil {
- vlog.Fatal(err)
- }
- vlog.Infof("discharger: %s", dischargerEndpoint.String())
-
- if *storeName != "" {
- revokerServer, err := r.NewServer()
- if err != nil {
- vlog.Fatal(err)
- }
- defer revokerServer.Stop()
- revokerEndpoint, err := revokerServer.Listen(*protocol, *address)
- if err != nil {
- vlog.Fatal(err)
- }
- revokerService, err := discharger.NewRevoker(*storeName, *pathInStore)
- if err != nil {
- vlog.Fatal(err)
- }
- err = revokerServer.Serve(*publish, ipc.SoloDispatcher(revokerService, authorizer(*revokerAclFile)))
- if err != nil {
- vlog.Fatal(err)
- }
- vlog.Infof("revoker: %s", revokerEndpoint.String())
- }
-
- <-signals.ShutdownOnSignals()
-}