Update dependencies
This commit is contained in:
parent
51e4dcbb1f
commit
65284441fa
98 changed files with 25265 additions and 1992 deletions
150
vendor/github.com/coreos/go-oidc/gen.go
generated
vendored
150
vendor/github.com/coreos/go-oidc/gen.go
generated
vendored
|
@ -1,150 +0,0 @@
|
|||
// +build ignore
|
||||
|
||||
// This file is used to generate keys for tests.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"text/template"
|
||||
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
|
||||
type key struct {
|
||||
name string
|
||||
new func() (crypto.Signer, error)
|
||||
}
|
||||
|
||||
var keys = []key{
|
||||
{
|
||||
"ECDSA_256", func() (crypto.Signer, error) {
|
||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
},
|
||||
},
|
||||
{
|
||||
"ECDSA_384", func() (crypto.Signer, error) {
|
||||
return ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
},
|
||||
},
|
||||
{
|
||||
"ECDSA_521", func() (crypto.Signer, error) {
|
||||
return ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||
},
|
||||
},
|
||||
{
|
||||
"RSA_1024", func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 1024)
|
||||
},
|
||||
},
|
||||
{
|
||||
"RSA_2048", func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 2048)
|
||||
},
|
||||
},
|
||||
{
|
||||
"RSA_4096", func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 4096)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func newJWK(k key, prefix, ident string) (privBytes, pubBytes []byte, err error) {
|
||||
priv, err := k.new()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("generate %s: %v", k.name, err)
|
||||
}
|
||||
pub := priv.Public()
|
||||
|
||||
privKey := &jose.JSONWebKey{Key: priv}
|
||||
thumbprint, err := privKey.Thumbprint(crypto.SHA256)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("computing thumbprint: %v", err)
|
||||
}
|
||||
|
||||
keyID := hex.EncodeToString(thumbprint)
|
||||
privKey.KeyID = keyID
|
||||
pubKey := &jose.JSONWebKey{Key: pub, KeyID: keyID}
|
||||
|
||||
privBytes, err = json.MarshalIndent(privKey, prefix, ident)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
pubBytes, err = json.MarshalIndent(pubKey, prefix, ident)
|
||||
return
|
||||
}
|
||||
|
||||
type keyData struct {
|
||||
Name string
|
||||
Priv string
|
||||
Pub string
|
||||
}
|
||||
|
||||
var tmpl = template.Must(template.New("").Parse(`// +build !golint
|
||||
|
||||
// This file contains statically created JWKs for tests created by gen.go
|
||||
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
|
||||
func mustLoadJWK(s string) jose.JSONWebKey {
|
||||
var jwk jose.JSONWebKey
|
||||
if err := json.Unmarshal([]byte(s), &jwk); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return jwk
|
||||
}
|
||||
|
||||
var (
|
||||
{{- range $i, $key := .Keys }}
|
||||
testKey{{ $key.Name }} = mustLoadJWK(` + "`" + `{{ $key.Pub }}` + "`" + `)
|
||||
testKey{{ $key.Name }}_Priv = mustLoadJWK(` + "`" + `{{ $key.Priv }}` + "`" + `)
|
||||
{{ end -}}
|
||||
)
|
||||
`))
|
||||
|
||||
func main() {
|
||||
var tmplData struct {
|
||||
Keys []keyData
|
||||
}
|
||||
for _, k := range keys {
|
||||
for i := 0; i < 4; i++ {
|
||||
log.Printf("generating %s", k.name)
|
||||
priv, pub, err := newJWK(k, "\t", "\t")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
name := fmt.Sprintf("%s_%d", k.name, i)
|
||||
|
||||
tmplData.Keys = append(tmplData.Keys, keyData{
|
||||
Name: name,
|
||||
Priv: string(priv),
|
||||
Pub: string(pub),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
buff := new(bytes.Buffer)
|
||||
if err := tmpl.Execute(buff, tmplData); err != nil {
|
||||
log.Fatalf("excuting template: %v", err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile("jose_test.go", buff.Bytes(), 0644); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
2
vendor/github.com/coreos/go-oidc/http/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/http/doc.go
generated
vendored
|
@ -1,2 +0,0 @@
|
|||
// Package http is DEPRECATED. Use net/http instead.
|
||||
package http
|
20
vendor/github.com/coreos/go-oidc/jose.go
generated
vendored
20
vendor/github.com/coreos/go-oidc/jose.go
generated
vendored
|
@ -1,20 +0,0 @@
|
|||
// +build !golint
|
||||
|
||||
// Don't lint this file. We don't want to have to add a comment to each constant.
|
||||
|
||||
package oidc
|
||||
|
||||
const (
|
||||
// JOSE asymmetric signing algorithm values as defined by RFC 7518
|
||||
//
|
||||
// see: https://tools.ietf.org/html/rfc7518#section-3.1
|
||||
RS256 = "RS256" // RSASSA-PKCS-v1.5 using SHA-256
|
||||
RS384 = "RS384" // RSASSA-PKCS-v1.5 using SHA-384
|
||||
RS512 = "RS512" // RSASSA-PKCS-v1.5 using SHA-512
|
||||
ES256 = "ES256" // ECDSA using P-256 and SHA-256
|
||||
ES384 = "ES384" // ECDSA using P-384 and SHA-384
|
||||
ES512 = "ES512" // ECDSA using P-521 and SHA-512
|
||||
PS256 = "PS256" // RSASSA-PSS using SHA256 and MGF1-SHA256
|
||||
PS384 = "PS384" // RSASSA-PSS using SHA384 and MGF1-SHA384
|
||||
PS512 = "PS512" // RSASSA-PSS using SHA512 and MGF1-SHA512
|
||||
)
|
2
vendor/github.com/coreos/go-oidc/jose/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/jose/doc.go
generated
vendored
|
@ -1,2 +0,0 @@
|
|||
// Package jose is DEPRECATED. Use gopkg.in/square/go-jose.v2 instead.
|
||||
package jose
|
4
vendor/github.com/coreos/go-oidc/jose/jwk.go
generated
vendored
4
vendor/github.com/coreos/go-oidc/jose/jwk.go
generated
vendored
|
@ -104,7 +104,7 @@ func encodeExponent(e int) string {
|
|||
break
|
||||
}
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(b[idx:])
|
||||
return base64.URLEncoding.EncodeToString(b[idx:])
|
||||
}
|
||||
|
||||
// Turns a URL encoded modulus of a key into a big int.
|
||||
|
@ -119,7 +119,7 @@ func decodeModulus(n string) (*big.Int, error) {
|
|||
}
|
||||
|
||||
func encodeModulus(n *big.Int) string {
|
||||
return base64.RawURLEncoding.EncodeToString(n.Bytes())
|
||||
return base64.URLEncoding.EncodeToString(n.Bytes())
|
||||
}
|
||||
|
||||
// decodeBase64URLPaddingOptional decodes Base64 whether there is padding or not.
|
||||
|
|
67
vendor/github.com/coreos/go-oidc/jose/sig_hmac.go
generated
vendored
Executable file
67
vendor/github.com/coreos/go-oidc/jose/sig_hmac.go
generated
vendored
Executable file
|
@ -0,0 +1,67 @@
|
|||
package jose
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
_ "crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type VerifierHMAC struct {
|
||||
KeyID string
|
||||
Hash crypto.Hash
|
||||
Secret []byte
|
||||
}
|
||||
|
||||
type SignerHMAC struct {
|
||||
VerifierHMAC
|
||||
}
|
||||
|
||||
func NewVerifierHMAC(jwk JWK) (*VerifierHMAC, error) {
|
||||
if jwk.Alg != "" && jwk.Alg != "HS256" {
|
||||
return nil, fmt.Errorf("unsupported key algorithm %q", jwk.Alg)
|
||||
}
|
||||
|
||||
v := VerifierHMAC{
|
||||
KeyID: jwk.ID,
|
||||
Secret: jwk.Secret,
|
||||
Hash: crypto.SHA256,
|
||||
}
|
||||
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (v *VerifierHMAC) ID() string {
|
||||
return v.KeyID
|
||||
}
|
||||
|
||||
func (v *VerifierHMAC) Alg() string {
|
||||
return "HS256"
|
||||
}
|
||||
|
||||
func (v *VerifierHMAC) Verify(sig []byte, data []byte) error {
|
||||
h := hmac.New(v.Hash.New, v.Secret)
|
||||
h.Write(data)
|
||||
if !bytes.Equal(sig, h.Sum(nil)) {
|
||||
return errors.New("invalid hmac signature")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewSignerHMAC(kid string, secret []byte) *SignerHMAC {
|
||||
return &SignerHMAC{
|
||||
VerifierHMAC: VerifierHMAC{
|
||||
KeyID: kid,
|
||||
Secret: secret,
|
||||
Hash: crypto.SHA256,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SignerHMAC) Sign(data []byte) ([]byte, error) {
|
||||
h := hmac.New(s.Hash.New, s.Secret)
|
||||
h.Write(data)
|
||||
return h.Sum(nil), nil
|
||||
}
|
200
vendor/github.com/coreos/go-oidc/jwks.go
generated
vendored
200
vendor/github.com/coreos/go-oidc/jwks.go
generated
vendored
|
@ -1,200 +0,0 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pquerna/cachecontrol"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
|
||||
// keysExpiryDelta is the allowed clock skew between a client and the OpenID Connect
|
||||
// server.
|
||||
//
|
||||
// When keys expire, they are valid for this amount of time after.
|
||||
//
|
||||
// If the keys have not expired, and an ID Token claims it was signed by a key not in
|
||||
// the cache, if and only if the keys expire in this amount of time, the keys will be
|
||||
// updated.
|
||||
const keysExpiryDelta = 30 * time.Second
|
||||
|
||||
func newRemoteKeySet(ctx context.Context, jwksURL string, now func() time.Time) *remoteKeySet {
|
||||
if now == nil {
|
||||
now = time.Now
|
||||
}
|
||||
return &remoteKeySet{jwksURL: jwksURL, ctx: ctx, now: now}
|
||||
}
|
||||
|
||||
type remoteKeySet struct {
|
||||
jwksURL string
|
||||
ctx context.Context
|
||||
now func() time.Time
|
||||
|
||||
// guard all other fields
|
||||
mu sync.Mutex
|
||||
|
||||
// inflightCtx suppresses parallel execution of updateKeys and allows
|
||||
// multiple goroutines to wait for its result.
|
||||
// Its Err() method returns any errors encountered during updateKeys.
|
||||
//
|
||||
// If nil, there is no inflight updateKeys request.
|
||||
inflightCtx *inflight
|
||||
|
||||
// A set of cached keys and their expiry.
|
||||
cachedKeys []jose.JSONWebKey
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
// inflight is used to wait on some in-flight request from multiple goroutines
|
||||
type inflight struct {
|
||||
done chan struct{}
|
||||
err error
|
||||
}
|
||||
|
||||
// Done returns a channel that is closed when the inflight request finishes.
|
||||
func (i *inflight) Done() <-chan struct{} {
|
||||
return i.done
|
||||
}
|
||||
|
||||
// Err returns any error encountered during request execution. May be nil.
|
||||
func (i *inflight) Err() error {
|
||||
return i.err
|
||||
}
|
||||
|
||||
// Cancel signals completion of the inflight request with error err.
|
||||
// Must be called only once for particular inflight instance.
|
||||
func (i *inflight) Cancel(err error) {
|
||||
i.err = err
|
||||
close(i.done)
|
||||
}
|
||||
|
||||
func (r *remoteKeySet) keysWithIDFromCache(keyIDs []string) ([]jose.JSONWebKey, bool) {
|
||||
r.mu.Lock()
|
||||
keys, expiry := r.cachedKeys, r.expiry
|
||||
r.mu.Unlock()
|
||||
|
||||
// Have the keys expired?
|
||||
if expiry.Add(keysExpiryDelta).Before(r.now()) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var signingKeys []jose.JSONWebKey
|
||||
for _, key := range keys {
|
||||
if contains(keyIDs, key.KeyID) {
|
||||
signingKeys = append(signingKeys, key)
|
||||
}
|
||||
}
|
||||
|
||||
if len(signingKeys) == 0 {
|
||||
// Are the keys about to expire?
|
||||
if r.now().Add(keysExpiryDelta).After(expiry) {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
return signingKeys, true
|
||||
}
|
||||
func (r *remoteKeySet) keysWithID(ctx context.Context, keyIDs []string) ([]jose.JSONWebKey, error) {
|
||||
keys, ok := r.keysWithIDFromCache(keyIDs)
|
||||
if ok {
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
var inflightCtx *inflight
|
||||
func() {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
|
||||
// If there's not a current inflight request, create one.
|
||||
if r.inflightCtx == nil {
|
||||
inflightCtx := &inflight{make(chan struct{}), nil}
|
||||
r.inflightCtx = inflightCtx
|
||||
|
||||
go func() {
|
||||
// TODO(ericchiang): Upstream Kubernetes request that we recover every time
|
||||
// we spawn a goroutine, because panics in a goroutine will bring down the
|
||||
// entire program. There's no way to recover from another goroutine's panic.
|
||||
//
|
||||
// Most users actually want to let the panic propagate and bring down the
|
||||
// program because it implies some unrecoverable state.
|
||||
//
|
||||
// Add a context key to allow the recover behavior.
|
||||
//
|
||||
// See: https://github.com/coreos/go-oidc/issues/89
|
||||
|
||||
// Sync keys and close inflightCtx when that's done.
|
||||
// Use the remoteKeySet's context instead of the requests context
|
||||
// because a re-sync is unique to the keys set and will span multiple
|
||||
// requests.
|
||||
inflightCtx.Cancel(r.updateKeys(r.ctx))
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.inflightCtx = nil
|
||||
}()
|
||||
}
|
||||
|
||||
inflightCtx = r.inflightCtx
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
case <-inflightCtx.Done():
|
||||
if err := inflightCtx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Since we've just updated keys, we don't care about the cache miss.
|
||||
keys, _ = r.keysWithIDFromCache(keyIDs)
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (r *remoteKeySet) updateKeys(ctx context.Context) error {
|
||||
req, err := http.NewRequest("GET", r.jwksURL, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("oidc: can't create request: %v", err)
|
||||
}
|
||||
|
||||
resp, err := ctxhttp.Do(ctx, clientFromContext(ctx), req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("oidc: get keys failed %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("oidc: read response body: %v", err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("oidc: get keys failed: %s %s", resp.Status, body)
|
||||
}
|
||||
|
||||
var keySet jose.JSONWebKeySet
|
||||
if err := json.Unmarshal(body, &keySet); err != nil {
|
||||
return fmt.Errorf("oidc: failed to decode keys: %v %s", err, body)
|
||||
}
|
||||
|
||||
// If the server doesn't provide cache control headers, assume the
|
||||
// keys expire immediately.
|
||||
expiry := r.now()
|
||||
|
||||
_, e, err := cachecontrol.CachableResponse(req, resp, cachecontrol.Options{})
|
||||
if err == nil && e.After(expiry) {
|
||||
expiry = e
|
||||
}
|
||||
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
r.cachedKeys = keySet.Keys
|
||||
r.expiry = expiry
|
||||
|
||||
return nil
|
||||
}
|
2
vendor/github.com/coreos/go-oidc/key/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/key/doc.go
generated
vendored
|
@ -1,2 +0,0 @@
|
|||
// Package key is DEPRECATED. Use github.com/coreos/go-oidc instead.
|
||||
package key
|
2
vendor/github.com/coreos/go-oidc/oauth2/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/oauth2/doc.go
generated
vendored
|
@ -1,2 +0,0 @@
|
|||
// Package oauth2 is DEPRECATED. Use golang.org/x/oauth instead.
|
||||
package oauth2
|
299
vendor/github.com/coreos/go-oidc/oidc.go
generated
vendored
299
vendor/github.com/coreos/go-oidc/oidc.go
generated
vendored
|
@ -1,299 +0,0 @@
|
|||
// Package oidc implements OpenID Connect client logic for the golang.org/x/oauth2 package.
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
"golang.org/x/oauth2"
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
// ScopeOpenID is the mandatory scope for all OpenID Connect OAuth2 requests.
|
||||
ScopeOpenID = "openid"
|
||||
|
||||
// ScopeOfflineAccess is an optional scope defined by OpenID Connect for requesting
|
||||
// OAuth2 refresh tokens.
|
||||
//
|
||||
// Support for this scope differs between OpenID Connect providers. For instance
|
||||
// Google rejects it, favoring appending "access_type=offline" as part of the
|
||||
// authorization request instead.
|
||||
//
|
||||
// See: https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
|
||||
ScopeOfflineAccess = "offline_access"
|
||||
)
|
||||
|
||||
// ClientContext returns a new Context that carries the provided HTTP client.
|
||||
//
|
||||
// This method sets the same context key used by the golang.org/x/oauth2 package,
|
||||
// so the returned context works for that package too.
|
||||
//
|
||||
// myClient := &http.Client{}
|
||||
// ctx := oidc.ClientContext(parentContext, myClient)
|
||||
//
|
||||
// // This will use the custom client
|
||||
// provider, err := oidc.NewProvider(ctx, "https://accounts.example.com")
|
||||
//
|
||||
func ClientContext(ctx context.Context, client *http.Client) context.Context {
|
||||
return context.WithValue(ctx, oauth2.HTTPClient, client)
|
||||
}
|
||||
|
||||
func clientFromContext(ctx context.Context) *http.Client {
|
||||
if client, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok {
|
||||
return client
|
||||
}
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
||||
// Provider represents an OpenID Connect server's configuration.
|
||||
type Provider struct {
|
||||
issuer string
|
||||
authURL string
|
||||
tokenURL string
|
||||
userInfoURL string
|
||||
|
||||
// Raw claims returned by the server.
|
||||
rawClaims []byte
|
||||
|
||||
remoteKeySet *remoteKeySet
|
||||
}
|
||||
|
||||
type cachedKeys struct {
|
||||
keys []jose.JSONWebKey
|
||||
expiry time.Time
|
||||
}
|
||||
|
||||
type providerJSON struct {
|
||||
Issuer string `json:"issuer"`
|
||||
AuthURL string `json:"authorization_endpoint"`
|
||||
TokenURL string `json:"token_endpoint"`
|
||||
JWKSURL string `json:"jwks_uri"`
|
||||
UserInfoURL string `json:"userinfo_endpoint"`
|
||||
}
|
||||
|
||||
// NewProvider uses the OpenID Connect discovery mechanism to construct a Provider.
|
||||
//
|
||||
// The issuer is the URL identifier for the service. For example: "https://accounts.google.com"
|
||||
// or "https://login.salesforce.com".
|
||||
func NewProvider(ctx context.Context, issuer string) (*Provider, error) {
|
||||
wellKnown := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration"
|
||||
resp, err := ctxhttp.Get(ctx, clientFromContext(ctx), wellKnown)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%s: %s", resp.Status, body)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var p providerJSON
|
||||
if err := json.Unmarshal(body, &p); err != nil {
|
||||
return nil, fmt.Errorf("oidc: failed to decode provider discovery object: %v", err)
|
||||
}
|
||||
if p.Issuer != issuer {
|
||||
return nil, fmt.Errorf("oidc: issuer did not match the issuer returned by provider, expected %q got %q", issuer, p.Issuer)
|
||||
}
|
||||
return &Provider{
|
||||
issuer: p.Issuer,
|
||||
authURL: p.AuthURL,
|
||||
tokenURL: p.TokenURL,
|
||||
userInfoURL: p.UserInfoURL,
|
||||
rawClaims: body,
|
||||
remoteKeySet: newRemoteKeySet(ctx, p.JWKSURL, time.Now),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Claims unmarshals raw fields returned by the server during discovery.
|
||||
//
|
||||
// var claims struct {
|
||||
// ScopesSupported []string `json:"scopes_supported"`
|
||||
// ClaimsSupported []string `json:"claims_supported"`
|
||||
// }
|
||||
//
|
||||
// if err := provider.Claims(&claims); err != nil {
|
||||
// // handle unmarshaling error
|
||||
// }
|
||||
//
|
||||
// For a list of fields defined by the OpenID Connect spec see:
|
||||
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
||||
func (p *Provider) Claims(v interface{}) error {
|
||||
if p.rawClaims == nil {
|
||||
return errors.New("oidc: claims not set")
|
||||
}
|
||||
return json.Unmarshal(p.rawClaims, v)
|
||||
}
|
||||
|
||||
// Endpoint returns the OAuth2 auth and token endpoints for the given provider.
|
||||
func (p *Provider) Endpoint() oauth2.Endpoint {
|
||||
return oauth2.Endpoint{AuthURL: p.authURL, TokenURL: p.tokenURL}
|
||||
}
|
||||
|
||||
// UserInfo represents the OpenID Connect userinfo claims.
|
||||
type UserInfo struct {
|
||||
Subject string `json:"sub"`
|
||||
Profile string `json:"profile"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
|
||||
claims []byte
|
||||
}
|
||||
|
||||
// Claims unmarshals the raw JSON object claims into the provided object.
|
||||
func (u *UserInfo) Claims(v interface{}) error {
|
||||
if u.claims == nil {
|
||||
return errors.New("oidc: claims not set")
|
||||
}
|
||||
return json.Unmarshal(u.claims, v)
|
||||
}
|
||||
|
||||
// UserInfo uses the token source to query the provider's user info endpoint.
|
||||
func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource) (*UserInfo, error) {
|
||||
if p.userInfoURL == "" {
|
||||
return nil, errors.New("oidc: user info endpoint is not supported by this provider")
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", p.userInfoURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc: create GET request: %v", err)
|
||||
}
|
||||
|
||||
token, err := tokenSource.Token()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc: get access token: %v", err)
|
||||
}
|
||||
token.SetAuthHeader(req)
|
||||
|
||||
resp, err := ctxhttp.Do(ctx, clientFromContext(ctx), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%s: %s", resp.Status, body)
|
||||
}
|
||||
|
||||
var userInfo UserInfo
|
||||
if err := json.Unmarshal(body, &userInfo); err != nil {
|
||||
return nil, fmt.Errorf("oidc: failed to decode userinfo: %v", err)
|
||||
}
|
||||
userInfo.claims = body
|
||||
return &userInfo, nil
|
||||
}
|
||||
|
||||
// IDToken is an OpenID Connect extension that provides a predictable representation
|
||||
// of an authorization event.
|
||||
//
|
||||
// The ID Token only holds fields OpenID Connect requires. To access additional
|
||||
// claims returned by the server, use the Claims method.
|
||||
type IDToken struct {
|
||||
// The URL of the server which issued this token. This will always be the same
|
||||
// as the URL used for initial discovery.
|
||||
Issuer string
|
||||
|
||||
// The client, or set of clients, that this token is issued for.
|
||||
Audience []string
|
||||
|
||||
// A unique string which identifies the end user.
|
||||
Subject string
|
||||
|
||||
IssuedAt time.Time
|
||||
Expiry time.Time
|
||||
Nonce string
|
||||
|
||||
// Raw payload of the id_token.
|
||||
claims []byte
|
||||
}
|
||||
|
||||
// Claims unmarshals the raw JSON payload of the ID Token into a provided struct.
|
||||
//
|
||||
// idToken, err := idTokenVerifier.Verify(rawIDToken)
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
// var claims struct {
|
||||
// Email string `json:"email"`
|
||||
// EmailVerified bool `json:"email_verified"`
|
||||
// }
|
||||
// if err := idToken.Claims(&claims); err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
//
|
||||
func (i *IDToken) Claims(v interface{}) error {
|
||||
if i.claims == nil {
|
||||
return errors.New("oidc: claims not set")
|
||||
}
|
||||
return json.Unmarshal(i.claims, v)
|
||||
}
|
||||
|
||||
type idToken struct {
|
||||
Issuer string `json:"iss"`
|
||||
Subject string `json:"sub"`
|
||||
Audience audience `json:"aud"`
|
||||
Expiry jsonTime `json:"exp"`
|
||||
IssuedAt jsonTime `json:"iat"`
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
|
||||
type audience []string
|
||||
|
||||
func (a *audience) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if json.Unmarshal(b, &s) == nil {
|
||||
*a = audience{s}
|
||||
return nil
|
||||
}
|
||||
var auds []string
|
||||
if err := json.Unmarshal(b, &auds); err != nil {
|
||||
return err
|
||||
}
|
||||
*a = audience(auds)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a audience) MarshalJSON() ([]byte, error) {
|
||||
if len(a) == 1 {
|
||||
return json.Marshal(a[0])
|
||||
}
|
||||
return json.Marshal([]string(a))
|
||||
}
|
||||
|
||||
type jsonTime time.Time
|
||||
|
||||
func (j *jsonTime) UnmarshalJSON(b []byte) error {
|
||||
var n json.Number
|
||||
if err := json.Unmarshal(b, &n); err != nil {
|
||||
return err
|
||||
}
|
||||
var unix int64
|
||||
|
||||
if t, err := n.Int64(); err == nil {
|
||||
unix = t
|
||||
} else {
|
||||
f, err := n.Float64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unix = int64(f)
|
||||
}
|
||||
*j = jsonTime(time.Unix(unix, 0))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j jsonTime) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(time.Time(j).Unix())
|
||||
}
|
2
vendor/github.com/coreos/go-oidc/oidc/doc.go
generated
vendored
2
vendor/github.com/coreos/go-oidc/oidc/doc.go
generated
vendored
|
@ -1,2 +0,0 @@
|
|||
// Package oidc is DEPRECATED. Use github.com/coreos/go-oidc instead.
|
||||
package oidc
|
4
vendor/github.com/coreos/go-oidc/oidc/provider.go
generated
vendored
4
vendor/github.com/coreos/go-oidc/oidc/provider.go
generated
vendored
|
@ -567,7 +567,7 @@ func (n *pcsStepNext) step(fn pcsStepFunc) (next pcsStepper) {
|
|||
next = &pcsStepNext{aft: ttl}
|
||||
} else {
|
||||
next = &pcsStepRetry{aft: time.Second}
|
||||
log.Printf("go-oidc: provider config sync failed, retrying in %v: %v", next.after(), err)
|
||||
log.Printf("go-oidc: provider config sync falied, retyring in %v: %v", next.after(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -586,7 +586,7 @@ func (r *pcsStepRetry) step(fn pcsStepFunc) (next pcsStepper) {
|
|||
next = &pcsStepNext{aft: ttl}
|
||||
} else {
|
||||
next = &pcsStepRetry{aft: timeutil.ExpBackoff(r.aft, time.Minute)}
|
||||
log.Printf("go-oidc: provider config sync failed, retrying in %v: %v", next.after(), err)
|
||||
log.Printf("go-oidc: provider config sync falied, retyring in %v: %v", next.after(), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
263
vendor/github.com/coreos/go-oidc/verify.go
generated
vendored
263
vendor/github.com/coreos/go-oidc/verify.go
generated
vendored
|
@ -1,263 +0,0 @@
|
|||
package oidc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
jose "gopkg.in/square/go-jose.v2"
|
||||
)
|
||||
|
||||
// IDTokenVerifier provides verification for ID Tokens.
|
||||
type IDTokenVerifier struct {
|
||||
keySet *remoteKeySet
|
||||
config *verificationConfig
|
||||
}
|
||||
|
||||
// verificationConfig is the unexported configuration for an IDTokenVerifier.
|
||||
//
|
||||
// Users interact with this struct using a VerificationOption.
|
||||
type verificationConfig struct {
|
||||
issuer string
|
||||
// If provided, this value must be in the ID Token audiences.
|
||||
audience string
|
||||
// If not nil, check the expiry of the id token.
|
||||
checkExpiry func() time.Time
|
||||
// If specified, only these sets of algorithms may be used to sign the JWT.
|
||||
requiredAlgs []string
|
||||
// If not nil, don't verify nonce.
|
||||
nonceSource NonceSource
|
||||
}
|
||||
|
||||
// VerificationOption provides additional checks on ID Tokens.
|
||||
type VerificationOption interface {
|
||||
// Unexport this method so other packages can't implement this interface.
|
||||
updateConfig(c *verificationConfig)
|
||||
}
|
||||
|
||||
// Verifier returns an IDTokenVerifier that uses the provider's key set to verify JWTs.
|
||||
//
|
||||
// The returned IDTokenVerifier is tied to the Provider's context and its behavior is
|
||||
// undefined once the Provider's context is canceled.
|
||||
func (p *Provider) Verifier(options ...VerificationOption) *IDTokenVerifier {
|
||||
config := &verificationConfig{issuer: p.issuer}
|
||||
for _, option := range options {
|
||||
option.updateConfig(config)
|
||||
}
|
||||
|
||||
return newVerifier(p.remoteKeySet, config)
|
||||
}
|
||||
|
||||
func newVerifier(keySet *remoteKeySet, config *verificationConfig) *IDTokenVerifier {
|
||||
// As discussed in the godocs for VerifrySigningAlg, because almost all providers
|
||||
// only support RS256, default to only allowing it.
|
||||
if len(config.requiredAlgs) == 0 {
|
||||
config.requiredAlgs = []string{RS256}
|
||||
}
|
||||
|
||||
return &IDTokenVerifier{
|
||||
keySet: keySet,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func parseJWT(p string) ([]byte, error) {
|
||||
parts := strings.Split(p, ".")
|
||||
if len(parts) < 2 {
|
||||
return nil, fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts))
|
||||
}
|
||||
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc: malformed jwt payload: %v", err)
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func contains(sli []string, ele string) bool {
|
||||
for _, s := range sli {
|
||||
if s == ele {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify parses a raw ID Token, verifies it's been signed by the provider, preforms
|
||||
// any additional checks passed as VerifictionOptions, and returns the payload.
|
||||
//
|
||||
// See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
//
|
||||
// oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
//
|
||||
// // Extract the ID Token from oauth2 token.
|
||||
// rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
// if !ok {
|
||||
// // handle error
|
||||
// }
|
||||
//
|
||||
// token, err := verifier.Verify(ctx, rawIDToken)
|
||||
//
|
||||
func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDToken, error) {
|
||||
jws, err := jose.ParseSigned(rawIDToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc: mallformed jwt: %v", err)
|
||||
}
|
||||
|
||||
// Throw out tokens with invalid claims before trying to verify the token. This lets
|
||||
// us do cheap checks before possibly re-syncing keys.
|
||||
payload, err := parseJWT(rawIDToken)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
|
||||
}
|
||||
var token idToken
|
||||
if err := json.Unmarshal(payload, &token); err != nil {
|
||||
return nil, fmt.Errorf("oidc: failed to unmarshal claims: %v", err)
|
||||
}
|
||||
|
||||
t := &IDToken{
|
||||
Issuer: token.Issuer,
|
||||
Subject: token.Subject,
|
||||
Audience: []string(token.Audience),
|
||||
Expiry: time.Time(token.Expiry),
|
||||
IssuedAt: time.Time(token.IssuedAt),
|
||||
Nonce: token.Nonce,
|
||||
claims: payload,
|
||||
}
|
||||
|
||||
// Check issuer.
|
||||
if t.Issuer != v.config.issuer {
|
||||
return nil, fmt.Errorf("oidc: id token issued by a different provider, expected %q got %q", v.config.issuer, t.Issuer)
|
||||
}
|
||||
|
||||
// If a client ID has been provided, make sure it's part of the audience.
|
||||
if v.config.audience != "" {
|
||||
if !contains(t.Audience, v.config.audience) {
|
||||
return nil, fmt.Errorf("oidc: expected audience %q got %q", v.config.audience, t.Audience)
|
||||
}
|
||||
}
|
||||
|
||||
// If a set of required algorithms has been provided, ensure that the signatures use those.
|
||||
var keyIDs, gotAlgs []string
|
||||
for _, sig := range jws.Signatures {
|
||||
if len(v.config.requiredAlgs) == 0 || contains(v.config.requiredAlgs, sig.Header.Algorithm) {
|
||||
keyIDs = append(keyIDs, sig.Header.KeyID)
|
||||
} else {
|
||||
gotAlgs = append(gotAlgs, sig.Header.Algorithm)
|
||||
}
|
||||
}
|
||||
if len(keyIDs) == 0 {
|
||||
return nil, fmt.Errorf("oidc: no signatures use a require algorithm, expected %q got %q", v.config.requiredAlgs, gotAlgs)
|
||||
}
|
||||
|
||||
// Get keys from the remote key set. This may trigger a re-sync.
|
||||
keys, err := v.keySet.keysWithID(ctx, keyIDs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc: get keys for id token: %v", err)
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
return nil, fmt.Errorf("oidc: no keys match signature ID(s) %q", keyIDs)
|
||||
}
|
||||
|
||||
// Try to use a key to validate the signature.
|
||||
var gotPayload []byte
|
||||
for _, key := range keys {
|
||||
if p, err := jws.Verify(&key); err == nil {
|
||||
gotPayload = p
|
||||
}
|
||||
}
|
||||
if len(gotPayload) == 0 {
|
||||
return nil, fmt.Errorf("oidc: failed to verify id token")
|
||||
}
|
||||
|
||||
// Ensure that the payload returned by the square actually matches the payload parsed earlier.
|
||||
if !bytes.Equal(gotPayload, payload) {
|
||||
return nil, errors.New("oidc: internal error, payload parsed did not match previous payload")
|
||||
}
|
||||
|
||||
// Check the nonce after we've verified the token. We don't want to allow unverified
|
||||
// payloads to trigger a nonce lookup.
|
||||
if v.config.nonceSource != nil {
|
||||
if err := v.config.nonceSource.ClaimNonce(t.Nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// VerifyAudience ensures that an ID Token was issued for the specific client.
|
||||
//
|
||||
// Note that a verified token may be valid for other clients, as OpenID Connect allows a token to have
|
||||
// multiple audiences.
|
||||
func VerifyAudience(clientID string) VerificationOption {
|
||||
return clientVerifier{clientID}
|
||||
}
|
||||
|
||||
type clientVerifier struct {
|
||||
clientID string
|
||||
}
|
||||
|
||||
func (v clientVerifier) updateConfig(c *verificationConfig) {
|
||||
c.audience = v.clientID
|
||||
}
|
||||
|
||||
// VerifyExpiry ensures that an ID Token has not expired.
|
||||
func VerifyExpiry() VerificationOption {
|
||||
return expiryVerifier{}
|
||||
}
|
||||
|
||||
type expiryVerifier struct{}
|
||||
|
||||
func (v expiryVerifier) updateConfig(c *verificationConfig) {
|
||||
c.checkExpiry = time.Now
|
||||
}
|
||||
|
||||
// VerifySigningAlg enforces that an ID Token is signed by a specific signing algorithm.
|
||||
//
|
||||
// Because so many providers only support RS256, if this verifiction option isn't used,
|
||||
// the IDTokenVerifier defaults to only allowing RS256.
|
||||
func VerifySigningAlg(allowedAlgs ...string) VerificationOption {
|
||||
return algVerifier{allowedAlgs}
|
||||
}
|
||||
|
||||
type algVerifier struct {
|
||||
algs []string
|
||||
}
|
||||
|
||||
func (v algVerifier) updateConfig(c *verificationConfig) {
|
||||
c.requiredAlgs = v.algs
|
||||
}
|
||||
|
||||
// Nonce returns an auth code option which requires the ID Token created by the
|
||||
// OpenID Connect provider to contain the specified nonce.
|
||||
func Nonce(nonce string) oauth2.AuthCodeOption {
|
||||
return oauth2.SetAuthURLParam("nonce", nonce)
|
||||
}
|
||||
|
||||
// NonceSource represents a source which can verify a nonce is valid and has not
|
||||
// been claimed before.
|
||||
type NonceSource interface {
|
||||
ClaimNonce(nonce string) error
|
||||
}
|
||||
|
||||
// VerifyNonce ensures that the ID Token contains a nonce which can be claimed by the nonce source.
|
||||
func VerifyNonce(source NonceSource) VerificationOption {
|
||||
return nonceVerifier{source}
|
||||
}
|
||||
|
||||
type nonceVerifier struct {
|
||||
nonceSource NonceSource
|
||||
}
|
||||
|
||||
func (n nonceVerifier) updateConfig(c *verificationConfig) {
|
||||
c.nonceSource = n.nonceSource
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue