m/n/c/rpc: trace authentication details

This slightly reworks the server interceptors to clearly log
authentication information and resulting PeerInfo, if any.

Change-Id: I2114b0a6958dd79cf9e4c91f07e909650e1f6de6
Reviewed-on: https://review.monogon.dev/c/monogon/+/543
Reviewed-by: Leopold Schabel <leo@nexantic.com>
diff --git a/metropolis/node/core/rpc/peerinfo.go b/metropolis/node/core/rpc/peerinfo.go
index a4d685c..9e9476d 100644
--- a/metropolis/node/core/rpc/peerinfo.go
+++ b/metropolis/node/core/rpc/peerinfo.go
@@ -2,17 +2,32 @@
 
 import (
 	"context"
+	"encoding/hex"
 	"fmt"
+	"sort"
+	"strings"
 
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 
+	"source.monogon.dev/metropolis/node/core/identity"
 	epb "source.monogon.dev/metropolis/proto/ext"
 )
 
 type Permissions map[epb.Permission]bool
 
+func (p Permissions) String() string {
+	var res []string
+
+	for k, _ := range p {
+		res = append(res, k.String())
+	}
+
+	sort.Strings(res)
+	return strings.Join(res, ", ")
+}
+
 // PeerInfo represents the Metropolis-level information about the remote side
 // of a gRPC RPC, ie. about the calling client in server handlers and about the
 // handling server in client code.
@@ -100,6 +115,22 @@
 	return fmt.Errorf("invalid PeerInfo: neither Unauthenticated, User nor Node is set")
 }
 
+func (p *PeerInfo) String() string {
+	if p == nil {
+		return "nil"
+	}
+	switch {
+	case p.Node != nil:
+		return fmt.Sprintf("node: %s, %s", identity.NodeID(p.Node.PublicKey), p.Node.Permissions)
+	case p.User != nil:
+		return fmt.Sprintf("user: %s", p.User.Identity)
+	case p.Unauthenticated != nil:
+		return fmt.Sprintf("unauthenticated: pubkey %s", hex.EncodeToString(p.Unauthenticated.SelfSignedPublicKey))
+	default:
+		return "invalid"
+	}
+}
+
 type peerInfoKeyType string
 
 // peerInfoKey is the context key for storing PeerInfo.