update dependencies

This commit is contained in:
dhax 2017-10-21 18:30:08 +02:00
parent fce1b99683
commit 397e9c0842
164 changed files with 5207 additions and 2213 deletions

View file

@ -1,5 +1,11 @@
# Changelog
## v3.3.0 (2017-10-10)
- New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage
- Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function
## v3.2.1 (2017-08-31)
- Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface

View file

@ -1,4 +1,4 @@
Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka)
Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.
MIT License

View file

@ -337,16 +337,19 @@ with `net/http` can be used with chi's mux.
| WithValue | Short-hand middleware to set a key/value on the request context |
-----------------------------------------------------------------------------------------------------------
### Auxiliary middlewares
### Auxiliary middlewares & packages
-----------------------------------------------------------------------------------------------------------
| package | description |
|:-------------------------------------------------|:------------------------------------------------------
| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) |
| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication |
| [httpcoala](https://github.com/go-chi/httpcoala) | HTTP request coalescer |
| [chi-authz](https://github.com/casbin/chi-authz) | Request ACL via https://github.com/hsluoyz/casbin |
-----------------------------------------------------------------------------------------------------------
Please see https://github.com/go-chi for additional packages.
-------------------------------------------------------------------------------------------------------------
| package | description |
|:---------------------------------------------------|:------------------------------------------------------
| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) |
| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication |
| [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing |
| [httpcoala](https://github.com/go-chi/httpcoala) | HTTP request coalescer |
| [chi-authz](https://github.com/casbin/chi-authz) | Request ACL via https://github.com/hsluoyz/casbin |
-------------------------------------------------------------------------------------------------------------
please [submit a PR](./CONTRIBUTING.md) if you'd like to include a link to a chi-compatible middleware

View file

@ -0,0 +1,33 @@
package main
import (
"net/http"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
)
func init() {
chi.RegisterMethod("LINK")
chi.RegisterMethod("UNLINK")
chi.RegisterMethod("WOOHOO")
}
func main() {
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.Logger)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
})
r.MethodFunc("LINK", "/link", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("custom link method"))
})
r.MethodFunc("WOOHOO", "/woo", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("custom woohoo method"))
})
r.HandleFunc("/everything", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("capturing all standard http methods, as well as LINK, UNLINK and WOOHOO"))
})
http.ListenAndServe(":3333", r)
}

View file

@ -1,4 +1,4 @@
// +build go1.8
// +build go1.8 appengine
package middleware

View file

@ -1,4 +1,4 @@
// +build go1.8
// +build go1.8 appengine
package middleware

View file

@ -1,4 +1,4 @@
// +build go1.8
// +build go1.8 appengine
package middleware

42
vendor/github.com/go-chi/chi/tree.go generated vendored
View file

@ -6,44 +6,59 @@ package chi
import (
"fmt"
"math"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
)
type methodTyp int
const (
mCONNECT methodTyp = 1 << iota
mSTUB methodTyp = 1 << iota
mCONNECT
mDELETE
mGET
mHEAD
mLINK
mOPTIONS
mPATCH
mPOST
mPUT
mTRACE
mUNLINK
mSTUB
mALL methodTyp = mCONNECT | mDELETE | mGET | mHEAD | mLINK |
mOPTIONS | mPATCH | mPOST | mPUT | mTRACE | mUNLINK
)
var mALL methodTyp = mCONNECT | mDELETE | mGET | mHEAD |
mOPTIONS | mPATCH | mPOST | mPUT | mTRACE
var methodMap = map[string]methodTyp{
"CONNECT": mCONNECT,
"DELETE": mDELETE,
"GET": mGET,
"HEAD": mHEAD,
"LINK": mLINK,
"OPTIONS": mOPTIONS,
"PATCH": mPATCH,
"POST": mPOST,
"PUT": mPUT,
"TRACE": mTRACE,
"UNLINK": mUNLINK,
}
func RegisterMethod(method string) {
if method == "" {
return
}
method = strings.ToUpper(method)
if _, ok := methodMap[method]; ok {
return
}
n := len(methodMap)
if n > strconv.IntSize {
panic(fmt.Sprintf("chi: max number of methods reached (%d)", strconv.IntSize))
}
mt := methodTyp(math.Exp2(float64(n)))
methodMap[method] = mt
mALL |= mt
}
type nodeTyp uint8
@ -676,6 +691,15 @@ func patNextSegment(pattern string) (nodeTyp, string, string, byte, int, int) {
key = key[:idx]
}
if len(rexpat) > 0 {
if rexpat[0] != '^' {
rexpat = "^" + rexpat
}
if rexpat[len(rexpat)-1] != '$' {
rexpat = rexpat + "$"
}
}
return nt, key, rexpat, tail, ps, pe
}

View file

@ -333,6 +333,31 @@ func TestTreeRegexp(t *testing.T) {
}
}
func TestTreeRegexMatchWholeParam(t *testing.T) {
hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
rctx := NewRouteContext()
tr := &node{}
tr.InsertRoute(mGET, "/{id:[0-9]+}", hStub1)
tests := []struct {
url string
expectedHandler http.Handler
}{
{url: "/13", expectedHandler: hStub1},
{url: "/a13", expectedHandler: nil},
{url: "/13.jpg", expectedHandler: nil},
{url: "/a13.jpg", expectedHandler: nil},
}
for _, tc := range tests {
_, _, handler := tr.FindRoute(rctx, mGET, tc.url)
if fmt.Sprintf("%v", tc.expectedHandler) != fmt.Sprintf("%v", handler) {
t.Errorf("expecting handler:%v , got:%v", tc.expectedHandler, handler)
}
}
}
func TestTreeFindPattern(t *testing.T) {
hStub1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
hStub2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})

View file

@ -1,2 +1,3 @@
vendor/
Gopkg.lock
.idea/

View file

@ -1,6 +1,6 @@
[[constraint]]
name = "github.com/dgrijalva/jwt-go"
version = "^3.0.0"
version = "^3.1.0"
[[constraint]]
name = "github.com/go-chi/chi"
version = "^3.0.0"

View file

@ -1,5 +1,6 @@
jwtauth - JWT authentication middleware for Go HTTP services
============================================================
[![GoDoc Widget]][GoDoc]
The `jwtauth` http middleware package provides a simple way to verify a JWT token
from a http request and send the result down the request context (`context.Context`).
@ -22,12 +23,11 @@ plain-text payload for all unverified tokens and passes the good ones through. Y
also copy the Authenticator and customize it to handle invalid tokens to better fit
your flow (ie. with a JSON error response body).
The `Verifier` will search for a JWT token in a http request, in the order:
By default, the `Verifier` will search for a JWT token in a http request, in the order:
1. 'jwt' URI query parameter
2. 'Authorization: BEARER T' request header
3. Cookie 'jwt' value
4. (optional), use `jwtauth.Verify("state")` for additional query/cookie parameter aliases
3. 'jwt' Cookie value
The first JWT string that is found as a query parameter, authorization header
or cookie header is then decoded by the `jwt-go` library and a *jwt.Token
@ -39,6 +39,11 @@ be the generic `jwtauth.Authenticator` middleware or your own custom handler
which checks the request context jwt token and error to prepare a custom
http response.
Note: jwtauth supports custom verification sequences for finding a token
from a request by using the `Verify` middleware instantiator directly. The default
`Verifier` is instantiated by calling `Verify(ja, TokenFromQuery, TokenFromHeader, TokenFromCookie)`.
# Usage
See the full [example](https://github.com/go-chi/jwtauth/blob/master/_example/main.go).
@ -105,3 +110,6 @@ func router() http.Handler {
# LICENSE
[MIT](/LICENSE)
[GoDoc]: https://godoc.org/github.com/go-chi/jwtauth
[GoDoc Widget]: https://godoc.org/github.com/go-chi/jwtauth?status.svg

View file

@ -21,16 +21,44 @@ var (
ErrExpired = errors.New("jwtauth: token is expired")
)
var (
// TokenFromCookie tries to retreive the token string from a cookie named
// "jwt".
TokenFromCookie = func(r *http.Request) string {
cookie, err := r.Cookie("jwt")
if err != nil {
return ""
}
return cookie.Value
}
// TokenFromHeader tries to retreive the token string from the
// "Authorization" reqeust header: "Authorization: BEARER T".
TokenFromHeader = func(r *http.Request) string {
// Get token from authorization header.
bearer := r.Header.Get("Authorization")
if len(bearer) > 7 && strings.ToUpper(bearer[0:6]) == "BEARER" {
return bearer[7:]
}
return ""
}
// TokenFromQuery tries to retreive the token string from the "jwt" URI
// query parameter.
TokenFromQuery = func(r *http.Request) string {
// Get token from query param named "jwt".
return r.URL.Query().Get("jwt")
}
)
type JwtAuth struct {
signKey []byte
verifyKey []byte
signKey interface{}
verifyKey interface{}
signer jwt.SigningMethod
parser *jwt.Parser
}
// New creates a JwtAuth authenticator instance that provides middleware handlers
// and encoding/decoding functions for JWT signing.
func New(alg string, signKey []byte, verifyKey []byte) *JwtAuth {
func New(alg string, signKey interface{}, verifyKey interface{}) *JwtAuth {
return NewWithParser(alg, &jwt.Parser{}, signKey, verifyKey)
}
@ -40,7 +68,7 @@ func New(alg string, signKey []byte, verifyKey []byte) *JwtAuth {
// We explicitly toggle `SkipClaimsValidation` in the `jwt-go` parser so that
// we can control when the claims are validated - in our case, by the Verifier
// http middleware handler.
func NewWithParser(alg string, parser *jwt.Parser, signKey []byte, verifyKey []byte) *JwtAuth {
func NewWithParser(alg string, parser *jwt.Parser, signKey interface{}, verifyKey interface{}) *JwtAuth {
parser.SkipClaimsValidation = true
return &JwtAuth{
signKey: signKey,
@ -68,15 +96,15 @@ func NewWithParser(alg string, parser *jwt.Parser, signKey []byte, verifyKey []b
// http response.
func Verifier(ja *JwtAuth) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return Verify(ja, "")(next)
return Verify(ja, TokenFromQuery, TokenFromHeader, TokenFromCookie)(next)
}
}
func Verify(ja *JwtAuth, paramAliases ...string) func(http.Handler) http.Handler {
func Verify(ja *JwtAuth, findTokenFns ...func(r *http.Request) string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
hfn := func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
token, err := VerifyRequest(ja, r, paramAliases...)
token, err := VerifyRequest(ja, r, findTokenFns...)
ctx = NewContext(ctx, token, err)
next.ServeHTTP(w, r.WithContext(ctx))
}
@ -84,37 +112,17 @@ func Verify(ja *JwtAuth, paramAliases ...string) func(http.Handler) http.Handler
}
}
func VerifyRequest(ja *JwtAuth, r *http.Request, paramAliases ...string) (*jwt.Token, error) {
func VerifyRequest(ja *JwtAuth, r *http.Request, findTokenFns ...func(r *http.Request) string) (*jwt.Token, error) {
var tokenStr string
var err error
// Get token from query params
tokenStr = r.URL.Query().Get("jwt")
// Get token from other param aliases
if tokenStr == "" && paramAliases != nil && len(paramAliases) > 0 {
for _, p := range paramAliases {
tokenStr = r.URL.Query().Get(p)
if tokenStr != "" {
break
}
}
}
// Get token from authorization header
if tokenStr == "" {
bearer := r.Header.Get("Authorization")
if len(bearer) > 7 && strings.ToUpper(bearer[0:6]) == "BEARER" {
tokenStr = bearer[7:]
}
}
// Get token from cookie
if tokenStr == "" {
// TODO: paramAliases should apply to cookies too..
cookie, err := r.Cookie("jwt")
if err == nil {
tokenStr = cookie.Value
// Extract token string from the request by calling token find functions in
// the order they where provided. Further extraction stops if a function
// returns a non-empty string.
for _, fn := range findTokenFns {
tokenStr = fn(r)
if tokenStr != "" {
break
}
}
@ -127,24 +135,17 @@ func VerifyRequest(ja *JwtAuth, r *http.Request, paramAliases ...string) (*jwt.T
case "token is expired":
err = ErrExpired
}
// ctx = NewContext(ctx, token, err)
// next.ServeHTTP(w, r.WithContext(ctx))
return token, err
}
if token == nil || !token.Valid || token.Method != ja.signer {
err = ErrUnauthorized
// ctx = NewContext(ctx, token, err)
// next.ServeHTTP(w, r.WithContext(ctx))
return token, err
}
// Check expiry via "exp" claim
if IsExpired(token) {
err = ErrExpired
// ctx = NewContext(ctx, token, err)
// next.ServeHTTP(w, r.WithContext(ctx))
return token, err
}
@ -173,7 +174,7 @@ func (ja *JwtAuth) Decode(tokenString string) (t *jwt.Token, err error) {
}
func (ja *JwtAuth) keyFunc(t *jwt.Token) (interface{}, error) {
if ja.verifyKey != nil && len(ja.verifyKey) > 0 {
if ja.verifyKey != nil {
return ja.verifyKey, nil
} else {
return ja.signKey, nil

View file

@ -1,12 +1,15 @@
package jwtauth_test
import (
"crypto/x509"
"encoding/pem"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"time"
@ -16,22 +19,83 @@ import (
)
var (
TokenAuth *jwtauth.JwtAuth
TokenSecret = []byte("secretpass")
TokenAuthHS256 *jwtauth.JwtAuth
TokenSecret = []byte("secretpass")
TokenAuthRS256 *jwtauth.JwtAuth
PrivateKeyRS256String = `-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBALxo3PCjFw4QjgOX06QCJIJBnXXNiEYwDLxxa5/7QyH6y77nCRQy
J3x3UwF9rUD0RCsp4sNdX5kOQ9PUyHyOtCUCAwEAAQJARjFLHtuj2zmPrwcBcjja
IS0Q3LKV8pA0LoCS+CdD+4QwCxeKFq0yEMZtMvcQOfqo9x9oAywFClMSlLRyl7ng
gQIhAOyerGbcdQxxwjwGpLS61Mprf4n2HzjwISg20cEEH1tfAiEAy9dXmgQpDPir
C6Q9QdLXpNgSB+o5CDqfor7TTyTCovsCIQDNCfpu795luDYN+dvD2JoIBfrwu9v2
ZO72f/pm/YGGlQIgUdRXyW9kH13wJFNBeBwxD27iBiVj0cbe8NFUONBUBmMCIQCN
jVK4eujt1lm/m60TlEhaWBC3p+3aPT2TqFPUigJ3RQ==
-----END RSA PRIVATE KEY-----
`
PublicKeyRS256String = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALxo3PCjFw4QjgOX06QCJIJBnXXNiEYw
DLxxa5/7QyH6y77nCRQyJ3x3UwF9rUD0RCsp4sNdX5kOQ9PUyHyOtCUCAwEAAQ==
-----END PUBLIC KEY-----
`
)
func init() {
TokenAuth = jwtauth.New("HS256", TokenSecret, nil)
TokenAuthHS256 = jwtauth.New("HS256", TokenSecret, nil)
}
//
// Tests
//
func TestSimpleRSA(t *testing.T) {
privateKeyBlock, _ := pem.Decode([]byte(PrivateKeyRS256String))
privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes)
if err != nil {
t.Fatalf(err.Error())
}
publicKeyBlock, _ := pem.Decode([]byte(PublicKeyRS256String))
publicKey, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
t.Fatalf(err.Error())
}
TokenAuthRS256 = jwtauth.New("RS256", privateKey, publicKey)
claims := jwtauth.Claims{
"key": "val",
"key2": "val2",
"key3": "val3",
}
_, tokenString, err := TokenAuthRS256.Encode(claims)
if err != nil {
t.Fatalf("Failed to encode claims %s\n", err.Error())
}
token, err := TokenAuthRS256.Decode(tokenString)
if err != nil {
t.Fatalf("Failed to decode token string %s\n", err.Error())
}
if !reflect.DeepEqual(claims, jwtauth.Claims(token.Claims.(jwt.MapClaims))) {
t.Fatalf("The decoded claims don't match the original ones\n")
}
}
func TestSimple(t *testing.T) {
r := chi.NewRouter()
r.Use(jwtauth.Verifier(TokenAuth), jwtauth.Authenticator)
r.Use(jwtauth.Verifier(TokenAuthHS256), jwtauth.Authenticator)
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("welcome"))
@ -76,7 +140,7 @@ func TestMore(t *testing.T) {
// Protected routes
r.Group(func(r chi.Router) {
r.Use(jwtauth.Verifier(TokenAuth))
r.Use(jwtauth.Verifier(TokenAuthHS256))
authenticator := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {