Add interceptor on the server to authenticate client
authorJulien Andrieux <julien@pantomath.io>
Fri, 6 Oct 2017 13:39:27 +0000 (15:39 +0200)
committerJulien Andrieux <julien@pantomath.io>
Fri, 6 Oct 2017 13:39:27 +0000 (15:39 +0200)
server/main.go

index 7b3a3e1..817f4db 100644 (file)
@@ -4,12 +4,59 @@ import (
        "fmt"
        "log"
        "net"
+       "strings"
+
+       "golang.org/x/net/context"
 
        "gitlab.com/pantomath-io/demo-grpc/api"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
+       "google.golang.org/grpc/metadata"
 )
 
+// private type for Context keys
+type contextKey int
+
+const (
+       clientIDKey contextKey = iota
+)
+
+// authenticateAgent check the client credentials
+func authenticateClient(ctx context.Context, s *api.Server) (string, error) {
+       if md, ok := metadata.FromIncomingContext(ctx); ok {
+               clientLogin := strings.Join(md["login"], "")
+               clientPassword := strings.Join(md["password"], "")
+
+               if clientLogin != "john" {
+                       return "", fmt.Errorf("unknown user %s", clientLogin)
+               }
+               if clientPassword != "doe" {
+                       return "", fmt.Errorf("bad password %s", clientPassword)
+               }
+
+               log.Printf("authenticated client: %s", clientLogin)
+
+               return "42", nil
+       }
+       return "", fmt.Errorf("missing credentials")
+}
+
+// unaryInterceptor call authenticateClient with current context
+func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
+       s, ok := info.Server.(*api.Server)
+       if !ok {
+               return nil, fmt.Errorf("unable to cast server")
+       }
+       clientID, err := authenticateClient(ctx, s)
+       if err != nil {
+               return nil, err
+       }
+
+       ctx = context.WithValue(ctx, clientIDKey, clientID)
+
+       return handler(ctx, req)
+}
+
 // main start a gRPC server and waits for connection
 func main() {
        // create a listener on TCP port 7777
@@ -28,7 +75,8 @@ func main() {
        }
 
        // Create an array of gRPC options with the credentials
-       opts := []grpc.ServerOption{grpc.Creds(creds)}
+       opts := []grpc.ServerOption{grpc.Creds(creds),
+               grpc.UnaryInterceptor(unaryInterceptor)}
 
        // create a gRPC server object
        grpcServer := grpc.NewServer(opts...)