vendor: revendor
This commit is contained in:
126
vendor/github.com/coreos/go-oidc/jose/claims.go
generated
vendored
Normal file
126
vendor/github.com/coreos/go-oidc/jose/claims.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Claims map[string]interface{}
|
||||
|
||||
func (c Claims) Add(name string, value interface{}) {
|
||||
c[name] = value
|
||||
}
|
||||
|
||||
func (c Claims) StringClaim(name string) (string, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
v, ok := cl.(string)
|
||||
if !ok {
|
||||
return "", false, fmt.Errorf("unable to parse claim as string: %v", name)
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
func (c Claims) StringsClaim(name string) ([]string, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
if v, ok := cl.([]string); ok {
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
// When unmarshaled, []string will become []interface{}.
|
||||
if v, ok := cl.([]interface{}); ok {
|
||||
var ret []string
|
||||
for _, vv := range v {
|
||||
str, ok := vv.(string)
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name)
|
||||
}
|
||||
ret = append(ret, str)
|
||||
}
|
||||
return ret, true, nil
|
||||
}
|
||||
|
||||
return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name)
|
||||
}
|
||||
|
||||
func (c Claims) Int64Claim(name string) (int64, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
v, ok := cl.(int64)
|
||||
if !ok {
|
||||
vf, ok := cl.(float64)
|
||||
if !ok {
|
||||
return 0, false, fmt.Errorf("unable to parse claim as int64: %v", name)
|
||||
}
|
||||
v = int64(vf)
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
func (c Claims) Float64Claim(name string) (float64, bool, error) {
|
||||
cl, ok := c[name]
|
||||
if !ok {
|
||||
return 0, false, nil
|
||||
}
|
||||
|
||||
v, ok := cl.(float64)
|
||||
if !ok {
|
||||
vi, ok := cl.(int64)
|
||||
if !ok {
|
||||
return 0, false, fmt.Errorf("unable to parse claim as float64: %v", name)
|
||||
}
|
||||
v = float64(vi)
|
||||
}
|
||||
|
||||
return v, true, nil
|
||||
}
|
||||
|
||||
func (c Claims) TimeClaim(name string) (time.Time, bool, error) {
|
||||
v, ok, err := c.Float64Claim(name)
|
||||
if !ok || err != nil {
|
||||
return time.Time{}, ok, err
|
||||
}
|
||||
|
||||
s := math.Trunc(v)
|
||||
ns := (v - s) * math.Pow(10, 9)
|
||||
return time.Unix(int64(s), int64(ns)).UTC(), true, nil
|
||||
}
|
||||
|
||||
func decodeClaims(payload []byte) (Claims, error) {
|
||||
var c Claims
|
||||
if err := json.Unmarshal(payload, &c); err != nil {
|
||||
return nil, fmt.Errorf("malformed JWT claims, unable to decode: %v", err)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func marshalClaims(c Claims) ([]byte, error) {
|
||||
b, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func encodeClaims(c Claims) (string, error) {
|
||||
b, err := marshalClaims(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encodeSegment(b), nil
|
||||
}
|
328
vendor/github.com/coreos/go-oidc/jose/claims_test.go
generated
vendored
Normal file
328
vendor/github.com/coreos/go-oidc/jose/claims_test.go
generated
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
tests := []struct {
|
||||
cl Claims
|
||||
key string
|
||||
ok bool
|
||||
err bool
|
||||
val string
|
||||
}{
|
||||
// ok, no err, claim exists
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": "bar",
|
||||
},
|
||||
key: "foo",
|
||||
val: "bar",
|
||||
ok: true,
|
||||
err: false,
|
||||
},
|
||||
// no claims
|
||||
{
|
||||
cl: Claims{},
|
||||
key: "foo",
|
||||
val: "",
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// missing claim
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": "bar",
|
||||
},
|
||||
key: "xxx",
|
||||
val: "",
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// unparsable: type
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": struct{}{},
|
||||
},
|
||||
key: "foo",
|
||||
val: "",
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
// unparsable: nil value
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": nil,
|
||||
},
|
||||
key: "foo",
|
||||
val: "",
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
val, ok, err := tt.cl.StringClaim(tt.key)
|
||||
|
||||
if tt.err && err == nil {
|
||||
t.Errorf("case %d: want err=non-nil, got err=nil", i)
|
||||
} else if !tt.err && err != nil {
|
||||
t.Errorf("case %d: want err=nil, got err=%v", i, err)
|
||||
}
|
||||
|
||||
if tt.ok != ok {
|
||||
t.Errorf("case %d: want ok=%v, got ok=%v", i, tt.ok, ok)
|
||||
}
|
||||
|
||||
if tt.val != val {
|
||||
t.Errorf("case %d: want val=%v, got val=%v", i, tt.val, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64(t *testing.T) {
|
||||
tests := []struct {
|
||||
cl Claims
|
||||
key string
|
||||
ok bool
|
||||
err bool
|
||||
val int64
|
||||
}{
|
||||
// ok, no err, claim exists
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": int64(100),
|
||||
},
|
||||
key: "foo",
|
||||
val: int64(100),
|
||||
ok: true,
|
||||
err: false,
|
||||
},
|
||||
// no claims
|
||||
{
|
||||
cl: Claims{},
|
||||
key: "foo",
|
||||
val: 0,
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// missing claim
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": "bar",
|
||||
},
|
||||
key: "xxx",
|
||||
val: 0,
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// unparsable: type
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": struct{}{},
|
||||
},
|
||||
key: "foo",
|
||||
val: 0,
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
// unparsable: nil value
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": nil,
|
||||
},
|
||||
key: "foo",
|
||||
val: 0,
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
val, ok, err := tt.cl.Int64Claim(tt.key)
|
||||
|
||||
if tt.err && err == nil {
|
||||
t.Errorf("case %d: want err=non-nil, got err=nil", i)
|
||||
} else if !tt.err && err != nil {
|
||||
t.Errorf("case %d: want err=nil, got err=%v", i, err)
|
||||
}
|
||||
|
||||
if tt.ok != ok {
|
||||
t.Errorf("case %d: want ok=%v, got ok=%v", i, tt.ok, ok)
|
||||
}
|
||||
|
||||
if tt.val != val {
|
||||
t.Errorf("case %d: want val=%v, got val=%v", i, tt.val, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTime(t *testing.T) {
|
||||
now := time.Now().UTC()
|
||||
unixNow := now.Unix()
|
||||
|
||||
tests := []struct {
|
||||
cl Claims
|
||||
key string
|
||||
ok bool
|
||||
err bool
|
||||
val time.Time
|
||||
}{
|
||||
// ok, no err, claim exists
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": unixNow,
|
||||
},
|
||||
key: "foo",
|
||||
val: time.Unix(now.Unix(), 0).UTC(),
|
||||
ok: true,
|
||||
err: false,
|
||||
},
|
||||
// no claims
|
||||
{
|
||||
cl: Claims{},
|
||||
key: "foo",
|
||||
val: time.Time{},
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// missing claim
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": "bar",
|
||||
},
|
||||
key: "xxx",
|
||||
val: time.Time{},
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// unparsable: type
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": struct{}{},
|
||||
},
|
||||
key: "foo",
|
||||
val: time.Time{},
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
// unparsable: nil value
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": nil,
|
||||
},
|
||||
key: "foo",
|
||||
val: time.Time{},
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
val, ok, err := tt.cl.TimeClaim(tt.key)
|
||||
|
||||
if tt.err && err == nil {
|
||||
t.Errorf("case %d: want err=non-nil, got err=nil", i)
|
||||
} else if !tt.err && err != nil {
|
||||
t.Errorf("case %d: want err=nil, got err=%v", i, err)
|
||||
}
|
||||
|
||||
if tt.ok != ok {
|
||||
t.Errorf("case %d: want ok=%v, got ok=%v", i, tt.ok, ok)
|
||||
}
|
||||
|
||||
if tt.val != val {
|
||||
t.Errorf("case %d: want val=%v, got val=%v", i, tt.val, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArray(t *testing.T) {
|
||||
tests := []struct {
|
||||
cl Claims
|
||||
key string
|
||||
ok bool
|
||||
err bool
|
||||
val []string
|
||||
}{
|
||||
// ok, no err, claim exists
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": []string{"bar", "faf"},
|
||||
},
|
||||
key: "foo",
|
||||
val: []string{"bar", "faf"},
|
||||
ok: true,
|
||||
err: false,
|
||||
},
|
||||
// ok, no err, []interface{}
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": []interface{}{"bar", "faf"},
|
||||
},
|
||||
key: "foo",
|
||||
val: []string{"bar", "faf"},
|
||||
ok: true,
|
||||
err: false,
|
||||
},
|
||||
// no claims
|
||||
{
|
||||
cl: Claims{},
|
||||
key: "foo",
|
||||
val: nil,
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// missing claim
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": "bar",
|
||||
},
|
||||
key: "xxx",
|
||||
val: nil,
|
||||
ok: false,
|
||||
err: false,
|
||||
},
|
||||
// unparsable: type
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": struct{}{},
|
||||
},
|
||||
key: "foo",
|
||||
val: nil,
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
// unparsable: nil value
|
||||
{
|
||||
cl: Claims{
|
||||
"foo": nil,
|
||||
},
|
||||
key: "foo",
|
||||
val: nil,
|
||||
ok: false,
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
val, ok, err := tt.cl.StringsClaim(tt.key)
|
||||
|
||||
if tt.err && err == nil {
|
||||
t.Errorf("case %d: want err=non-nil, got err=nil", i)
|
||||
} else if !tt.err && err != nil {
|
||||
t.Errorf("case %d: want err=nil, got err=%v", i, err)
|
||||
}
|
||||
|
||||
if tt.ok != ok {
|
||||
t.Errorf("case %d: want ok=%v, got ok=%v", i, tt.ok, ok)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.val, val) {
|
||||
t.Errorf("case %d: want val=%v, got val=%v", i, tt.val, val)
|
||||
}
|
||||
}
|
||||
}
|
2
vendor/github.com/coreos/go-oidc/jose/doc.go
generated
vendored
Normal file
2
vendor/github.com/coreos/go-oidc/jose/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package jose is DEPRECATED. Use gopkg.in/square/go-jose.v2 instead.
|
||||
package jose
|
112
vendor/github.com/coreos/go-oidc/jose/jose.go
generated
vendored
Normal file
112
vendor/github.com/coreos/go-oidc/jose/jose.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
HeaderMediaType = "typ"
|
||||
HeaderKeyAlgorithm = "alg"
|
||||
HeaderKeyID = "kid"
|
||||
)
|
||||
|
||||
const (
|
||||
// Encryption Algorithm Header Parameter Values for JWS
|
||||
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-6
|
||||
AlgHS256 = "HS256"
|
||||
AlgHS384 = "HS384"
|
||||
AlgHS512 = "HS512"
|
||||
AlgRS256 = "RS256"
|
||||
AlgRS384 = "RS384"
|
||||
AlgRS512 = "RS512"
|
||||
AlgES256 = "ES256"
|
||||
AlgES384 = "ES384"
|
||||
AlgES512 = "ES512"
|
||||
AlgPS256 = "PS256"
|
||||
AlgPS384 = "PS384"
|
||||
AlgPS512 = "PS512"
|
||||
AlgNone = "none"
|
||||
)
|
||||
|
||||
const (
|
||||
// Algorithm Header Parameter Values for JWE
|
||||
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#section-4.1
|
||||
AlgRSA15 = "RSA1_5"
|
||||
AlgRSAOAEP = "RSA-OAEP"
|
||||
AlgRSAOAEP256 = "RSA-OAEP-256"
|
||||
AlgA128KW = "A128KW"
|
||||
AlgA192KW = "A192KW"
|
||||
AlgA256KW = "A256KW"
|
||||
AlgDir = "dir"
|
||||
AlgECDHES = "ECDH-ES"
|
||||
AlgECDHESA128KW = "ECDH-ES+A128KW"
|
||||
AlgECDHESA192KW = "ECDH-ES+A192KW"
|
||||
AlgECDHESA256KW = "ECDH-ES+A256KW"
|
||||
AlgA128GCMKW = "A128GCMKW"
|
||||
AlgA192GCMKW = "A192GCMKW"
|
||||
AlgA256GCMKW = "A256GCMKW"
|
||||
AlgPBES2HS256A128KW = "PBES2-HS256+A128KW"
|
||||
AlgPBES2HS384A192KW = "PBES2-HS384+A192KW"
|
||||
AlgPBES2HS512A256KW = "PBES2-HS512+A256KW"
|
||||
)
|
||||
|
||||
const (
|
||||
// Encryption Algorithm Header Parameter Values for JWE
|
||||
// See: https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40#page-22
|
||||
EncA128CBCHS256 = "A128CBC-HS256"
|
||||
EncA128CBCHS384 = "A128CBC-HS384"
|
||||
EncA256CBCHS512 = "A256CBC-HS512"
|
||||
EncA128GCM = "A128GCM"
|
||||
EncA192GCM = "A192GCM"
|
||||
EncA256GCM = "A256GCM"
|
||||
)
|
||||
|
||||
type JOSEHeader map[string]string
|
||||
|
||||
func (j JOSEHeader) Validate() error {
|
||||
if _, exists := j[HeaderKeyAlgorithm]; !exists {
|
||||
return fmt.Errorf("header missing %q parameter", HeaderKeyAlgorithm)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeHeader(seg string) (JOSEHeader, error) {
|
||||
b, err := decodeSegment(seg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var h JOSEHeader
|
||||
err = json.Unmarshal(b, &h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func encodeHeader(h JOSEHeader) (string, error) {
|
||||
b, err := json.Marshal(h)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return encodeSegment(b), nil
|
||||
}
|
||||
|
||||
// Decode JWT specific base64url encoding with padding stripped
|
||||
func decodeSegment(seg string) ([]byte, error) {
|
||||
if l := len(seg) % 4; l != 0 {
|
||||
seg += strings.Repeat("=", 4-l)
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(seg)
|
||||
}
|
||||
|
||||
// Encode JWT specific base64url encoding with padding stripped
|
||||
func encodeSegment(seg []byte) string {
|
||||
return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
|
||||
}
|
135
vendor/github.com/coreos/go-oidc/jose/jwk.go
generated
vendored
Normal file
135
vendor/github.com/coreos/go-oidc/jose/jwk.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JSON Web Key
|
||||
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-36#page-5
|
||||
type JWK struct {
|
||||
ID string
|
||||
Type string
|
||||
Alg string
|
||||
Use string
|
||||
Exponent int
|
||||
Modulus *big.Int
|
||||
Secret []byte
|
||||
}
|
||||
|
||||
type jwkJSON struct {
|
||||
ID string `json:"kid"`
|
||||
Type string `json:"kty"`
|
||||
Alg string `json:"alg"`
|
||||
Use string `json:"use"`
|
||||
Exponent string `json:"e"`
|
||||
Modulus string `json:"n"`
|
||||
}
|
||||
|
||||
func (j *JWK) MarshalJSON() ([]byte, error) {
|
||||
t := jwkJSON{
|
||||
ID: j.ID,
|
||||
Type: j.Type,
|
||||
Alg: j.Alg,
|
||||
Use: j.Use,
|
||||
Exponent: encodeExponent(j.Exponent),
|
||||
Modulus: encodeModulus(j.Modulus),
|
||||
}
|
||||
|
||||
return json.Marshal(&t)
|
||||
}
|
||||
|
||||
func (j *JWK) UnmarshalJSON(data []byte) error {
|
||||
var t jwkJSON
|
||||
err := json.Unmarshal(data, &t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e, err := decodeExponent(t.Exponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := decodeModulus(t.Modulus)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
j.ID = t.ID
|
||||
j.Type = t.Type
|
||||
j.Alg = t.Alg
|
||||
j.Use = t.Use
|
||||
j.Exponent = e
|
||||
j.Modulus = n
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type JWKSet struct {
|
||||
Keys []JWK `json:"keys"`
|
||||
}
|
||||
|
||||
func decodeExponent(e string) (int, error) {
|
||||
decE, err := decodeBase64URLPaddingOptional(e)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var eBytes []byte
|
||||
if len(decE) < 8 {
|
||||
eBytes = make([]byte, 8-len(decE), 8)
|
||||
eBytes = append(eBytes, decE...)
|
||||
} else {
|
||||
eBytes = decE
|
||||
}
|
||||
eReader := bytes.NewReader(eBytes)
|
||||
var E uint64
|
||||
err = binary.Read(eReader, binary.BigEndian, &E)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(E), nil
|
||||
}
|
||||
|
||||
func encodeExponent(e int) string {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, uint64(e))
|
||||
var idx int
|
||||
for ; idx < 8; idx++ {
|
||||
if b[idx] != 0x0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(b[idx:])
|
||||
}
|
||||
|
||||
// Turns a URL encoded modulus of a key into a big int.
|
||||
func decodeModulus(n string) (*big.Int, error) {
|
||||
decN, err := decodeBase64URLPaddingOptional(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
N := big.NewInt(0)
|
||||
N.SetBytes(decN)
|
||||
return N, nil
|
||||
}
|
||||
|
||||
func encodeModulus(n *big.Int) string {
|
||||
return base64.URLEncoding.EncodeToString(n.Bytes())
|
||||
}
|
||||
|
||||
// decodeBase64URLPaddingOptional decodes Base64 whether there is padding or not.
|
||||
// The stdlib version currently doesn't handle this.
|
||||
// We can get rid of this is if this bug:
|
||||
// https://github.com/golang/go/issues/4237
|
||||
// ever closes.
|
||||
func decodeBase64URLPaddingOptional(e string) ([]byte, error) {
|
||||
if m := len(e) % 4; m != 0 {
|
||||
e += strings.Repeat("=", 4-m)
|
||||
}
|
||||
return base64.URLEncoding.DecodeString(e)
|
||||
}
|
64
vendor/github.com/coreos/go-oidc/jose/jwk_test.go
generated
vendored
Normal file
64
vendor/github.com/coreos/go-oidc/jose/jwk_test.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeBase64URLPaddingOptional(t *testing.T) {
|
||||
tests := []struct {
|
||||
encoded string
|
||||
decoded string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
// With padding
|
||||
encoded: "VGVjdG9uaWM=",
|
||||
decoded: "Tectonic",
|
||||
},
|
||||
{
|
||||
// Without padding
|
||||
encoded: "VGVjdG9uaWM",
|
||||
decoded: "Tectonic",
|
||||
},
|
||||
{
|
||||
// Even More padding
|
||||
encoded: "VGVjdG9uaQ==",
|
||||
decoded: "Tectoni",
|
||||
},
|
||||
{
|
||||
// And take it away!
|
||||
encoded: "VGVjdG9uaQ",
|
||||
decoded: "Tectoni",
|
||||
},
|
||||
{
|
||||
// Too much padding.
|
||||
encoded: "VGVjdG9uaWNh=",
|
||||
decoded: "",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
// Too much padding.
|
||||
encoded: "VGVjdG9uaWNh=",
|
||||
decoded: "",
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
got, err := decodeBase64URLPaddingOptional(tt.encoded)
|
||||
if tt.err {
|
||||
if err == nil {
|
||||
t.Errorf("case %d: expected non-nil err", i)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("case %d: want nil err, got: %v", i, err)
|
||||
}
|
||||
|
||||
if string(got) != tt.decoded {
|
||||
t.Errorf("case %d: want=%q, got=%q", i, tt.decoded, got)
|
||||
}
|
||||
}
|
||||
}
|
51
vendor/github.com/coreos/go-oidc/jose/jws.go
generated
vendored
Normal file
51
vendor/github.com/coreos/go-oidc/jose/jws.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type JWS struct {
|
||||
RawHeader string
|
||||
Header JOSEHeader
|
||||
RawPayload string
|
||||
Payload []byte
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// Given a raw encoded JWS token parses it and verifies the structure.
|
||||
func ParseJWS(raw string) (JWS, error) {
|
||||
parts := strings.Split(raw, ".")
|
||||
if len(parts) != 3 {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, only %d segments", len(parts))
|
||||
}
|
||||
|
||||
rawSig := parts[2]
|
||||
jws := JWS{
|
||||
RawHeader: parts[0],
|
||||
RawPayload: parts[1],
|
||||
}
|
||||
|
||||
header, err := decodeHeader(jws.RawHeader)
|
||||
if err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, unable to decode header, %s", err)
|
||||
}
|
||||
if err = header.Validate(); err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, %s", err)
|
||||
}
|
||||
jws.Header = header
|
||||
|
||||
payload, err := decodeSegment(jws.RawPayload)
|
||||
if err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, unable to decode payload: %s", err)
|
||||
}
|
||||
jws.Payload = payload
|
||||
|
||||
sig, err := decodeSegment(rawSig)
|
||||
if err != nil {
|
||||
return JWS{}, fmt.Errorf("malformed JWS, unable to decode signature: %s", err)
|
||||
}
|
||||
jws.Signature = sig
|
||||
|
||||
return jws, nil
|
||||
}
|
74
vendor/github.com/coreos/go-oidc/jose/jws_test.go
generated
vendored
Normal file
74
vendor/github.com/coreos/go-oidc/jose/jws_test.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testCase struct{ t string }
|
||||
|
||||
var validInput []testCase
|
||||
|
||||
var invalidInput []testCase
|
||||
|
||||
func init() {
|
||||
validInput = []testCase{
|
||||
{
|
||||
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
|
||||
},
|
||||
}
|
||||
|
||||
invalidInput = []testCase{
|
||||
// empty
|
||||
{
|
||||
"",
|
||||
},
|
||||
// undecodeable
|
||||
{
|
||||
"aaa.bbb.ccc",
|
||||
},
|
||||
// missing parts
|
||||
{
|
||||
"aaa",
|
||||
},
|
||||
// missing parts
|
||||
{
|
||||
"aaa.bbb",
|
||||
},
|
||||
// too many parts
|
||||
{
|
||||
"aaa.bbb.ccc.ddd",
|
||||
},
|
||||
// invalid header
|
||||
// EncodeHeader(map[string]string{"foo": "bar"})
|
||||
{
|
||||
"eyJmb28iOiJiYXIifQ.bbb.ccc",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseJWS(t *testing.T) {
|
||||
for i, tt := range validInput {
|
||||
jws, err := ParseJWS(tt.t)
|
||||
if err != nil {
|
||||
t.Errorf("test: %d. expected: valid, actual: invalid", i)
|
||||
}
|
||||
|
||||
expectedHeader := strings.Split(tt.t, ".")[0]
|
||||
if jws.RawHeader != expectedHeader {
|
||||
t.Errorf("test: %d. expected: %s, actual: %s", i, expectedHeader, jws.RawHeader)
|
||||
}
|
||||
|
||||
expectedPayload := strings.Split(tt.t, ".")[1]
|
||||
if jws.RawPayload != expectedPayload {
|
||||
t.Errorf("test: %d. expected: %s, actual: %s", i, expectedPayload, jws.RawPayload)
|
||||
}
|
||||
}
|
||||
|
||||
for i, tt := range invalidInput {
|
||||
_, err := ParseJWS(tt.t)
|
||||
if err == nil {
|
||||
t.Errorf("test: %d. expected: invalid, actual: valid", i)
|
||||
}
|
||||
}
|
||||
}
|
82
vendor/github.com/coreos/go-oidc/jose/jwt.go
generated
vendored
Normal file
82
vendor/github.com/coreos/go-oidc/jose/jwt.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package jose
|
||||
|
||||
import "strings"
|
||||
|
||||
type JWT JWS
|
||||
|
||||
func ParseJWT(token string) (jwt JWT, err error) {
|
||||
jws, err := ParseJWS(token)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return JWT(jws), nil
|
||||
}
|
||||
|
||||
func NewJWT(header JOSEHeader, claims Claims) (jwt JWT, err error) {
|
||||
jwt = JWT{}
|
||||
|
||||
jwt.Header = header
|
||||
jwt.Header[HeaderMediaType] = "JWT"
|
||||
|
||||
claimBytes, err := marshalClaims(claims)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jwt.Payload = claimBytes
|
||||
|
||||
eh, err := encodeHeader(header)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jwt.RawHeader = eh
|
||||
|
||||
ec, err := encodeClaims(claims)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jwt.RawPayload = ec
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (j *JWT) KeyID() (string, bool) {
|
||||
kID, ok := j.Header[HeaderKeyID]
|
||||
return kID, ok
|
||||
}
|
||||
|
||||
func (j *JWT) Claims() (Claims, error) {
|
||||
return decodeClaims(j.Payload)
|
||||
}
|
||||
|
||||
// Encoded data part of the token which may be signed.
|
||||
func (j *JWT) Data() string {
|
||||
return strings.Join([]string{j.RawHeader, j.RawPayload}, ".")
|
||||
}
|
||||
|
||||
// Full encoded JWT token string in format: header.claims.signature
|
||||
func (j *JWT) Encode() string {
|
||||
d := j.Data()
|
||||
s := encodeSegment(j.Signature)
|
||||
return strings.Join([]string{d, s}, ".")
|
||||
}
|
||||
|
||||
func NewSignedJWT(claims Claims, s Signer) (*JWT, error) {
|
||||
header := JOSEHeader{
|
||||
HeaderKeyAlgorithm: s.Alg(),
|
||||
HeaderKeyID: s.ID(),
|
||||
}
|
||||
|
||||
jwt, err := NewJWT(header, claims)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := s.Sign([]byte(jwt.Data()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jwt.Signature = sig
|
||||
|
||||
return &jwt, nil
|
||||
}
|
94
vendor/github.com/coreos/go-oidc/jose/jwt_test.go
generated
vendored
Normal file
94
vendor/github.com/coreos/go-oidc/jose/jwt_test.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseJWT(t *testing.T) {
|
||||
tests := []struct {
|
||||
r string
|
||||
h JOSEHeader
|
||||
c Claims
|
||||
}{
|
||||
{
|
||||
// Example from JWT spec:
|
||||
// http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#ExampleJWT
|
||||
"eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
|
||||
JOSEHeader{
|
||||
HeaderMediaType: "JWT",
|
||||
HeaderKeyAlgorithm: "HS256",
|
||||
},
|
||||
Claims{
|
||||
"iss": "joe",
|
||||
// NOTE: test numbers must be floats for equality checks to work since values are converted form interface{} to float64 by default.
|
||||
"exp": 1300819380.0,
|
||||
"http://example.com/is_root": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
jwt, err := ParseJWT(tt.r)
|
||||
if err != nil {
|
||||
t.Errorf("raw token should parse. test: %d. expected: valid, actual: invalid. err=%v", i, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tt.h, jwt.Header) {
|
||||
t.Errorf("JOSE headers should match. test: %d. expected: %v, actual: %v", i, tt.h, jwt.Header)
|
||||
}
|
||||
|
||||
claims, err := jwt.Claims()
|
||||
if err != nil {
|
||||
t.Errorf("test: %d. expected: valid claim parsing. err=%v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.c, claims) {
|
||||
t.Errorf("claims should match. test: %d. expected: %v, actual: %v", i, tt.c, claims)
|
||||
}
|
||||
|
||||
enc := jwt.Encode()
|
||||
if enc != tt.r {
|
||||
t.Errorf("encoded jwt should match raw jwt. test: %d. expected: %v, actual: %v", i, tt.r, enc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewJWTHeaderType(t *testing.T) {
|
||||
jwt, err := NewJWT(JOSEHeader{}, Claims{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want := "JWT"
|
||||
got := jwt.Header[HeaderMediaType]
|
||||
if want != got {
|
||||
t.Fatalf("Header %q incorrect: want=%s got=%s", HeaderMediaType, want, got)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNewJWTHeaderKeyID(t *testing.T) {
|
||||
jwt, err := NewJWT(JOSEHeader{HeaderKeyID: "foo"}, Claims{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
want := "foo"
|
||||
got, ok := jwt.KeyID()
|
||||
if !ok {
|
||||
t.Fatalf("KeyID not set")
|
||||
} else if want != got {
|
||||
t.Fatalf("KeyID incorrect: want=%s got=%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewJWTHeaderKeyIDNotSet(t *testing.T) {
|
||||
jwt, err := NewJWT(JOSEHeader{}, Claims{})
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if _, ok := jwt.KeyID(); ok {
|
||||
t.Fatalf("KeyID set, but should not be")
|
||||
}
|
||||
}
|
24
vendor/github.com/coreos/go-oidc/jose/sig.go
generated
vendored
Executable file
24
vendor/github.com/coreos/go-oidc/jose/sig.go
generated
vendored
Executable file
@@ -0,0 +1,24 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Verifier interface {
|
||||
ID() string
|
||||
Alg() string
|
||||
Verify(sig []byte, data []byte) error
|
||||
}
|
||||
|
||||
type Signer interface {
|
||||
Verifier
|
||||
Sign(data []byte) (sig []byte, err error)
|
||||
}
|
||||
|
||||
func NewVerifier(jwk JWK) (Verifier, error) {
|
||||
if jwk.Type != "RSA" {
|
||||
return nil, fmt.Errorf("unsupported key type %q", jwk.Type)
|
||||
}
|
||||
|
||||
return NewVerifierRSA(jwk)
|
||||
}
|
67
vendor/github.com/coreos/go-oidc/jose/sig_rsa.go
generated
vendored
Executable file
67
vendor/github.com/coreos/go-oidc/jose/sig_rsa.go
generated
vendored
Executable file
@@ -0,0 +1,67 @@
|
||||
package jose
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type VerifierRSA struct {
|
||||
KeyID string
|
||||
Hash crypto.Hash
|
||||
PublicKey rsa.PublicKey
|
||||
}
|
||||
|
||||
type SignerRSA struct {
|
||||
PrivateKey rsa.PrivateKey
|
||||
VerifierRSA
|
||||
}
|
||||
|
||||
func NewVerifierRSA(jwk JWK) (*VerifierRSA, error) {
|
||||
if jwk.Alg != "" && jwk.Alg != "RS256" {
|
||||
return nil, fmt.Errorf("unsupported key algorithm %q", jwk.Alg)
|
||||
}
|
||||
|
||||
v := VerifierRSA{
|
||||
KeyID: jwk.ID,
|
||||
PublicKey: rsa.PublicKey{
|
||||
N: jwk.Modulus,
|
||||
E: jwk.Exponent,
|
||||
},
|
||||
Hash: crypto.SHA256,
|
||||
}
|
||||
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func NewSignerRSA(kid string, key rsa.PrivateKey) *SignerRSA {
|
||||
return &SignerRSA{
|
||||
PrivateKey: key,
|
||||
VerifierRSA: VerifierRSA{
|
||||
KeyID: kid,
|
||||
PublicKey: key.PublicKey,
|
||||
Hash: crypto.SHA256,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *VerifierRSA) ID() string {
|
||||
return v.KeyID
|
||||
}
|
||||
|
||||
func (v *VerifierRSA) Alg() string {
|
||||
return "RS256"
|
||||
}
|
||||
|
||||
func (v *VerifierRSA) Verify(sig []byte, data []byte) error {
|
||||
h := v.Hash.New()
|
||||
h.Write(data)
|
||||
return rsa.VerifyPKCS1v15(&v.PublicKey, v.Hash, h.Sum(nil), sig)
|
||||
}
|
||||
|
||||
func (s *SignerRSA) Sign(data []byte) ([]byte, error) {
|
||||
h := s.Hash.New()
|
||||
h.Write(data)
|
||||
return rsa.SignPKCS1v15(rand.Reader, &s.PrivateKey, s.Hash, h.Sum(nil))
|
||||
}
|
Reference in New Issue
Block a user