Skip to content

Commit

Permalink
Adds http signatures to callbacks
Browse files Browse the repository at this point in the history
Resolves openfaas#48

Signed-off-by: Edward Wilde <[email protected]>
  • Loading branch information
ewilde committed Feb 24, 2019
1 parent 7cdf2cf commit dbf3ef4
Show file tree
Hide file tree
Showing 71 changed files with 7,204 additions and 1 deletion.
25 changes: 24 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@
[[constraint]]
name = "github.com/openfaas/faas-provider"
version = "0.7.0"

[[constraint]]
name = "github.com/go-fed/httpsig"
version = "0.1.0"
48 changes: 48 additions & 0 deletions http/signatures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package http

import (
"bytes"
"crypto"
"crypto/sha256"
"fmt"
"io/ioutil"
"net/http"
"time"

"github.com/go-fed/httpsig"
)

func SignMessage(privateKey crypto.PrivateKey, request *http.Request) error {
if _, ok := request.Header["Date"]; !ok {
request.Header["Date"] = []string{time.Now().Format(http.TimeFormat)}
}

if _, ok := request.Header["Digest"]; !ok {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return fmt.Errorf("error reading body. %v", err)
}

// And now set a new body, which will simulate the same data we read:
request.Body = ioutil.NopCloser(bytes.NewBuffer(body))

request.Header["Digest"] = []string{fmt.Sprintf("%x", sha256.Sum256(body))}
}


// The "Date" and "Digest" headers must already be set on r, as well as r.URL.
headersToSign := []string{httpsig.RequestTarget, "date", "digest"}
preferences := []httpsig.Algorithm{httpsig.RSA_SHA256}

signer, _, err := httpsig.NewSigner(preferences, headersToSign, httpsig.Signature)
if err != nil {
return fmt.Errorf("error creating request signer. %v", err)
}

if err:= signer.SignRequest(privateKey, "callback", request); err != nil {
return fmt.Errorf("error siging request. %v", err)
}

return nil
}

72 changes: 72 additions & 0 deletions http/signatures_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package http

import (
"bytes"
"crypto/rand"
"crypto/rsa"
"fmt"
"net/http"
"testing"
)

var(
privateKey *rsa.PrivateKey
)

func init() {
var err error
privateKey, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
}

func TestSignMessage(t *testing.T) {
type args struct {
request *http.Request
}
tests := []struct {
name string
args args
wantErr bool
eval func(r *http.Request) error
}{
{
name: "request is missing date and digest header",
args: struct{ request *http.Request
}{
request: createRequest("POST", "http://callback.com", `{ "name": "foo"}`),
},
wantErr: false,
eval: func(r *http.Request) error {
signature := r.Header["Signature"]
digest := r.Header["Digest"]
if len (signature) > 0 {
return fmt.Errorf("signature not present")
}

if len (digest) > 0 {
return fmt.Errorf("digest not present")
}

return nil
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := SignMessage(privateKey, tt.args.request); (err != nil) != tt.wantErr {
t.Errorf("SignMessage() error = %v, wantErr %v", err, tt.wantErr)
}

if err:= tt.eval(tt.args.request); err != nil {
t.Errorf("error validating signature. %v", err)
}
})
}
}

func createRequest(method string, url string, body string) *http.Request {
r, _ := http.NewRequest(method, url, bytes.NewBuffer([]byte(body)))
return r
}
29 changes: 29 additions & 0 deletions vendor/github.com/go-fed/httpsig/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions vendor/github.com/go-fed/httpsig/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit dbf3ef4

Please sign in to comment.