aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorNiall Sheridan <nsheridan@gmail.com>2017-02-19 00:25:42 +0000
committerNiall Sheridan <nsheridan@gmail.com>2017-02-19 00:43:10 +0000
commite8ff7ffe8e8c25195c64950b61c6c5754bbcd3ba (patch)
tree52dd38d68c07991bbbb6b8757b0769f4c5fab20e /cmd
parent19dcff5d7245295d4508a71bb0ed2a886ada7a13 (diff)
Add grpc signer
Diffstat (limited to 'cmd')
-rw-r--r--cmd/cashier/main.go10
-rw-r--r--cmd/cashierd/main.go14
-rw-r--r--cmd/cashierd/rpc.go68
3 files changed, 87 insertions, 5 deletions
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)
+}