Update go dependencies
This commit is contained in:
parent
293223eea0
commit
b7a799bf82
432 changed files with 37346 additions and 25783 deletions
334
vendor/gopkg.in/square/go-jose.v2/jwt/builder.go
generated
vendored
Normal file
334
vendor/gopkg.in/square/go-jose.v2/jwt/builder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
|
||||
"gopkg.in/square/go-jose.v2/json"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
|
||||
// Builder is a utility for making JSON Web Tokens. Calls can be chained, and
|
||||
// errors are accumulated until the final call to CompactSerialize/FullSerialize.
|
||||
type Builder interface {
|
||||
// Claims encodes claims into JWE/JWS form. Multiple calls will merge claims
|
||||
// into single JSON object. If you are passing private claims, make sure to set
|
||||
// struct field tags to specify the name for the JSON key to be used when
|
||||
// serializing.
|
||||
Claims(i interface{}) Builder
|
||||
// Token builds a JSONWebToken from provided data.
|
||||
Token() (*JSONWebToken, error)
|
||||
// FullSerialize serializes a token using the full serialization format.
|
||||
FullSerialize() (string, error)
|
||||
// CompactSerialize serializes a token using the compact serialization format.
|
||||
CompactSerialize() (string, error)
|
||||
}
|
||||
|
||||
// NestedBuilder is a utility for making Signed-Then-Encrypted JSON Web Tokens.
|
||||
// Calls can be chained, and errors are accumulated until final call to
|
||||
// CompactSerialize/FullSerialize.
|
||||
type NestedBuilder interface {
|
||||
// Claims encodes claims into JWE/JWS form. Multiple calls will merge claims
|
||||
// into single JSON object. If you are passing private claims, make sure to set
|
||||
// struct field tags to specify the name for the JSON key to be used when
|
||||
// serializing.
|
||||
Claims(i interface{}) NestedBuilder
|
||||
// Token builds a NestedJSONWebToken from provided data.
|
||||
Token() (*NestedJSONWebToken, error)
|
||||
// FullSerialize serializes a token using the full serialization format.
|
||||
FullSerialize() (string, error)
|
||||
// CompactSerialize serializes a token using the compact serialization format.
|
||||
CompactSerialize() (string, error)
|
||||
}
|
||||
|
||||
type builder struct {
|
||||
payload map[string]interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
type signedBuilder struct {
|
||||
builder
|
||||
sig jose.Signer
|
||||
}
|
||||
|
||||
type encryptedBuilder struct {
|
||||
builder
|
||||
enc jose.Encrypter
|
||||
}
|
||||
|
||||
type nestedBuilder struct {
|
||||
builder
|
||||
sig jose.Signer
|
||||
enc jose.Encrypter
|
||||
}
|
||||
|
||||
// Signed creates builder for signed tokens.
|
||||
func Signed(sig jose.Signer) Builder {
|
||||
return &signedBuilder{
|
||||
sig: sig,
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypted creates builder for encrypted tokens.
|
||||
func Encrypted(enc jose.Encrypter) Builder {
|
||||
return &encryptedBuilder{
|
||||
enc: enc,
|
||||
}
|
||||
}
|
||||
|
||||
// SignedAndEncrypted creates builder for signed-then-encrypted tokens.
|
||||
// ErrInvalidContentType will be returned if encrypter doesn't have JWT content type.
|
||||
func SignedAndEncrypted(sig jose.Signer, enc jose.Encrypter) NestedBuilder {
|
||||
if contentType, _ := enc.Options().ExtraHeaders[jose.HeaderContentType].(jose.ContentType); contentType != "JWT" {
|
||||
return &nestedBuilder{
|
||||
builder: builder{
|
||||
err: ErrInvalidContentType,
|
||||
},
|
||||
}
|
||||
}
|
||||
return &nestedBuilder{
|
||||
sig: sig,
|
||||
enc: enc,
|
||||
}
|
||||
}
|
||||
|
||||
func (b builder) claims(i interface{}) builder {
|
||||
if b.err != nil {
|
||||
return b
|
||||
}
|
||||
|
||||
m, ok := i.(map[string]interface{})
|
||||
switch {
|
||||
case ok:
|
||||
return b.merge(m)
|
||||
case reflect.Indirect(reflect.ValueOf(i)).Kind() == reflect.Struct:
|
||||
m, err := normalize(i)
|
||||
if err != nil {
|
||||
return builder{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
return b.merge(m)
|
||||
default:
|
||||
return builder{
|
||||
err: ErrInvalidClaims,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func normalize(i interface{}) (map[string]interface{}, error) {
|
||||
m := make(map[string]interface{})
|
||||
|
||||
raw, err := json.Marshal(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d := json.NewDecoder(bytes.NewReader(raw))
|
||||
d.UseNumber()
|
||||
|
||||
if err := d.Decode(&m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (b *builder) merge(m map[string]interface{}) builder {
|
||||
p := make(map[string]interface{})
|
||||
for k, v := range b.payload {
|
||||
p[k] = v
|
||||
}
|
||||
for k, v := range m {
|
||||
p[k] = v
|
||||
}
|
||||
|
||||
return builder{
|
||||
payload: p,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *builder) token(p func(interface{}) ([]byte, error), h []jose.Header) (*JSONWebToken, error) {
|
||||
return &JSONWebToken{
|
||||
payload: p,
|
||||
Headers: h,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *signedBuilder) Claims(i interface{}) Builder {
|
||||
return &signedBuilder{
|
||||
builder: b.builder.claims(i),
|
||||
sig: b.sig,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *signedBuilder) Token() (*JSONWebToken, error) {
|
||||
sig, err := b.sign()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
h := make([]jose.Header, len(sig.Signatures))
|
||||
for i, v := range sig.Signatures {
|
||||
h[i] = v.Header
|
||||
}
|
||||
|
||||
return b.builder.token(sig.Verify, h)
|
||||
}
|
||||
|
||||
func (b *signedBuilder) CompactSerialize() (string, error) {
|
||||
sig, err := b.sign()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return sig.CompactSerialize()
|
||||
}
|
||||
|
||||
func (b *signedBuilder) FullSerialize() (string, error) {
|
||||
sig, err := b.sign()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return sig.FullSerialize(), nil
|
||||
}
|
||||
|
||||
func (b *signedBuilder) sign() (*jose.JSONWebSignature, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
|
||||
p, err := json.Marshal(b.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.sig.Sign(p)
|
||||
}
|
||||
|
||||
func (b *encryptedBuilder) Claims(i interface{}) Builder {
|
||||
return &encryptedBuilder{
|
||||
builder: b.builder.claims(i),
|
||||
enc: b.enc,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *encryptedBuilder) CompactSerialize() (string, error) {
|
||||
enc, err := b.encrypt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return enc.CompactSerialize()
|
||||
}
|
||||
|
||||
func (b *encryptedBuilder) FullSerialize() (string, error) {
|
||||
enc, err := b.encrypt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return enc.FullSerialize(), nil
|
||||
}
|
||||
|
||||
func (b *encryptedBuilder) Token() (*JSONWebToken, error) {
|
||||
enc, err := b.encrypt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.builder.token(enc.Decrypt, []jose.Header{enc.Header})
|
||||
}
|
||||
|
||||
func (b *encryptedBuilder) encrypt() (*jose.JSONWebEncryption, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
|
||||
p, err := json.Marshal(b.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.enc.Encrypt(p)
|
||||
}
|
||||
|
||||
func (b *nestedBuilder) Claims(i interface{}) NestedBuilder {
|
||||
return &nestedBuilder{
|
||||
builder: b.builder.claims(i),
|
||||
sig: b.sig,
|
||||
enc: b.enc,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *nestedBuilder) Token() (*NestedJSONWebToken, error) {
|
||||
enc, err := b.signAndEncrypt()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &NestedJSONWebToken{
|
||||
enc: enc,
|
||||
Headers: []jose.Header{enc.Header},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *nestedBuilder) CompactSerialize() (string, error) {
|
||||
enc, err := b.signAndEncrypt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return enc.CompactSerialize()
|
||||
}
|
||||
|
||||
func (b *nestedBuilder) FullSerialize() (string, error) {
|
||||
enc, err := b.signAndEncrypt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return enc.FullSerialize(), nil
|
||||
}
|
||||
|
||||
func (b *nestedBuilder) signAndEncrypt() (*jose.JSONWebEncryption, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
|
||||
p, err := json.Marshal(b.payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := b.sig.Sign(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p2, err := sig.CompactSerialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b.enc.Encrypt([]byte(p2))
|
||||
}
|
||||
507
vendor/gopkg.in/square/go-jose.v2/jwt/builder_test.go
generated
vendored
Normal file
507
vendor/gopkg.in/square/go-jose.v2/jwt/builder_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,507 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"gopkg.in/square/go-jose.v2/json"
|
||||
)
|
||||
|
||||
type testClaims struct {
|
||||
Subject string `json:"sub"`
|
||||
}
|
||||
|
||||
type invalidMarshalClaims struct {
|
||||
}
|
||||
|
||||
var errInvalidMarshalClaims = errors.New("Failed marshaling invalid claims.")
|
||||
|
||||
func (c invalidMarshalClaims) MarshalJSON() ([]byte, error) {
|
||||
return nil, errInvalidMarshalClaims
|
||||
}
|
||||
|
||||
var sampleClaims = Claims{
|
||||
Subject: "42",
|
||||
IssuedAt: NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
Issuer: "issuer",
|
||||
Audience: Audience{"a1", "a2"},
|
||||
}
|
||||
|
||||
type numberClaims struct {
|
||||
Int int64 `json:"int"`
|
||||
Float float64 `json:"float"`
|
||||
}
|
||||
|
||||
func TestIntegerAndFloatsNormalize(t *testing.T) {
|
||||
c := numberClaims{1 << 60, 12345.6789}
|
||||
|
||||
normalized, err := normalize(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ni, err := (normalized["int"].(json.Number)).Int64()
|
||||
nf, err := (normalized["float"].(json.Number)).Float64()
|
||||
|
||||
if ni != c.Int {
|
||||
t.Error(fmt.Sprintf("normalize failed to preserve int64 (got %v, wanted %v, type %s)", normalized["int"], c.Int, reflect.TypeOf(normalized["int"])))
|
||||
}
|
||||
if nf != c.Float {
|
||||
t.Error(fmt.Sprintf("normalize failed to preserve float64 (got %v, wanted %v, type %s)", normalized["float"], c.Float, reflect.TypeOf(normalized["float"])))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderCustomClaimsNonPointer(t *testing.T) {
|
||||
jwt, err := Signed(rsaSigner).Claims(testClaims{"foo"}).CompactSerialize()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
|
||||
parsed, err := ParseSigned(jwt)
|
||||
require.NoError(t, err, "Error parsing JWT.")
|
||||
|
||||
out := &testClaims{}
|
||||
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
|
||||
assert.Equal(t, "foo", out.Subject)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderCustomClaimsPointer(t *testing.T) {
|
||||
jwt, err := Signed(rsaSigner).Claims(&testClaims{"foo"}).CompactSerialize()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
|
||||
parsed, err := ParseSigned(jwt)
|
||||
require.NoError(t, err, "Error parsing JWT.")
|
||||
|
||||
out := &testClaims{}
|
||||
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, out), "Error unmarshaling claims.") {
|
||||
assert.Equal(t, "foo", out.Subject)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderMergeClaims(t *testing.T) {
|
||||
jwt, err := Signed(rsaSigner).
|
||||
Claims(&Claims{
|
||||
Subject: "42",
|
||||
}).
|
||||
Claims(map[string]interface{}{
|
||||
"Scopes": []string{"read:users"},
|
||||
}).
|
||||
CompactSerialize()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
|
||||
parsed, err := ParseSigned(jwt)
|
||||
require.NoError(t, err, "Error parsing JWT.")
|
||||
|
||||
out := make(map[string]interface{})
|
||||
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"sub": "42",
|
||||
"Scopes": []interface{}{"read:users"},
|
||||
}, out)
|
||||
}
|
||||
|
||||
_, err = Signed(rsaSigner).Claims("invalid-claims").Claims(&testClaims{"foo"}).CompactSerialize()
|
||||
assert.Equal(t, err, ErrInvalidClaims)
|
||||
|
||||
_, err = Signed(rsaSigner).Claims(&invalidMarshalClaims{}).CompactSerialize()
|
||||
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
}
|
||||
|
||||
func TestSignedFullSerializeAndToken(t *testing.T) {
|
||||
b := Signed(rsaSigner).Claims(&testClaims{"foo"})
|
||||
|
||||
jwt, err := b.FullSerialize()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
parsed, err := ParseSigned(jwt)
|
||||
require.NoError(t, err, "Error parsing JWT.")
|
||||
out := &testClaims{}
|
||||
if assert.NoError(t, parsed.Claims(&testPrivRSAKey1.PublicKey, &out), "Error unmarshaling claims.") {
|
||||
assert.Equal(t, &testClaims{
|
||||
Subject: "foo",
|
||||
}, out)
|
||||
}
|
||||
|
||||
jwt2, err := b.Token()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
out2 := &testClaims{}
|
||||
if assert.NoError(t, jwt2.Claims(&testPrivRSAKey1.PublicKey, &out2), "Error unmarshaling claims.") {
|
||||
assert.Equal(t, &testClaims{
|
||||
Subject: "foo",
|
||||
}, out2)
|
||||
}
|
||||
|
||||
b2 := Signed(rsaSigner).Claims(&invalidMarshalClaims{})
|
||||
_, err = b2.FullSerialize()
|
||||
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
_, err = b2.Token()
|
||||
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
}
|
||||
|
||||
func TestEncryptedFullSerializeAndToken(t *testing.T) {
|
||||
recipient := jose.Recipient{
|
||||
Algorithm: jose.RSA1_5,
|
||||
Key: testPrivRSAKey1.Public(),
|
||||
}
|
||||
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
|
||||
require.NoError(t, err, "Error creating encrypter.")
|
||||
|
||||
b := Encrypted(encrypter).Claims(&testClaims{"foo"})
|
||||
|
||||
jwt, err := b.FullSerialize()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
parsed, err := ParseEncrypted(jwt)
|
||||
require.NoError(t, err, "Error parsing JWT.")
|
||||
out := &testClaims{}
|
||||
if assert.NoError(t, parsed.Claims(testPrivRSAKey1, &out)) {
|
||||
assert.Equal(t, &testClaims{
|
||||
Subject: "foo",
|
||||
}, out)
|
||||
}
|
||||
|
||||
jwt2, err := b.Token()
|
||||
require.NoError(t, err, "Error creating JWT.")
|
||||
out2 := &testClaims{}
|
||||
if assert.NoError(t, jwt2.Claims(testPrivRSAKey1, &out2)) {
|
||||
assert.Equal(t, &testClaims{
|
||||
Subject: "foo",
|
||||
}, out2)
|
||||
}
|
||||
|
||||
b2 := Encrypted(encrypter).Claims(&invalidMarshalClaims{})
|
||||
|
||||
_, err = b2.FullSerialize()
|
||||
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
_, err = b2.Token()
|
||||
require.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
}
|
||||
|
||||
func TestBuilderSignedAndEncrypted(t *testing.T) {
|
||||
recipient := jose.Recipient{
|
||||
Algorithm: jose.RSA1_5,
|
||||
Key: testPrivRSAKey1.Public(),
|
||||
}
|
||||
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, (&jose.EncrypterOptions{}).WithContentType("JWT").WithType("JWT"))
|
||||
require.NoError(t, err, "Error creating encrypter.")
|
||||
|
||||
jwt1, err := SignedAndEncrypted(rsaSigner, encrypter).Claims(&testClaims{"foo"}).Token()
|
||||
require.NoError(t, err, "Error marshaling signed-then-encrypted token.")
|
||||
if nested, err := jwt1.Decrypt(testPrivRSAKey1); assert.NoError(t, err, "Error decrypting signed-then-encrypted token.") {
|
||||
out := &testClaims{}
|
||||
assert.NoError(t, nested.Claims(&testPrivRSAKey1.PublicKey, out))
|
||||
assert.Equal(t, &testClaims{"foo"}, out)
|
||||
}
|
||||
|
||||
b := SignedAndEncrypted(rsaSigner, encrypter).Claims(&testClaims{"foo"})
|
||||
tok1, err := b.CompactSerialize()
|
||||
if assert.NoError(t, err) {
|
||||
jwt, err := ParseSignedAndEncrypted(tok1)
|
||||
if assert.NoError(t, err, "Error parsing signed-then-encrypted compact token.") {
|
||||
if nested, err := jwt.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
|
||||
out := &testClaims{}
|
||||
assert.NoError(t, nested.Claims(&testPrivRSAKey1.PublicKey, out))
|
||||
assert.Equal(t, &testClaims{"foo"}, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tok2, err := b.FullSerialize()
|
||||
if assert.NoError(t, err) {
|
||||
jwe, err := ParseSignedAndEncrypted(tok2)
|
||||
if assert.NoError(t, err, "Error parsing signed-then-encrypted full token.") {
|
||||
assert.Equal(t, []jose.Header{{
|
||||
Algorithm: string(jose.RSA1_5),
|
||||
ExtraHeaders: map[jose.HeaderKey]interface{}{
|
||||
jose.HeaderType: "JWT",
|
||||
jose.HeaderContentType: "JWT",
|
||||
"enc": "A128CBC-HS256",
|
||||
},
|
||||
}}, jwe.Headers)
|
||||
if jws, err := jwe.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
|
||||
assert.Equal(t, []jose.Header{{
|
||||
Algorithm: string(jose.RS256),
|
||||
ExtraHeaders: map[jose.HeaderKey]interface{}{
|
||||
jose.HeaderType: "JWT",
|
||||
},
|
||||
}}, jws.Headers)
|
||||
out := &testClaims{}
|
||||
assert.NoError(t, jws.Claims(&testPrivRSAKey1.PublicKey, out))
|
||||
assert.Equal(t, &testClaims{"foo"}, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b2 := SignedAndEncrypted(rsaSigner, encrypter).Claims(&invalidMarshalClaims{})
|
||||
_, err = b2.CompactSerialize()
|
||||
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
_, err = b2.FullSerialize()
|
||||
assert.EqualError(t, err, "json: error calling MarshalJSON for type *jwt.invalidMarshalClaims: Failed marshaling invalid claims.")
|
||||
|
||||
encrypter2, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, nil)
|
||||
require.NoError(t, err, "Error creating encrypter.")
|
||||
_, err = SignedAndEncrypted(rsaSigner, encrypter2).CompactSerialize()
|
||||
assert.EqualError(t, err, "square/go-jose/jwt: expected content type to be JWT (cty header)")
|
||||
}
|
||||
|
||||
func TestBuilderHeadersSigner(t *testing.T) {
|
||||
tests := []struct {
|
||||
Keys []*rsa.PrivateKey
|
||||
Claims interface{}
|
||||
}{
|
||||
{
|
||||
Keys: []*rsa.PrivateKey{testPrivRSAKey1},
|
||||
Claims: &Claims{Issuer: "foo"},
|
||||
},
|
||||
{
|
||||
Keys: []*rsa.PrivateKey{testPrivRSAKey1, testPrivRSAKey2},
|
||||
Claims: &Claims{Issuer: "foo"},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
wantKeyIDs := make([]string, len(tc.Keys))
|
||||
signingKeys := make([]jose.SigningKey, len(tc.Keys))
|
||||
|
||||
for j, key := range tc.Keys {
|
||||
keyIDBytes := make([]byte, 20)
|
||||
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
|
||||
t.Fatalf("failed to read random bytes: %v", err)
|
||||
}
|
||||
keyID := hex.EncodeToString(keyIDBytes)
|
||||
|
||||
wantKeyIDs[j] = keyID
|
||||
signingKeys[j] = jose.SigningKey{
|
||||
Algorithm: jose.RS256,
|
||||
Key: &jose.JSONWebKey{
|
||||
KeyID: keyID,
|
||||
Algorithm: "RSA",
|
||||
Key: key,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
signer, err := jose.NewMultiSigner(signingKeys, nil)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: NewMultiSigner(): %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
var token string
|
||||
if len(tc.Keys) == 1 {
|
||||
token, err = Signed(signer).Claims(tc.Claims).CompactSerialize()
|
||||
} else {
|
||||
token, err = Signed(signer).Claims(tc.Claims).FullSerialize()
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("case %d: failed to create token: %v", i, err)
|
||||
continue
|
||||
}
|
||||
jws, err := jose.ParseSigned(token)
|
||||
if err != nil {
|
||||
t.Errorf("case %d: parse signed: %v", i, err)
|
||||
continue
|
||||
}
|
||||
gotKeyIDs := make([]string, len(jws.Signatures))
|
||||
for i, sig := range jws.Signatures {
|
||||
gotKeyIDs[i] = sig.Header.KeyID
|
||||
}
|
||||
sort.Strings(wantKeyIDs)
|
||||
sort.Strings(gotKeyIDs)
|
||||
if !reflect.DeepEqual(wantKeyIDs, gotKeyIDs) {
|
||||
t.Errorf("case %d: wanted=%q got=%q", i, wantKeyIDs, gotKeyIDs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderHeadersEncrypter(t *testing.T) {
|
||||
key := testPrivRSAKey1
|
||||
claims := &Claims{Issuer: "foo"}
|
||||
|
||||
keyIDBytes := make([]byte, 20)
|
||||
if _, err := io.ReadFull(rand.Reader, keyIDBytes); err != nil {
|
||||
t.Fatalf("failed to read random bytes: %v", err)
|
||||
}
|
||||
keyID := hex.EncodeToString(keyIDBytes)
|
||||
|
||||
wantKeyID := keyID
|
||||
recipient := jose.Recipient{
|
||||
Algorithm: jose.RSA1_5,
|
||||
Key: key.Public(),
|
||||
KeyID: keyID,
|
||||
}
|
||||
|
||||
wantType := jose.ContentType("JWT")
|
||||
encrypter, err := jose.NewEncrypter(jose.A128CBC_HS256, recipient, (&jose.EncrypterOptions{}).WithType(wantType))
|
||||
require.NoError(t, err, "failed to create encrypter")
|
||||
|
||||
token, err := Encrypted(encrypter).Claims(claims).CompactSerialize()
|
||||
require.NoError(t, err, "failed to create token")
|
||||
|
||||
jwe, err := jose.ParseEncrypted(token)
|
||||
if assert.NoError(t, err, "error parsing encrypted token") {
|
||||
assert.Equal(t, jose.Header{
|
||||
ExtraHeaders: map[jose.HeaderKey]interface{}{
|
||||
jose.HeaderType: string(wantType),
|
||||
"enc": "A128CBC-HS256",
|
||||
},
|
||||
Algorithm: string(jose.RSA1_5),
|
||||
KeyID: wantKeyID,
|
||||
}, jwe.Header)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMapClaims(b *testing.B) {
|
||||
m := map[string]interface{}{
|
||||
"sub": "42",
|
||||
"iat": 1451606400,
|
||||
"iss": "issuer",
|
||||
"aud": []string{"a1", "a2"},
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Signed(rsaSigner).Claims(m)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStructClaims(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Signed(rsaSigner).Claims(sampleClaims)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSignedCompactSerializeRSA(b *testing.B) {
|
||||
tb := Signed(rsaSigner).Claims(sampleClaims)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tb.CompactSerialize()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSignedCompactSerializeSHA(b *testing.B) {
|
||||
tb := Signed(hmacSigner).Claims(sampleClaims)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tb.CompactSerialize()
|
||||
}
|
||||
}
|
||||
|
||||
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
|
||||
block, _ := pem.Decode([]byte(data))
|
||||
if block == nil {
|
||||
panic("failed to decode PEM data")
|
||||
}
|
||||
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic("failed to parse RSA key: " + err.Error())
|
||||
}
|
||||
if key, ok := key.(*rsa.PrivateKey); ok {
|
||||
return key
|
||||
}
|
||||
panic("key is not of type *rsa.PrivateKey")
|
||||
}
|
||||
|
||||
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, (&jose.SignerOptions{}).WithType("JWT"))
|
||||
if err != nil {
|
||||
panic("failed to create signer:" + err.Error())
|
||||
}
|
||||
|
||||
return sig
|
||||
}
|
||||
|
||||
var (
|
||||
sharedKey = []byte("secret")
|
||||
sharedEncryptionKey = []byte("itsa16bytesecret")
|
||||
|
||||
testPrivRSAKey1 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
|
||||
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
|
||||
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
|
||||
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
|
||||
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
|
||||
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
|
||||
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
|
||||
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
|
||||
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
|
||||
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
|
||||
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
|
||||
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
|
||||
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
|
||||
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
|
||||
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
|
||||
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
|
||||
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
|
||||
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
|
||||
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
|
||||
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
|
||||
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
|
||||
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
|
||||
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
|
||||
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
|
||||
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
|
||||
b9Ym/nxaqyTu0PxajXkKm5Q=
|
||||
-----END PRIVATE KEY-----`)
|
||||
|
||||
testPrivRSAKey2 = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxJ09jkXZ5Okyq
|
||||
FrEKrs+GTzZRvoLziyzDTIZLJC6BVryau4gaFjuBG+pnm4z53oDP0XVnjFsx1mBw
|
||||
R6RHeXlXbxLXsMfJpMzU9I2SRen9DokpD187CAnjLOoN9QRl1h8CA+sqR5Jw9mdl
|
||||
mdaBKC99M9QYAPK3vGNfPC4soo8LDSBiemmt5raL4WSfoYh/6qg5rHUTymY28uxV
|
||||
ew3I9Yp+3ltIw+WlRDtW5l+MM5CSUofjj2zcgcG3LEuPtvyZ+CSObxxcZZugm9zc
|
||||
JdiazNyUxtX8yAj3Xg8Hde0jt0QDXv7A+U0KMVi9lX6PJEaNj4tOhOmQhJVMzAyr
|
||||
1W/bifZVAgMBAAECggEAduKnn21GMZLTUi4KP94SvNK55F/Sp7hVoPbhBNpSL1BT
|
||||
IBAMBV24LyvZwhAcqq8MiOrLPGNv6+EvNQqPD7xQl0GeRouHeCYVpDA+NdSfc8jm
|
||||
eVysjwQVBpTkudsdSW5JvuN8VRJVD2P8/a0gy+p4/C/k/Prd6DoQAiBz6FZrYoEd
|
||||
iYgIegHOMXWd4vzO3ENOWSIUI6ci7Aro+Y0Z75kfiVokAGhUcFgrZ58E82fBYh8I
|
||||
cxO20oMnucGrLicQzj536jx4wX3Cdd4jr9UVEJ9ZII1ldlp03nZlFLXqJH1547Aq
|
||||
ZM+3vVcBGoJ8T9ZQ4VDAL++0K2DLC9JkTARAYCEi/QKBgQDebIc1+2zblhQtVQ/e
|
||||
IbEErZcB7v+TkUoRoBfR0lj7bKBFJgRe37fgu1xf95/s63okdnOw/OuQqtGmgx/J
|
||||
TL3yULBdNcwTCRm41t+cqoGymjK0VRbqk6CWBId0E3r5TaCVWedk2JI2XwTvIJ1A
|
||||
eDiqfJeDHUD44yaonwbysj9ZDwKBgQDL5VQfTppVaJk2PXNwhAkRQklZ8RFmt/7p
|
||||
yA3dddQNdwMk4Fl8F7QuO1gBxDiHdnwIrlEOz6fTsM3LwIS+Q12P1vYFIhpo7HDB
|
||||
wvjfMwCPxBIS4jI28RgcAf0VbZ/+CHAm6bb9iDwsjXhh1J5oOm5VKnju6/rPH/QY
|
||||
+md40pnSWwKBgBnKPbdNquafNUG4XjmkcHEZa6wGuU20CAGZLYnfuP+WLdM2wET7
|
||||
7cc6ElDyVnHTL/twXKPF/85rcBm9lH7zzgZ9wqVcKoh+gqQDDjSNNLKv3Hc6cojK
|
||||
i1E5vzb/Vz/290q5/PGdhv6U7+6GOpWSGwfxoGPMjY8OT5o3rkeP0XaTAoGBALLR
|
||||
GQmr4eZtqZDMK+XNpjYgsDvVE7HGRCW7cY17vNFiQruglloiX778BJ7n+7uxye3D
|
||||
EwuuSj15ncLHwKMsaW2w1GqEEi1azzjfSWxWSnPLPR6aifdtUfueMtsMHXio5dL6
|
||||
vaV0SXG5UI5b7eDy/bhrW0wOYRQtreIKGZz49jZpAoGBAIvxYngkLwmq6g6MmnAc
|
||||
YK4oT6YAm2wfSy2mzpEQP5r1igp1rN7T46o7FMUPDLS9wK3ESAaIYe01qT6Yftcc
|
||||
5qF+yiOGDTr9XQiHwe4BcyrNEMfUjDhDU5ao2gH8+t1VGr1KspLsUNbedrJwZsY4
|
||||
UCZVKEEDHzKfLO/iBgKjJQF7
|
||||
-----END PRIVATE KEY-----`)
|
||||
|
||||
rsaSigner = mustMakeSigner(jose.RS256, testPrivRSAKey1)
|
||||
hmacSigner = mustMakeSigner(jose.HS256, sharedKey)
|
||||
)
|
||||
115
vendor/gopkg.in/square/go-jose.v2/jwt/claims.go
generated
vendored
Normal file
115
vendor/gopkg.in/square/go-jose.v2/jwt/claims.go
generated
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Claims represents public claim values (as specified in RFC 7519).
|
||||
type Claims struct {
|
||||
Issuer string `json:"iss,omitempty"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
Audience Audience `json:"aud,omitempty"`
|
||||
Expiry NumericDate `json:"exp,omitempty"`
|
||||
NotBefore NumericDate `json:"nbf,omitempty"`
|
||||
IssuedAt NumericDate `json:"iat,omitempty"`
|
||||
ID string `json:"jti,omitempty"`
|
||||
}
|
||||
|
||||
// NumericDate represents date and time as the number of seconds since the
|
||||
// epoch, including leap seconds. Non-integer values can be represented
|
||||
// in the serialized format, but we round to the nearest second.
|
||||
type NumericDate int64
|
||||
|
||||
// NewNumericDate constructs NumericDate from time.Time value.
|
||||
func NewNumericDate(t time.Time) NumericDate {
|
||||
if t.IsZero() {
|
||||
return NumericDate(0)
|
||||
}
|
||||
|
||||
// While RFC 7519 technically states that NumericDate values may be
|
||||
// non-integer values, we don't bother serializing timestamps in
|
||||
// claims with sub-second accurancy and just round to the nearest
|
||||
// second instead. Not convined sub-second accuracy is useful here.
|
||||
return NumericDate(t.Unix())
|
||||
}
|
||||
|
||||
// MarshalJSON serializes the given NumericDate into its JSON representation.
|
||||
func (n NumericDate) MarshalJSON() ([]byte, error) {
|
||||
return []byte(strconv.FormatInt(int64(n), 10)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON reads a date from its JSON representation.
|
||||
func (n *NumericDate) UnmarshalJSON(b []byte) error {
|
||||
s := string(b)
|
||||
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return ErrUnmarshalNumericDate
|
||||
}
|
||||
|
||||
*n = NumericDate(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Time returns time.Time representation of NumericDate.
|
||||
func (n NumericDate) Time() time.Time {
|
||||
return time.Unix(int64(n), 0)
|
||||
}
|
||||
|
||||
// Audience represents the recipents that the token is intended for.
|
||||
type Audience []string
|
||||
|
||||
// UnmarshalJSON reads an audience from its JSON representation.
|
||||
func (s *Audience) UnmarshalJSON(b []byte) error {
|
||||
var v interface{}
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
*s = []string{v}
|
||||
case []interface{}:
|
||||
a := make([]string, len(v))
|
||||
for i, e := range v {
|
||||
s, ok := e.(string)
|
||||
if !ok {
|
||||
return ErrUnmarshalAudience
|
||||
}
|
||||
a[i] = s
|
||||
}
|
||||
*s = a
|
||||
default:
|
||||
return ErrUnmarshalAudience
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Audience) Contains(v string) bool {
|
||||
for _, a := range s {
|
||||
if a == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
80
vendor/gopkg.in/square/go-jose.v2/jwt/claims_test.go
generated
vendored
Normal file
80
vendor/gopkg.in/square/go-jose.v2/jwt/claims_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/square/go-jose.v2/json"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEncodeClaims(t *testing.T) {
|
||||
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
c := Claims{
|
||||
Issuer: "issuer",
|
||||
Subject: "subject",
|
||||
Audience: Audience{"a1", "a2"},
|
||||
NotBefore: NewNumericDate(time.Time{}),
|
||||
IssuedAt: NewNumericDate(now),
|
||||
Expiry: NewNumericDate(now.Add(1 * time.Hour)),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(c)
|
||||
assert.NoError(t, err)
|
||||
|
||||
expected := `{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`
|
||||
assert.Equal(t, expected, string(b))
|
||||
}
|
||||
|
||||
func TestDecodeClaims(t *testing.T) {
|
||||
s := []byte(`{"iss":"issuer","sub":"subject","aud":["a1","a2"],"exp":1451610000,"iat":1451606400}`)
|
||||
now := time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
c := Claims{}
|
||||
if err := json.Unmarshal(s, &c); assert.NoError(t, err) {
|
||||
assert.Equal(t, "issuer", c.Issuer)
|
||||
assert.Equal(t, "subject", c.Subject)
|
||||
assert.Equal(t, Audience{"a1", "a2"}, c.Audience)
|
||||
assert.True(t, now.Equal(c.IssuedAt.Time()))
|
||||
assert.True(t, now.Add(1*time.Hour).Equal(c.Expiry.Time()))
|
||||
}
|
||||
|
||||
s2 := []byte(`{"aud": "a1"}`)
|
||||
c2 := Claims{}
|
||||
if err := json.Unmarshal(s2, &c2); assert.NoError(t, err) {
|
||||
assert.Equal(t, Audience{"a1"}, c2.Audience)
|
||||
}
|
||||
|
||||
invalid := []struct {
|
||||
Raw string
|
||||
Err error
|
||||
}{
|
||||
{`{"aud": 5}`, ErrUnmarshalAudience},
|
||||
{`{"aud": ["foo", 5, "bar"]}`, ErrUnmarshalAudience},
|
||||
{`{"exp": "invalid"}`, ErrUnmarshalNumericDate},
|
||||
}
|
||||
|
||||
for _, v := range invalid {
|
||||
c := Claims{}
|
||||
assert.Equal(t, v.Err, json.Unmarshal([]byte(v.Raw), &c))
|
||||
}
|
||||
}
|
||||
22
vendor/gopkg.in/square/go-jose.v2/jwt/doc.go
generated
vendored
Normal file
22
vendor/gopkg.in/square/go-jose.v2/jwt/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*-
|
||||
* Copyright 2017 Square Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Package jwt provides an implementation of the JSON Web Token standard.
|
||||
|
||||
*/
|
||||
package jwt
|
||||
50
vendor/gopkg.in/square/go-jose.v2/jwt/errors.go
generated
vendored
Normal file
50
vendor/gopkg.in/square/go-jose.v2/jwt/errors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrUnmarshalAudience indicates that aud claim could not be unmarshalled.
|
||||
var ErrUnmarshalAudience = errors.New("square/go-jose/jwt: expected string or array value to unmarshal to Audience")
|
||||
|
||||
// ErrUnmarshalNumericDate indicates that JWT NumericDate could not be unmarshalled.
|
||||
var ErrUnmarshalNumericDate = errors.New("square/go-jose/jwt: expected number value to unmarshal NumericDate")
|
||||
|
||||
// ErrInvalidClaims indicates that given claims have invalid type.
|
||||
var ErrInvalidClaims = errors.New("square/go-jose/jwt: expected claims to be value convertible into JSON object")
|
||||
|
||||
// ErrInvalidIssuer indicates invalid iss claim.
|
||||
var ErrInvalidIssuer = errors.New("square/go-jose/jwt: validation failed, invalid issuer claim (iss)")
|
||||
|
||||
// ErrInvalidSubject indicates invalid sub claim.
|
||||
var ErrInvalidSubject = errors.New("square/go-jose/jwt: validation failed, invalid subject claim (sub)")
|
||||
|
||||
// ErrInvalidAudience indicated invalid aud claim.
|
||||
var ErrInvalidAudience = errors.New("square/go-jose/jwt: validation failed, invalid audience claim (aud)")
|
||||
|
||||
// ErrInvalidID indicates invalid jti claim.
|
||||
var ErrInvalidID = errors.New("square/go-jose/jwt: validation failed, invalid ID claim (jti)")
|
||||
|
||||
// ErrNotValidYet indicates that token is used before time indicated in nbf claim.
|
||||
var ErrNotValidYet = errors.New("square/go-jose/jwt: validation failed, token not valid yet (nbf)")
|
||||
|
||||
// ErrExpired indicates that token is used after expiry time indicated in exp claim.
|
||||
var ErrExpired = errors.New("square/go-jose/jwt: validation failed, token is expired (exp)")
|
||||
|
||||
// ErrInvalidContentType indicated that token requires JWT cty header.
|
||||
var ErrInvalidContentType = errors.New("square/go-jose/jwt: expected content type to be JWT (cty header)")
|
||||
340
vendor/gopkg.in/square/go-jose.v2/jwt/example_test.go
generated
vendored
Normal file
340
vendor/gopkg.in/square/go-jose.v2/jwt/example_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
)
|
||||
|
||||
var sharedKey = []byte("secret")
|
||||
var sharedEncryptionKey = []byte("itsa16bytesecret")
|
||||
var signer, _ = jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: sharedKey}, &jose.SignerOptions{})
|
||||
|
||||
func ExampleParseSigned() {
|
||||
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
|
||||
tok, err := jwt.ParseSigned(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := jwt.Claims{}
|
||||
if err := tok.Claims(sharedKey, &out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
|
||||
// Output: iss: issuer, sub: subject
|
||||
}
|
||||
|
||||
func ExampleParseEncrypted() {
|
||||
key := []byte("itsa16bytesecret")
|
||||
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..jg45D9nmr6-8awml.z-zglLlEw9MVkYHi-Znd9bSwc-oRGbqKzf9WjXqZxno.kqji2DiZHZmh-1bLF6ARPw`
|
||||
tok, err := jwt.ParseEncrypted(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := jwt.Claims{}
|
||||
if err := tok.Claims(key, &out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
|
||||
// Output: iss: issuer, sub: subject
|
||||
}
|
||||
|
||||
func ExampleParseSignedAndEncrypted() {
|
||||
raw := `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIiwiY3R5IjoiSldUIn0..-keV-9YpsxotBEHw.yC9SHWgnkjykgJqXZGlzYC5Wg_EdWKO5TgfqeqsWWJYw7fX9zXQE3NtXmA3nAiUrYOr3H2s0AgTeAhTNbELLEHQu0blfRaPa_uKOAgFgmhJwbGe2iFLn9J0U72wk56318nI-pTLCV8FijoGpXvAxQlaKrPLKkl9yDQimPhb7UiDwLWYkJeoayciAXhR5f40E8ORGjCz8oawXRvjDaSjgRElUwy4kMGzvJy_difemEh4lfMSIwUNVEqJkEYaalRttSymMYuV6NvBVU0N0Jb6omdM4tW961OySB4KPWCWH9UJUX0XSEcqbW9WLxpg3ftx5R7xNiCnaVaCx_gJZfXJ9yFLqztIrKh2N05zHM0tddSOwCOnq7_1rJtaVz0nTXjSjf1RrVaxJya59p3K-e41QutiGFiJGzXG-L2OyLETIaVSU3ptvaCz4IxCF3GzeCvOgaICvXkpBY1-bv-fk1ilyjmcTDnLp2KivWIxcnoQmpN9xj06ZjagdG09AHUhS5WixADAg8mIdGcanNblALecnCWG-otjM9Kw.RZoaHtSgnzOin2od3D9tnA`
|
||||
tok, err := jwt.ParseSignedAndEncrypted(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
nested, err := tok.Decrypt(sharedEncryptionKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := jwt.Claims{}
|
||||
if err := nested.Claims(&rsaPrivKey.PublicKey, &out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("iss: %s, sub: %s\n", out.Issuer, out.Subject)
|
||||
// Output: iss: issuer, sub: subject
|
||||
}
|
||||
|
||||
func ExampleClaims_Validate() {
|
||||
cl := jwt.Claims{
|
||||
Subject: "subject",
|
||||
Issuer: "issuer",
|
||||
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
Expiry: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 15, 0, 0, time.UTC)),
|
||||
Audience: jwt.Audience{"leela", "fry"},
|
||||
}
|
||||
|
||||
err := cl.Validate(jwt.Expected{
|
||||
Issuer: "issuer",
|
||||
Time: time.Date(2016, 1, 1, 0, 10, 0, 0, time.UTC),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("valid!")
|
||||
// Output: valid!
|
||||
}
|
||||
|
||||
func ExampleClaims_Validate_withParse() {
|
||||
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
|
||||
tok, err := jwt.ParseSigned(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cl := jwt.Claims{}
|
||||
if err := tok.Claims(sharedKey, &cl); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = cl.Validate(jwt.Expected{
|
||||
Issuer: "issuer",
|
||||
Subject: "subject",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("valid!")
|
||||
// Output: valid!
|
||||
}
|
||||
|
||||
func ExampleSigned() {
|
||||
key := []byte("secret")
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cl := jwt.Claims{
|
||||
Subject: "subject",
|
||||
Issuer: "issuer",
|
||||
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
Audience: jwt.Audience{"leela", "fry"},
|
||||
}
|
||||
raw, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(raw)
|
||||
// Output: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiaXNzIjoiaXNzdWVyIiwibmJmIjoxNDUxNjA2NDAwLCJzdWIiOiJzdWJqZWN0In0.4PgCj0VO-uG_cb1mNA38NjJyp0N-NdGIDLoYelEkciw
|
||||
}
|
||||
|
||||
func ExampleSigned_privateClaims() {
|
||||
key := []byte("secret")
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, (&jose.SignerOptions{}).WithType("JWT"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cl := jwt.Claims{
|
||||
Subject: "subject",
|
||||
Issuer: "issuer",
|
||||
NotBefore: jwt.NewNumericDate(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)),
|
||||
Audience: jwt.Audience{"leela", "fry"},
|
||||
}
|
||||
|
||||
// When setting private claims, make sure to add struct tags
|
||||
// to specify how to serialize the field. The naming behavior
|
||||
// should match the encoding/json package otherwise.
|
||||
privateCl := struct {
|
||||
CustomClaim string `json:"custom"`
|
||||
}{
|
||||
"custom claim value",
|
||||
}
|
||||
|
||||
raw, err := jwt.Signed(sig).Claims(cl).Claims(privateCl).CompactSerialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(raw)
|
||||
// Ouput: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsibGVlbGEiLCJmcnkiXSwiY3VzdG9tIjoiY3VzdG9tIGNsYWltIHZhbHVlIiwiaXNzIjoiaXNzdWVyIiwibmJmIjoxNDUxNjA2NDAwLCJzdWIiOiJzdWJqZWN0In0.knXH3ReNJToS5XI7BMCkk80ugpCup3tOy53xq-ga47o
|
||||
}
|
||||
|
||||
func ExampleEncrypted() {
|
||||
enc, err := jose.NewEncrypter(
|
||||
jose.A128GCM,
|
||||
jose.Recipient{Algorithm: jose.DIRECT, Key: sharedEncryptionKey},
|
||||
(&jose.EncrypterOptions{}).WithType("JWT"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cl := jwt.Claims{
|
||||
Subject: "subject",
|
||||
Issuer: "issuer",
|
||||
}
|
||||
raw, err := jwt.Encrypted(enc).Claims(cl).CompactSerialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(raw)
|
||||
}
|
||||
|
||||
func ExampleSignedAndEncrypted() {
|
||||
enc, err := jose.NewEncrypter(
|
||||
jose.A128GCM,
|
||||
jose.Recipient{
|
||||
Algorithm: jose.DIRECT,
|
||||
Key: sharedEncryptionKey,
|
||||
},
|
||||
(&jose.EncrypterOptions{}).WithType("JWT").WithContentType("JWT"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cl := jwt.Claims{
|
||||
Subject: "subject",
|
||||
Issuer: "issuer",
|
||||
}
|
||||
raw, err := jwt.SignedAndEncrypted(rsaSigner, enc).Claims(cl).CompactSerialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(raw)
|
||||
}
|
||||
|
||||
func ExampleSigned_multipleClaims() {
|
||||
c := &jwt.Claims{
|
||||
Subject: "subject",
|
||||
Issuer: "issuer",
|
||||
}
|
||||
c2 := struct {
|
||||
Scopes []string
|
||||
}{
|
||||
[]string{"foo", "bar"},
|
||||
}
|
||||
raw, err := jwt.Signed(signer).Claims(c).Claims(c2).CompactSerialize()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println(raw)
|
||||
// Output: eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y
|
||||
}
|
||||
|
||||
func ExampleJSONWebToken_Claims_map() {
|
||||
raw := `eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzdWIiOiJzdWJqZWN0In0.gpHyA1B1H6X4a4Edm9wo7D3X2v3aLSDBDG2_5BzXYe0`
|
||||
tok, err := jwt.ParseSigned(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := make(map[string]interface{})
|
||||
if err := tok.Claims(sharedKey, &out); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("iss: %s, sub: %s\n", out["iss"], out["sub"])
|
||||
// Output: iss: issuer, sub: subject
|
||||
}
|
||||
|
||||
func ExampleJSONWebToken_Claims_multiple() {
|
||||
raw := `eyJhbGciOiJIUzI1NiJ9.eyJTY29wZXMiOlsiZm9vIiwiYmFyIl0sImlzcyI6Imlzc3VlciIsInN1YiI6InN1YmplY3QifQ.esKOIsmwkudr_gnfnB4SngxIr-7pspd5XzG3PImfQ6Y`
|
||||
tok, err := jwt.ParseSigned(raw)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := jwt.Claims{}
|
||||
out2 := struct {
|
||||
Scopes []string
|
||||
}{}
|
||||
if err := tok.Claims(sharedKey, &out, &out2); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("iss: %s, sub: %s, scopes: %s\n", out.Issuer, out.Subject, strings.Join(out2.Scopes, ","))
|
||||
// Output: iss: issuer, sub: subject, scopes: foo,bar
|
||||
}
|
||||
|
||||
func mustUnmarshalRSA(data string) *rsa.PrivateKey {
|
||||
block, _ := pem.Decode([]byte(data))
|
||||
if block == nil {
|
||||
panic("failed to decode PEM data")
|
||||
}
|
||||
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic("failed to parse RSA key: " + err.Error())
|
||||
}
|
||||
if key, ok := key.(*rsa.PrivateKey); ok {
|
||||
return key
|
||||
}
|
||||
panic("key is not of type *rsa.PrivateKey")
|
||||
}
|
||||
|
||||
func mustMakeSigner(alg jose.SignatureAlgorithm, k interface{}) jose.Signer {
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: alg, Key: k}, nil)
|
||||
if err != nil {
|
||||
panic("failed to create signer:" + err.Error())
|
||||
}
|
||||
|
||||
return sig
|
||||
}
|
||||
|
||||
var rsaPrivKey = mustUnmarshalRSA(`-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIHBvDHAr7jh8h
|
||||
xaqBCl11fjI9YZtdC5b3HtXTXZW3c2dIOImNUjffT8POP6p5OpzivmC1om7iOyuZ
|
||||
3nJjC9LT3zqqs3f2i5d4mImxEuqG6uWdryFfkp0uIv5VkjVO+iQWd6pDAPGP7r1Z
|
||||
foXCleyCtmyNH4JSkJneNPOk/4BxO8vcvRnCMT/Gv81IT6H+OQ6OovWOuJr8RX9t
|
||||
1wuCjC9ezZxeI9ONffhiO5FMrVh5H9LJTl3dPOVa4aEcOvgd45hBmvxAyXqf8daE
|
||||
6Kl2O7vQ4uwgnSTVXYIIjCjbepuersApIMGx/XPSgiU1K3Xtah/TBvep+S3VlwPc
|
||||
q/QH25S9AgMBAAECggEAe+y8XKYfPw4SxY1uPB+5JSwT3ON3nbWxtjSIYy9Pqp5z
|
||||
Vcx9kuFZ7JevQSk4X38m7VzM8282kC/ono+d8yy9Uayq3k/qeOqV0X9Vti1qxEbw
|
||||
ECkG1/MqGApfy4qSLOjINInDDV+mOWa2KJgsKgdCwuhKbVMYGB2ozG2qfYIlfvlY
|
||||
vLcBEpGWmswJHNmkcjTtGFIyJgPbsI6ndkkOeQbqQKAaadXtG1xUzH+vIvqaUl/l
|
||||
AkNf+p4qhPkHsoAWXf1qu9cYa2T8T+mEo79AwlgVC6awXQWNRTiyClDJC7cu6NBy
|
||||
ZHXCLFMbalzWF9qeI2OPaFX2x3IBWrbyDxcJ4TSdQQKBgQD/Fp/uQonMBh1h4Vi4
|
||||
HlxZdqSOArTitXValdLFGVJ23MngTGV/St4WH6eRp4ICfPyldsfcv6MZpNwNm1Rn
|
||||
lB5Gtpqpby1dsrOSfvVbY7U3vpLnd8+hJ/lT5zCYt5Eor46N6iWRkYWzNe4PixiF
|
||||
z1puGUvFCbZdeeACVrPLmW3JKQKBgQDI0y9WTf8ezKPbtap4UEE6yBf49ftohVGz
|
||||
p4iD6Ng1uqePwKahwoVXKOc179CjGGtW/UUBORAoKRmxdHajHq6LJgsBxpaARz21
|
||||
COPy99BUyp9ER5P8vYn63lC7Cpd/K7uyMjaz1DAzYBZIeVZHIw8O9wuGNJKjRFy9
|
||||
SZyD3V0ddQKBgFMdohrWH2QVEfnUnT3Q1rJn0BJdm2bLTWOosbZ7G72TD0xAWEnz
|
||||
sQ1wXv88n0YER6X6YADziEdQykq8s/HT91F/KkHO8e83zP8M0xFmGaQCOoelKEgQ
|
||||
aFMIX3NDTM7+9OoUwwz9Z50PE3SJFAJ1n7eEEoYvNfabQXxBl+/dHEKRAoGAPEvU
|
||||
EaiXacrtg8EWrssB2sFLGU/ZrTciIbuybFCT4gXp22pvXXAHEvVP/kzDqsRhLhwb
|
||||
BNP6OuSkNziNikpjA5pngZ/7fgZly54gusmW/m5bxWdsUl0iOXVYbeAvPlqGH2me
|
||||
LP4Pfs1hw17S/cbT9Z1NE31jbavP4HFikeD73SUCgYEArQfuudml6ei7XZ1Emjq8
|
||||
jZiD+fX6e6BD/ISatVnuyZmGj9wPFsEhY2BpLiAMQHMDIvH9nlKzsFvjkTPB86qG
|
||||
jCh3D67Os8eSBk5uRC6iW3Fc4DXvB5EFS0W9/15Sl+V5vXAcrNMpYS82OTSMG2Gt
|
||||
b9Ym/nxaqyTu0PxajXkKm5Q=
|
||||
-----END PRIVATE KEY-----`)
|
||||
|
||||
var rsaSigner = mustMakeSigner(jose.RS256, rsaPrivKey)
|
||||
113
vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go
generated
vendored
Normal file
113
vendor/gopkg.in/square/go-jose.v2/jwt/jwt.go
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"gopkg.in/square/go-jose.v2/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JSONWebToken represents a JSON Web Token (as specified in RFC7519).
|
||||
type JSONWebToken struct {
|
||||
payload func(k interface{}) ([]byte, error)
|
||||
Headers []jose.Header
|
||||
}
|
||||
|
||||
type NestedJSONWebToken struct {
|
||||
enc *jose.JSONWebEncryption
|
||||
Headers []jose.Header
|
||||
}
|
||||
|
||||
// Claims deserializes a JSONWebToken into dest using the provided key.
|
||||
func (t *JSONWebToken) Claims(key interface{}, dest ...interface{}) error {
|
||||
b, err := t.payload(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range dest {
|
||||
if err := json.Unmarshal(b, d); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *NestedJSONWebToken) Decrypt(decryptionKey interface{}) (*JSONWebToken, error) {
|
||||
b, err := t.enc.Decrypt(decryptionKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := ParseSigned(string(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
// ParseSigned parses token from JWS form.
|
||||
func ParseSigned(s string) (*JSONWebToken, error) {
|
||||
sig, err := jose.ParseSigned(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
headers := make([]jose.Header, len(sig.Signatures))
|
||||
for i, signature := range sig.Signatures {
|
||||
headers[i] = signature.Header
|
||||
}
|
||||
|
||||
return &JSONWebToken{
|
||||
payload: sig.Verify,
|
||||
Headers: headers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseEncrypted parses token from JWE form.
|
||||
func ParseEncrypted(s string) (*JSONWebToken, error) {
|
||||
enc, err := jose.ParseEncrypted(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &JSONWebToken{
|
||||
payload: enc.Decrypt,
|
||||
Headers: []jose.Header{enc.Header},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseSignedAndEncrypted parses signed-then-encrypted token from JWE form.
|
||||
func ParseSignedAndEncrypted(s string) (*NestedJSONWebToken, error) {
|
||||
enc, err := jose.ParseEncrypted(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contentType, _ := enc.Header.ExtraHeaders[jose.HeaderContentType].(string)
|
||||
if strings.ToUpper(contentType) != "JWT" {
|
||||
return nil, ErrInvalidContentType
|
||||
}
|
||||
|
||||
return &NestedJSONWebToken{
|
||||
enc: enc,
|
||||
Headers: []jose.Header{enc.Header},
|
||||
}, nil
|
||||
}
|
||||
137
vendor/gopkg.in/square/go-jose.v2/jwt/jwt_test.go
generated
vendored
Normal file
137
vendor/gopkg.in/square/go-jose.v2/jwt/jwt_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
hmacSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0.Y6_PfQHrzRJ_Vlxij5VI07-pgDIuJNN3Z_g5sSaGQ0c`
|
||||
rsaSignedToken = `eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJzY29wZXMiOlsiczEiLCJzMiJdLCJzdWIiOiJzdWJqZWN0In0.UDDtyK9gC9kyHltcP7E_XODsnqcJWZIiXeGmSAH7SE9YKy3N0KSfFIN85dCNjTfs6zvy4rkrCHzLB7uKAtzMearh3q7jL4nxbhUMhlUcs_9QDVoN4q_j58XmRqBqRnBk-RmDu9TgcV8RbErP4awpIhwWb5UU-hR__4_iNbHdKqwSUPDKYGlf5eicuiYrPxH8mxivk4LRD-vyRdBZZKBt0XIDnEU4TdcNCzAXojkftqcFWYsczwS8R4JHd1qYsMyiaWl4trdHZkO4QkeLe34z4ZAaPMt3wE-gcU-VoqYTGxz-K3Le2VaZ0r3j_z6bOInsv0yngC_cD1dCXMyQJWnWjQ`
|
||||
invalidPayloadSignedToken = `eyJhbGciOiJIUzI1NiJ9.aW52YWxpZC1wYXlsb2Fk.ScBKKm18jcaMLGYDNRUqB5gVMRZl4DM6dh3ShcxeNgY`
|
||||
invalidPartsSignedToken = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaXNzIjoiaXNzdWVyIiwic2NvcGVzIjpbInMxIiwiczIiXX0`
|
||||
hmacEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4.1-zuiZ4RbHrTTUoA8Dvfhg`
|
||||
rsaEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.IvkVHHiI8JwwavvTR80xGjYvkzubMrZ-TDDx8k8SNJMEylfFfNUc7F2rC3WAABF_xmJ3SW2A6on-S6EAG97k0RsjqHHNqZuaFpDvjeuLqZFfYKzI45aCtkGG4C2ij2GbeySqJ784CcvFJPUWJ-6VPN2Ho2nhefUSqig0jE2IvOKy1ywTj_VBVBxF_dyXFnXwxPKGUQr3apxrWeRJfDh2Cf8YPBlLiRznjfBfwgePB1jP7WCZNwItj10L7hsT_YWEx01XJcbxHaXFLwKyVzwWaDhreFyaWMRbGqEfqVuOT34zfmhLDhQlgLLwkXrvYqX90NsQ9Ftg0LLIfRMbsfdgug.BFy2Tj1RZN8yq2Lk-kMiZQ.9Z0eOyPiv5cEzmXh64RlAQ36Uvz0WpZgqRcc2_69zHTmUOv0Vnl1I6ks8sTraUEvukAilolNBjBj47s0b4b-Og.VM8-eJg5ZsqnTqs0LtGX_Q`
|
||||
invalidPayloadEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..T4jCS4Yyw1GCH0aW.y4gFaMITdBs_QZM8RKrL.6MPyk1cMVaOJFoNGlEuaRQ`
|
||||
invalidPartsEncryptedToken = `eyJhbGciOiJkaXIiLCJlbmMiOiJBMTI4R0NNIn0..NZrU98U4QNO0y-u6.HSq5CvlmkUT1BPqLGZ4`
|
||||
signedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiY3R5IjoiSldUIn0.icnR7M1HSgMDaUnJhfzT5nLmT0eRPeNsKPkioNcyq9TZsm-LgbE7wZkNFGfQqYwvbmrZ3UpOhNkrq4n2KN3N1dtjH9TVxzfMxz2OMh0dRWUNMi58EMadhmIpH3PLyyaeDyd0dyHpOIRPFTAoOdn2GoO_flV5CvPMhgdVKYB3h3vQW-ZZDu4cOZwXAjTuThdoUZCNWFhJhXyj-PrKLyVpX6rE1o4X05IS8008SLZyx-PZlsUPyLs6CJi7Z4PzZRzOJTV00a-7UOi-fBKBZV5V8eRpWuzJ673pMALlRCBzrRin-JeEA_QnAejtMAHG7RSGP60easQN4I-0jLTQNNNynw.oFrO-5ZgRrnWmbkPsbyMiQ.BVaWUzlrdfhe0otPJpb3DGoDCT6-BOmN_Pgq5NOqVFYIAwG5pM4pf7TaiPUJeQLf0phbLgpT4RfJ20Zhwfc2MH5unCqc8TZEP2dOrYRhb8o-X57x6IQppIDbjK2i_CAWf3yF5JUB7qRqOizpKZTh3HFTVEglY3WF8tAJ8KpnatTUmwcnqlyjdBFvYu4usiyvc_u9wNbXx5-lFt0slQYleHQMUirBprKyswIBjMoFJEe7kDvU_MCKI4NI9_fSfWJpaUdNxQEvRYR1PV4ZQdwBY0X9u2n2QH5iVQMrmgmQ5hPbWxwRv1-7jXBMPBpGeFQZHeEtSwif1_Umwyt8cDyRChb3OM7XQ3eY0UJRrbmvhcLWIcMp8FpblDaBinbjD6qIVXZVmaAdIbi2a_HblfoeL3-UABb82AAxOqQcAFjDEDTR2TFalDXSwgPZrAaQ_Mql3eFe9r2y0UVkgG7XYF4ik8sSK48CkZPUvkZFr-K9QMq-RZLzT3Zw0edxNaKgje27S26H9qClh6CCr9nk38AZZ76_Xz7f-Fil5xI0Dq95UzvwW__U3JJWE6OVUVx_RVJgdOJn8_B7hluckwBLUblscA.83pPXNnH0sKgHvFboiJVDA`
|
||||
invalidSignedAndEncryptedToken = `eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.QKYu3DkFEXBUa2U0Sgtm-e44BMuaFVbMu2T-GB3qEGONrmOuaB5BtNCvBUnuj6HR0v6u-tvawToRSzExQQLFTvPcLiQR8iclWirqAFUqLrg8kRU3qIRLkmErYeGIfCML1jq9ofKg0DI5-YrU5RSyUg9cwfXKEx8KNwFcjeVeDZwWEACdU8xBnQp57rNfr0Tj-dPnGKID7LU5ZV0vhK90FpEG7UqOeSHFmvONQyz6Ca-ZkE8X2swqGad-q5xl8f9pApdFqHzADox5OlgtxPkr-Khkm6WGfvf1K_e-iW5LYtvWIAjNByft2TexsNcYpdAO2oNAgh2nkhoohl-zCWU-og.UAU65JWKqvHZ_Z0V-xLyjQ.M6sQ4lAzKFelSmL6C6uoK00rB8IFCAK-eJ0iByGhtg8eYtmSBFsP_oUySfKPtxcPRkQ7YxnEX5D-DOo20wCV7il2Be9No__0R6_5heISOMXcKmKP3D6pFusaPisNGOgLw8SKXBuVpe20PvOJ9RgOXRKucSR2UMINXtqIn9RdxbKOlBBmMJhnX4TeQ00fRILng2sMbUHsWExSthQODHGx6VcwLFp-Aqmsnv2q2KkLpA8sEm48AHHFQXSGtlVGVgWKi3dOQYUnDJW4P64Xxr1Uq3yT7w_dRwK4BA7l3Biecj5dwkKrFMJ_RaCt-ED_R15zpxg6PmnXeeJnif58Fai40ZWOsGvLZNYwL1jbi-TrsargpdUQedfzuTk8Na2NkCzFNg2BYXVDHJ_WAX1daVyhvunaURwAlBatAcmnOGxWebwV1xQoQ7iHg6ZGohCannn_pqGwJlMHMgnCcnCIhwfj9uL9Ejz_TVceZNMlT1KvLRafVfxGhkp48bdnd8OcXmjT9pQzZUB3OqrstWKhbItZ1xMpy6dZ54ldWvtTTyQ4tQJaVWgXERUM1erDT6Ypyl15-fumOB9MRcgMG3NDblKowA.P9WTBITvVUgrLjX6bS0opQ`
|
||||
)
|
||||
|
||||
type customClaims struct {
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
}
|
||||
|
||||
func TestDecodeToken(t *testing.T) {
|
||||
tok, err := ParseSigned(hmacSignedToken)
|
||||
if assert.NoError(t, err, "Error parsing signed token.") {
|
||||
c := &Claims{}
|
||||
c2 := &customClaims{}
|
||||
if assert.NoError(t, tok.Claims(sharedKey, c, c2)) {
|
||||
assert.Equal(t, "subject", c.Subject)
|
||||
assert.Equal(t, "issuer", c.Issuer)
|
||||
assert.Equal(t, []string{"s1", "s2"}, c2.Scopes)
|
||||
}
|
||||
}
|
||||
assert.EqualError(t, tok.Claims([]byte("invalid-secret")), "square/go-jose: error in cryptographic primitive")
|
||||
|
||||
tok2, err := ParseSigned(rsaSignedToken)
|
||||
if assert.NoError(t, err, "Error parsing encrypted token.") {
|
||||
c := make(map[string]interface{})
|
||||
if assert.NoError(t, tok2.Claims(&testPrivRSAKey1.PublicKey, &c)) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"sub": "subject",
|
||||
"iss": "issuer",
|
||||
"scopes": []interface{}{"s1", "s2"},
|
||||
}, c)
|
||||
}
|
||||
}
|
||||
assert.EqualError(t, tok.Claims(&testPrivRSAKey2.PublicKey), "square/go-jose: error in cryptographic primitive")
|
||||
|
||||
tok3, err := ParseSigned(invalidPayloadSignedToken)
|
||||
if assert.NoError(t, err, "Error parsing signed token.") {
|
||||
assert.Error(t, tok3.Claims(sharedKey, &Claims{}), "Expected unmarshaling claims to fail.")
|
||||
}
|
||||
|
||||
_, err = ParseSigned(invalidPartsSignedToken)
|
||||
assert.EqualError(t, err, "square/go-jose: compact JWS format must have three parts")
|
||||
|
||||
tok4, err := ParseEncrypted(hmacEncryptedToken)
|
||||
if assert.NoError(t, err, "Error parsing encrypted token.") {
|
||||
c := Claims{}
|
||||
if assert.NoError(t, tok4.Claims(sharedEncryptionKey, &c)) {
|
||||
assert.Equal(t, "foo", c.Subject)
|
||||
}
|
||||
}
|
||||
assert.EqualError(t, tok4.Claims([]byte("invalid-secret-key")), "square/go-jose: error in cryptographic primitive")
|
||||
|
||||
tok5, err := ParseEncrypted(rsaEncryptedToken)
|
||||
if assert.NoError(t, err, "Error parsing encrypted token.") {
|
||||
c := make(map[string]interface{})
|
||||
if assert.NoError(t, tok5.Claims(testPrivRSAKey1, &c)) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"sub": "subject",
|
||||
"iss": "issuer",
|
||||
"scopes": []interface{}{"s1", "s2"},
|
||||
}, c)
|
||||
}
|
||||
}
|
||||
assert.EqualError(t, tok5.Claims(testPrivRSAKey2), "square/go-jose: error in cryptographic primitive")
|
||||
|
||||
tok6, err := ParseEncrypted(invalidPayloadEncryptedToken)
|
||||
if assert.NoError(t, err, "Error parsing encrypted token.") {
|
||||
assert.Error(t, tok6.Claims(sharedEncryptionKey, &Claims{}))
|
||||
}
|
||||
|
||||
_, err = ParseEncrypted(invalidPartsEncryptedToken)
|
||||
assert.EqualError(t, err, "square/go-jose: compact JWE format must have five parts")
|
||||
|
||||
tok7, err := ParseSignedAndEncrypted(signedAndEncryptedToken)
|
||||
if assert.NoError(t, err, "Error parsing signed-then-encrypted token.") {
|
||||
c := make(map[string]interface{})
|
||||
if nested, err := tok7.Decrypt(testPrivRSAKey1); assert.NoError(t, err) {
|
||||
assert.NoError(t, nested.Claims(testPrivRSAKey1.Public(), &c))
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"sub": "subject",
|
||||
"iss": "issuer",
|
||||
"scopes": []interface{}{"s1", "s2"},
|
||||
}, c)
|
||||
assert.EqualError(t, nested.Claims(testPrivRSAKey2.Public()), "square/go-jose: error in cryptographic primitive")
|
||||
}
|
||||
}
|
||||
_, err = tok7.Decrypt(testPrivRSAKey2)
|
||||
assert.EqualError(t, err, "square/go-jose: error in cryptographic primitive")
|
||||
|
||||
_, err = ParseSignedAndEncrypted(invalidSignedAndEncryptedToken)
|
||||
assert.EqualError(t, err, "square/go-jose/jwt: expected content type to be JWT (cty header)")
|
||||
}
|
||||
|
||||
func BenchmarkDecodeSignedToken(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
ParseSigned(hmacSignedToken)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecodeEncryptedHMACToken(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
ParseEncrypted(hmacEncryptedToken)
|
||||
}
|
||||
}
|
||||
89
vendor/gopkg.in/square/go-jose.v2/jwt/validation.go
generated
vendored
Normal file
89
vendor/gopkg.in/square/go-jose.v2/jwt/validation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
// DefaultLeeway defines the default leeway for matching NotBefore/Expiry claims.
|
||||
DefaultLeeway = 1.0 * time.Minute
|
||||
)
|
||||
|
||||
// Expected defines values used for protected claims validation.
|
||||
// If field has zero value then validation is skipped.
|
||||
type Expected struct {
|
||||
// Issuer matches the "iss" claim exactly.
|
||||
Issuer string
|
||||
// Subject matches the "sub" claim exactly.
|
||||
Subject string
|
||||
// Audience matches the values in "aud" claim, regardless of their order.
|
||||
Audience Audience
|
||||
// ID matches the "jti" claim exactly.
|
||||
ID string
|
||||
// Time matches the "exp" and "ebf" claims with leeway.
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// WithTime copies expectations with new time.
|
||||
func (e Expected) WithTime(t time.Time) Expected {
|
||||
e.Time = t
|
||||
return e
|
||||
}
|
||||
|
||||
// Validate checks claims in a token against expected values.
|
||||
// A default leeway value of one minute is used to compare time values.
|
||||
func (c Claims) Validate(e Expected) error {
|
||||
return c.ValidateWithLeeway(e, DefaultLeeway)
|
||||
}
|
||||
|
||||
// ValidateWithLeeway checks claims in a token against expected values. A
|
||||
// custom leeway may be specified for comparing time values. You may pass a
|
||||
// zero value to check time values with no leeway, but you should not that
|
||||
// numeric date values are rounded to the nearest second and sub-second
|
||||
// precision is not supported.
|
||||
func (c Claims) ValidateWithLeeway(e Expected, leeway time.Duration) error {
|
||||
if e.Issuer != "" && e.Issuer != c.Issuer {
|
||||
return ErrInvalidIssuer
|
||||
}
|
||||
|
||||
if e.Subject != "" && e.Subject != c.Subject {
|
||||
return ErrInvalidSubject
|
||||
}
|
||||
|
||||
if e.ID != "" && e.ID != c.ID {
|
||||
return ErrInvalidID
|
||||
}
|
||||
|
||||
if len(e.Audience) != 0 {
|
||||
for _, v := range e.Audience {
|
||||
if !c.Audience.Contains(v) {
|
||||
return ErrInvalidAudience
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !e.Time.IsZero() && e.Time.Add(leeway).Before(c.NotBefore.Time()) {
|
||||
return ErrNotValidYet
|
||||
}
|
||||
|
||||
if !e.Time.IsZero() && e.Time.Add(-leeway).After(c.Expiry.Time()) {
|
||||
return ErrExpired
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
92
vendor/gopkg.in/square/go-jose.v2/jwt/validation_test.go
generated
vendored
Normal file
92
vendor/gopkg.in/square/go-jose.v2/jwt/validation_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*-
|
||||
* Copyright 2016 Zbigniew Mandziejewicz
|
||||
* Copyright 2016 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFieldsMatch(t *testing.T) {
|
||||
c := Claims{
|
||||
Issuer: "issuer",
|
||||
Subject: "subject",
|
||||
Audience: []string{"a1", "a2"},
|
||||
ID: "42",
|
||||
}
|
||||
|
||||
valid := []Expected{
|
||||
{Issuer: "issuer"},
|
||||
{Subject: "subject"},
|
||||
{Audience: Audience{"a1", "a2"}},
|
||||
{Audience: Audience{"a2", "a1"}},
|
||||
{ID: "42"},
|
||||
}
|
||||
|
||||
for _, v := range valid {
|
||||
assert.NoError(t, c.Validate(v))
|
||||
}
|
||||
|
||||
invalid := []struct {
|
||||
Expected Expected
|
||||
Error error
|
||||
}{
|
||||
{Expected{Issuer: "invalid-issuer"}, ErrInvalidIssuer},
|
||||
{Expected{Subject: "invalid-subject"}, ErrInvalidSubject},
|
||||
{Expected{Audience: Audience{"invalid-audience"}}, ErrInvalidAudience},
|
||||
{Expected{ID: "invalid-id"}, ErrInvalidID},
|
||||
}
|
||||
|
||||
for _, v := range invalid {
|
||||
assert.Equal(t, v.Error, c.Validate(v.Expected))
|
||||
}
|
||||
}
|
||||
|
||||
func TestExpiryAndNotBefore(t *testing.T) {
|
||||
now := time.Date(2016, 1, 1, 12, 0, 0, 0, time.UTC)
|
||||
twelveHoursAgo := now.Add(-12 * time.Hour)
|
||||
|
||||
c := Claims{
|
||||
IssuedAt: NewNumericDate(twelveHoursAgo),
|
||||
NotBefore: NewNumericDate(twelveHoursAgo),
|
||||
Expiry: NewNumericDate(now),
|
||||
}
|
||||
|
||||
// expired - default leeway (1 minute)
|
||||
assert.NoError(t, c.Validate(Expected{Time: now}))
|
||||
err := c.Validate(Expected{Time: now.Add(2 * DefaultLeeway)})
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, err, ErrExpired)
|
||||
}
|
||||
|
||||
// expired - no leeway
|
||||
assert.NoError(t, c.ValidateWithLeeway(Expected{Time: now}, 0))
|
||||
err = c.ValidateWithLeeway(Expected{Time: now.Add(1 * time.Second)}, 0)
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, err, ErrExpired)
|
||||
}
|
||||
|
||||
// not before - default leeway (1 minute)
|
||||
assert.NoError(t, c.Validate(Expected{Time: twelveHoursAgo}))
|
||||
err = c.Validate(Expected{Time: twelveHoursAgo.Add(-2 * DefaultLeeway)})
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, err, ErrNotValidYet)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue