-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
fukun
committed
May 10, 2017
0 parents
commit 7505560
Showing
21 changed files
with
1,069 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Contributing | ||
Enhancements or fixes are welcome | ||
|
||
## Issues | ||
Check if a ticket for your issue already exists in GitHub issues. If you don't | ||
find a ticket submit a new one. | ||
|
||
## Pull Requests | ||
1. Fork the repo | ||
1. Check out a new topic branch from `dev`. | ||
1. Make your changes. | ||
1. Commit and push the topic branch. | ||
1. Extra credit if you squash your commits first. | ||
1. Submit a pull request back to `dev`. | ||
|
||
###Style | ||
- Your code should pass golint. | ||
- Follow the existing conventions. | ||
|
||
###Tests | ||
- If you add any functionality be sure to also add a test for it. | ||
- All regressions need to pass before I can accept your pull | ||
|
||
## License | ||
By contributing to this project you agree that your contributions will be | ||
licensed under its MIT license. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2016 Clifton Kaznocha | ||
|
||
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# bearerware | ||
|
||
[](https://travis-ci.org/ckaznocha/go-JWTBearerware) | ||
[](https://coveralls.io/github/ckaznocha/go-JWTBearerware?branch=master) | ||
[](http://ckaznocha.mit-license.org) | ||
[](https://godoc.org/github.com/ckaznocha/go-JWTBearerware) | ||
[](https://goreportcard.com/report/ckaznocha/go-JWTBearerware) | ||
|
||
Package bearerware provides a library and middleware to make using [JSON Web Tokens](https://jwt.io/) in gRPC and HTTP requests more convenient. Middleware functions and examples for popular routers are in the `midleware` directory. | ||
|
||
This project was inspire by [auth0/go-jwt-middleware](https://github.com/auth0/go-jwt-middleware). | ||
|
||
Requires go1.7 or newer. | ||
|
||
For more info see the example files and the [GoDoc](https://godoc.org/github.com/ckaznocha/go-JWTBearerware) page. | ||
|
||
-- | ||
import "github.com/ckaznocha/go-JWTBearerware" | ||
|
||
|
||
## Usage | ||
|
||
#### func JWTFromContext | ||
|
||
```go | ||
func JWTFromContext( | ||
ctx context.Context, | ||
keyFunc jwt.Keyfunc, | ||
signingMethod jwt.SigningMethod, | ||
) (*jwt.Token, error) | ||
``` | ||
JWTFromContext **deprecated** use `JWTFromIncomingContext` | ||
|
||
#### func JWTFromHeader | ||
|
||
```go | ||
func JWTFromHeader( | ||
r *http.Request, | ||
keyFunc jwt.Keyfunc, | ||
signingMethod jwt.SigningMethod, | ||
) (*jwt.Token, error) | ||
``` | ||
JWTFromHeader extracts a valid JWT from an http.Request or returns and error | ||
|
||
#### func JWTFromIncomingContext | ||
|
||
```go | ||
func JWTFromIncomingContext( | ||
ctx context.Context, | ||
keyFunc jwt.Keyfunc, | ||
signingMethod jwt.SigningMethod, | ||
) (*jwt.Token, error) | ||
``` | ||
JWTFromIncomingContext extracts a valid JWT from a context.Contexts or returns | ||
and error | ||
|
||
#### func NewJWTAccessFromJWT | ||
|
||
```go | ||
func NewJWTAccessFromJWT(jsonKey string) (credentials.PerRPCCredentials, error) | ||
``` | ||
NewJWTAccessFromJWT creates a JWT credentials.PerRPCCredentials for use in gRPC requests. | ||
|
||
#### func WriteAuthError | ||
|
||
```go | ||
func WriteAuthError(w http.ResponseWriter, err error) | ||
``` | ||
WriteAuthError is a convenience function for setting the WWW-Authenticate header | ||
and sending an http.Error() | ||
|
||
#### type JWTContexter | ||
|
||
```go | ||
type JWTContexter interface { | ||
WriteJWT(*http.Request, *jwt.Token) | ||
ReadJWT(*http.Request) (*jwt.Token, bool) | ||
DeleteJWT(*http.Request) | ||
} | ||
``` | ||
|
||
JWTContexter provides and interface for safe access to a shared map to get a jwt | ||
for the current request scope when using net/http. | ||
|
||
#### func NewJWTContext | ||
|
||
```go | ||
func NewJWTContext() JWTContexter | ||
``` | ||
NewJWTContext creates a new JWTContexter |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package bearerware | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
jwt "github.com/dgrijalva/jwt-go" | ||
) | ||
|
||
const ( | ||
authHeader = "authorization" | ||
bearer = "bearer " | ||
bearerLen = len(bearer) | ||
|
||
invalidRequest = "invalid_request" | ||
invalidToken = "invalid_token" | ||
//insufficientScope = "insufficient_scope" | ||
|
||
errSigningMethod = `Expected signing method %s but token is signed using %s` | ||
) | ||
|
||
var ( | ||
errRestricted = errors.New("Bearer realm=Restricted") | ||
errBearerFormat = errors.New( | ||
"Authorization header format must be Bearer {token}", | ||
) | ||
errTokenInvalid = errors.New("Token is invalid") | ||
) | ||
|
||
type jwtError struct { | ||
err error | ||
code string | ||
} | ||
|
||
func (j *jwtError) Error() string { | ||
s := errRestricted.Error() | ||
if len(j.code) > 0 { | ||
s += fmt.Sprintf(`,error="%s",error_description="%s"`, j.code, j.err) | ||
} | ||
return s | ||
} | ||
|
||
func isBearerToken(s string) bool { | ||
return len(s) > bearerLen && strings.ToLower(s)[:bearerLen] == bearer | ||
} | ||
|
||
func tokenFromBearer(s string) (string, bool) { | ||
if isBearerToken(s) { | ||
return s[bearerLen:], true | ||
} | ||
return "", false | ||
} | ||
|
||
//CheckJWT checks if the JWT was issued by this app | ||
func validJWTFromString( | ||
token string, | ||
keyFunc jwt.Keyfunc, | ||
signingMethod jwt.SigningMethod, | ||
) (*jwt.Token, error) { | ||
var ( | ||
err error | ||
parsedToken *jwt.Token | ||
) | ||
if len(token) == 0 { | ||
return nil, &jwtError{ | ||
err: errBearerFormat, | ||
code: invalidRequest, | ||
} | ||
} | ||
parsedToken, err = jwt.Parse(token, keyFunc) | ||
if err != nil { | ||
return nil, &jwtError{ | ||
err: fmt.Errorf("Error parsing token: %v", err), | ||
code: invalidToken, | ||
} | ||
} | ||
if alg := parsedToken.Header["alg"]; alg != signingMethod.Alg() { | ||
return nil, &jwtError{ | ||
err: fmt.Errorf(errSigningMethod, signingMethod.Alg(), alg), | ||
code: invalidToken, | ||
} | ||
} | ||
if !parsedToken.Valid { | ||
return nil, &jwtError{ | ||
err: errTokenInvalid, | ||
code: invalidToken, | ||
} | ||
} | ||
return parsedToken, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package bearerware | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/dgrijalva/jwt-go" | ||
) | ||
|
||
func Test_validJWTFromString(t *testing.T) { | ||
var ( | ||
jwtKeyFunc = func(token *jwt.Token) (interface{}, error) { | ||
return []byte(" "), nil | ||
} | ||
tests = []struct { | ||
jwt string | ||
signingMethod jwt.SigningMethod | ||
isValidJWT bool | ||
err error | ||
}{ | ||
{ | ||
jwt: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOm51bGwsImV4cCI6bnVsbCwiYXVkIjoiIiwic3ViIjoiIn0.IlffGJz3IyFX1ADQ6-jOTQ_0D-K0kuKq5SpB_oirCrk", | ||
signingMethod: jwt.SigningMethodHS256, | ||
isValidJWT: true, | ||
err: nil, | ||
}, | ||
{ | ||
jwt: "", | ||
signingMethod: jwt.SigningMethodHS256, | ||
isValidJWT: false, | ||
err: errors.New(`Bearer realm=Restricted,error="invalid_request",error_description="Authorization header format must be Bearer {token}"`), | ||
}, | ||
{ | ||
jwt: "foo", | ||
signingMethod: jwt.SigningMethodHS256, | ||
isValidJWT: false, | ||
err: errors.New(`Bearer realm=Restricted,error="invalid_token",error_description="Error parsing token: token contains an invalid number of segments"`), | ||
}, | ||
{ | ||
jwt: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOm51bGwsImV4cCI6bnVsbCwiYXVkIjoiIiwic3ViIjoiIn0.IlffGJz3IyFX1ADQ6-jOTQ_0D-K0kuKq5SpB_oirCrk", | ||
signingMethod: jwt.SigningMethodES256, | ||
isValidJWT: false, | ||
err: errors.New(`Bearer realm=Restricted,error="invalid_token",error_description="Expected signing method ES256 but token is signed using HS256"`), | ||
}, | ||
{ | ||
jwt: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOm51bGwsImV4cCI6bnVsbCwiYXVkIjoiIiwic3ViIjoiIn0.EK492gkeFLTSWLrQlu2hTNbFw3scKJqU5CA3sIsLf68", | ||
signingMethod: jwt.SigningMethodES256, | ||
isValidJWT: false, | ||
err: errors.New(`Bearer realm=Restricted,error="invalid_token",error_description="Error parsing token: signature is invalid"`), | ||
}, | ||
} | ||
) | ||
for _, test := range tests { | ||
_, err := validJWTFromString(test.jwt, jwtKeyFunc, test.signingMethod) | ||
switch { | ||
case test.isValidJWT && err != nil: | ||
t.Error(err) | ||
case !test.isValidJWT && err.Error() != test.err.Error(): | ||
t.Errorf("Expected Err: %s, Got: %s", test.err, err) | ||
|
||
} | ||
} | ||
} | ||
|
||
func Test_isBearerToken(t *testing.T) { | ||
var ( | ||
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOm51bGwsImV4cCI6bnVsbCwiYXVkIjoiIiwic3ViIjoiIn0.IlffGJz3IyFX1ADQ6-jOTQ_0D-K0kuKq5SpB_oirCrk" | ||
tests = []struct { | ||
s string | ||
valid bool | ||
}{ | ||
{s: fmt.Sprintf("Bearer %s", token), valid: true}, | ||
{s: fmt.Sprintf("bearer %s", token), valid: true}, | ||
{s: fmt.Sprintf("beaRer %s", token), valid: true}, | ||
{s: fmt.Sprintf("Bearer%s", token), valid: false}, | ||
{s: fmt.Sprintf("%s", token), valid: false}, | ||
{s: fmt.Sprintf("MAC %s", token), valid: false}, | ||
} | ||
) | ||
for _, test := range tests { | ||
got, valid := tokenFromBearer(test.s) | ||
if valid != test.valid { | ||
t.Errorf("Expected %t, got %t", test.valid, valid) | ||
} | ||
if test.valid && got != token { | ||
t.Errorf("Expected %s, got %s", token, got) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/* | ||
Package bearerware provides a library and middleware to make using JSON Web | ||
Tokens in gRPC and HTTP requests more convenient. Middleware functions and | ||
examples for popular routers are in the `midleware` directory. | ||
This project was inspire by github.com/auth0/go-jwt-middleware. | ||
*/ | ||
package bearerware |
Oops, something went wrong.