From e8ff7ffe8e8c25195c64950b61c6c5754bbcd3ba Mon Sep 17 00:00:00 2001 From: Niall Sheridan Date: Sun, 19 Feb 2017 00:25:42 +0000 Subject: Add grpc signer --- cmd/cashier/main.go | 10 +++++++- cmd/cashierd/main.go | 14 +++++++---- cmd/cashierd/rpc.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 cmd/cashierd/rpc.go (limited to 'cmd') diff --git a/cmd/cashier/main.go b/cmd/cashier/main.go index 77a0b4b..97747f3 100644 --- a/cmd/cashier/main.go +++ b/cmd/cashier/main.go @@ -12,6 +12,7 @@ import ( "github.com/nsheridan/cashier/client" "github.com/pkg/browser" "github.com/spf13/pflag" + "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" ) @@ -23,10 +24,12 @@ var ( validity = pflag.Duration("validity", time.Hour*24, "Key lifetime. May be overridden by the CA at signing time") keytype = pflag.String("key_type", "", "Type of private key to generate - rsa, ecdsa or ed25519. (default \"rsa\")") publicFilePrefix = pflag.String("public_file_prefix", "", "Prefix for filename for public key and cert (optional, no default)") + useGRPC = pflag.Bool("use_grpc", false, "Use grpc (experimental)") ) func main() { pflag.Parse() + var err error c, err := client.ReadConfig(*cfg) if err != nil { @@ -46,7 +49,12 @@ func main() { var token string fmt.Scanln(&token) - cert, err := client.Sign(pub, token, c) + var cert *ssh.Certificate + if *useGRPC { + cert, err = client.RPCSign(pub, token, c) + } else { + cert, err = client.Sign(pub, token, c) + } if err != nil { log.Fatalln(err) } diff --git a/cmd/cashierd/main.go b/cmd/cashierd/main.go index 8164cf7..d355604 100644 --- a/cmd/cashierd/main.go +++ b/cmd/cashierd/main.go @@ -17,6 +17,7 @@ import ( "strings" "github.com/pkg/errors" + "github.com/soheilhy/cmux" "go4.org/wkfs" "golang.org/x/crypto/acme/autocert" @@ -153,8 +154,7 @@ func signHandler(a *appContext, w http.ResponseWriter, r *http.Request) (int, er token := &oauth2.Token{ AccessToken: t, } - ok := authprovider.Valid(token) - if !ok { + if !authprovider.Valid(token) { return http.StatusUnauthorized, errors.New(http.StatusText(http.StatusUnauthorized)) } @@ -174,7 +174,7 @@ func signHandler(a *appContext, w http.ResponseWriter, r *http.Request) (int, er } if err := json.NewEncoder(w).Encode(&lib.SignResponse{ Status: "ok", - Response: lib.GetPublicKey(cert), + Response: string(lib.GetPublicKey(cert)), }); err != nil { return http.StatusInternalServerError, errors.Wrap(err, "error encoding response") } @@ -425,5 +425,11 @@ func main() { s := &http.Server{ Handler: h, } - log.Fatal(s.Serve(l)) + + cm := cmux.New(l) + httpl := cm.Match(cmux.HTTP1Fast()) + grpcl := cm.Match(cmux.HTTP2HeaderField("content-type", "application/grpc")) + go s.Serve(httpl) + go newGrpcServer(grpcl) + log.Fatal(cm.Serve()) } diff --git a/cmd/cashierd/rpc.go b/cmd/cashierd/rpc.go new file mode 100644 index 0000000..ad8aa5d --- /dev/null +++ b/cmd/cashierd/rpc.go @@ -0,0 +1,68 @@ +package main + +import ( + "log" + "net" + + "golang.org/x/net/context" + + "golang.org/x/oauth2" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + + "github.com/nsheridan/cashier/lib" + "github.com/nsheridan/cashier/proto" +) + +type rpcServer struct{} + +type key int + +const usernameKey key = 0 + +func (s *rpcServer) Sign(ctx context.Context, req *proto.SignRequest) (*proto.SignResponse, error) { + username, ok := ctx.Value(usernameKey).(string) + if !ok { + return nil, grpc.Errorf(codes.InvalidArgument, "Error reading username") + } + cert, err := keysigner.SignUserKeyFromRPC(req, username) + if err != nil { + return nil, grpc.Errorf(codes.InvalidArgument, err.Error()) + } + if err := certstore.SetCert(cert); err != nil { + log.Printf("Error recording cert: %v", err) + } + resp := &proto.SignResponse{ + Cert: lib.GetPublicKey(cert), + } + return resp, nil +} + +func authInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + md, ok := metadata.FromContext(ctx) + if !ok { + return nil, grpc.Errorf(codes.Unauthenticated, "request not authenticated") + } + switch md["security"][0] { + case "authorization": + token := &oauth2.Token{ + AccessToken: md["payload"][0], + } + if !authprovider.Valid(token) { + return nil, grpc.Errorf(codes.PermissionDenied, "access denied") + } + authprovider.Revoke(token) + ctx = context.WithValue(ctx, usernameKey, authprovider.Username(token)) + default: + return nil, grpc.Errorf(codes.InvalidArgument, "unknown argument") + } + return handler(ctx, req) +} + +func newGrpcServer(l net.Listener) { + serv := grpc.NewServer(grpc.UnaryInterceptor(authInterceptor)) + proto.RegisterSignerServer(serv, &rpcServer{}) + serv.Serve(l) +} -- cgit v1.2.3