"veyron/tools/principal": RecvBlessings flags

Per @jregan's request (for the Veyron security tutorial),
this CL adds the '--for_peer' flag (for specifying the peer
pattern with which the received blessing musts be marked with)
and '--set_default' flag (for specifying whether the received
blessings must be set as default) to the 'recvblessings' command
on the principal tool.

Change-Id: I0e37d4a3a7f7fbc30e1118b26be456bbe16b92ef
diff --git a/tools/principal/main.go b/tools/principal/main.go
index e90e3df..643d70b 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -45,6 +45,10 @@
 	// Flags common to many commands
 	flagAddToRoots bool
 
+	// Flags for the "recvblessings" command
+	flagRecvBlessingsSetDefault bool
+	flagRecvBlessingsForPeer    string
+
 	cmdDump = &cmdline.Command{
 		Name:  "dump",
 		Short: "Dump out information about the principal",
@@ -513,8 +517,8 @@
 The blessings are sought for the principal specified by the environment that
 this tool is running in.
 
-The blessings obtained are set as default, unless a --skip_set_default flag
-is provided, and are also set for sharing with all peers, unless a more
+The blessings obtained are set as default, unless the --set_default flag is
+set to true, and are also set for sharing with all peers, unless a more
 specific peer pattern is provided using the --for_peer flag.
 `,
 		Run: func(cmd *cmdline.Command, args []string) error {
@@ -579,8 +583,9 @@
 from another invocation of this tool (remote process) and prints out the
 command to be run as the remote principal.
 
-The received blessings are set as the default blessing of this principal
-and also as the blessing to be shared with all peers.
+The received blessings are set as default, unless the --set_default flag is
+set to true, and are also set for sharing with all peers, unless a more
+specific peer pattern is provided using the --for_peer flag.
 
 TODO(ashankar,cnicolaou): Make this next paragraph possible! Requires
 the ability to obtain the proxied endpoint.
@@ -667,6 +672,9 @@
 
 	cmdCreate.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
 
+	cmdRecvBlessings.Flags.BoolVar(&flagRecvBlessingsSetDefault, "set_default", true, "If true, the blessings received will be set as the default blessing in the store")
+	cmdRecvBlessings.Flags.StringVar(&flagRecvBlessingsForPeer, "for_peer", string(security.AllPrincipals), "If non-empty, the blessings received will be marked for peers matching this pattern in the store")
+
 	cmdStore := &cmdline.Command{
 		Name:  "store",
 		Short: "Manipulate and inspect the principal's blessing store",
@@ -807,12 +815,15 @@
 	if subtle.ConstantTimeCompare([]byte(token), []byte(r.token)) != 1 {
 		return fmt.Errorf("blessings received from unexpected sender")
 	}
-	// Maybe flagify the "SetDefault" and "Set" calls?
-	if err := r.principal.BlessingStore().SetDefault(b); err != nil {
-		return fmt.Errorf("failed to add granted blessings: %v", err)
+	if flagRecvBlessingsSetDefault {
+		if err := r.principal.BlessingStore().SetDefault(b); err != nil {
+			return fmt.Errorf("failed to set blessings %v as default: %v", b, err)
+		}
 	}
-	if _, err := r.principal.BlessingStore().Set(b, security.AllPrincipals); err != nil {
-		return fmt.Errorf("failed to add granted blessings: %v", err)
+	if pattern := security.BlessingPattern(flagRecvBlessingsForPeer); len(pattern) > 0 {
+		if _, err := r.principal.BlessingStore().Set(b, pattern); err != nil {
+			return fmt.Errorf("failed to set blessings %v for peers %v: %v", b, pattern, err)
+		}
 	}
 	if flagAddToRoots {
 		if err := r.principal.AddToRoots(b); err != nil {
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index 4a456ab..6687ddd 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -54,7 +54,8 @@
   "${PRINCIPAL_BIN}" --veyron.credentials=./bob store set alice.bless alice/... || shell_test::fail "line ${LINENO}: store set failed"
   "${PRINCIPAL_BIN}" --veyron.credentials=./bob store forpeer alice/server >bob.store.forpeer || shell_test::fail "line ${LINENO}: store forpeer failed" 
 
-  # Run recvblessings on carol, and have alice send blessings over.
+  # Run recvblessings on carol, and have alice send blessings over
+  # (blessings received must be set as default and shareable with all peers.)
   "${PRINCIPAL_BIN}" --veyron.credentials=./carol --veyron.tcp.address=127.0.0.1:0 recvblessings >carol.recvblessings&
   shell::timed_wait_for "${shell_test_DEFAULT_MESSAGE_TIMEOUT}" carol.recvblessings "bless --remote_key" || shell_test::fail "line ${LINENO}: recvblessings did not print command for sender"
   local -r PRINCIPAL_BIN_DIR=$(dirname "${PRINCIPAL_BIN}")
@@ -62,6 +63,14 @@
   SEND_BLESSINGS_CMD="${PRINCIPAL_BIN_DIR}/${SEND_BLESSINGS_CMD}"
   $(${SEND_BLESSINGS_CMD}) || shell_test::fail "line ${LINENO}: ${SEND_BLESSINGS_CMD} failed"
   grep "Received blessings: alice/friend/carol" carol.recvblessings >/dev/null || shell_test::fail "line ${LINENO}: recvblessings did not log any blessings received $(cat carol.recvblessings)"
+  # Run recvblessings on carol, and have alice send blessings over
+  # (blessings received must be set as shareable with peers matching 'alice/...'.)
+  "${PRINCIPAL_BIN}" --veyron.credentials=./carol --veyron.tcp.address=127.0.0.1:0 recvblessings --for_peer=alice/... --set_default=false >carol.recvblessings&
+  shell::timed_wait_for "${shell_test_DEFAULT_MESSAGE_TIMEOUT}" carol.recvblessings "bless --remote_key" || shell_test::fail "line ${LINENO}: recvblessings did not print command for sender"
+  SEND_BLESSINGS_CMD=$(grep "bless --remote_key" carol.recvblessings | sed -e 's|extension[0-9]*|friend/carol/foralice|')
+  SEND_BLESSINGS_CMD="${PRINCIPAL_BIN_DIR}/${SEND_BLESSINGS_CMD}"
+  $(${SEND_BLESSINGS_CMD}) || shell_test::fail "line ${LINENO}: ${SEND_BLESSINGS_CMD} failed"
+  grep "Received blessings: alice/friend/carol/foralice" carol.recvblessings >/dev/null || shell_test::fail "line ${LINENO}: recvblessings did not log any blessings received $(cat carol.recvblessings)"
   # Mucking around with the private key should fail
   "${PRINCIPAL_BIN}" --veyron.credentials=./carol --veyron.tcp.address=127.0.0.1:0 recvblessings >carol.recvblessings&
   shell::timed_wait_for "${shell_test_DEFAULT_MESSAGE_TIMEOUT}" carol.recvblessings "bless --remote_key" || shell_test::fail "line ${LINENO}: recvblessings did not print command for sender"
@@ -146,6 +155,7 @@
 Default blessings: alice/friend/carol
 Peer pattern                   : Blessings
 ...                            : alice/friend/carol
+alice/...                      : alice/friend/carol/foralice
 ---------------- BlessingRoots ----------------
 Public key                                      : Pattern
 XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice/...]