Documentation ¶
Overview ¶
Package signature provides validation of signed HTTP requests from Manifold.
signature includes middleware that conforms to the http.Handler interface, wrapping another http.Handler. If the request is invalid, the middleware will respond directly, instead of calling your handler.
Using the included middleware:
verifier := signature.NewVerifier(signature.ManifoldKey) http.Handle("/v1", verifier.WrapFunc(func (rw http.ResponseWriter, r *http.Request) { // your code goes here. }))
Verifying a request manually:
body, err := ioutil.ReadAll(req.Body) buf := bytes.NewBuffer(body) verifiier := signature.NewVerifier(signature.ManifoldKey) if err := verifiier.Verify(req, buf); err != nil { // return an error... } // continue using the request and body
Manual verification may be useful if you are not using a standard net/http setup.
Index ¶
Examples ¶
Constants ¶
const ManifoldKey = "PtISNzqQmQPBxNlUw3CdxsWczXbIwyExxlkRqZ7E690"
ManifoldKey is Manifold's public master signing key, base64 encoded.
const PermittedTimeSkew = 5 * time.Minute
PermittedTimeSkew is the time skew allowed on requests, on either side.
Variables ¶
var ErrInvalidPublicKey = errors.New("The provided base64 public key is not valid")
ErrInvalidPublicKey is returned from NewVerifier when the provided public key is not valid
Functions ¶
func Canonize ¶
Canonize builds the canonical representation of the given request, for use in verifying the Manifold request signature applied to it. The request body is not read directly, instead, body is read, allowing buffering or duplication of the body to be handled outside of this func.
Example ¶
body := bytes.NewBufferString("Test body data") req, _ := http.NewRequest("PUT", "/v1/resources?foo=bar", body) req.Header.Set("X-Signed-Headers", "date") req.Header.Set("Date", "2017-03-05T23:53:08Z") b, _ := Canonize(req, body) fmt.Println() fmt.Println(string(b))
Output: put /v1/resources?foo=bar date: 2017-03-05T23:53:08Z x-signed-headers: date Test body data
Types ¶
type Error ¶
Error represents an unsuccessful HTTP error response.
func (*Error) Respond ¶
func (e *Error) Respond(rw http.ResponseWriter)
Respond writes the Error to the provided ResponseWriter as JSON, in the format expected by Manifold for errors.
type Middleware ¶
type Middleware func(http.ResponseWriter, *http.Request, http.HandlerFunc)
Middleware implements the Negroni middleware interface for funcs
func (Middleware) ServeHTTP ¶
func (m Middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
type Signature ¶
type Signature struct { Value *base64.Value PublicKey *base64.Value Endorsement *base64.Value }
Signature represents a Signature of an HTTP request
func ParseSignature ¶
ParseSignature parses the given string and returns a Signature struct
type Verifier ¶
type Verifier struct {
// contains filtered or unexported fields
}
Verifier verifies that HTTP requests are signed by Manifold
func NewVerifier ¶
NewVerifier returns a new Verifier, configured with the provided raw base64 URL encoded public key.
It returns an error if the given public key is not a valid base64 URL encoded value, or if it is not a valid Ed25519 public key.
func (*Verifier) Negroni ¶
func (v *Verifier) Negroni() Middleware
Negroni returns a Negroni compatible middleware for verifying requests. This middleware behaves like Wrap; it will not pass through to the next Handler in the chain if the request does not have a valid signature.
func (*Verifier) Verify ¶
Verify verifies that the given request is signed by Manifold. It returns an error if the signature is invalid. The request body is not read directly, instead, body is read, allowing buffering or duplication of the body to be handled outside of this method.
Example ¶
body := bytes.NewBufferString("{\"id\":\"2686c96868emyj61cgt2ma7vdntg4\",\"plan\":\"low\",\"product\":\"generators\",\"region\":\"aws::us-east-1\",\"user_id\":\"200e7aeg2kf2d6nud8jran3zxnz5j\"}\n") req, _ := http.NewRequest("PUT", "https://127.0.0.1:4567/v1/resources/2686c96868emyj61cgt2ma7vdntg4", body) req.Host = "127.0.0.1:4567" req.Header.Set("Date", "2017-03-05T23:53:08Z") req.Header.Set("Content-Length", "143") req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Signed-Headers", "host date content-type content-length") req.Header.Set("X-Signature", "Nb9iJZVDFrcf8-dw7AsuSCPtdoxoAr61YVWQe-5b9z_YiuQW73wR7RRsDBPnrBMtXIg_h8yKWsr-ZNRgYbM7CA FzNbTkRjAGjkpwHUbAhjvLsIlAlL_M6EUh5E9OVEwXs qGR6iozBfLUCHbRywz1mHDdGYeqZ0JEcseV4KcwjEVeZtQN54odcJ1_QyZkmHacbQeHEai2-Aw9EF8-Ceh09Cg") // For production usage, use verifier.ManifoldKey dummyKey := "PY7wu3q3-adYr9-0ES6CMRixup9OjO5iL7EFDFpolhk" verifier, _ := NewVerifier(dummyKey) err := verifier.Verify(req, body) if err != nil { fmt.Println("Signature is not valid:", err) } else { fmt.Println("Signature is ok!") }
Output: Signature is ok!