Skip to content

Commit

Permalink
sign manifest when sending to providers
Browse files Browse the repository at this point in the history
fixes: #206
  • Loading branch information
aastein authored May 31, 2018
1 parent 1ab104d commit 94bce58
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 45 deletions.
4 changes: 2 additions & 2 deletions cmd/akash/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"github.com/ovrclk/akash/cmd/akash/session"
"github.com/ovrclk/akash/cmd/common"
"github.com/ovrclk/akash/keys"
"github.com/ovrclk/akash/manifest"
"github.com/ovrclk/akash/provider"
"github.com/ovrclk/akash/provider/event"
"github.com/ovrclk/akash/provider/manifest/http"
psession "github.com/ovrclk/akash/provider/session"
"github.com/ovrclk/akash/types"
ptype "github.com/ovrclk/akash/types/provider"
Expand Down Expand Up @@ -177,7 +177,7 @@ func doProviderRunCommand(session session.Session, cmd *cobra.Command, args []st

go func() {
defer cancel()
errch <- manifest.RunServer(ctx, session.Log(), "3001", service.ManifestHandler())
errch <- http.RunServer(ctx, session.Log(), "3001", service.ManifestHandler())
}()

var reterr error
Expand Down
24 changes: 20 additions & 4 deletions manifest/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,40 @@ import (
)

func Send(manifest *types.Manifest, signer txutil.Signer, provider *types.Provider, deployment []byte) error {
_, buf, err := SignManifest(manifest, signer, deployment)
if err != nil {
return err
}
return post(provider.GetHostURI(), buf)
}

func SignManifest(manifest *types.Manifest, signer txutil.Signer, deployment []byte) (*types.ManifestRequest, []byte, error) {
mr := &types.ManifestRequest{
Deployment: deployment,
Manifest: manifest,
}

buf, err := marshalRequest(mr)
if err != nil {
return err
return nil, nil, err
}
return post(provider.GetHostURI(), buf)
sig, key, err := signer.SignBytes(buf)
if err != nil {
return nil, nil, err
}
mr.Signature = sig.Bytes()
mr.Key = key.Bytes()
buf, err = marshalRequest(mr)
if err != nil {
return nil, nil, err
}
return mr, buf, nil
}

// XXX assumes url is http/https
func post(url string, data []byte) error {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
req.Header.Set("X-Custom-Header", "Akash")
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
Expand Down
127 changes: 100 additions & 27 deletions manifest/manifest_test.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
package manifest_test
package manifest

import (
"context"
"bytes"
"net/http"
"net/http/httptest"
"testing"

"github.com/ovrclk/akash/manifest"
pmanifest "github.com/ovrclk/akash/provider/manifest"
pmock "github.com/ovrclk/akash/provider/manifest/mocks"
"github.com/ovrclk/akash/sdl"
"github.com/ovrclk/akash/testutil"
"github.com/ovrclk/akash/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
crypto "github.com/tendermint/go-crypto"
)

func TestManifest(t *testing.T) {
func TestSignManifest(t *testing.T) {
sdl, err := sdl.ReadFile("../_docs/deployment.yml")
require.NoError(t, err)

mani, err := sdl.Manifest()
require.NoError(t, err)

_, kmgr := testutil.NewNamedKey(t)
signer := testutil.Signer(t, kmgr)

deployment := testutil.DeploymentAddress(t)

mr, buf, err := SignManifest(mani, signer, deployment)
assert.NoError(t, err)

gotmr, err := unmarshalRequest(bytes.NewReader(buf))
assert.NoError(t, err)

assert.Equal(t, mr.Key, gotmr.Key)
assert.Equal(t, mr.Signature, gotmr.Signature)
assert.Equal(t, mr.Deployment, gotmr.Deployment)

err = VerifyRequestSig(gotmr)
assert.NoError(t, err)
}

func TestVerifySig(t *testing.T) {
sdl, err := sdl.ReadFile("../_docs/deployment.yml")
require.NoError(t, err)

Expand All @@ -27,33 +50,83 @@ func TestManifest(t *testing.T) {
_, kmgr := testutil.NewNamedKey(t)
signer := testutil.Signer(t, kmgr)

provider := &types.Provider{
HostURI: "http://localhost:3001/manifest",
}
deployment := testutil.DeploymentAddress(t)

mr, _, err := SignManifest(mani, signer, deployment)
assert.NoError(t, err)

err = VerifyRequestSig(mr)
assert.NoError(t, err)
}

func TestVerifySig_InvalidSig(t *testing.T) {
sdl, err := sdl.ReadFile("../_docs/deployment.yml")
require.NoError(t, err)

mani, err := sdl.Manifest()
require.NoError(t, err)

_, kmgr := testutil.NewNamedKey(t)
signer := testutil.Signer(t, kmgr)

deployment := testutil.DeploymentAddress(t)

handler := new(pmock.Handler)
handler.On("HandleManifest", mock.Anything).Return(nil).Once()
mr, _, err := SignManifest(mani, signer, deployment)
assert.NoError(t, err)

_, otherKmgr := testutil.NewNamedKey(t)
otherSigner := testutil.Signer(t, otherKmgr)
otherMr, _, err := SignManifest(mani, otherSigner, deployment)
assert.NoError(t, err)

mr.Key = otherMr.Key

withServer(t, func() {
err = manifest.Send(mani, signer, provider, deployment)
require.NoError(t, err)
}, handler)
err = VerifyRequestSig(mr)
assert.Error(t, err)
}

func withServer(t *testing.T, fn func(), h pmanifest.Handler) {
donech := make(chan struct{})
defer func() { <-donech }()
func TestDoPost(t *testing.T) {

sdl, err := sdl.ReadFile("../_docs/deployment.yml")
require.NoError(t, err)

mani, err := sdl.Manifest()
require.NoError(t, err)

_, kmgr := testutil.NewNamedKey(t)
signer := testutil.Signer(t, kmgr)

deployment := testutil.DeploymentAddress(t)

mr, buf, err := SignManifest(mani, signer, deployment)
require.NoError(t, err)

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotmr, err := unmarshalRequest(bytes.NewReader(buf))
assert.NoError(t, err)

assert.Equal(t, mr.Key, gotmr.Key)
assert.Equal(t, mr.Signature, gotmr.Signature)
assert.Equal(t, mr.Deployment, gotmr.Deployment)

pbytes, err := marshalRequest(&types.ManifestRequest{
Deployment: gotmr.Deployment,
Manifest: gotmr.Manifest,
})
assert.NoError(t, err)

key, err := crypto.PubKeyFromBytes(gotmr.Key)
assert.NoError(t, err)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()
sig, err := crypto.SignatureFromBytes(gotmr.Signature)
assert.NoError(t, err)

go func() {
defer close(donech)
err := manifest.RunServer(ctx, testutil.Logger(), "3001", h)
assert.Error(t, http.ErrServerClosed, err)
}()
if !key.VerifyBytes(pbytes, sig) {
t.Error("invalid signature")
}
}))
defer ts.Close()

fn()
err = post(ts.URL, buf)
assert.NoError(t, err)
}
40 changes: 40 additions & 0 deletions manifest/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package manifest

import (
"bytes"
"errors"

"github.com/gogo/protobuf/jsonpb"
"github.com/ovrclk/akash/types"
crypto "github.com/tendermint/go-crypto"
)

var ErrInvalidSignature = errors.New("Invalid signature")

func VerifyRequestSig(mr *types.ManifestRequest) error {
buf := bytes.Buffer{}
marshaler := jsonpb.Marshaler{}
baseReq := &types.ManifestRequest{
Deployment: mr.Deployment,
Manifest: mr.Manifest,
}
if err := marshaler.Marshal(&buf, baseReq); err != nil {
return err
}

key, err := crypto.PubKeyFromBytes(mr.Key)
if err != nil {
return err
}

sig, err := crypto.SignatureFromBytes(mr.Signature)
if err != nil {
return err
}

if !key.VerifyBytes(buf.Bytes(), sig) {
return ErrInvalidSignature
}

return nil
}
Binary file added provider/manifest/debug.test
Binary file not shown.
7 changes: 6 additions & 1 deletion provider/manifest/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"sync"

lifecycle "github.com/boz/go-lifecycle"
manifestUtil "github.com/ovrclk/akash/manifest"
"github.com/ovrclk/akash/provider/event"
"github.com/ovrclk/akash/provider/session"
"github.com/ovrclk/akash/types"
Expand Down Expand Up @@ -144,7 +145,11 @@ loop:
}

case req := <-h.mreqch:
// Manifest received. Look up state, add ManifestRequest, check state for completion.
// Manifest received. Validate signature, look up state, add ManifestRequest, check state for completion.
if err := manifestUtil.VerifyRequestSig(req.value); err != nil {
req.ch <- err
break
}

did := req.value.Deployment
mstate := h.getManifestState(did)
Expand Down
6 changes: 6 additions & 0 deletions provider/manifest/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"
"time"

manifestUtil "github.com/ovrclk/akash/manifest"
"github.com/ovrclk/akash/provider/event"
"github.com/ovrclk/akash/provider/manifest"
"github.com/ovrclk/akash/provider/session"
Expand Down Expand Up @@ -90,6 +91,11 @@ func withHandler(t *testing.T, fn testfn) {
Manifest: mani,
}

_, kmgr := testutil.NewNamedKey(t)
signer := testutil.Signer(t, kmgr)
mreq, _, err = manifestUtil.SignManifest(mani, signer, deployment.Address)
require.NoError(t, err)

fn(h, bus, mreq, lease, dgroup)

timer := time.NewTimer(time.Second)
Expand Down
26 changes: 15 additions & 11 deletions manifest/server.go → provider/manifest/http/server.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package manifest
package http

import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/gogo/protobuf/jsonpb"
"github.com/gorilla/mux"
pmanifest "github.com/ovrclk/akash/provider/manifest"
"github.com/ovrclk/akash/provider/manifest"
"github.com/ovrclk/akash/types"
"github.com/tendermint/tmlibs/log"
)

Expand All @@ -16,7 +18,7 @@ const (
)

type handler struct {
phandler pmanifest.Handler
phandler manifest.Handler
log log.Logger
}

Expand All @@ -38,17 +40,19 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

obj, err := unmarshalRequest(r.Body)
if err != nil {
obj := &types.ManifestRequest{}
if err := jsonpb.Unmarshal(r.Body, obj); err != nil {
h.error(w, http.StatusBadRequest, "Error decoding body")
return
}
r.Body.Close()

h.log.Debug(fmt.Sprintf("%+v", obj))

h.phandler.HandleManifest(obj)

// XXX check if signer is tenant of lease
if err := h.phandler.HandleManifest(obj); err != nil {
h.error(w, http.StatusBadRequest, "Invalid manifest")
return
}

// respond with success
w.WriteHeader(http.StatusOK)
Expand All @@ -62,7 +66,7 @@ func (h *handler) error(w http.ResponseWriter, status int, message string) {
json.NewEncoder(w).Encode(map[string]string{"message": message})
}

func newHandler(log log.Logger, phandler pmanifest.Handler) http.Handler {
func newHandler(log log.Logger, phandler manifest.Handler) http.Handler {
return &handler{
log: log,
phandler: phandler,
Expand All @@ -78,14 +82,14 @@ func requestLogger(log log.Logger) mux.MiddlewareFunc {
}
}

func createHandlers(log log.Logger, handler pmanifest.Handler) http.Handler {
func createHandlers(log log.Logger, handler manifest.Handler) http.Handler {
r := mux.NewRouter()
r.Handle("/manifest", newHandler(log, handler))
r.Use(requestLogger(log))
return r
}

func RunServer(ctx context.Context, log log.Logger, port string, handler pmanifest.Handler) error {
func RunServer(ctx context.Context, log log.Logger, port string, handler manifest.Handler) error {

address := fmt.Sprintf(":%v", port)

Expand Down
Loading

0 comments on commit 94bce58

Please sign in to comment.