Merge ""veyron/tools/principal": Fork Command"
diff --git a/security/principal.go b/security/principal.go
index 4ebf6e6..304c4d1 100644
--- a/security/principal.go
+++ b/security/principal.go
@@ -114,23 +114,31 @@
 	return NewPrincipalFromSigner(security.NewInMemoryECDSASigner(key), state)
 }
 
+// SetDefaultBlessings sets the provided blessings as default and shareable with
+// all peers on provided principal's BlessingStore, and also adds it as a root to
+// the principal's BlessingRoots.
+func SetDefaultBlessings(p security.Principal, blessings security.Blessings) error {
+	if err := p.BlessingStore().SetDefault(blessings); err != nil {
+		return err
+	}
+	if _, err := p.BlessingStore().Set(blessings, security.AllPrincipals); err != nil {
+		return err
+	}
+	if err := p.AddToRoots(blessings); err != nil {
+		return err
+	}
+	return nil
+}
+
 // InitDefaultBlessings uses the provided principal to create a self blessing for name 'name',
 // sets it as default on the principal's BlessingStore and adds it as root to the principal's BlessingRoots.
+// TODO(ataly): Get rid this function given that we have SetDefaultBlessings.
 func InitDefaultBlessings(p security.Principal, name string) error {
 	blessing, err := p.BlessSelf(name)
 	if err != nil {
 		return err
 	}
-	if err := p.BlessingStore().SetDefault(blessing); err != nil {
-		return err
-	}
-	if _, err := p.BlessingStore().Set(blessing, security.AllPrincipals); err != nil {
-		return err
-	}
-	if err := p.AddToRoots(blessing); err != nil {
-		return err
-	}
-	return nil
+	return SetDefaultBlessings(p, blessing)
 }
 
 func mkDir(dir string) error {
diff --git a/tools/principal/main.go b/tools/principal/main.go
index dfbfd1a..62b4f61 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -39,11 +39,9 @@
 	flagSeekBlessingsSetDefault bool
 	flagSeekBlessingsForPeer    string
 
-	// Flag for the create command
-	flagCreateOverwrite bool
-
 	// Flags common to many commands
-	flagAddToRoots bool
+	flagAddToRoots      bool
+	flagCreateOverwrite bool
 
 	// Flags for the "recvblessings" command
 	flagRecvBlessingsSetDefault bool
@@ -172,7 +170,7 @@
 		Long: `
 Bless another principal.
 
-The blesser is obtained from the runtime this tool is using.  The blessing that
+The blesser is obtained from the runtime this tool is using. The blessing that
 will be extended is the default one from the blesser's store, or specified by
 the --with flag. Caveats on the blessing are controlled via the --for flag.
 
@@ -456,16 +454,16 @@
 		Short: "Create a new principal and persist it into a directory",
 		Long: `
 Creates a new principal with a single self-blessed blessing and writes it out
-to the provided directory. The same directory can be used to set the VEYRON_CREDENTIALS
-environment variables for other veyron applications.
+to the provided directory. The same directory can then be used to set the
+VEYRON_CREDENTIALS environment variable for other veyron applications.
 
 The operation fails if the directory already contains a principal. In this case
-the --overwrite flag can be provided to clear the directory and write out a
+the --overwrite flag can be provided to clear the directory and write out the
 new principal.
 `,
 		ArgsName: "<directory> <blessing>",
 		ArgsLong: `
-	<directory> is the directory to which the principal will be persisted.
+	<directory> is the directory to which the new principal will be persisted.
 	<blessing> is the self-blessed blessing that the principal will be setup to use by default.
 	`,
 		Run: func(cmd *cmdline.Command, args []string) error {
@@ -474,18 +472,12 @@
 			}
 			dir, name := args[0], args[1]
 			// TODO(suharshs,ashankar,ataly): How should we make an ecrypted pk... or is that up to the agent?
-			var (
-				p   security.Principal
-				err error
-			)
 			if flagCreateOverwrite {
-				if err = os.RemoveAll(dir); err != nil {
+				if err := os.RemoveAll(dir); err != nil {
 					return err
 				}
-				p, err = vsecurity.CreatePersistentPrincipal(dir, nil)
-			} else {
-				p, err = vsecurity.CreatePersistentPrincipal(dir, nil)
 			}
+			p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
 			if err != nil {
 				return err
 			}
@@ -493,14 +485,81 @@
 			if err != nil {
 				return fmt.Errorf("BlessSelf(%q) failed: %v", name, err)
 			}
-			if err := p.BlessingStore().SetDefault(blessings); err != nil {
-				return fmt.Errorf("BlessingStore.SetDefault(%v) failed: %v", blessings, err)
+			if err := vsecurity.SetDefaultBlessings(p, blessings); err != nil {
+				return fmt.Errorf("could not set blessings %v as default: %v", blessings, err)
 			}
-			if _, err := p.BlessingStore().Set(blessings, security.AllPrincipals); err != nil {
-				return fmt.Errorf("BlessingStore.Set(%v, %q) failed: %v", blessings, security.AllPrincipals, err)
+			return nil
+		},
+	}
+
+	cmdFork = &cmdline.Command{
+		Name:  "fork",
+		Short: "Fork a new principal from the principal that this tool is running as and persist it into a directory",
+		Long: `
+Creates a new principal with a blessing from the principal specified by the
+environment that this tool is running in, and writes it out to the provided
+directory. The blessing that will be extended is the default one from the
+blesser's store, or specified by the --with flag. Caveats on the blessing
+are controlled via the --for flag. The blessing is marked as default and
+shareable with all peers on the new principal's blessing store.
+
+The operation fails if the directory already contains a principal. In this case
+the --overwrite flag can be provided to clear the directory and write out the
+forked principal.
+`,
+		ArgsName: "<directory> <extension>",
+		ArgsLong: `
+	<directory> is the directory to which the forked principal will be persisted.
+	<extension> is the extension under which the forked principal is blessed.
+	`,
+		Run: func(cmd *cmdline.Command, args []string) error {
+			if len(args) != 2 {
+				return fmt.Errorf("requires exactly two arguments: <directory> and <extension>, provided %d", len(args))
 			}
-			if err := p.AddToRoots(blessings); err != nil {
-				return fmt.Errorf("AddToRoots(%v) failed: %v", blessings, err)
+			dir, extension := args[0], args[1]
+
+			if flagCreateOverwrite {
+				if err := os.RemoveAll(dir); err != nil {
+					return err
+				}
+			}
+			p, err := vsecurity.CreatePersistentPrincipal(dir, nil)
+			if err != nil {
+				return err
+			}
+
+			runtime, err := rt.New()
+			if err != nil {
+				return err
+			}
+			defer runtime.Cleanup()
+
+			var (
+				with    security.Blessings
+				caveats []security.Caveat
+			)
+			if len(flagBlessWith) > 0 {
+				if with, err = decodeBlessings(flagBlessWith); err != nil {
+					return fmt.Errorf("failed to read blessings from --with=%q: %v", flagBlessWith, err)
+				}
+			} else {
+				with = runtime.Principal().BlessingStore().Default()
+			}
+			if c, err := security.ExpiryCaveat(time.Now().Add(flagBlessFor)); err != nil {
+				return fmt.Errorf("failed to create ExpiryCaveat: %v", err)
+			} else {
+				caveats = append(caveats, c)
+			}
+			// TODO(ashankar,ataly,suharshs): Work out how to add additional caveats, like maybe
+			// revocation, method etc.
+
+			key := p.PublicKey()
+			blessings, err := runtime.Principal().Bless(key, with, extension, caveats[0], caveats[1:]...)
+			if err != nil {
+				return fmt.Errorf("Bless(%v, %v, %q, ...) failed: %v", key, with, extension, err)
+			}
+			if err := vsecurity.SetDefaultBlessings(p, blessings); err != nil {
+				return fmt.Errorf("could not set blessings %v as default: %v", blessings, err)
 			}
 			return nil
 		},
@@ -671,6 +730,9 @@
 	cmdStoreSetDefault.Flags.BoolVar(&flagAddToRoots, "add_to_roots", true, "If true, the root certificate of the blessing will be added to the principal's set of recognized root certificates")
 
 	cmdCreate.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
+	cmdFork.Flags.BoolVar(&flagCreateOverwrite, "overwrite", false, "If true, any existing principal data in the directory will be overwritten")
+	cmdFork.Flags.DurationVar(&flagBlessFor, "for", time.Minute, "Duration of blessing validity")
+	cmdFork.Flags.StringVar(&flagBlessWith, "with", "", "Path to file containing blessing to extend")
 
 	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")
@@ -695,7 +757,7 @@
 
 All objects are printed using base64-VOM-encoding.
 `,
-		Children: []*cmdline.Command{cmdCreate, cmdSeekBlessings, cmdRecvBlessings, cmdDump, cmdDumpBlessings, cmdBlessSelf, cmdBless, cmdStore},
+		Children: []*cmdline.Command{cmdCreate, cmdFork, cmdSeekBlessings, cmdRecvBlessings, cmdDump, cmdDumpBlessings, cmdBlessSelf, cmdBless, cmdStore},
 	}).Main()
 }
 
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index 9761be0..b6404df 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -84,11 +84,21 @@
   SEND_BLESSINGS_CMD="${PRINCIPAL_BIN_DIR}/${SEND_BLESSINGS_CMD}"
   $(${SEND_BLESSINGS_CMD} 2>error) && shell_test::fail "line ${LINENO}: ${SEND_BLESSINGS_CMD} should have failed"
   grep "blessings received from unexpected sender" error >/dev/null || shell_test::fail "line ${LINENO}: unexpected sender error not printed"
+  kill -9 "${RECV_BLESSINGS_PID}"
   # Dump carol out, the only blessing that survives should be from the first
   # "bless" command. (alice/friend/carol).
-  kill -9 "${RECV_BLESSINGS_PID}"
   "${PRINCIPAL_BIN}" --veyron.credentials=./carol dump >carol.dump || shell_test::fail "line ${LINENO}: dump failed"
 
+  # Run fork to setup up credentials for alice-phone that are blessed by alice under the extension "phone".
+  "${PRINCIPAL_BIN}" --veyron.credentials=./alice fork ./alice-phone "phone" >/dev/null || shell_test::fail "line ${LINENO}: fork failed"
+  # Dump alice-phone out, the only blessings it has must be from alice (alice/phone).
+  "${PRINCIPAL_BIN}" --veyron.credentials=./alice-phone dump >alice-phone.dump || shell_test::fail "line ${LINENO}: dump failed"
+
+  # Run fork to setup up credentials for alice-phone-calendar that are blessed by alice-phone under the extension "calendar".
+  "${PRINCIPAL_BIN}" --veyron.credentials=./alice-phone fork ./alice-phone-calendar "calendar" >/dev/null || shell_test::fail "line ${LINENO}: fork failed"
+  # Dump alice-phone-calendar out, the only blessings it has must be from alice-phone (alice/phone/calendar).
+  "${PRINCIPAL_BIN}" --veyron.credentials=./alice-phone-calendar dump >alice-phone-calendar.dump || shell_test::fail "line ${LINENO}: dump failed"
+
   # Any other commands to be run without VEYRON_CREDENTIALS set.
   unset VEYRON_CREDENTIALS
 
@@ -166,6 +176,36 @@
   if ! diff -C 5 got want; then
     shell_test::fail "line ${LINENO}"
   fi
+
+  cat alice-phone.dump | rmpublickey >got || shell_test::fail "line ${LINENO}: cat alice-phone.dump | rmpublickey failed"
+  cat >want <<EOF
+Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice/phone
+Peer pattern                   : Blessings
+...                            : alice/phone
+---------------- BlessingRoots ----------------
+Public key                                      : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice/...]
+EOF
+  if ! diff -C 5 got want; then
+    shell_test::fail "line ${LINENO}"
+  fi
+
+  cat alice-phone-calendar.dump | rmpublickey >got || shell_test::fail "line ${LINENO}: cat alice-phone-calendar.dump | rmpublickey failed"
+  cat >want <<EOF
+Public key : XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
+---------------- BlessingStore ----------------
+Default blessings: alice/phone/calendar
+Peer pattern                   : Blessings
+...                            : alice/phone/calendar
+---------------- BlessingRoots ----------------
+Public key                                      : Pattern
+XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX : [alice/...]
+EOF
+  if ! diff -C 5 got want; then
+    shell_test::fail "line ${LINENO}"
+  fi
   shell_test::pass
 }