veyron2/security: Make the timestamp and method tags available in
security.Context
This commit makes two additions to the Context interface:
(1) Timestamp: The time at which the context was created/the time at
which the authorization check is to be made.
The expiry caveat now uses the time from the Context (instead of
time.Now()) to validate. This allows for more deterministic caveat
validation (eg. blessings.ForContext(ctx) will always return the
same result for the same 'ctx' now. Without this change, it could
return different results at different times based on the time
difference between the two calls).
(2) MethodTags: This is motivated by:
https://docs.google.com/a/google.com/document/d/1DZUu2sGKrf-b4p9JFdIbN0ULhz9Loa8reuPNKsdMKD0/edit?usp=sharing
Change-Id: I7f979948670c09ae9bdd483cce4bff839624f158
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 7ec8122..34f8bb5 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -310,7 +310,7 @@
if flow.RemoteBlessings() == nil {
return nil, nil, fmt.Errorf("server has not presented any blessings")
}
- serverBlessings = flow.RemoteBlessings().ForContext(serverAuthContext{flow})
+ serverBlessings = flow.RemoteBlessings().ForContext(serverAuthContext{flow, time.Now()})
for _, o := range opts {
switch v := o.(type) {
case options.RemoteID:
@@ -566,13 +566,16 @@
// authorize a server.
type serverAuthContext struct {
stream.Flow
+ timestamp time.Time
}
// TODO(ashankar,ataly): Set Method, Name, Suffix etc. once third-party caveat
// validation for a server's blessings are eanbled.
// Returning zero values affects more than third-party caveats, so yeah, have
// to remove them soon!
+func (c serverAuthContext) Timestamp() time.Time { return c.timestamp }
func (serverAuthContext) Method() string { return "" }
+func (serverAuthContext) MethodTags() []interface{} { return nil }
func (serverAuthContext) Name() string { return "" }
func (serverAuthContext) Suffix() string { return "" }
func (serverAuthContext) Label() (l security.Label) { return l }
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 6d8e1dd..44ae7ab 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -655,9 +655,9 @@
// Fields filled in during the server invocation.
blessings security.Blessings
method, suffix string
- label security.Label
+ tags []interface{}
discharges map[string]security.Discharge
- deadline time.Time
+ starttime time.Time
endStreamArgs bool // are the stream args at EOF?
allowDebug bool // true if the caller is permitted to view debug information.
}
@@ -787,8 +787,7 @@
}
func (fs *flowServer) processRequest() ([]interface{}, verror.E) {
- start := time.Now()
-
+ fs.starttime = time.Now()
req, verr := fs.readIPCRequest()
if verr != nil {
// We don't know what the ipc call was supposed to be, but we'll create
@@ -806,7 +805,7 @@
var cancel context.CancelFunc
if req.Timeout != ipc.NoTimeout {
- fs.T, cancel = fs.WithDeadline(start.Add(time.Duration(req.Timeout)))
+ fs.T, cancel = fs.WithDeadline(fs.starttime.Add(time.Duration(req.Timeout)))
} else {
fs.T, cancel = fs.WithCancel()
}
@@ -857,7 +856,7 @@
// Prepare invoker and decode args.
numArgs := int(req.NumPosArgs)
argptrs, tags, err := invoker.Prepare(req.Method, numArgs)
- fs.label = labelFromTags(tags)
+ fs.tags = tags
if err != nil {
return nil, verror.Makef(verror.ErrorID(err), "%s: name: %q", err, req.Suffix)
}
@@ -882,7 +881,7 @@
}
results, err := invoker.Invoke(req.Method, fs, argptrs)
- fs.server.stats.record(req.Method, time.Since(start))
+ fs.server.stats.record(req.Method, time.Since(fs.starttime))
return results, verror.Convert(err)
}
@@ -968,7 +967,7 @@
}
argptrs, tags, err := invoker.Prepare("Glob", 1)
- i.fs.label = labelFromTags(tags)
+ i.fs.tags = tags
if err != nil {
return verror.Makef(verror.ErrorID(err), "%s", err)
}
@@ -1079,10 +1078,18 @@
//nologcall
return fs.server
}
+func (fs *flowServer) Timestamp() time.Time {
+ //nologcall
+ return fs.starttime
+}
func (fs *flowServer) Method() string {
//nologcall
return fs.method
}
+func (fs *flowServer) MethodTags() []interface{} {
+ //nologcall
+ return fs.tags
+}
// TODO(cnicolaou): remove Name from ipc.ServerContext and all of
// its implementations
@@ -1096,7 +1103,12 @@
}
func (fs *flowServer) Label() security.Label {
//nologcall
- return fs.label
+ for _, t := range fs.tags {
+ if l, ok := t.(security.Label); ok {
+ return l
+ }
+ }
+ return security.AdminLabel
}
func (fs *flowServer) LocalPrincipal() security.Principal {
//nologcall
@@ -1122,12 +1134,3 @@
//nologcall
return fs.flow.RemoteEndpoint()
}
-
-func labelFromTags(tags []interface{}) security.Label {
- for _, t := range tags {
- if l, ok := t.(security.Label); ok {
- return l
- }
- }
- return security.AdminLabel
-}
diff --git a/runtimes/google/ipc/stream/vc/auth.go b/runtimes/google/ipc/stream/vc/auth.go
index af2be25..3c95308 100644
--- a/runtimes/google/ipc/stream/vc/auth.go
+++ b/runtimes/google/ipc/stream/vc/auth.go
@@ -5,6 +5,7 @@
"errors"
"fmt"
"io"
+ "time"
"veyron.io/veyron/veyron/runtimes/google/ipc/stream/crypto"
"veyron.io/veyron/veyron/runtimes/google/lib/iobuf"
@@ -59,8 +60,9 @@
return nil, nil, err
}
serverB := server.ForContext(&serverAuthContext{
- self: principal,
- remote: server,
+ self: principal,
+ remote: server,
+ timestamp: time.Now(),
// TODO(ashankar): Get the local and remote endpoint here?
// There is also a bootstrapping problem here. For example, let's say
// (1) server has the blessing "provider/server" with a PeerIdentity caveat of "provider/client"
@@ -135,11 +137,14 @@
// security.Context implementation used when extracting blessings from what the
// server presents during authentication.
type serverAuthContext struct {
- self security.Principal
- remote security.Blessings
+ self security.Principal
+ remote security.Blessings
+ timestamp time.Time
}
+func (c *serverAuthContext) Timestamp() time.Time { return c.timestamp }
func (*serverAuthContext) Method() string { return "" }
+func (*serverAuthContext) MethodTags() []interface{} { return nil }
func (*serverAuthContext) Name() string { return "" }
func (*serverAuthContext) Suffix() string { return "" }
func (*serverAuthContext) Label() (l security.Label) { return l }
diff --git a/runtimes/google/rt/rt_test.go b/runtimes/google/rt/rt_test.go
index e76dcd5..e391f1f 100644
--- a/runtimes/google/rt/rt_test.go
+++ b/runtimes/google/rt/rt_test.go
@@ -27,7 +27,9 @@
local security.Principal
}
+func (*context) Timestamp() (t time.Time) { return t }
func (*context) Method() string { return "" }
+func (*context) MethodTags() []interface{} { return nil }
func (*context) Name() string { return "" }
func (*context) Suffix() string { return "" }
func (*context) Label() (l security.Label) { return }
diff --git a/security/acl_authorizer_test.go b/security/acl_authorizer_test.go
index d784a44..f8785fa 100644
--- a/security/acl_authorizer_test.go
+++ b/security/acl_authorizer_test.go
@@ -5,6 +5,7 @@
"os"
"runtime"
"testing"
+ "time"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/security"
@@ -18,7 +19,9 @@
label security.Label
}
+func (c *context) Timestamp() (t time.Time) { return t }
func (c *context) Method() string { return c.method }
+func (c *context) MethodTags() []interface{} { return nil }
func (c *context) Name() string { return "" }
func (c *context) Suffix() string { return "" }
func (c *context) Label() security.Label { return c.label }