mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 02:08:13 +00:00 
			
		
		
		
	bump(github.com/coreos/go-oidc): 065b426bd41667456c1a924468f507673629c46b
This commit is contained in:
		
							
								
								
									
										374
									
								
								vendor/github.com/coreos/go-oidc/oidc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								vendor/github.com/coreos/go-oidc/oidc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,374 @@ | ||||
| // Package oidc implements OpenID Connect client logic for the golang.org/x/oauth2 package. | ||||
| package oidc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/sha256" | ||||
| 	"crypto/sha512" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 	"io/ioutil" | ||||
| 	"mime" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"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" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	errNoAtHash      = errors.New("id token did not have an access token hash") | ||||
| 	errInvalidAtHash = errors.New("access token hash does not match value in ID token") | ||||
| ) | ||||
|  | ||||
| // 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 doRequest(ctx context.Context, req *http.Request) (*http.Response, error) { | ||||
| 	client := http.DefaultClient | ||||
| 	if c, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok { | ||||
| 		client = c | ||||
| 	} | ||||
| 	return client.Do(req.WithContext(ctx)) | ||||
| } | ||||
|  | ||||
| // 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 KeySet | ||||
| } | ||||
|  | ||||
| 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" | ||||
| 	req, err := http.NewRequest("GET", wellKnown, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	resp, err := doRequest(ctx, req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	body, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("unable to read response body: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		return nil, fmt.Errorf("%s: %s", resp.Status, body) | ||||
| 	} | ||||
|  | ||||
| 	var p providerJSON | ||||
| 	err = unmarshalResp(resp, body, &p) | ||||
| 	if 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), | ||||
| 	}, 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 := doRequest(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. OpenID Connect | ||||
| 	// requires this value always be identical to the URL used for | ||||
| 	// initial discovery. | ||||
| 	// | ||||
| 	// Note: Because of a known issue with Google Accounts' implementation | ||||
| 	// this value may differ when using Google. | ||||
| 	// | ||||
| 	// See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo | ||||
| 	Issuer string | ||||
|  | ||||
| 	// The client ID, or set of client IDs, that this token is issued for. For | ||||
| 	// common uses, this is the client that initialized the auth flow. | ||||
| 	// | ||||
| 	// This package ensures the audience contains an expected value. | ||||
| 	Audience []string | ||||
|  | ||||
| 	// A unique string which identifies the end user. | ||||
| 	Subject string | ||||
|  | ||||
| 	// Expiry of the token. Ths package will not process tokens that have | ||||
| 	// expired unless that validation is explicitly turned off. | ||||
| 	Expiry time.Time | ||||
| 	// When the token was issued by the provider. | ||||
| 	IssuedAt time.Time | ||||
|  | ||||
| 	// Initial nonce provided during the authentication redirect. | ||||
| 	// | ||||
| 	// This package does NOT provided verification on the value of this field | ||||
| 	// and it's the user's responsibility to ensure it contains a valid value. | ||||
| 	Nonce string | ||||
|  | ||||
| 	// at_hash claim, if set in the ID token. Callers can verify an access token | ||||
| 	// that corresponds to the ID token using the VerifyAccessToken method. | ||||
| 	AccessTokenHash string | ||||
|  | ||||
| 	// signature algorithm used for ID token, needed to compute a verification hash of an | ||||
| 	// access token | ||||
| 	sigAlgorithm 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) | ||||
| } | ||||
|  | ||||
| // VerifyAccessToken verifies that the hash of the access token that corresponds to the iD token | ||||
| // matches the hash in the id token. It returns an error if the hashes  don't match. | ||||
| // It is the caller's responsibility to ensure that the optional access token hash is present for the ID token | ||||
| // before calling this method. See https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken | ||||
| func (i *IDToken) VerifyAccessToken(accessToken string) error { | ||||
| 	if i.AccessTokenHash == "" { | ||||
| 		return errNoAtHash | ||||
| 	} | ||||
| 	var h hash.Hash | ||||
| 	switch i.sigAlgorithm { | ||||
| 	case RS256, ES256, PS256: | ||||
| 		h = sha256.New() | ||||
| 	case RS384, ES384, PS384: | ||||
| 		h = sha512.New384() | ||||
| 	case RS512, ES512, PS512: | ||||
| 		h = sha512.New() | ||||
| 	default: | ||||
| 		return fmt.Errorf("oidc: unsupported signing algorithm %q", i.sigAlgorithm) | ||||
| 	} | ||||
| 	h.Write([]byte(accessToken)) // hash documents that Write will never return an error | ||||
| 	sum := h.Sum(nil)[:h.Size()/2] | ||||
| 	actual := base64.RawURLEncoding.EncodeToString(sum) | ||||
| 	if actual != i.AccessTokenHash { | ||||
| 		return errInvalidAtHash | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| 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"` | ||||
| 	AtHash   string   `json:"at_hash"` | ||||
| } | ||||
|  | ||||
| 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 | ||||
| } | ||||
|  | ||||
| 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 unmarshalResp(r *http.Response, body []byte, v interface{}) error { | ||||
| 	err := json.Unmarshal(body, &v) | ||||
| 	if err == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	ct := r.Header.Get("Content-Type") | ||||
| 	mediaType, _, parseErr := mime.ParseMediaType(ct) | ||||
| 	if parseErr == nil && mediaType == "application/json" { | ||||
| 		return fmt.Errorf("got Content-Type = application/json, but could not unmarshal as JSON: %v", err) | ||||
| 	} | ||||
| 	return fmt.Errorf("expected Content-Type = application/json, got %q: %v", ct, err) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Eric Chiang
					Eric Chiang