jws: added parsing from http requests
diff --git a/jws/errors.go b/jws/errors.go index 6120bc1..0512a0e 100644 --- a/jws/errors.go +++ b/jws/errors.go
@@ -56,4 +56,7 @@ // ErrNotEnoughValidSignatures means the JWS did not meet the required // number of signatures. ErrNotEnoughValidSignatures = errors.New("not enough valid signatures in the JWS") + + // ErrNoTokenInRequest means there's no token present inside the *http.Request. + ErrNoTokenInRequest = errors.New("no token present in request") )
diff --git a/jws/jws.go b/jws/jws.go index 6673c9c..e84db43 100644 --- a/jws/jws.go +++ b/jws/jws.go
@@ -3,6 +3,8 @@ import ( "bytes" "encoding/json" + "net/http" + "strings" "github.com/SermoDigital/jose" "github.com/SermoDigital/jose/crypto" @@ -302,7 +304,7 @@ return parseCompact(encoded, false) } -func parseCompact(encoded []byte, jwt bool) (*jws, error) { +func parseCompact(encoded []byte, jwt bool, u ...json.Unmarshaler) (*jws, error) { // This section loosely follows // https://tools.ietf.org/html/rfc7519#section-7.2 @@ -329,8 +331,13 @@ return nil, err } + var pl payload + if len(u) > 0 { + pl.u = u[0] + } + j := jws{ - payload: &payload{}, + payload: &pl, plcache: parts[1], sb: []sigHead{s}, isJWT: jwt, @@ -354,6 +361,79 @@ return &j, nil } +var ( + // JWSFormKey is the form "key" which should be used inside + // ParseFromRequest if the request is a multipart.Form. + JWSFormKey = "access_token" + + // MaxMemory is maximum amount of memory which should be used + // inside ParseFromRequest while parsing the multipart.Form + // if the request is a multipart.Form. + MaxMemory int64 = 10e6 +) + +// Format specifies which "format" the JWS is in -- Flat, General, +// or compact. Additionally, constants for JWT/Unknown are added. +type Format uint8 + +const ( + // Unknown format. + Unknown Format = iota + + // Flat format. + Flat + + // General format. + General + + // Compact format. + Compact +) + +var parseJumpTable = [^uint8(0)]func([]byte, ...json.Unmarshaler) (JWS, error){ + Unknown: Parse, + Flat: ParseFlat, + General: ParseGeneral, + Compact: ParseCompact, +} + +func init() { + for i := range parseJumpTable { + if parseJumpTable[i] == nil { + parseJumpTable[i] = Parse + } + } +} + +func fromHeader(req *http.Request) ([]byte, bool) { + if ah := req.Header.Get("Authorization"); ah != "" && len(ah) > 6 && strings.EqualFold(ah[0:6], "BEARER") { + return []byte(ah[:7]), true + } + return nil, false +} + +func fromForm(req *http.Request) ([]byte, bool) { + if err := req.ParseMultipartForm(MaxMemory); err != nil { + return nil, false + } + if tokStr := req.Form.Get(JWSFormKey); tokStr != "" { + return []byte(tokStr), true + } + return nil, false +} + +// ParseFromRequest tries to find the JWS in an http.Request. +// This method will call ParseMultipartForm if there's no token in the header. +func ParseFromRequest(req *http.Request, format Format, u ...json.Unmarshaler) (JWS, error) { + if b, ok := fromHeader(req); ok { + return parseJumpTable[format](b, u...) + } + if b, ok := fromForm(req); ok { + return parseJumpTable[format](b, u...) + } + return nil, ErrNoTokenInRequest +} + // IgnoreDupes should be set to true if the internal duplicate header key check // should ignore duplicate Header keys instead of reporting an error when // duplicate Header keys are found.
diff --git a/jws/jwt.go b/jws/jwt.go index 51090b4..67f18f7 100644 --- a/jws/jwt.go +++ b/jws/jwt.go
@@ -1,6 +1,7 @@ package jws import ( + "net/http" "time" "github.com/SermoDigital/jose/crypto" @@ -33,6 +34,18 @@ return nil } +// ParseJWTFromRequest tries to find the JWT in an http.Request. +// This method will call ParseMultipartForm if there's no token in the header. +func ParseJWTFromRequest(req *http.Request) (jwt.JWT, error) { + if b, ok := fromHeader(req); ok { + return ParseJWT(b) + } + if b, ok := fromForm(req); ok { + return ParseJWT(b) + } + return nil, ErrNoTokenInRequest +} + // ParseJWT parses a serialized jwt.JWT into a physical jwt.JWT. // If its payload isn't a set of claims (or able to be coerced into // a set of claims) it'll return an error stating the