vendor dependencies with dep
This commit is contained in:
parent
93d8310491
commit
1384296a47
2712 changed files with 965742 additions and 0 deletions
2
vendor/github.com/go-chi/jwtauth/.gitignore
generated
vendored
Normal file
2
vendor/github.com/go-chi/jwtauth/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
vendor/
|
||||
Gopkg.lock
|
||||
15
vendor/github.com/go-chi/jwtauth/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/go-chi/jwtauth/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- tip
|
||||
|
||||
install:
|
||||
- go get -u golang.org/x/tools/cmd/goimports
|
||||
|
||||
script:
|
||||
- go get -d -t ./...
|
||||
- go test ./...
|
||||
- >
|
||||
goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || :
|
||||
20
vendor/github.com/go-chi/jwtauth/LICENSE
generated
vendored
Normal file
20
vendor/github.com/go-chi/jwtauth/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2015-Present https://github.com/go-chi authors
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
107
vendor/github.com/go-chi/jwtauth/README.md
generated
vendored
Normal file
107
vendor/github.com/go-chi/jwtauth/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
jwtauth - JWT authentication middleware for Go HTTP services
|
||||
============================================================
|
||||
|
||||
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`).
|
||||
|
||||
Please note, `jwtauth` works with any Go http router, but resides under the go-chi group
|
||||
for maintenance and organization - its only 3rd party dependency is the underlying jwt library
|
||||
"github.com/dgrijalva/jwt-go".
|
||||
|
||||
This package uses the new `context` package in Go 1.7 stdlib and [net/http#Request.Context](https://golang.org/pkg/net/http/#Request.Context) to pass values between handler chains.
|
||||
|
||||
In a complete JWT-authentication flow, you'll first capture the token from a http
|
||||
request, decode it, verify it and then validate that its correctly signed and hasn't
|
||||
expired - the `jwtauth.Verifier` middleware handler takes care of all of that. The
|
||||
`jwtauth.Verifier` will set the context values on keys `jwtauth.TokenCtxKey` and
|
||||
`jwtauth.ErrorCtxKey`.
|
||||
|
||||
Next, it's up to an authentication handler to respond or continue processing after the
|
||||
`jwtauth.Verifier`. The `jwtauth.Authenticator` middleware responds with a 401 Unauthorized
|
||||
plain-text payload for all unverified tokens and passes the good ones through. You can
|
||||
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:
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
object is set on the request context. In the case of a signature decoding error
|
||||
the Verifier will also set the error on the request context.
|
||||
|
||||
The Verifier always calls the next http handler in sequence, which can either
|
||||
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.
|
||||
|
||||
# Usage
|
||||
|
||||
See the full [example](https://github.com/go-chi/jwtauth/blob/master/_example/main.go).
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/jwtauth"
|
||||
)
|
||||
|
||||
var tokenAuth *jwtauth.JwtAuth
|
||||
|
||||
func init() {
|
||||
tokenAuth = jwtauth.New("HS256", []byte("secret"), nil)
|
||||
|
||||
// For debugging/example purposes, we generate and print
|
||||
// a sample jwt token with claims `user_id:123` here:
|
||||
_, tokenString, _ := tokenAuth.Encode(jwtauth.Claims{"user_id": 123})
|
||||
fmt.Printf("DEBUG: a sample jwt is %s\n\n", tokenString)
|
||||
}
|
||||
|
||||
func main() {
|
||||
addr := ":3333"
|
||||
fmt.Printf("Starting server on %v\n", addr)
|
||||
http.ListenAndServe(addr, router())
|
||||
}
|
||||
|
||||
func router() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
|
||||
// Protected routes
|
||||
r.Group(func(r chi.Router) {
|
||||
// Seek, verify and validate JWT tokens
|
||||
r.Use(jwtauth.Verifier(tokenAuth))
|
||||
|
||||
// Handle valid / invalid tokens. In this example, we use
|
||||
// the provided authenticator middleware, but you can write your
|
||||
// own very easily, look at the Authenticator method in jwtauth.go
|
||||
// and tweak it, its not scary.
|
||||
r.Use(jwtauth.Authenticator)
|
||||
|
||||
r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, claims, _ := jwtauth.FromContext(r.Context())
|
||||
w.Write([]byte(fmt.Sprintf("protected area. hi %v", claims["user_id"])))
|
||||
})
|
||||
})
|
||||
|
||||
// Public routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("welcome anonymous"))
|
||||
})
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
# LICENSE
|
||||
|
||||
[MIT](/LICENSE)
|
||||
6
vendor/github.com/go-chi/jwtauth/_Gopkg.toml
generated
vendored
Normal file
6
vendor/github.com/go-chi/jwtauth/_Gopkg.toml
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[[constraint]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
version = "^3.0.0"
|
||||
[[constraint]]
|
||||
name = "github.com/go-chi/chi"
|
||||
version = "^3.0.0"
|
||||
114
vendor/github.com/go-chi/jwtauth/_example/main.go
generated
vendored
Normal file
114
vendor/github.com/go-chi/jwtauth/_example/main.go
generated
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// jwtauth example
|
||||
//
|
||||
// Sample output:
|
||||
//
|
||||
// [peter@pak ~]$ curl -v http://localhost:3333/
|
||||
// * Trying ::1...
|
||||
// * Connected to localhost (::1) port 3333 (#0)
|
||||
// > GET / HTTP/1.1
|
||||
// > Host: localhost:3333
|
||||
// > User-Agent: curl/7.49.1
|
||||
// > Accept: */*
|
||||
// >
|
||||
// < HTTP/1.1 200 OK
|
||||
// < Date: Tue, 13 Sep 2016 15:53:17 GMT
|
||||
// < Content-Length: 17
|
||||
// < Content-Type: text/plain; charset=utf-8
|
||||
// <
|
||||
// * Connection #0 to host localhost left intact
|
||||
// welcome anonymous%
|
||||
//
|
||||
//
|
||||
// [peter@pak ~]$ curl -v http://localhost:3333/admin
|
||||
// * Trying ::1...
|
||||
// * Connected to localhost (::1) port 3333 (#0)
|
||||
// > GET /admin HTTP/1.1
|
||||
// > Host: localhost:3333
|
||||
// > User-Agent: curl/7.49.1
|
||||
// > Accept: */*
|
||||
// >
|
||||
// < HTTP/1.1 401 Unauthorized
|
||||
// < Content-Type: text/plain; charset=utf-8
|
||||
// < X-Content-Type-Options: nosniff
|
||||
// < Date: Tue, 13 Sep 2016 15:53:19 GMT
|
||||
// < Content-Length: 13
|
||||
// <
|
||||
// Unauthorized
|
||||
// * Connection #0 to host localhost left intact
|
||||
//
|
||||
//
|
||||
// [peter@pak ~]$ curl -H"Authorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.PZLMJBT9OIVG2qgp9hQr685oVYFgRgWpcSPmNcw6y7M" -v http://localhost:3333/admin
|
||||
// * Trying ::1...
|
||||
// * Connected to localhost (::1) port 3333 (#0)
|
||||
// > GET /admin HTTP/1.1
|
||||
// > Host: localhost:3333
|
||||
// > User-Agent: curl/7.49.1
|
||||
// > Accept: */*
|
||||
// > Authorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.PZLMJBT9OIVG2qgp9hQr685oVYFgRgWpcSPmNcw6y7M
|
||||
// >
|
||||
// < HTTP/1.1 200 OK
|
||||
// < Date: Tue, 13 Sep 2016 15:54:26 GMT
|
||||
// < Content-Length: 22
|
||||
// < Content-Type: text/plain; charset=utf-8
|
||||
// <
|
||||
// * Connection #0 to host localhost left intact
|
||||
// protected area. hi 123%
|
||||
//
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/jwtauth"
|
||||
)
|
||||
|
||||
var tokenAuth *jwtauth.JwtAuth
|
||||
|
||||
func init() {
|
||||
tokenAuth = jwtauth.New("HS256", []byte("secret"), nil)
|
||||
|
||||
// For debugging/example purposes, we generate and print
|
||||
// a sample jwt token with claims `user_id:123` here:
|
||||
_, tokenString, _ := tokenAuth.Encode(jwtauth.Claims{"user_id": 123})
|
||||
fmt.Printf("DEBUG: a sample jwt is %s\n\n", tokenString)
|
||||
}
|
||||
|
||||
func main() {
|
||||
addr := ":3333"
|
||||
fmt.Printf("Starting server on %v\n", addr)
|
||||
http.ListenAndServe(addr, router())
|
||||
}
|
||||
|
||||
func router() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
|
||||
// Protected routes
|
||||
r.Group(func(r chi.Router) {
|
||||
// Seek, verify and validate JWT tokens
|
||||
r.Use(jwtauth.Verifier(tokenAuth))
|
||||
|
||||
// Handle valid / invalid tokens. In this example, we use
|
||||
// the provided authenticator middleware, but you can write your
|
||||
// own very easily, look at the Authenticator method in jwtauth.go
|
||||
// and tweak it, its not scary.
|
||||
r.Use(jwtauth.Authenticator)
|
||||
|
||||
r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, claims, _ := jwtauth.FromContext(r.Context())
|
||||
w.Write([]byte(fmt.Sprintf("protected area. hi %v", claims["user_id"])))
|
||||
})
|
||||
})
|
||||
|
||||
// Public routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("welcome anonymous"))
|
||||
})
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
321
vendor/github.com/go-chi/jwtauth/jwtauth.go
generated
vendored
Normal file
321
vendor/github.com/go-chi/jwtauth/jwtauth.go
generated
vendored
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
package jwtauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
var (
|
||||
TokenCtxKey = &contextKey{"Token"}
|
||||
ErrorCtxKey = &contextKey{"Error"}
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnauthorized = errors.New("jwtauth: token is unauthorized")
|
||||
ErrExpired = errors.New("jwtauth: token is expired")
|
||||
)
|
||||
|
||||
type JwtAuth struct {
|
||||
signKey []byte
|
||||
verifyKey []byte
|
||||
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 {
|
||||
return NewWithParser(alg, &jwt.Parser{}, signKey, verifyKey)
|
||||
}
|
||||
|
||||
// NewWithParser is the same as New, except it supports custom parser settings
|
||||
// introduced in jwt-go/v2.4.0.
|
||||
//
|
||||
// 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 {
|
||||
parser.SkipClaimsValidation = true
|
||||
return &JwtAuth{
|
||||
signKey: signKey,
|
||||
verifyKey: verifyKey,
|
||||
signer: jwt.GetSigningMethod(alg),
|
||||
parser: parser,
|
||||
}
|
||||
}
|
||||
|
||||
// Verifier http middleware handler will verify a JWT string from a http request.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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
|
||||
// object is set on the request context. In the case of a signature decoding error
|
||||
// the Verifier will also set the error on the request context.
|
||||
//
|
||||
// The Verifier always calls the next http handler in sequence, which can either
|
||||
// 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.
|
||||
func Verifier(ja *JwtAuth) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return Verify(ja, "")(next)
|
||||
}
|
||||
}
|
||||
|
||||
func Verify(ja *JwtAuth, paramAliases ...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...)
|
||||
ctx = NewContext(ctx, token, err)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
}
|
||||
return http.HandlerFunc(hfn)
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyRequest(ja *JwtAuth, r *http.Request, paramAliases ...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
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: what other kinds of validations should we do / error messages?
|
||||
|
||||
// Verify the token
|
||||
token, err := ja.Decode(tokenStr)
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
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
|
||||
}
|
||||
|
||||
// Valid!
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (ja *JwtAuth) Encode(claims Claims) (t *jwt.Token, tokenString string, err error) {
|
||||
t = jwt.New(ja.signer)
|
||||
t.Claims = claims
|
||||
tokenString, err = t.SignedString(ja.signKey)
|
||||
t.Raw = tokenString
|
||||
return
|
||||
}
|
||||
|
||||
func (ja *JwtAuth) Decode(tokenString string) (t *jwt.Token, err error) {
|
||||
// Decode the tokenString, but avoid using custom Claims via jwt-go's
|
||||
// ParseWithClaims as the jwt-go types will cause some glitches, so easier
|
||||
// to decode as MapClaims then wrap the underlying map[string]interface{}
|
||||
// to our Claims type
|
||||
t, err = ja.parser.Parse(tokenString, ja.keyFunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (ja *JwtAuth) keyFunc(t *jwt.Token) (interface{}, error) {
|
||||
if ja.verifyKey != nil && len(ja.verifyKey) > 0 {
|
||||
return ja.verifyKey, nil
|
||||
} else {
|
||||
return ja.signKey, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticator is a default authentication middleware to enforce access from the
|
||||
// Verifier middleware request context values. The Authenticator sends a 401 Unauthorized
|
||||
// response for any unverified tokens and passes the good ones through. It's just fine
|
||||
// until you decide to write something similar and customize your client response.
|
||||
func Authenticator(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token, _, err := FromContext(r.Context())
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(401), 401)
|
||||
return
|
||||
}
|
||||
|
||||
if token == nil || !token.Valid {
|
||||
http.Error(w, http.StatusText(401), 401)
|
||||
return
|
||||
}
|
||||
|
||||
// Token is authenticated, pass it through
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func NewContext(ctx context.Context, t *jwt.Token, err error) context.Context {
|
||||
ctx = context.WithValue(ctx, TokenCtxKey, t)
|
||||
ctx = context.WithValue(ctx, ErrorCtxKey, err)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func FromContext(ctx context.Context) (*jwt.Token, Claims, error) {
|
||||
token, _ := ctx.Value(TokenCtxKey).(*jwt.Token)
|
||||
|
||||
var claims Claims
|
||||
if token != nil {
|
||||
tokenClaims, ok := token.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
panic("jwtauth: expecting jwt.MapClaims")
|
||||
}
|
||||
claims = Claims(tokenClaims)
|
||||
} else {
|
||||
claims = Claims{}
|
||||
}
|
||||
|
||||
err, _ := ctx.Value(ErrorCtxKey).(error)
|
||||
|
||||
return token, claims, err
|
||||
}
|
||||
|
||||
func IsExpired(t *jwt.Token) bool {
|
||||
claims, ok := t.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
panic("jwtauth: expecting jwt.MapClaims")
|
||||
}
|
||||
|
||||
if expv, ok := claims["exp"]; ok {
|
||||
var exp int64
|
||||
switch v := expv.(type) {
|
||||
case float64:
|
||||
exp = int64(v)
|
||||
case int64:
|
||||
exp = v
|
||||
case json.Number:
|
||||
exp, _ = v.Int64()
|
||||
default:
|
||||
}
|
||||
|
||||
if exp < EpochNow() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Claims is a convenience type to manage a JWT claims hash.
|
||||
type Claims map[string]interface{}
|
||||
|
||||
// NOTE: as of v3.0 of jwt-go, Valid() interface method is called to verify
|
||||
// the claims. However, the current design we test these claims in the
|
||||
// Verifier middleware, so we skip this step.
|
||||
func (c Claims) Valid() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Claims) Set(k string, v interface{}) Claims {
|
||||
c[k] = v
|
||||
return c
|
||||
}
|
||||
|
||||
func (c Claims) Get(k string) (interface{}, bool) {
|
||||
v, ok := c[k]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// Set issued at ("iat") to specified time in the claims
|
||||
func (c Claims) SetIssuedAt(tm time.Time) Claims {
|
||||
c["iat"] = tm.UTC().Unix()
|
||||
return c
|
||||
}
|
||||
|
||||
// Set issued at ("iat") to present time in the claims
|
||||
func (c Claims) SetIssuedNow() Claims {
|
||||
c["iat"] = EpochNow()
|
||||
return c
|
||||
}
|
||||
|
||||
// Set expiry ("exp") in the claims and return itself so it can be chained
|
||||
func (c Claims) SetExpiry(tm time.Time) Claims {
|
||||
c["exp"] = tm.UTC().Unix()
|
||||
return c
|
||||
}
|
||||
|
||||
// Set expiry ("exp") in the claims to some duration from the present time
|
||||
// and return itself so it can be chained
|
||||
func (c Claims) SetExpiryIn(tm time.Duration) Claims {
|
||||
c["exp"] = ExpireIn(tm)
|
||||
return c
|
||||
}
|
||||
|
||||
// Helper function that returns the NumericDate time value used by the spec
|
||||
func EpochNow() int64 {
|
||||
return time.Now().UTC().Unix()
|
||||
}
|
||||
|
||||
// Helper function to return calculated time in the future for "exp" claim.
|
||||
func ExpireIn(tm time.Duration) int64 {
|
||||
return EpochNow() + int64(tm.Seconds())
|
||||
}
|
||||
|
||||
// contextKey is a value for use with context.WithValue. It's used as
|
||||
// a pointer so it fits in an interface{} without allocation. This technique
|
||||
// for defining context keys was copied from Go 1.7's new use of context in net/http.
|
||||
type contextKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (k *contextKey) String() string {
|
||||
return "jwtauth context value " + k.name
|
||||
}
|
||||
237
vendor/github.com/go-chi/jwtauth/jwtauth_test.go
generated
vendored
Normal file
237
vendor/github.com/go-chi/jwtauth/jwtauth_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
package jwtauth_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/jwtauth"
|
||||
)
|
||||
|
||||
var (
|
||||
TokenAuth *jwtauth.JwtAuth
|
||||
TokenSecret = []byte("secretpass")
|
||||
)
|
||||
|
||||
func init() {
|
||||
TokenAuth = jwtauth.New("HS256", TokenSecret, nil)
|
||||
}
|
||||
|
||||
//
|
||||
// Tests
|
||||
//
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(jwtauth.Verifier(TokenAuth), jwtauth.Authenticator)
|
||||
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("welcome"))
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(r)
|
||||
defer ts.Close()
|
||||
|
||||
// sending unauthorized requests
|
||||
if status, resp := testRequest(t, ts, "GET", "/", nil, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
|
||||
h := http.Header{}
|
||||
h.Set("Authorization", "BEARER "+newJwtToken([]byte("wrong"), map[string]interface{}{}))
|
||||
if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
h.Set("Authorization", "BEARER asdf")
|
||||
if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
// wrong token secret and wrong alg
|
||||
h.Set("Authorization", "BEARER "+newJwt512Token([]byte("wrong"), map[string]interface{}{}))
|
||||
if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
// correct token secret but wrong alg
|
||||
h.Set("Authorization", "BEARER "+newJwt512Token(TokenSecret, map[string]interface{}{}))
|
||||
if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
|
||||
// sending authorized requests
|
||||
if status, resp := testRequest(t, ts, "GET", "/", newAuthHeader(), nil); status != 200 || resp != "welcome" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMore(t *testing.T) {
|
||||
r := chi.NewRouter()
|
||||
|
||||
// Protected routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(jwtauth.Verifier(TokenAuth))
|
||||
|
||||
authenticator := func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
token, _, err := jwtauth.FromContext(r.Context())
|
||||
|
||||
if err != nil {
|
||||
switch err {
|
||||
default:
|
||||
http.Error(w, http.StatusText(401), 401)
|
||||
return
|
||||
case jwtauth.ErrExpired:
|
||||
http.Error(w, "expired", 401)
|
||||
return
|
||||
case jwtauth.ErrUnauthorized:
|
||||
http.Error(w, http.StatusText(401), 401)
|
||||
return
|
||||
case nil:
|
||||
// no error
|
||||
}
|
||||
}
|
||||
|
||||
if token == nil || !token.Valid {
|
||||
http.Error(w, http.StatusText(401), 401)
|
||||
return
|
||||
}
|
||||
|
||||
// Token is authenticated, pass it through
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
r.Use(authenticator)
|
||||
|
||||
r.Get("/admin", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, claims, err := jwtauth.FromContext(r.Context())
|
||||
|
||||
if err != nil {
|
||||
w.Write([]byte(fmt.Sprintf("error! %v", err)))
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(fmt.Sprintf("protected, user:%v", claims["user_id"])))
|
||||
})
|
||||
})
|
||||
|
||||
// Public routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("welcome"))
|
||||
})
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(r)
|
||||
defer ts.Close()
|
||||
|
||||
// sending unauthorized requests
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", nil, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
|
||||
h := http.Header{}
|
||||
h.Set("Authorization", "BEARER "+newJwtToken([]byte("wrong"), map[string]interface{}{}))
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
h.Set("Authorization", "BEARER asdf")
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
// wrong token secret and wrong alg
|
||||
h.Set("Authorization", "BEARER "+newJwt512Token([]byte("wrong"), map[string]interface{}{}))
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
// correct token secret but wrong alg
|
||||
h.Set("Authorization", "BEARER "+newJwt512Token(TokenSecret, map[string]interface{}{}))
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "Unauthorized\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
|
||||
h = newAuthHeader((jwtauth.Claims{}).Set("exp", jwtauth.EpochNow()-1000))
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 || resp != "expired\n" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
|
||||
// sending authorized requests
|
||||
if status, resp := testRequest(t, ts, "GET", "/", nil, nil); status != 200 || resp != "welcome" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
|
||||
h = newAuthHeader((jwtauth.Claims{"user_id": 31337}).SetExpiryIn(5 * time.Minute))
|
||||
if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 200 || resp != "protected, user:31337" {
|
||||
t.Fatalf(resp)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Test helper functions
|
||||
//
|
||||
|
||||
func testRequest(t *testing.T, ts *httptest.Server, method, path string, header http.Header, body io.Reader) (int, string) {
|
||||
req, err := http.NewRequest(method, ts.URL+path, body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
req.Header.Set(k, v[0])
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return 0, ""
|
||||
}
|
||||
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return 0, ""
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return resp.StatusCode, string(respBody)
|
||||
}
|
||||
|
||||
func newJwtToken(secret []byte, claims ...jwtauth.Claims) string {
|
||||
token := jwt.New(jwt.GetSigningMethod("HS256"))
|
||||
if len(claims) > 0 {
|
||||
token.Claims = claims[0]
|
||||
}
|
||||
tokenStr, err := token.SignedString(secret)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return tokenStr
|
||||
}
|
||||
|
||||
func newJwt512Token(secret []byte, claims ...jwtauth.Claims) string {
|
||||
// use-case: when token is signed with a different alg than expected
|
||||
token := jwt.New(jwt.GetSigningMethod("HS512"))
|
||||
if len(claims) > 0 {
|
||||
token.Claims = claims[0]
|
||||
}
|
||||
tokenStr, err := token.SignedString(secret)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return tokenStr
|
||||
}
|
||||
|
||||
func newAuthHeader(claims ...jwtauth.Claims) http.Header {
|
||||
h := http.Header{}
|
||||
h.Set("Authorization", "BEARER "+newJwtToken(TokenSecret, claims...))
|
||||
return h
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue