func (p ProviderConfig) Valid() error {
	grantTypes := p.GrantTypesSupported
	if len(grantTypes) == 0 {
		grantTypes = DefaultGrantTypesSupported
	}
	implicitOnly := true
	for _, grantType := range grantTypes {
		if grantType != oauth2.GrantTypeImplicit {
			implicitOnly = false
			break
		}
	}
	if len(p.SubjectTypesSupported) == 0 {
		return errors.New("missing required field subject_types_supported")
	}
	if len(p.IDTokenSigningAlgValues) == 0 {
		return errors.New("missing required field id_token_signing_alg_values_supported")
	}
	if len(p.ScopesSupported) != 0 && !contains(p.ScopesSupported, "openid") {
		return errors.New("scoped_supported must be unspecified or include 'openid'")
	}
	if !contains(p.IDTokenSigningAlgValues, "RS256") {
		return errors.New("id_token_signing_alg_values_supported must include 'RS256'")
	}
	if contains(p.TokenEndpointAuthMethodsSupported, "none") {
		return errors.New("token_endpoint_auth_signing_alg_values_supported cannot include 'none'")
	}
	uris := []struct {
		val      *url.URL
		name     string
		required bool
	}{
		{p.Issuer, "issuer", true},
		{p.AuthEndpoint, "authorization_endpoint", true},
		{p.TokenEndpoint, "token_endpoint", !implicitOnly},
		{p.UserInfoEndpoint, "userinfo_endpoint", false},
		{p.KeysEndpoint, "jwks_uri", true},
		{p.RegistrationEndpoint, "registration_endpoint", false},
		{p.ServiceDocs, "service_documentation", false},
		{p.Policy, "op_policy_uri", false},
		{p.TermsOfService, "op_tos_uri", false},
	}
	for _, uri := range uris {
		if uri.val == nil {
			if !uri.required {
				continue
			}
			return fmt.Errorf("empty value for required uri field %s", uri.name)
		}
		if uri.val.Host == "" {
			return fmt.Errorf("no host for uri field %s", uri.name)
		}
		if uri.val.Scheme != "http" && uri.val.Scheme != "https" {
			return fmt.Errorf("uri field %s schemeis not http or https", uri.name)
		}
	}
	return nil
}
Valid determines if a ProviderConfig conforms with the OIDC specification.
If Valid returns successfully it guarantees required field are non-nil and
URLs are well formed.

Valid is called by UnmarshalJSON.

NOTE(ericchiang): For development purposes Valid does not mandate 'https' for
URLs fields where the OIDC spec requires it. This may change in future releases
of this package. See: https://github.com/coreos/go-oidc/issues/34
package oidc
import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
	"github.com/coreos/pkg/capnslog"
	"github.com/coreos/pkg/timeutil"
	"github.com/jonboulle/clockwork"
	phttp "github.com/coreos/go-oidc/http"
	"github.com/coreos/go-oidc/oauth2"
)
var (
	log = capnslog.NewPackageLogger("github.com/coreos/go-oidc", "http")
)
const (
	SubjectTypePublic   = "public"
	SubjectTypePairwise = "pairwise"
)
var (
	DefaultGrantTypesSupported               = []string{oauth2.GrantTypeAuthCode, oauth2.GrantTypeImplicit}
	DefaultResponseModesSupported            = []string{"query", "fragment"}
	DefaultTokenEndpointAuthMethodsSupported = []string{oauth2.AuthMethodClientSecretBasic}
	DefaultClaimTypesSupported               = []string{"normal"}
)
const (
	MaximumProviderConfigSyncInterval = 24 * time.Hour
	MinimumProviderConfigSyncInterval = time.Minute
	discoveryConfigPath = "/.well-known/openid-configuration"
)
var minimumProviderConfigSyncInterval = MinimumProviderConfigSyncInterval
var (
	_ json.Marshaler   = &ProviderConfig{}
	_ json.Unmarshaler = &ProviderConfig{}
)
type ProviderConfig struct {
	Issuer               *url.URL  
	AuthEndpoint         *url.URL  
	TokenEndpoint        *url.URL  
	UserInfoEndpoint     *url.URL
	KeysEndpoint         *url.URL  
	RegistrationEndpoint *url.URL
	ScopesSupported []string
	ResponseTypesSupported []string  
	ResponseModesSupported []string
	GrantTypesSupported []string
	ACRValuesSupported  []string
	SubjectTypesSupported []string  
	IDTokenSigningAlgValues    []string  
	IDTokenEncryptionAlgValues []string
	IDTokenEncryptionEncValues []string
	UserInfoSigningAlgValues    []string
	UserInfoEncryptionAlgValues []string
	UserInfoEncryptionEncValues []string
	ReqObjSigningAlgValues    []string
	ReqObjEncryptionAlgValues []string
	ReqObjEncryptionEncValues []string
	TokenEndpointAuthMethodsSupported          []string
	TokenEndpointAuthSigningAlgValuesSupported []string
	DisplayValuesSupported                     []string
	ClaimTypesSupported                        []string
	ClaimsSupported                            []string
	ServiceDocs                                *url.URL
	ClaimsLocalsSupported                      []string
	UILocalsSupported                          []string
	ClaimsParameterSupported                   bool
	RequestParameterSupported                  bool
	RequestURIParamaterSupported               bool
	RequireRequestURIRegistration              bool
	Policy         *url.URL
	TermsOfService *url.URL
	ExpiresAt time.Time
}
func (p ProviderConfig) Defaults() ProviderConfig {
	setDefault := func(val *[]string, defaultVal []string) {
		if len(*val) == 0 {
			*val = defaultVal
		}
	}
	setDefault(&p.GrantTypesSupported, DefaultGrantTypesSupported)
	setDefault(&p.ResponseModesSupported, DefaultResponseModesSupported)
	setDefault(&p.TokenEndpointAuthMethodsSupported, DefaultTokenEndpointAuthMethodsSupported)
	setDefault(&p.ClaimTypesSupported, DefaultClaimTypesSupported)
	return p
}
func (p *ProviderConfig) MarshalJSON() ([]byte, error) {
	e := p.toEncodableStruct()
	return json.Marshal(&e)
}
func (p *ProviderConfig) UnmarshalJSON(data []byte) error {
	var e encodableProviderConfig
	if err := json.Unmarshal(data, &e); err != nil {
		return err
	}
	conf, err := e.toStruct()
	if err != nil {
		return err
	}
	if err := conf.Valid(); err != nil {
		return err
	}
	*p = conf
	return nil
}
type encodableProviderConfig struct {
	Issuer               string `json:"issuer"`
	AuthEndpoint         string `json:"authorization_endpoint"`
	TokenEndpoint        string `json:"token_endpoint"`
	UserInfoEndpoint     string `json:"userinfo_endpoint,omitempty"`
	KeysEndpoint         string `json:"jwks_uri"`
	RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
	ScopesSupported        []string `json:"scopes_supported,omitempty"`
	ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
	ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
	GrantTypesSupported    []string `json:"grant_types_supported,omitempty"`
	ACRValuesSupported     []string `json:"acr_values_supported,omitempty"`
	SubjectTypesSupported  []string `json:"subject_types_supported,omitempty"`
	IDTokenSigningAlgValues     []string `json:"id_token_signing_alg_values_supported,omitempty"`
	IDTokenEncryptionAlgValues  []string `json:"id_token_encryption_alg_values_supported,omitempty"`
	IDTokenEncryptionEncValues  []string `json:"id_token_encryption_enc_values_supported,omitempty"`
	UserInfoSigningAlgValues    []string `json:"userinfo_signing_alg_values_supported,omitempty"`
	UserInfoEncryptionAlgValues []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
	UserInfoEncryptionEncValues []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
	ReqObjSigningAlgValues      []string `json:"request_object_signing_alg_values_supported,omitempty"`
	ReqObjEncryptionAlgValues   []string `json:"request_object_encryption_alg_values_supported,omitempty"`
	ReqObjEncryptionEncValues   []string `json:"request_object_encryption_enc_values_supported,omitempty"`
	TokenEndpointAuthMethodsSupported          []string `json:"token_endpoint_auth_methods_supported,omitempty"`
	TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
	DisplayValuesSupported        []string `json:"display_values_supported,omitempty"`
	ClaimTypesSupported           []string `json:"claim_types_supported,omitempty"`
	ClaimsSupported               []string `json:"claims_supported,omitempty"`
	ServiceDocs                   string   `json:"service_documentation,omitempty"`
	ClaimsLocalsSupported         []string `json:"claims_locales_supported,omitempty"`
	UILocalsSupported             []string `json:"ui_locales_supported,omitempty"`
	ClaimsParameterSupported      bool     `json:"claims_parameter_supported,omitempty"`
	RequestParameterSupported     bool     `json:"request_parameter_supported,omitempty"`
	RequestURIParamaterSupported  bool     `json:"request_uri_parameter_supported,omitempty"`
	RequireRequestURIRegistration bool     `json:"require_request_uri_registration,omitempty"`
	Policy         string `json:"op_policy_uri,omitempty"`
	TermsOfService string `json:"op_tos_uri,omitempty"`
}
func (cfg ProviderConfig) toEncodableStruct() encodableProviderConfig {
	return encodableProviderConfig{
		Issuer:                                     uriToString(cfg.Issuer),
		AuthEndpoint:                               uriToString(cfg.AuthEndpoint),
		TokenEndpoint:                              uriToString(cfg.TokenEndpoint),
		UserInfoEndpoint:                           uriToString(cfg.UserInfoEndpoint),
		KeysEndpoint:                               uriToString(cfg.KeysEndpoint),
		RegistrationEndpoint:                       uriToString(cfg.RegistrationEndpoint),
		ScopesSupported:                            cfg.ScopesSupported,
		ResponseTypesSupported:                     cfg.ResponseTypesSupported,
		ResponseModesSupported:                     cfg.ResponseModesSupported,
		GrantTypesSupported:                        cfg.GrantTypesSupported,
		ACRValuesSupported:                         cfg.ACRValuesSupported,
		SubjectTypesSupported:                      cfg.SubjectTypesSupported,
		IDTokenSigningAlgValues:                    cfg.IDTokenSigningAlgValues,
		IDTokenEncryptionAlgValues:                 cfg.IDTokenEncryptionAlgValues,
		IDTokenEncryptionEncValues:                 cfg.IDTokenEncryptionEncValues,
		UserInfoSigningAlgValues:                   cfg.UserInfoSigningAlgValues,
		UserInfoEncryptionAlgValues:                cfg.UserInfoEncryptionAlgValues,
		UserInfoEncryptionEncValues:                cfg.UserInfoEncryptionEncValues,
		ReqObjSigningAlgValues:                     cfg.ReqObjSigningAlgValues,
		ReqObjEncryptionAlgValues:                  cfg.ReqObjEncryptionAlgValues,
		ReqObjEncryptionEncValues:                  cfg.ReqObjEncryptionEncValues,
		TokenEndpointAuthMethodsSupported:          cfg.TokenEndpointAuthMethodsSupported,
		TokenEndpointAuthSigningAlgValuesSupported: cfg.TokenEndpointAuthSigningAlgValuesSupported,
		DisplayValuesSupported:                     cfg.DisplayValuesSupported,
		ClaimTypesSupported:                        cfg.ClaimTypesSupported,
		ClaimsSupported:                            cfg.ClaimsSupported,
		ServiceDocs:                                uriToString(cfg.ServiceDocs),
		ClaimsLocalsSupported:                      cfg.ClaimsLocalsSupported,
		UILocalsSupported:                          cfg.UILocalsSupported,
		ClaimsParameterSupported:                   cfg.ClaimsParameterSupported,
		RequestParameterSupported:                  cfg.RequestParameterSupported,
		RequestURIParamaterSupported:               cfg.RequestURIParamaterSupported,
		RequireRequestURIRegistration:              cfg.RequireRequestURIRegistration,
		Policy:         uriToString(cfg.Policy),
		TermsOfService: uriToString(cfg.TermsOfService),
	}
}
func (e encodableProviderConfig) toStruct() (ProviderConfig, error) {
	p := stickyErrParser{}
	conf := ProviderConfig{
		Issuer:                                     p.parseURI(e.Issuer, "issuer"),
		AuthEndpoint:                               p.parseURI(e.AuthEndpoint, "authorization_endpoint"),
		TokenEndpoint:                              p.parseURI(e.TokenEndpoint, "token_endpoint"),
		UserInfoEndpoint:                           p.parseURI(e.UserInfoEndpoint, "userinfo_endpoint"),
		KeysEndpoint:                               p.parseURI(e.KeysEndpoint, "jwks_uri"),
		RegistrationEndpoint:                       p.parseURI(e.RegistrationEndpoint, "registration_endpoint"),
		ScopesSupported:                            e.ScopesSupported,
		ResponseTypesSupported:                     e.ResponseTypesSupported,
		ResponseModesSupported:                     e.ResponseModesSupported,
		GrantTypesSupported:                        e.GrantTypesSupported,
		ACRValuesSupported:                         e.ACRValuesSupported,
		SubjectTypesSupported:                      e.SubjectTypesSupported,
		IDTokenSigningAlgValues:                    e.IDTokenSigningAlgValues,
		IDTokenEncryptionAlgValues:                 e.IDTokenEncryptionAlgValues,
		IDTokenEncryptionEncValues:                 e.IDTokenEncryptionEncValues,
		UserInfoSigningAlgValues:                   e.UserInfoSigningAlgValues,
		UserInfoEncryptionAlgValues:                e.UserInfoEncryptionAlgValues,
		UserInfoEncryptionEncValues:                e.UserInfoEncryptionEncValues,
		ReqObjSigningAlgValues:                     e.ReqObjSigningAlgValues,
		ReqObjEncryptionAlgValues:                  e.ReqObjEncryptionAlgValues,
		ReqObjEncryptionEncValues:                  e.ReqObjEncryptionEncValues,
		TokenEndpointAuthMethodsSupported:          e.TokenEndpointAuthMethodsSupported,
		TokenEndpointAuthSigningAlgValuesSupported: e.TokenEndpointAuthSigningAlgValuesSupported,
		DisplayValuesSupported:                     e.DisplayValuesSupported,
		ClaimTypesSupported:                        e.ClaimTypesSupported,
		ClaimsSupported:                            e.ClaimsSupported,
		ServiceDocs:                                p.parseURI(e.ServiceDocs, "service_documentation"),
		ClaimsLocalsSupported:                      e.ClaimsLocalsSupported,
		UILocalsSupported:                          e.UILocalsSupported,
		ClaimsParameterSupported:                   e.ClaimsParameterSupported,
		RequestParameterSupported:                  e.RequestParameterSupported,
		RequestURIParamaterSupported:               e.RequestURIParamaterSupported,
		RequireRequestURIRegistration:              e.RequireRequestURIRegistration,
		Policy:         p.parseURI(e.Policy, "op_policy-uri"),
		TermsOfService: p.parseURI(e.TermsOfService, "op_tos_uri"),
	}
	if p.firstErr != nil {
		return ProviderConfig{}, p.firstErr
	}
	return conf, nil
}
func (p ProviderConfig) Empty() bool {
	return p.Issuer == nil
}
func contains(sli []string, ele string) bool {
	for _, s := range sli {
		if s == ele {
			return true
		}
	}
	return false
}