naming,security: Server authorization via trusted mounttables
(Part 2 of 2).

Details in commit 4312a8df4ba0cc5e77a9202ff464bd06a84928e4
(https://vanadium-review.googlesource.com/#/c/2971/)

This commit represents steps (c) & (d) in the commit description
referenced above.

Change-Id: Ifa28de3a49c6be5ad07f5ae37e4080f2ff73615e
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index d650d92..5e0815e 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -426,7 +426,6 @@
 // the servers that were successfully connected to and authorized).
 func (c *client) tryCall(ctx *context.T, name, method string, args []interface{}, opts []ipc.CallOpt) (ipc.Call, verror.ActionCode, error) {
 	var resolved *naming.MountEntry
-	var pattern security.BlessingPattern
 	var err error
 	if resolved, err = c.ns.Resolve(ctx, name, getResolveOpts(opts)...); err != nil {
 		vlog.Errorf("Resolve: %v", err)
@@ -438,7 +437,6 @@
 		}
 		return nil, verror.NoRetry, verror.New(verror.ErrNoServers, ctx, name, err)
 	} else {
-		pattern = security.BlessingPattern(resolved.Pattern)
 		if len(resolved.Servers) == 0 {
 			return nil, verror.RetryRefetch, verror.New(verror.ErrNoServers, ctx, name)
 		}
@@ -448,7 +446,7 @@
 		}
 	}
 
-	// servers is now orderd by the priority heurestic implemented in
+	// servers is now ordered by the priority heurestic implemented in
 	// filterAndOrderServers.
 	//
 	// Try to connect to all servers in parallel.  Provide sufficient
@@ -519,7 +517,8 @@
 			if r.flow.LocalPrincipal() != nil {
 				// Validate caveats on the server's identity for the context associated with this call.
 				var err error
-				if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, pattern, opts); err != nil {
+				patterns := resolved.Servers[r.index].BlessingPatterns
+				if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, patterns, opts); err != nil {
 					r.err = verror.New(errNotTrusted, ctx, name, r.flow.RemoteBlessings(), err)
 					vlog.VI(2).Infof("ipc: err: %s", r.err)
 					r.flow.Close()
@@ -642,7 +641,7 @@
 // the RPC name.method for the client (local end of the flow). It returns the blessings at the
 // server that are authorized for this purpose and any blessings that are to be granted to
 // the server (via ipc.Granter implementations in opts.)
-func (c *client) authorizeServer(ctx *context.T, flow stream.Flow, name, method string, serverPattern security.BlessingPattern, opts []ipc.CallOpt) (serverBlessings []string, grantedBlessings security.Blessings, err error) {
+func (c *client) authorizeServer(ctx *context.T, flow stream.Flow, name, method string, serverPatterns []string, opts []ipc.CallOpt) (serverBlessings []string, grantedBlessings security.Blessings, err error) {
 	if flow.RemoteBlessings() == nil {
 		return nil, nil, verror.New(errNoBlessings, ctx)
 	}
@@ -655,16 +654,9 @@
 		RemoteDischarges: flow.RemoteDischarges(),
 		Method:           method,
 		Suffix:           name})
-	serverBlessings, serverErr := flow.RemoteBlessings().ForContext(ctxt)
-	if serverPattern != "" {
-		if !serverPattern.MatchedBy(serverBlessings...) {
-			return nil, nil, verror.New(errAuthNoPatternMatch, ctx, serverBlessings, serverPattern, serverErr)
-		}
-	} else if enableSecureServerAuth {
-		if err := (defaultAuthorizer{}).Authorize(ctxt); err != nil {
-			return nil, nil, verror.New(errDefaultAuthDenied, ctx, serverBlessings)
-		}
-	}
+	var rejectedBlessings []security.RejectedBlessing
+	serverBlessings, rejectedBlessings = flow.RemoteBlessings().ForContext(ctxt)
+	var ignorePatterns bool
 	for _, o := range opts {
 		switch v := o.(type) {
 		case options.ServerPublicKey:
@@ -682,6 +674,8 @@
 			if !allowed {
 				return nil, nil, verror.New(errAuthServerNotAllowed, ctx, v, serverBlessings)
 			}
+		case options.SkipResolveAuthorization:
+			ignorePatterns = true
 		case ipc.Granter:
 			if b, err := v.Grant(flow.RemoteBlessings()); err != nil {
 				return nil, nil, verror.New(errBlessingGrant, ctx, serverBlessings, err)
@@ -690,6 +684,22 @@
 			}
 		}
 	}
+	if len(serverPatterns) > 0 && !ignorePatterns {
+		matched := false
+		for _, p := range serverPatterns {
+			if security.BlessingPattern(p).MatchedBy(serverBlessings...) {
+				matched = true
+				break
+			}
+		}
+		if !matched {
+			return nil, nil, verror.New(errAuthNoPatternMatch, ctx, serverBlessings, serverPatterns, rejectedBlessings)
+		}
+	} else if enableSecureServerAuth && !ignorePatterns {
+		if err := (defaultAuthorizer{}).Authorize(ctxt); err != nil {
+			return nil, nil, verror.New(errDefaultAuthDenied, ctx, serverBlessings)
+		}
+	}
 	return serverBlessings, grantedBlessings, nil
 }