Merge "veyron/services/security/revoker: revocation service"
diff --git a/services/security/discharger/discharger.go b/services/security/discharger/discharger.go
new file mode 100644
index 0000000..9bcb9ae
--- /dev/null
+++ b/services/security/discharger/discharger.go
@@ -0,0 +1,31 @@
+package discharger
+
+import (
+ "fmt"
+ "time"
+ ssecurity "veyron/services/security"
+ "veyron2/ipc"
+ "veyron2/security"
+ "veyron2/vdl/vdlutil"
+)
+
+// dischargerd issues discharges for all caveats present in the current
+// namespace with no additional caveats iff the caveat is valid.
+type dischargerd struct {
+ id security.PrivateID
+}
+
+// TODO(andreser,ataly): make it easier for third party public key caveats to specify the caveats on their discharges
+
+func (d dischargerd) Discharge(ctx ipc.ServerContext, caveatAny vdlutil.Any) (vdlutil.Any, error) {
+ caveat, ok := caveatAny.(security.ThirdPartyCaveat)
+ if !ok {
+ return nil, fmt.Errorf("type %T does not implement security.ThirdPartyCaveat", caveatAny)
+ }
+ 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})
+}
diff --git a/services/security/discharger/revoker.go b/services/security/discharger/revoker.go
new file mode 100644
index 0000000..4f32574
--- /dev/null
+++ b/services/security/discharger/revoker.go
@@ -0,0 +1,123 @@
+package discharger
+
+import (
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "path/filepath"
+ "strings"
+ "sync"
+ "veyron/security/caveat"
+ ssecurity "veyron/services/security"
+ "veyron2/ipc"
+ "veyron2/naming"
+ "veyron2/rt"
+ "veyron2/security"
+ "veyron2/storage"
+ "veyron2/storage/vstore"
+ "veyron2/storage/vstore/primitives"
+ "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).
+
+type revocationServiceT struct {
+ store storage.Store
+ pathInStore string
+}
+
+var revocationService struct {
+ *revocationServiceT
+ 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 := rt.R().NewContext()
+ revocation := revocationService.store.Bind(naming.Join(revocationService.pathInStore,
+ hex.EncodeToString(cav[:])))
+ tx := primitives.NewTransaction(rctx)
+ defer tx.Abort(rctx)
+ exists, err := revocation.Exists(rctx, tx)
+ if err != nil {
+ return err
+ }
+ if exists {
+ return fmt.Errorf("revoked")
+ }
+ return nil
+}
+
+// NewRevocationCaveat returns a security.ThirdPartyCaveat that discharger will
+// mint discharges until explicitly told not to by calling Revoke on it
+// (using the returned revocation token)
+func NewRevocationCaveat(dischargerID security.PublicID, dischargerLocation string) (ssecurity.RevocationToken, security.ThirdPartyCaveat, error) {
+ var revocation ssecurity.RevocationToken
+ if _, err := rand.Read(revocation[:]); err != nil {
+ return revocation, nil, err
+ }
+ restriction := revocationCaveat(sha256.Sum256(revocation[:]))
+ cav, err := caveat.NewPublicKeyCaveat(restriction, dischargerID, dischargerLocation)
+ return revocation, cav, err
+}
+
+func (revoceationService *revocationServiceT) Revoke(ctx ipc.ServerContext, caveatPreimage ssecurity.RevocationToken) error {
+ caveatNonce := sha256.Sum256(caveatPreimage[:])
+ tx := primitives.NewTransaction(ctx)
+ revocation := revocationService.store.Bind(naming.Join(revocationService.pathInStore, hex.EncodeToString(caveatNonce[:])))
+ if _, err := revocation.Put(ctx, tx, caveatPreimage[:]); err != nil {
+ tx.Abort(ctx)
+ return err
+ }
+ return tx.Commit(ctx)
+}
+
+// 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) {
+ revocationService.Lock()
+ defer revocationService.Unlock()
+ if revocationService.revocationServiceT != nil {
+ return nil, fmt.Errorf("revoker.Revoker called more than once")
+ }
+ var err error
+ revocationService.revocationServiceT = new(revocationServiceT)
+ revocationService.store, err = vstore.New(storeName)
+ if err != nil {
+ return nil, err
+ }
+
+ rctx := rt.R().NewContext()
+ tx := primitives.NewTransaction(rctx)
+
+ // 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.Bind(prefix)
+ if exist, err := o.Exists(rctx, tx); err != nil {
+ vlog.Infof("Error checking existence at %q: %s", prefix, err)
+ } else if !exist {
+ if _, err := o.Put(rctx, tx, &Dir{}); err != nil {
+ vlog.Infof("Error creating directory %q: %s", prefix, err)
+ }
+ }
+ }
+ if err := tx.Commit(rctx); err != nil {
+ vlog.Fatalf("Commit creation of revocer root et %s: %s", pathInStore, err)
+ }
+ return ssecurity.NewServerRevoker(revocationService.revocationServiceT), nil
+}
+
+func init() {
+ vom.Register(revocationCaveat{})
+}
diff --git a/services/security/discharger/revoker_test.go b/services/security/discharger/revoker_test.go
new file mode 100644
index 0000000..acb89e9
--- /dev/null
+++ b/services/security/discharger/revoker_test.go
@@ -0,0 +1,97 @@
+package discharger
+
+import (
+ "testing"
+ ssecurity "veyron/services/security"
+ teststore "veyron/services/store/testutil"
+ "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())
+
+ // Create and start revoker and revocation discharge service
+ revokerServer, err := rt.R().NewServer()
+ if err != nil {
+ t.Fatalf("rt.R().NewServer: %s", err)
+ }
+ revokerEP, err := revokerServer.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("revokerServer.Listen failed: %v", err)
+ }
+ revokerService, err := NewRevoker(storeVeyronName, "/testrevoker")
+ if err != nil {
+ t.Fatalf("setup revoker service: %s", err)
+ }
+ err = revokerServer.Serve("", ipc.SoloDispatcher(revokerService, nil))
+ if err != nil {
+ t.Fatalf("revokerServer.Serve discharger: %s", err)
+ }
+
+ dischargerServer, err := rt.R().NewServer()
+ if err != nil {
+ t.Fatalf("rt.R().NewServer: %s", err)
+ }
+ dischargerEP, err := dischargerServer.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("revokerServer.Listen failed: %v", err)
+ }
+ err = dischargerServer.Serve("", ipc.SoloDispatcher(New(rt.R().Identity()), nil))
+ if err != nil {
+ t.Fatalf("revokerServer.Serve revoker: %s", err)
+ }
+ return rt.R().Identity().PublicID(),
+ naming.JoinAddressName(dischargerEP.String(), ""),
+ naming.JoinAddressName(revokerEP.String(), ""),
+ func() {
+ revokerServer.Stop()
+ dischargerServer.Stop()
+ closeStore()
+ }
+}
+
+func TestDischargeRevokeDischargeRevokeDischarge(t *testing.T) {
+ dcID, dc, rv, closeFunc := setup(t)
+ defer closeFunc()
+ revoker, err := ssecurity.BindRevoker(rv)
+ if err != nil {
+ t.Fatalf("error binding to server: ", err)
+ }
+ discharger, err := ssecurity.BindDischarger(dc)
+ if err != nil {
+ t.Fatalf("error binding to server: ", err)
+ }
+
+ preimage, cav, err := NewRevocationCaveat(dcID, dc)
+ if err != nil {
+ t.Fatalf("failed to create public key caveat: %s", err)
+ }
+
+ if _, err = discharger.Discharge(rt.R().NewContext(), cav); err != nil {
+ t.Fatalf("failed to get discharge: %s", err)
+ }
+ if err = revoker.Revoke(rt.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 {
+ t.Fatalf("got a discharge for a revoked caveat: %s", err)
+ }
+ if err = revoker.Revoke(rt.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 {
+ t.Fatalf("got a discharge for a doubly revoked caveat: %s", err)
+ }
+}
diff --git a/services/security/discharger/schema.vdl b/services/security/discharger/schema.vdl
new file mode 100644
index 0000000..d92d035
--- /dev/null
+++ b/services/security/discharger/schema.vdl
@@ -0,0 +1,3 @@
+package discharger
+
+type Dir struct {} // TODO(tilaks, andreser): move this to store?
diff --git a/services/security/discharger/schema.vdl.go b/services/security/discharger/schema.vdl.go
new file mode 100644
index 0000000..462d255
--- /dev/null
+++ b/services/security/discharger/schema.vdl.go
@@ -0,0 +1,7 @@
+// This file was auto-generated by the veyron vdl tool.
+// Source: schema.vdl
+
+package discharger
+
+type Dir struct {
+} // TODO(tilaks, andreser): move this to store?
diff --git a/services/security/dischargerd/main.go b/services/security/dischargerd/main.go
new file mode 100644
index 0000000..cde9103
--- /dev/null
+++ b/services/security/dischargerd/main.go
@@ -0,0 +1,73 @@
+package main
+
+import (
+ "flag"
+
+ "veyron/lib/signals"
+ "veyron/services/security/discharger"
+ "veyron2/ipc"
+ "veyron2/rt"
+ "veyron2/security"
+ "veyron2/vlog"
+)
+
+var (
+ 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 security.NewACLAuthorizer(security.ACL{security.AllPrincipals: security.AllLabels})
+ }
+ return security.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()
+}
diff --git a/services/security/revoker.vdl b/services/security/revoker.vdl
new file mode 100644
index 0000000..da13597
--- /dev/null
+++ b/services/security/revoker.vdl
@@ -0,0 +1,27 @@
+package security
+
+import "veyron2/security"
+
+// RevocationToken can be presented to a revocation service to revoke a caveat
+type RevocationToken [16]byte
+
+// Revoker is the interface for preventing discharges from being issued. The
+// dicharger ensures that no discharges will be issued for caveats that
+// have been explicitly revoked using this interface. To prevent discharge
+// stealing caveats just have to be unique; the exact structure is not relevant
+// to the client or the verifier. To make Revoker's job easy, each caveat
+// contains a SHA256 hash of its revocation token. To revoke a caveat C and
+// have it added to the discharger's blacklist, one simply needs to call
+// Revoke(x) with an x s.t. SHA256(x) = C. All caveats for which this has not
+// been revoked will get discharges, irrespective of who created them. This
+// means that the existence of a valid discharge does not imply that a
+// corresponding caveat exists, and even if it does, it may not be meant for
+// use with this revocation service. Just looking at discharges is meaningless,
+// a valid (Caveat, Discharge) pair is what can be relied on for
+// authentication. Not keeping track of non-revoked caveats enables
+// performance improvements on the Discharger side.
+type Revoker interface {
+ // Revoke ensures that iff a nil is returned, all discharge requests to the
+ // caveat with nonce sha256(caveatPreimage) are going to be denied.
+ Revoke(caveatPreimage RevocationToken) error {security.WriteLabel}
+}
diff --git a/services/security/revoker.vdl.go b/services/security/revoker.vdl.go
new file mode 100644
index 0000000..811fbe2
--- /dev/null
+++ b/services/security/revoker.vdl.go
@@ -0,0 +1,202 @@
+// This file was auto-generated by the veyron vdl tool.
+// Source: revoker.vdl
+
+package security
+
+import (
+ "veyron2/security"
+
+ // The non-user imports are prefixed with "_gen_" to prevent collisions.
+ _gen_veyron2 "veyron2"
+ _gen_context "veyron2/context"
+ _gen_ipc "veyron2/ipc"
+ _gen_naming "veyron2/naming"
+ _gen_rt "veyron2/rt"
+ _gen_vdlutil "veyron2/vdl/vdlutil"
+ _gen_wiretype "veyron2/wiretype"
+)
+
+// RevocationToken can be presented to a revocation service to revoke a caveat
+type RevocationToken [16]byte
+
+// Revoker is the interface for preventing discharges from being issued. The
+// dicharger ensures ensures that no discharges will be issued for caveats that
+// have been explicitly revoked using this interface. To prevent discharge
+// stealing caveats just have to be unique; the exact structure is not relevant
+// to the client or the verifier. To make Revoker's job easy, each caveat
+// contains a SHA256 hash of its revocation token. To revoke a caveat C and
+// have it added to the discharger's blacklist, one simply needs to call
+// Revoke(x) with an x s.t. SHA256(x) = C. All caveats for which this has not
+// been revoked will get discharges, irrespective of who created them. This
+// means that the existence of a valid discharge does not imply that a
+// corresponding caveat exists, and even if it does, it may not be meant for
+// use with this revocation service. Just looking at discharges is meaningless,
+// a valid (Caveat, Discharge) pair is what can be relied on for
+// authentication. Not keeping track of non-revoked caveats enables
+// performance improvements on the Discharger side.
+// Revoker is the interface the client binds and uses.
+// Revoker_ExcludingUniversal is the interface without internal framework-added methods
+// to enable embedding without method collisions. Not to be used directly by clients.
+type Revoker_ExcludingUniversal interface {
+ // Revoke ensures that iff a nil is returned, all discharge requests to the
+ // caveat with nonce sha256(caveatPreimage) are going to be denied.
+ Revoke(ctx _gen_context.T, caveatPreimage RevocationToken, opts ..._gen_ipc.CallOpt) (err error)
+}
+type Revoker interface {
+ _gen_ipc.UniversalServiceMethods
+ Revoker_ExcludingUniversal
+}
+
+// RevokerService is the interface the server implements.
+type RevokerService interface {
+
+ // Revoke ensures that iff a nil is returned, all discharge requests to the
+ // caveat with nonce sha256(caveatPreimage) are going to be denied.
+ Revoke(context _gen_ipc.ServerContext, caveatPreimage RevocationToken) (err error)
+}
+
+// BindRevoker returns the client stub implementing the Revoker
+// interface.
+//
+// If no _gen_ipc.Client is specified, the default _gen_ipc.Client in the
+// global Runtime is used.
+func BindRevoker(name string, opts ..._gen_ipc.BindOpt) (Revoker, error) {
+ var client _gen_ipc.Client
+ switch len(opts) {
+ case 0:
+ client = _gen_rt.R().Client()
+ case 1:
+ switch o := opts[0].(type) {
+ case _gen_veyron2.Runtime:
+ client = o.Client()
+ case _gen_ipc.Client:
+ client = o
+ default:
+ return nil, _gen_vdlutil.ErrUnrecognizedOption
+ }
+ default:
+ return nil, _gen_vdlutil.ErrTooManyOptionsToBind
+ }
+ stub := &clientStubRevoker{client: client, name: name}
+
+ return stub, nil
+}
+
+// NewServerRevoker creates a new server stub.
+//
+// It takes a regular server implementing the RevokerService
+// interface, and returns a new server stub.
+func NewServerRevoker(server RevokerService) interface{} {
+ return &ServerStubRevoker{
+ service: server,
+ }
+}
+
+// clientStubRevoker implements Revoker.
+type clientStubRevoker struct {
+ client _gen_ipc.Client
+ name string
+}
+
+func (__gen_c *clientStubRevoker) Revoke(ctx _gen_context.T, caveatPreimage RevocationToken, opts ..._gen_ipc.CallOpt) (err error) {
+ var call _gen_ipc.Call
+ if call, err = __gen_c.client.StartCall(ctx, __gen_c.name, "Revoke", []interface{}{caveatPreimage}, opts...); err != nil {
+ return
+ }
+ if ierr := call.Finish(&err); ierr != nil {
+ err = ierr
+ }
+ return
+}
+
+func (__gen_c *clientStubRevoker) UnresolveStep(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply []string, err error) {
+ var call _gen_ipc.Call
+ if call, err = __gen_c.client.StartCall(ctx, __gen_c.name, "UnresolveStep", nil, opts...); err != nil {
+ return
+ }
+ if ierr := call.Finish(&reply, &err); ierr != nil {
+ err = ierr
+ }
+ return
+}
+
+func (__gen_c *clientStubRevoker) Signature(ctx _gen_context.T, opts ..._gen_ipc.CallOpt) (reply _gen_ipc.ServiceSignature, err error) {
+ var call _gen_ipc.Call
+ if call, err = __gen_c.client.StartCall(ctx, __gen_c.name, "Signature", nil, opts...); err != nil {
+ return
+ }
+ if ierr := call.Finish(&reply, &err); ierr != nil {
+ err = ierr
+ }
+ return
+}
+
+func (__gen_c *clientStubRevoker) GetMethodTags(ctx _gen_context.T, method string, opts ..._gen_ipc.CallOpt) (reply []interface{}, err error) {
+ var call _gen_ipc.Call
+ if call, err = __gen_c.client.StartCall(ctx, __gen_c.name, "GetMethodTags", []interface{}{method}, opts...); err != nil {
+ return
+ }
+ if ierr := call.Finish(&reply, &err); ierr != nil {
+ err = ierr
+ }
+ return
+}
+
+// ServerStubRevoker wraps a server that implements
+// RevokerService and provides an object that satisfies
+// the requirements of veyron2/ipc.ReflectInvoker.
+type ServerStubRevoker struct {
+ service RevokerService
+}
+
+func (__gen_s *ServerStubRevoker) GetMethodTags(call _gen_ipc.ServerCall, method string) ([]interface{}, error) {
+ // TODO(bprosnitz) GetMethodTags() will be replaces with Signature().
+ // Note: This exhibits some weird behavior like returning a nil error if the method isn't found.
+ // This will change when it is replaced with Signature().
+ switch method {
+ case "Revoke":
+ return []interface{}{security.Label(2)}, nil
+ default:
+ return nil, nil
+ }
+}
+
+func (__gen_s *ServerStubRevoker) Signature(call _gen_ipc.ServerCall) (_gen_ipc.ServiceSignature, error) {
+ result := _gen_ipc.ServiceSignature{Methods: make(map[string]_gen_ipc.MethodSignature)}
+ result.Methods["Revoke"] = _gen_ipc.MethodSignature{
+ InArgs: []_gen_ipc.MethodArgument{
+ {Name: "caveatPreimage", Type: 66},
+ },
+ OutArgs: []_gen_ipc.MethodArgument{
+ {Name: "", Type: 67},
+ },
+ }
+
+ result.TypeDefs = []_gen_vdlutil.Any{
+ _gen_wiretype.NamedPrimitiveType{Type: 0x32, Name: "byte", Tags: []string(nil)}, _gen_wiretype.ArrayType{Elem: 0x41, Len: 0x10, Name: "veyron/services/security.RevocationToken", Tags: []string(nil)}, _gen_wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}
+
+ return result, nil
+}
+
+func (__gen_s *ServerStubRevoker) UnresolveStep(call _gen_ipc.ServerCall) (reply []string, err error) {
+ if unresolver, ok := __gen_s.service.(_gen_ipc.Unresolver); ok {
+ return unresolver.UnresolveStep(call)
+ }
+ if call.Server() == nil {
+ return
+ }
+ var published []string
+ if published, err = call.Server().Published(); err != nil || published == nil {
+ return
+ }
+ reply = make([]string, len(published))
+ for i, p := range published {
+ reply[i] = _gen_naming.Join(p, call.Name())
+ }
+ return
+}
+
+func (__gen_s *ServerStubRevoker) Revoke(call _gen_ipc.ServerCall, caveatPreimage RevocationToken) (err error) {
+ err = __gen_s.service.Revoke(call, caveatPreimage)
+ return
+}
diff --git a/services/security/simpledischarged/main.go b/services/security/simpledischarged/main.go
deleted file mode 100644
index 427942d..0000000
--- a/services/security/simpledischarged/main.go
+++ /dev/null
@@ -1,78 +0,0 @@
-package main
-
-import (
- "errors"
- "flag"
- "fmt"
- "log"
- "time"
-
- "veyron/lib/signals"
- isecurity "veyron/services/security"
- "veyron2/ipc"
- "veyron2/rt"
- "veyron2/security"
- "veyron2/vdl/vdlutil"
-)
-
-// TODO(ataly, andreser): ideally, the expiration time (and other caveats) of
-// the discharge would be determined by a function much like ThirdPartyCaveat.Validate
-var expiration = flag.String("expiration", "10s", "time interval after which a discharge will expire")
-var protocol = flag.String("protocol", "bluetooth", "protocol to listen on")
-var address = flag.String("address", "", "address to listen on")
-var port = flag.Int("port", 0, "port to listen on")
-var publish = flag.String("publish", "", "the namespace where to publish this service")
-
-type dischargeAuthorizer struct{}
-
-func (dischargeAuthorizer) Authorize(c security.Context) error {
- if c.Method() == "Discharge" {
- return nil
- }
- return fmt.Errorf("Only authorized for method \"Discharge\"")
-}
-
-// discharged implements ipc.Dispatcher. It issues discharges for all caveats
-// present in the current namespace with no additional caveats iff the caveat
-// is valid.
-type discharged struct {
- id security.PrivateID
- expiration time.Duration
-}
-
-func (d *discharged) Discharge(ctx ipc.ServerContext, Caveat vdlutil.Any) (
- Discharge vdlutil.Any, err error) {
- caveat, ok := Caveat.(security.ThirdPartyCaveat)
- if !ok {
- err = errors.New("unknown caveat")
- return
- }
- return d.id.MintDischarge(caveat, ctx, d.expiration, nil)
-}
-
-func main() {
- flag.Parse()
- expiration, err := time.ParseDuration(*expiration)
- if err != nil {
- log.Fatalf("--expiration: ", err)
- }
-
- r := rt.Init()
- server, err := r.NewServer()
- if err != nil {
- log.Fatal(err)
- }
-
- discharger := isecurity.NewServerDischarger(&discharged{
- id: r.Identity(), expiration: expiration})
- dispatcher := ipc.SoloDispatcher(discharger, dischargeAuthorizer{})
- endpoint, err := server.Listen(*protocol, *address+":"+fmt.Sprint(*port))
- if err != nil {
- log.Fatal(err)
- }
- if err := server.Serve(*publish, dispatcher); err != nil {
- log.Fatal(err)
- }
- fmt.Println(endpoint)
- <-signals.ShutdownOnSignals()
-}