From 7311a794c7559127f946cafbab07d9b1e07ffcfe Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:32:45 +0200 Subject: [PATCH] chore: reduce registry code bloat and improve DI (#3794) --- client/handler.go | 17 +- client/registry.go | 4 +- consent/strategy_logout_test.go | 1 + driver/di.go | 70 ++++ driver/factory.go | 56 +-- driver/registry.go | 50 +-- driver/registry_base.go | 583 ------------------------------- driver/registry_base_test.go | 124 ------- driver/registry_sql.go | 588 +++++++++++++++++++++++++++++++- driver/registry_sql_test.go | 104 ++++++ fositex/token_strategy.go | 6 +- fositex/token_strategy_test.go | 4 +- go.mod | 6 +- go.sum | 12 +- hsm/manager_hsm_test.go | 8 +- internal/httpclient/go.sum | 347 +++++++++++++++++++ oauth2/helper_test.go | 2 +- 17 files changed, 1178 insertions(+), 804 deletions(-) create mode 100644 driver/di.go delete mode 100644 driver/registry_base.go delete mode 100644 driver/registry_base_test.go diff --git a/client/handler.go b/client/handler.go index 8fac902ba7e..a3bcdc90985 100644 --- a/client/handler.go +++ b/client/handler.go @@ -818,13 +818,26 @@ func (h *Handler) ValidDynamicAuth(r *http.Request, ps httprouter.Params) (fosit } token := strings.TrimPrefix(fosite.AccessTokenFromRequest(r), "ory_at_") - if err := h.r.OAuth2HMACStrategy().Enigma.Validate(r.Context(), token); err != nil { + if err := h.r.OAuth2HMACStrategy().ValidateAccessToken( + r.Context(), + // The strategy checks the expiry time of the token. Registration tokens don't expire (we don't have a way of + // rotating them) so we set the expiry time to a time in the future. + &fosite.Request{ + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.AccessToken: time.Now().Add(time.Hour), + }, + }, + RequestedAt: time.Now(), + }, + token, + ); err != nil { return nil, herodot.ErrUnauthorized. WithTrace(err). WithReason("The requested OAuth 2.0 client does not exist or you provided incorrect credentials.").WithDebug(err.Error()) } - signature := h.r.OAuth2HMACStrategy().Enigma.Signature(token) + signature := h.r.OAuth2EnigmaStrategy().Signature(token) if subtle.ConstantTimeCompare([]byte(c.RegistrationAccessTokenSignature), []byte(signature)) == 0 { return nil, errors.WithStack(herodot.ErrUnauthorized. WithReason("The requested OAuth 2.0 client does not exist or you provided incorrect credentials.").WithDebug("Registration access tokens do not match.")) diff --git a/client/registry.go b/client/registry.go index d7e179a558c..bfec25ace91 100644 --- a/client/registry.go +++ b/client/registry.go @@ -8,6 +8,7 @@ import ( "github.com/ory/fosite" foauth2 "github.com/ory/fosite/handler/oauth2" + enigma "github.com/ory/fosite/token/hmac" "github.com/ory/hydra/v2/jwk" "github.com/ory/hydra/v2/x" ) @@ -22,6 +23,7 @@ type Registry interface { ClientManager() Manager ClientHasher() fosite.Hasher OpenIDJWTStrategy() jwk.JWTSigner - OAuth2HMACStrategy() *foauth2.HMACSHAStrategy + OAuth2HMACStrategy() foauth2.CoreStrategy + OAuth2EnigmaStrategy() *enigma.HMACStrategy config.Provider } diff --git a/consent/strategy_logout_test.go b/consent/strategy_logout_test.go index d64c843b1c9..81dd0743785 100644 --- a/consent/strategy_logout_test.go +++ b/consent/strategy_logout_test.go @@ -40,6 +40,7 @@ func TestLogoutFlows(t *testing.T) { reg := internal.NewMockedRegistry(t, &contextx.Default{}) reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") reg.Config().MustSet(ctx, config.KeyConsentRequestMaxAge, time.Hour) + reg.WithKratos(fakeKratos) defaultRedirectedMessage := "redirected to default server" diff --git a/driver/di.go b/driver/di.go new file mode 100644 index 00000000000..584bf76c043 --- /dev/null +++ b/driver/di.go @@ -0,0 +1,70 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package driver + +import ( + "github.com/pkg/errors" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/fositex" + "github.com/ory/hydra/v2/hsm" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/x/contextx" + "github.com/ory/x/logrusx" +) + +// WritableRegistry is a deprecated interface that should not be used anymore. +// +// Deprecate this at some point. +type WritableRegistry interface { + // WithBuildInfo(v, h, d string) Registry + + WithConfig(c *config.DefaultProvider) Registry + WithContextualizer(ctxer contextx.Contextualizer) Registry + WithLogger(l *logrusx.Logger) Registry + WithTracer(t trace.Tracer) Registry + WithTracerWrapper(TracerWrapper) Registry + WithKratos(k kratos.Client) Registry + WithExtraFositeFactories(f []fositex.Factory) Registry + ExtraFositeFactories() []fositex.Factory + WithOAuth2Provider(f fosite.OAuth2Provider) + WithConsentStrategy(c consent.Strategy) + WithHsmContext(h hsm.Context) +} + +type RegistryModifier func(r Registry) error + +func WithRegistryModifiers(f ...RegistryModifier) OptionsModifier { + return func(o *Options) { + o.registryModifiers = f + } +} + +func RegistryWithHMACSHAStrategy(s func(r Registry) oauth2.CoreStrategy) RegistryModifier { + return func(r Registry) error { + switch rt := r.(type) { + case *RegistrySQL: + rt.hmacs = s(r) + default: + return errors.Errorf("unable to set HMAC strategy on registry of type %T", r) + } + return nil + } +} + +func RegistryWithHsmContext(h hsm.Context) RegistryModifier { + return func(r Registry) error { + switch rt := r.(type) { + case *RegistrySQL: + rt.hsm = h + default: + return errors.Errorf("unable to set HMAC strategy on registry of type %T", r) + } + return nil + } +} diff --git a/driver/factory.go b/driver/factory.go index 75599399938..c7b5d30c3f4 100644 --- a/driver/factory.go +++ b/driver/factory.go @@ -19,40 +19,45 @@ import ( ) type ( - options struct { + Options struct { preload bool validate bool opts []configx.OptionModifier config *config.DefaultProvider // The first default refers to determining the NID at startup; the second default referes to the fact that the Contextualizer may dynamically change the NID. - skipNetworkInit bool - tracerWrapper TracerWrapper - extraMigrations []fs.FS - goMigrations []popx.Migration - fositexFactories []fositex.Factory - inspect func(Registry) error + skipNetworkInit bool + tracerWrapper TracerWrapper + extraMigrations []fs.FS + goMigrations []popx.Migration + fositexFactories []fositex.Factory + registryModifiers []RegistryModifier + inspect func(Registry) error } - OptionsModifier func(*options) + OptionsModifier func(*Options) TracerWrapper func(*otelx.Tracer) *otelx.Tracer ) -func newOptions() *options { - return &options{ +func NewOptions(opts []OptionsModifier) *Options { + o := &Options{ validate: true, preload: true, opts: []configx.OptionModifier{}, } + for _, f := range opts { + f(o) + } + return o } func WithConfig(config *config.DefaultProvider) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.config = config } } func WithOptions(opts ...configx.OptionModifier) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.opts = append(o.opts, opts...) } } @@ -61,61 +66,58 @@ func WithOptions(opts ...configx.OptionModifier) OptionsModifier { // // This does not affect schema validation! func DisableValidation() OptionsModifier { - return func(o *options) { + return func(o *Options) { o.validate = false } } // DisablePreloading will not preload the config. func DisablePreloading() OptionsModifier { - return func(o *options) { + return func(o *Options) { o.preload = false } } func SkipNetworkInit() OptionsModifier { - return func(o *options) { + return func(o *Options) { o.skipNetworkInit = true } } // WithTracerWrapper sets a function that wraps the tracer. func WithTracerWrapper(wrapper TracerWrapper) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.tracerWrapper = wrapper } } // WithExtraMigrations specifies additional database migration. func WithExtraMigrations(m ...fs.FS) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.extraMigrations = append(o.extraMigrations, m...) } } func WithGoMigrations(m ...popx.Migration) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.goMigrations = append(o.goMigrations, m...) } } func WithExtraFositeFactories(f ...fositex.Factory) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.fositexFactories = append(o.fositexFactories, f...) } } func Inspect(f func(Registry) error) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.inspect = f } } func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifier) (Registry, error) { - o := newOptions() - for _, f := range opts { - f(o) - } + o := NewOptions(opts) l := sl.Logger() if l == nil { @@ -151,6 +153,12 @@ func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifie r.WithExtraFositeFactories(o.fositexFactories) + for _, f := range o.registryModifiers { + if err := f(r); err != nil { + return nil, err + } + } + if err = r.Init(ctx, o.skipNetworkInit, false, ctxter, o.extraMigrations, o.goMigrations); err != nil { l.WithError(err).Error("Unable to initialize service registry.") return nil, err diff --git a/driver/registry.go b/driver/registry.go index c28aafcdfc9..954d77a5ad4 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -8,23 +8,16 @@ import ( "io/fs" "net/http" - "go.opentelemetry.io/otel/trace" - - "github.com/ory/hydra/v2/fositex" - "github.com/ory/hydra/v2/internal/kratos" - "github.com/ory/x/httprouterx" + enigma "github.com/ory/fosite/token/hmac" "github.com/ory/x/popx" "github.com/ory/hydra/v2/aead" - "github.com/ory/hydra/v2/hsm" + "github.com/ory/hydra/v2/internal/kratos" "github.com/ory/x/contextx" + "github.com/ory/x/httprouterx" "github.com/ory/hydra/v2/oauth2/trust" - "github.com/pkg/errors" - - "github.com/ory/x/errorsx" - "github.com/ory/fosite" foauth2 "github.com/ory/fosite/handler/oauth2" @@ -47,22 +40,13 @@ import ( type Registry interface { dbal.Driver + WritableRegistry Init(ctx context.Context, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer, extraMigrations []fs.FS, goMigrations []popx.Migration) error - WithBuildInfo(v, h, d string) Registry - WithConfig(c *config.DefaultProvider) Registry - WithContextualizer(ctxer contextx.Contextualizer) Registry - WithLogger(l *logrusx.Logger) Registry - WithTracer(t trace.Tracer) Registry - WithTracerWrapper(TracerWrapper) Registry - WithKratos(k kratos.Client) Registry x.HTTPClientProvider GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy - WithExtraFositeFactories(f []fositex.Factory) Registry - ExtraFositeFactories() []fositex.Factory - contextx.Provider config.Provider persistence.Provider @@ -86,12 +70,10 @@ type Registry interface { ConsentHandler() *consent.Handler OAuth2Handler() *oauth2.Handler HealthHandler() *healthx.Handler + OAuth2EnigmaStrategy() *enigma.HMACStrategy OAuth2AwareMiddleware() func(h http.Handler) http.Handler - OAuth2HMACStrategy() *foauth2.HMACSHAStrategy - WithOAuth2Provider(f fosite.OAuth2Provider) - WithConsentStrategy(c consent.Strategy) - WithHsmContext(h hsm.Context) + OAuth2HMACStrategy() foauth2.CoreStrategy } func NewRegistryFromDSN(ctx context.Context, c *config.DefaultProvider, l *logrusx.Logger, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer) (Registry, error) { @@ -99,22 +81,26 @@ func NewRegistryFromDSN(ctx context.Context, c *config.DefaultProvider, l *logru if err != nil { return nil, err } + if err := registry.Init(ctx, skipNetworkInit, migrate, ctxer, nil, nil); err != nil { return nil, err } + return registry, nil } func NewRegistryWithoutInit(c *config.DefaultProvider, l *logrusx.Logger) (Registry, error) { - driver, err := dbal.GetDriverFor(c.DSN()) - if err != nil { - return nil, errorsx.WithStack(err) - } - registry, ok := driver.(Registry) - if !ok { - return nil, errors.Errorf("driver of type %T does not implement interface Registry", driver) + registry := NewRegistrySQL( + c, l, config.Version, config.Commit, config.Date, + ) + + if !registry.CanHandle(c.DSN()) { + if dbal.IsSQLite(c.DSN()) { + return nil, dbal.ErrSQLiteSupportMissing + } + + return nil, dbal.ErrNoResponsibleDriverFound } - registry = registry.WithLogger(l).WithConfig(c).WithBuildInfo(config.Version, config.Commit, config.Date) return registry, nil } diff --git a/driver/registry_base.go b/driver/registry_base.go deleted file mode 100644 index a541e06ce19..00000000000 --- a/driver/registry_base.go +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package driver - -import ( - "context" - "crypto/sha256" - "fmt" - "net/http" - "time" - - "github.com/gorilla/sessions" - "github.com/hashicorp/go-retryablehttp" - "github.com/pkg/errors" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/rs/cors" - "go.opentelemetry.io/otel/trace" - - "github.com/ory/fosite" - "github.com/ory/fosite/compose" - foauth2 "github.com/ory/fosite/handler/oauth2" - "github.com/ory/fosite/handler/openid" - "github.com/ory/herodot" - "github.com/ory/hydra/v2/aead" - "github.com/ory/hydra/v2/client" - "github.com/ory/hydra/v2/consent" - "github.com/ory/hydra/v2/driver/config" - "github.com/ory/hydra/v2/fositex" - "github.com/ory/hydra/v2/hsm" - "github.com/ory/hydra/v2/internal/kratos" - "github.com/ory/hydra/v2/jwk" - "github.com/ory/hydra/v2/oauth2" - "github.com/ory/hydra/v2/oauth2/trust" - "github.com/ory/hydra/v2/persistence" - "github.com/ory/hydra/v2/x" - "github.com/ory/hydra/v2/x/oauth2cors" - "github.com/ory/x/contextx" - "github.com/ory/x/healthx" - "github.com/ory/x/httprouterx" - "github.com/ory/x/httpx" - "github.com/ory/x/logrusx" - "github.com/ory/x/otelx" - "github.com/ory/x/popx" - prometheus "github.com/ory/x/prometheusx" -) - -var ( - _ contextx.Provider = (*RegistryBase)(nil) -) - -type RegistryBase struct { - l *logrusx.Logger - al *logrusx.Logger - conf *config.DefaultProvider - ch *client.Handler - fh fosite.Hasher - jwtGrantH *trust.Handler - jwtGrantV *trust.GrantValidator - kh *jwk.Handler - cv *client.Validator - ctxer contextx.Contextualizer - hh *healthx.Handler - migrationStatus *popx.MigrationStatuses - kc *aead.AESGCM - flowc *aead.XChaCha20Poly1305 - cos consent.Strategy - writer herodot.Writer - hsm hsm.Context - forv *openid.OpenIDConnectRequestValidator - fop fosite.OAuth2Provider - coh *consent.Handler - oah *oauth2.Handler - sia map[string]consent.SubjectIdentifierAlgorithm - trc *otelx.Tracer - tracerWrapper func(*otelx.Tracer) *otelx.Tracer - pmm *prometheus.MetricsManager - oa2mw func(h http.Handler) http.Handler - arhs []oauth2.AccessRequestHook - buildVersion string - buildHash string - buildDate string - r Registry - persister persistence.Persister - jfs fosite.JWKSFetcherStrategy - oc fosite.Configurator - oidcs jwk.JWTSigner - ats jwk.JWTSigner - hmacs *foauth2.HMACSHAStrategy - fc *fositex.Config - publicCORS *cors.Cors - kratos kratos.Client - fositeFactories []fositex.Factory -} - -func (m *RegistryBase) GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy { - if m.jfs == nil { - m.jfs = fosite.NewDefaultJWKSFetcherStrategy(fosite.JWKSFetcherWithHTTPClientSource(func(ctx context.Context) *retryablehttp.Client { - return m.HTTPClient(ctx) - })) - } - return m.jfs -} - -func (m *RegistryBase) WithContextualizer(ctxer contextx.Contextualizer) Registry { - m.ctxer = ctxer - return m.r -} - -func (m *RegistryBase) Contextualizer() contextx.Contextualizer { - if m.ctxer == nil { - panic("registry Contextualizer not set") - } - return m.ctxer -} - -func (m *RegistryBase) with(r Registry) *RegistryBase { - m.r = r - return m -} - -func (m *RegistryBase) WithBuildInfo(version, hash, date string) Registry { - m.buildVersion = version - m.buildHash = hash - m.buildDate = date - return m.r -} - -func (m *RegistryBase) OAuth2AwareMiddleware() func(h http.Handler) http.Handler { - if m.oa2mw == nil { - m.oa2mw = oauth2cors.Middleware(m.r) - } - return m.oa2mw -} - -func (m *RegistryBase) addPublicCORSOnHandler(ctx context.Context) func(http.Handler) http.Handler { - corsConfig, corsEnabled := m.Config().CORS(ctx, config.PublicInterface) - if !corsEnabled { - return func(h http.Handler) http.Handler { - return h - } - } - if m.publicCORS == nil { - m.publicCORS = cors.New(corsConfig) - } - return func(h http.Handler) http.Handler { - return m.publicCORS.Handler(h) - } -} - -func (m *RegistryBase) RegisterRoutes(ctx context.Context, admin *httprouterx.RouterAdmin, public *httprouterx.RouterPublic) { - m.HealthHandler().SetHealthRoutes(admin.Router, true) - m.HealthHandler().SetVersionRoutes(admin.Router) - - m.HealthHandler().SetHealthRoutes(public.Router, false, healthx.WithMiddleware(m.addPublicCORSOnHandler(ctx))) - - admin.Handler("GET", prometheus.MetricsPrometheusPath, promhttp.Handler()) - - m.ConsentHandler().SetRoutes(admin) - m.KeyHandler().SetRoutes(admin, public, m.OAuth2AwareMiddleware()) - m.ClientHandler().SetRoutes(admin, public) - m.OAuth2Handler().SetRoutes(admin, public, m.OAuth2AwareMiddleware()) - m.JWTGrantHandler().SetRoutes(admin) -} - -func (m *RegistryBase) BuildVersion() string { - return m.buildVersion -} - -func (m *RegistryBase) BuildDate() string { - return m.buildDate -} - -func (m *RegistryBase) BuildHash() string { - return m.buildHash -} - -func (m *RegistryBase) WithConfig(c *config.DefaultProvider) Registry { - m.conf = c - return m.r -} - -func (m *RegistryBase) Writer() herodot.Writer { - if m.writer == nil { - h := herodot.NewJSONWriter(m.Logger()) - h.ErrorEnhancer = x.ErrorEnhancer - m.writer = h - } - return m.writer -} - -func (m *RegistryBase) WithLogger(l *logrusx.Logger) Registry { - m.l = l - return m.r -} - -func (m *RegistryBase) WithTracer(t trace.Tracer) Registry { - m.trc = new(otelx.Tracer).WithOTLP(t) - return m.r -} - -func (m *RegistryBase) WithTracerWrapper(wrapper TracerWrapper) Registry { - m.tracerWrapper = wrapper - return m.r -} - -func (m *RegistryBase) WithKratos(k kratos.Client) Registry { - m.kratos = k - return m.r -} - -func (m *RegistryBase) Logger() *logrusx.Logger { - if m.l == nil { - m.l = logrusx.New("Ory Hydra", m.BuildVersion()) - } - return m.l -} - -func (m *RegistryBase) AuditLogger() *logrusx.Logger { - if m.al == nil { - m.al = logrusx.NewAudit("Ory Hydra", m.BuildVersion()) - m.al.UseConfig(m.Config().Source(contextx.RootContext)) - } - return m.al -} - -func (m *RegistryBase) ClientHasher() fosite.Hasher { - if m.fh == nil { - m.fh = x.NewHasher(m.Config()) - } - return m.fh -} - -func (m *RegistryBase) ClientHandler() *client.Handler { - if m.ch == nil { - m.ch = client.NewHandler(m.r) - } - return m.ch -} - -func (m *RegistryBase) ClientValidator() *client.Validator { - if m.cv == nil { - m.cv = client.NewValidator(m.r) - } - return m.cv -} - -func (m *RegistryBase) KeyHandler() *jwk.Handler { - if m.kh == nil { - m.kh = jwk.NewHandler(m.r) - } - return m.kh -} - -func (m *RegistryBase) JWTGrantHandler() *trust.Handler { - if m.jwtGrantH == nil { - m.jwtGrantH = trust.NewHandler(m.r) - } - return m.jwtGrantH -} - -func (m *RegistryBase) GrantValidator() *trust.GrantValidator { - if m.jwtGrantV == nil { - m.jwtGrantV = trust.NewGrantValidator() - } - return m.jwtGrantV -} - -func (m *RegistryBase) HealthHandler() *healthx.Handler { - if m.hh == nil { - m.hh = healthx.NewHandler(m.Writer(), m.buildVersion, healthx.ReadyCheckers{ - "database": func(_ *http.Request) error { - return m.r.Ping() - }, - "migrations": func(r *http.Request) error { - if m.migrationStatus != nil && !m.migrationStatus.HasPending() { - return nil - } - - status, err := m.r.Persister().MigrationStatus(r.Context()) - if err != nil { - return err - } - - if status.HasPending() { - err := errors.Errorf("migrations have not yet been fully applied: %+v", status) - m.Logger().WithField("status", fmt.Sprintf("%+v", status)).WithError(err).Warn("Instance is not yet ready because migrations have not yet been fully applied.") - return err - } - - m.migrationStatus = &status - return nil - }, - }) - } - - return m.hh -} - -func (m *RegistryBase) ConsentStrategy() consent.Strategy { - if m.cos == nil { - m.cos = consent.NewStrategy(m.r, m.Config()) - } - return m.cos -} - -func (m *RegistryBase) KeyCipher() *aead.AESGCM { - if m.kc == nil { - m.kc = aead.NewAESGCM(m.Config()) - } - return m.kc -} - -func (m *RegistryBase) FlowCipher() *aead.XChaCha20Poly1305 { - if m.flowc == nil { - m.flowc = aead.NewXChaCha20Poly1305(m.Config()) - } - return m.flowc -} - -func (m *RegistryBase) CookieStore(ctx context.Context) (sessions.Store, error) { - var keys [][]byte - secrets, err := m.conf.GetCookieSecrets(ctx) - if err != nil { - return nil, err - } - - for _, k := range secrets { - encrypt := sha256.Sum256(k) - keys = append(keys, k, encrypt[:]) - } - - cs := sessions.NewCookieStore(keys...) - cs.Options.Secure = m.Config().CookieSecure(ctx) - cs.Options.HttpOnly = true - - // CookieStore MaxAge is set to 86400 * 30 by default. This prevents secure cookies retrieval with expiration > 30 days. - // MaxAge(0) disables internal MaxAge check by SecureCookie, see: - // - // https://github.com/ory/hydra/pull/2488#discussion_r618992698 - cs.MaxAge(0) - - if domain := m.Config().CookieDomain(ctx); domain != "" { - cs.Options.Domain = domain - } - - cs.Options.Path = "/" - if sameSite := m.Config().CookieSameSiteMode(ctx); sameSite != 0 { - cs.Options.SameSite = sameSite - } - - return cs, nil -} - -func (m *RegistryBase) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { - opts = append(opts, - httpx.ResilientClientWithLogger(m.Logger()), - httpx.ResilientClientWithMaxRetry(2), - httpx.ResilientClientWithConnectionTimeout(30*time.Second)) - - tracer := m.Tracer(ctx) - if tracer.IsLoaded() { - opts = append(opts, httpx.ResilientClientWithTracer(tracer.Tracer())) - } - - if m.Config().ClientHTTPNoPrivateIPRanges() { - opts = append( - opts, - httpx.ResilientClientDisallowInternalIPs(), - httpx.ResilientClientAllowInternalIPRequestsTo(m.Config().ClientHTTPPrivateIPExceptionURLs()...), - ) - } - return httpx.NewResilientClient(opts...) -} - -func (m *RegistryBase) OAuth2Provider() fosite.OAuth2Provider { - if m.fop != nil { - return m.fop - } - - m.fop = fosite.NewOAuth2Provider(m.r.OAuth2Storage(), m.OAuth2ProviderConfig()) - return m.fop -} - -func (m *RegistryBase) OpenIDJWTStrategy() jwk.JWTSigner { - if m.oidcs != nil { - return m.oidcs - } - - m.oidcs = jwk.NewDefaultJWTSigner(m.Config(), m.r, x.OpenIDConnectKeyName) - return m.oidcs -} - -func (m *RegistryBase) AccessTokenJWTStrategy() jwk.JWTSigner { - if m.ats != nil { - return m.ats - } - - m.ats = jwk.NewDefaultJWTSigner(m.Config(), m.r, x.OAuth2JWTKeyName) - return m.ats -} - -func (m *RegistryBase) OAuth2HMACStrategy() *foauth2.HMACSHAStrategy { - if m.hmacs != nil { - return m.hmacs - } - - m.hmacs = compose.NewOAuth2HMACStrategy(m.OAuth2Config()) - return m.hmacs -} - -func (m *RegistryBase) OAuth2Config() *fositex.Config { - if m.fc != nil { - return m.fc - } - - m.fc = fositex.NewConfig(m.r) - return m.fc -} - -func (m *RegistryBase) ExtraFositeFactories() []fositex.Factory { - return m.fositeFactories -} - -func (m *RegistryBase) WithExtraFositeFactories(f []fositex.Factory) Registry { - m.fositeFactories = f - - return m.r -} - -func (m *RegistryBase) OAuth2ProviderConfig() fosite.Configurator { - if m.oc != nil { - return m.oc - } - - conf := m.OAuth2Config() - hmacAtStrategy := m.OAuth2HMACStrategy() - oidcSigner := m.OpenIDJWTStrategy() - atSigner := m.AccessTokenJWTStrategy() - jwtAtStrategy := &foauth2.DefaultJWTStrategy{ - Signer: atSigner, - HMACSHAStrategy: hmacAtStrategy, - Config: conf, - } - - conf.LoadDefaultHandlers(&compose.CommonStrategy{ - CoreStrategy: fositex.NewTokenStrategy(m.Config(), hmacAtStrategy, &foauth2.DefaultJWTStrategy{ - Signer: jwtAtStrategy, - HMACSHAStrategy: hmacAtStrategy, - Config: conf, - }), - OpenIDConnectTokenStrategy: &openid.DefaultStrategy{ - Config: conf, - Signer: oidcSigner, - }, - Signer: oidcSigner, - }) - - m.oc = conf - return m.oc -} - -func (m *RegistryBase) OpenIDConnectRequestValidator() *openid.OpenIDConnectRequestValidator { - if m.forv == nil { - m.forv = openid.NewOpenIDConnectRequestValidator(&openid.DefaultStrategy{ - Config: m.OAuth2ProviderConfig(), - Signer: m.OpenIDJWTStrategy(), - }, m.OAuth2ProviderConfig()) - } - return m.forv -} - -func (m *RegistryBase) AudienceStrategy() fosite.AudienceMatchingStrategy { - return fosite.DefaultAudienceMatchingStrategy -} - -func (m *RegistryBase) ConsentHandler() *consent.Handler { - if m.coh == nil { - m.coh = consent.NewHandler(m.r, m.Config()) - } - return m.coh -} - -func (m *RegistryBase) OAuth2Handler() *oauth2.Handler { - if m.oah == nil { - m.oah = oauth2.NewHandler(m.r, m.Config()) - } - return m.oah -} - -func (m *RegistryBase) SubjectIdentifierAlgorithm(ctx context.Context) map[string]consent.SubjectIdentifierAlgorithm { - if m.sia == nil { - m.sia = map[string]consent.SubjectIdentifierAlgorithm{} - for _, t := range m.Config().SubjectTypesSupported(ctx) { - switch t { - case "public": - m.sia["public"] = consent.NewSubjectIdentifierAlgorithmPublic() - case "pairwise": - m.sia["pairwise"] = consent.NewSubjectIdentifierAlgorithmPairwise([]byte(m.Config().SubjectIdentifierAlgorithmSalt(ctx))) - } - } - } - return m.sia -} - -func (m *RegistryBase) Tracer(_ context.Context) *otelx.Tracer { - if m.trc == nil { - t, err := otelx.New("Ory Hydra", m.l, m.conf.Tracing()) - if err != nil { - m.Logger().WithError(err).Error("Unable to initialize Tracer.") - } else { - // Wrap the tracer if required - if m.tracerWrapper != nil { - t = m.tracerWrapper(t) - } - - m.trc = t - } - } - if m.trc.Tracer() == nil { - m.trc = otelx.NewNoop(m.l, m.Config().Tracing()) - } - - return m.trc -} - -func (m *RegistryBase) PrometheusManager() *prometheus.MetricsManager { - if m.pmm == nil { - m.pmm = prometheus.NewMetricsManagerWithPrefix("hydra", prometheus.HTTPMetrics, m.buildVersion, m.buildHash, m.buildDate) - } - return m.pmm -} - -func (m *RegistryBase) Persister() persistence.Persister { - return m.persister -} - -// Config returns the configuration for the given context. It may or may not be the same as the global configuration. -func (m *RegistryBase) Config() *config.DefaultProvider { - return m.conf -} - -// WithOAuth2Provider forces an oauth2 provider which is only used for testing. -func (m *RegistryBase) WithOAuth2Provider(f fosite.OAuth2Provider) { - m.fop = f -} - -// WithConsentStrategy forces a consent strategy which is only used for testing. -func (m *RegistryBase) WithConsentStrategy(c consent.Strategy) { - m.cos = c -} - -func (m *RegistryBase) AccessRequestHooks() []oauth2.AccessRequestHook { - if m.arhs == nil { - m.arhs = []oauth2.AccessRequestHook{ - oauth2.RefreshTokenHook(m), - oauth2.TokenHook(m), - } - } - return m.arhs -} - -func (m *RegistryBase) WithHsmContext(h hsm.Context) { - m.hsm = h -} - -func (m *RegistryBase) HSMContext() hsm.Context { - if m.hsm == nil { - m.hsm = hsm.NewContext(m.Config(), m.l) - } - return m.hsm -} - -func (m *RegistrySQL) ClientAuthenticator() x.ClientAuthenticator { - return m.OAuth2Provider().(*fosite.Fosite) -} - -func (m *RegistryBase) Kratos() kratos.Client { - if m.kratos == nil { - m.kratos = kratos.New(m) - } - return m.kratos -} diff --git a/driver/registry_base_test.go b/driver/registry_base_test.go deleted file mode 100644 index 5f0d4fc29cd..00000000000 --- a/driver/registry_base_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package driver - -import ( - "context" - "errors" - "fmt" - "io" - "net/http" - "net/http/httptest" - "testing" - - "github.com/ory/x/randx" - - "github.com/stretchr/testify/require" - - "github.com/ory/x/httpx" - - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/assert" - - "github.com/ory/hydra/v2/driver/config" - "github.com/ory/x/configx" - "github.com/ory/x/contextx" - "github.com/ory/x/logrusx" - - "github.com/gorilla/sessions" -) - -func TestGetJWKSFetcherStrategyHostEnforcment(t *testing.T) { - ctx := context.Background() - l := logrusx.New("", "") - c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) - c.MustSet(ctx, config.KeyDSN, "memory") - c.MustSet(ctx, config.HSMEnabled, "false") - c.MustSet(ctx, config.KeyClientHTTPNoPrivateIPRanges, true) - - registry, err := NewRegistryWithoutInit(c, l) - require.NoError(t, err) - - _, err = registry.GetJWKSFetcherStrategy().Resolve(ctx, "http://localhost:8080", true) - require.ErrorAs(t, err, new(httpx.ErrPrivateIPAddressDisallowed)) -} - -func TestRegistryBase_newKeyStrategy_handlesNetworkError(t *testing.T) { - // Test ensures any network specific error is logged with a - // specific message when attempting to create a new key strategy: issue #2338 - - hook := test.Hook{} // Test hook for asserting log messages - ctx := context.Background() - - l := logrusx.New("", "", logrusx.WithHook(&hook)) - l.Logrus().SetOutput(io.Discard) - l.Logrus().ExitFunc = func(int) {} // Override the exit func to avoid call to os.Exit - - // Create a config and set a valid but unresolvable DSN - c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) - c.MustSet(ctx, config.KeyDSN, "postgres://user:password@127.0.0.1:9999/postgres") - c.MustSet(ctx, config.HSMEnabled, "false") - - registry, err := NewRegistryWithoutInit(c, l) - if err != nil { - t.Errorf("Failed to create registry: %s", err) - return - } - - r := registry.(*RegistrySQL) - r.initialPing = failedPing(errors.New("snizzles")) - - _ = r.Init(context.Background(), true, false, &contextx.TestContextualizer{}, nil, nil) - - registryBase := RegistryBase{r: r, l: l} - registryBase.WithConfig(c) - - assert.Equal(t, logrus.FatalLevel, hook.LastEntry().Level) - assert.Contains(t, hook.LastEntry().Message, "snizzles") -} - -func TestRegistryBase_CookieStore_MaxAgeZero(t *testing.T) { - // Test ensures that CookieStore MaxAge option is equal to zero after initialization - - ctx := context.Background() - r := new(RegistryBase) - r.WithConfig(config.MustNew(context.Background(), logrusx.New("", ""), configx.WithValue(config.KeyGetSystemSecret, []string{randx.MustString(32, randx.AlphaNum)}))) - - s, err := r.CookieStore(ctx) - require.NoError(t, err) - cs := s.(*sessions.CookieStore) - - assert.Equal(t, cs.Options.MaxAge, 0) -} - -func TestRegistryBase_HTTPClient(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) { - writer.WriteHeader(http.StatusOK) - })) - defer ts.Close() - - t.Setenv("CLIENTS_HTTP_PRIVATE_IP_EXCEPTION_URLS", fmt.Sprintf("[%q]", ts.URL+"/exception/*")) - - ctx := context.Background() - r := new(RegistryBase) - r.WithConfig(config.MustNew( - ctx, - logrusx.New("", ""), - configx.WithValues(map[string]interface{}{ - config.KeyClientHTTPNoPrivateIPRanges: true, - }), - )) - - t.Run("case=matches exception glob", func(t *testing.T) { - res, err := r.HTTPClient(ctx).Get(ts.URL + "/exception/foo") - require.NoError(t, err) - assert.Equal(t, 200, res.StatusCode) - }) - - t.Run("case=does not match exception glob", func(t *testing.T) { - _, err := r.HTTPClient(ctx).Get(ts.URL + "/foo") - require.Error(t, err) - }) -} diff --git a/driver/registry_sql.go b/driver/registry_sql.go index 1fa8b9bbb61..bf0b1dfedd8 100644 --- a/driver/registry_sql.go +++ b/driver/registry_sql.go @@ -5,14 +5,45 @@ package driver import ( "context" + "crypto/sha256" + "fmt" "io/fs" + "net/http" "strings" "time" + "github.com/gorilla/sessions" + "github.com/hashicorp/go-retryablehttp" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/rs/cors" + + "github.com/ory/fosite" + "github.com/ory/fosite/compose" + foauth2 "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/handler/openid" + "github.com/ory/fosite/token/hmac" + "github.com/ory/herodot" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/fositex" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/persistence" + "github.com/ory/hydra/v2/x/oauth2cors" + "github.com/ory/x/healthx" + "github.com/ory/x/httprouterx" + "github.com/ory/x/httpx" + "github.com/ory/x/logrusx" + "github.com/ory/x/otelx" + prometheus "github.com/ory/x/prometheusx" + "github.com/gobuffalo/pop/v6" _ "github.com/jackc/pgx/v4/stdlib" "github.com/luna-duclos/instrumentedsql" + "go.opentelemetry.io/otel/trace" + "github.com/ory/hydra/v2/client" "github.com/ory/hydra/v2/consent" "github.com/ory/hydra/v2/hsm" @@ -30,12 +61,57 @@ import ( ) type RegistrySQL struct { - *RegistryBase + l *logrusx.Logger + al *logrusx.Logger + conf *config.DefaultProvider + ch *client.Handler + fh fosite.Hasher + jwtGrantH *trust.Handler + jwtGrantV *trust.GrantValidator + kh *jwk.Handler + cv *client.Validator + ctxer contextx.Contextualizer + hh *healthx.Handler + migrationStatus *popx.MigrationStatuses + kc *aead.AESGCM + flowc *aead.XChaCha20Poly1305 + cos consent.Strategy + writer herodot.Writer + hsm hsm.Context + forv *openid.OpenIDConnectRequestValidator + fop fosite.OAuth2Provider + coh *consent.Handler + oah *oauth2.Handler + sia map[string]consent.SubjectIdentifierAlgorithm + trc *otelx.Tracer + tracerWrapper func(*otelx.Tracer) *otelx.Tracer + pmm *prometheus.MetricsManager + oa2mw func(h http.Handler) http.Handler + arhs []oauth2.AccessRequestHook + buildVersion string + buildHash string + buildDate string + r Registry + persister persistence.Persister + jfs fosite.JWKSFetcherStrategy + oc fosite.Configurator + oidcs jwk.JWTSigner + ats jwk.JWTSigner + hmacs foauth2.CoreStrategy + enigmaHMAC *hmac.HMACStrategy + fc *fositex.Config + publicCORS *cors.Cors + kratos kratos.Client + fositeFactories []fositex.Factory + defaultKeyManager jwk.Manager initialPing func(r *RegistrySQL) error } -var _ Registry = new(RegistrySQL) +var ( + _ contextx.Provider = (*RegistrySQL)(nil) + _ Registry = (*RegistrySQL)(nil) +) // defaultInitialPing is the default function that will be called within RegistrySQL.Init to make sure // the database is reachable. It can be injected for test purposes by changing the value @@ -48,20 +124,20 @@ var defaultInitialPing = func(m *RegistrySQL) error { return nil } -func init() { - dbal.RegisterDriver( - func() dbal.Driver { - return NewRegistrySQL() - }, - ) -} - -func NewRegistrySQL() *RegistrySQL { +func NewRegistrySQL( + c *config.DefaultProvider, + l *logrusx.Logger, + version, hash, date string, +) *RegistrySQL { r := &RegistrySQL{ - RegistryBase: new(RegistryBase), + buildVersion: version, + buildHash: hash, + buildDate: date, + l: l, + conf: c, initialPing: defaultInitialPing, } - r.RegistryBase.with(r) + return r } @@ -198,3 +274,489 @@ func (m *RegistrySQL) SoftwareKeyManager() jwk.Manager { func (m *RegistrySQL) GrantManager() trust.GrantManager { return m.Persister() } + +func (m *RegistrySQL) GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy { + if m.jfs == nil { + m.jfs = fosite.NewDefaultJWKSFetcherStrategy(fosite.JWKSFetcherWithHTTPClientSource(func(ctx context.Context) *retryablehttp.Client { + return m.HTTPClient(ctx) + })) + } + return m.jfs +} + +func (m *RegistrySQL) WithContextualizer(ctxer contextx.Contextualizer) Registry { + m.ctxer = ctxer + return m +} + +func (m *RegistrySQL) Contextualizer() contextx.Contextualizer { + if m.ctxer == nil { + panic("registry Contextualizer not set") + } + return m.ctxer +} + +func (m *RegistrySQL) OAuth2AwareMiddleware() func(h http.Handler) http.Handler { + if m.oa2mw == nil { + m.oa2mw = oauth2cors.Middleware(m) + } + return m.oa2mw +} + +func (m *RegistrySQL) addPublicCORSOnHandler(ctx context.Context) func(http.Handler) http.Handler { + corsConfig, corsEnabled := m.Config().CORS(ctx, config.PublicInterface) + if !corsEnabled { + return func(h http.Handler) http.Handler { + return h + } + } + if m.publicCORS == nil { + m.publicCORS = cors.New(corsConfig) + } + return func(h http.Handler) http.Handler { + return m.publicCORS.Handler(h) + } +} + +func (m *RegistrySQL) RegisterRoutes(ctx context.Context, admin *httprouterx.RouterAdmin, public *httprouterx.RouterPublic) { + m.HealthHandler().SetHealthRoutes(admin.Router, true) + m.HealthHandler().SetVersionRoutes(admin.Router) + + m.HealthHandler().SetHealthRoutes(public.Router, false, healthx.WithMiddleware(m.addPublicCORSOnHandler(ctx))) + + admin.Handler("GET", prometheus.MetricsPrometheusPath, promhttp.Handler()) + + m.ConsentHandler().SetRoutes(admin) + m.KeyHandler().SetRoutes(admin, public, m.OAuth2AwareMiddleware()) + m.ClientHandler().SetRoutes(admin, public) + m.OAuth2Handler().SetRoutes(admin, public, m.OAuth2AwareMiddleware()) + m.JWTGrantHandler().SetRoutes(admin) +} + +func (m *RegistrySQL) BuildVersion() string { + return m.buildVersion +} + +func (m *RegistrySQL) BuildDate() string { + return m.buildDate +} + +func (m *RegistrySQL) BuildHash() string { + return m.buildHash +} + +func (m *RegistrySQL) WithConfig(c *config.DefaultProvider) Registry { + m.conf = c + return m +} + +func (m *RegistrySQL) Writer() herodot.Writer { + if m.writer == nil { + h := herodot.NewJSONWriter(m.Logger()) + h.ErrorEnhancer = x.ErrorEnhancer + m.writer = h + } + return m.writer +} + +func (m *RegistrySQL) WithLogger(l *logrusx.Logger) Registry { + m.l = l + return m +} + +func (m *RegistrySQL) WithTracer(t trace.Tracer) Registry { + m.trc = new(otelx.Tracer).WithOTLP(t) + return m +} + +func (m *RegistrySQL) WithTracerWrapper(wrapper TracerWrapper) Registry { + m.tracerWrapper = wrapper + return m +} + +func (m *RegistrySQL) WithKratos(k kratos.Client) Registry { + m.kratos = k + return m +} + +func (m *RegistrySQL) Logger() *logrusx.Logger { + if m.l == nil { + m.l = logrusx.New("Ory Hydra", m.BuildVersion()) + } + return m.l +} + +func (m *RegistrySQL) AuditLogger() *logrusx.Logger { + if m.al == nil { + m.al = logrusx.NewAudit("Ory Hydra", m.BuildVersion()) + m.al.UseConfig(m.Config().Source(contextx.RootContext)) + } + return m.al +} + +func (m *RegistrySQL) ClientHasher() fosite.Hasher { + if m.fh == nil { + m.fh = x.NewHasher(m.Config()) + } + return m.fh +} + +func (m *RegistrySQL) ClientHandler() *client.Handler { + if m.ch == nil { + m.ch = client.NewHandler(m) + } + return m.ch +} + +func (m *RegistrySQL) ClientValidator() *client.Validator { + if m.cv == nil { + m.cv = client.NewValidator(m) + } + return m.cv +} + +func (m *RegistrySQL) KeyHandler() *jwk.Handler { + if m.kh == nil { + m.kh = jwk.NewHandler(m) + } + return m.kh +} + +func (m *RegistrySQL) JWTGrantHandler() *trust.Handler { + if m.jwtGrantH == nil { + m.jwtGrantH = trust.NewHandler(m) + } + return m.jwtGrantH +} + +func (m *RegistrySQL) GrantValidator() *trust.GrantValidator { + if m.jwtGrantV == nil { + m.jwtGrantV = trust.NewGrantValidator() + } + return m.jwtGrantV +} + +func (m *RegistrySQL) HealthHandler() *healthx.Handler { + if m.hh == nil { + m.hh = healthx.NewHandler(m.Writer(), m.buildVersion, healthx.ReadyCheckers{ + "database": func(_ *http.Request) error { + return m.Ping() + }, + "migrations": func(r *http.Request) error { + if m.migrationStatus != nil && !m.migrationStatus.HasPending() { + return nil + } + + status, err := m.Persister().MigrationStatus(r.Context()) + if err != nil { + return err + } + + if status.HasPending() { + err := errors.Errorf("migrations have not yet been fully applied: %+v", status) + m.Logger().WithField("status", fmt.Sprintf("%+v", status)).WithError(err).Warn("Instance is not yet ready because migrations have not yet been fully applied.") + return err + } + + m.migrationStatus = &status + return nil + }, + }) + } + + return m.hh +} + +func (m *RegistrySQL) ConsentStrategy() consent.Strategy { + if m.cos == nil { + m.cos = consent.NewStrategy(m, m.Config()) + } + return m.cos +} + +func (m *RegistrySQL) KeyCipher() *aead.AESGCM { + if m.kc == nil { + m.kc = aead.NewAESGCM(m.Config()) + } + return m.kc +} + +func (m *RegistrySQL) FlowCipher() *aead.XChaCha20Poly1305 { + if m.flowc == nil { + m.flowc = aead.NewXChaCha20Poly1305(m.Config()) + } + return m.flowc +} + +func (m *RegistrySQL) CookieStore(ctx context.Context) (sessions.Store, error) { + var keys [][]byte + secrets, err := m.conf.GetCookieSecrets(ctx) + if err != nil { + return nil, err + } + + for _, k := range secrets { + encrypt := sha256.Sum256(k) + keys = append(keys, k, encrypt[:]) + } + + cs := sessions.NewCookieStore(keys...) + cs.Options.Secure = m.Config().CookieSecure(ctx) + cs.Options.HttpOnly = true + + // CookieStore MaxAge is set to 86400 * 30 by default. This prevents secure cookies retrieval with expiration > 30 days. + // MaxAge(0) disables internal MaxAge check by SecureCookie, see: + // + // https://github.com/ory/hydra/pull/2488#discussion_r618992698 + cs.MaxAge(0) + + if domain := m.Config().CookieDomain(ctx); domain != "" { + cs.Options.Domain = domain + } + + cs.Options.Path = "/" + if sameSite := m.Config().CookieSameSiteMode(ctx); sameSite != 0 { + cs.Options.SameSite = sameSite + } + + return cs, nil +} + +func (m *RegistrySQL) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { + opts = append(opts, + httpx.ResilientClientWithLogger(m.Logger()), + httpx.ResilientClientWithMaxRetry(2), + httpx.ResilientClientWithConnectionTimeout(30*time.Second)) + + tracer := m.Tracer(ctx) + if tracer.IsLoaded() { + opts = append(opts, httpx.ResilientClientWithTracer(tracer.Tracer())) + } + + if m.Config().ClientHTTPNoPrivateIPRanges() { + opts = append( + opts, + httpx.ResilientClientDisallowInternalIPs(), + httpx.ResilientClientAllowInternalIPRequestsTo(m.Config().ClientHTTPPrivateIPExceptionURLs()...), + ) + } + return httpx.NewResilientClient(opts...) +} + +func (m *RegistrySQL) OAuth2Provider() fosite.OAuth2Provider { + if m.fop != nil { + return m.fop + } + + m.fop = fosite.NewOAuth2Provider(m.OAuth2Storage(), m.OAuth2ProviderConfig()) + return m.fop +} + +func (m *RegistrySQL) OpenIDJWTStrategy() jwk.JWTSigner { + if m.oidcs != nil { + return m.oidcs + } + + m.oidcs = jwk.NewDefaultJWTSigner(m.Config(), m, x.OpenIDConnectKeyName) + return m.oidcs +} + +func (m *RegistrySQL) AccessTokenJWTStrategy() jwk.JWTSigner { + if m.ats != nil { + return m.ats + } + + m.ats = jwk.NewDefaultJWTSigner(m.Config(), m, x.OAuth2JWTKeyName) + return m.ats +} + +func (m *RegistrySQL) OAuth2EnigmaStrategy() *hmac.HMACStrategy { + if m.enigmaHMAC != nil { + return m.enigmaHMAC + } + + m.enigmaHMAC = &hmac.HMACStrategy{Config: m.OAuth2Config()} + return m.enigmaHMAC +} + +func (m *RegistrySQL) OAuth2HMACStrategy() foauth2.CoreStrategy { + if m.hmacs != nil { + return m.hmacs + } + + m.hmacs = foauth2.NewHMACSHAStrategy(m.OAuth2EnigmaStrategy(), m.OAuth2Config()) + return m.hmacs +} + +func (m *RegistrySQL) OAuth2Config() *fositex.Config { + if m.fc != nil { + return m.fc + } + + m.fc = fositex.NewConfig(m) + return m.fc +} + +func (m *RegistrySQL) ExtraFositeFactories() []fositex.Factory { + return m.fositeFactories +} + +func (m *RegistrySQL) WithExtraFositeFactories(f []fositex.Factory) Registry { + m.fositeFactories = f + + return m +} + +func (m *RegistrySQL) OAuth2ProviderConfig() fosite.Configurator { + if m.oc != nil { + return m.oc + } + + conf := m.OAuth2Config() + hmacAtStrategy := m.OAuth2HMACStrategy() + oidcSigner := m.OpenIDJWTStrategy() + atSigner := m.AccessTokenJWTStrategy() + jwtAtStrategy := &foauth2.DefaultJWTStrategy{ + Signer: atSigner, + HMACSHAStrategy: hmacAtStrategy, + Config: conf, + } + + conf.LoadDefaultHandlers(&compose.CommonStrategy{ + CoreStrategy: fositex.NewTokenStrategy(m.Config(), hmacAtStrategy, &foauth2.DefaultJWTStrategy{ + Signer: jwtAtStrategy, + HMACSHAStrategy: hmacAtStrategy, + Config: conf, + }), + OpenIDConnectTokenStrategy: &openid.DefaultStrategy{ + Config: conf, + Signer: oidcSigner, + }, + Signer: oidcSigner, + }) + + m.oc = conf + return m.oc +} + +func (m *RegistrySQL) OpenIDConnectRequestValidator() *openid.OpenIDConnectRequestValidator { + if m.forv == nil { + m.forv = openid.NewOpenIDConnectRequestValidator(&openid.DefaultStrategy{ + Config: m.OAuth2ProviderConfig(), + Signer: m.OpenIDJWTStrategy(), + }, m.OAuth2ProviderConfig()) + } + return m.forv +} + +func (m *RegistrySQL) AudienceStrategy() fosite.AudienceMatchingStrategy { + return fosite.DefaultAudienceMatchingStrategy +} + +func (m *RegistrySQL) ConsentHandler() *consent.Handler { + if m.coh == nil { + m.coh = consent.NewHandler(m, m.Config()) + } + return m.coh +} + +func (m *RegistrySQL) OAuth2Handler() *oauth2.Handler { + if m.oah == nil { + m.oah = oauth2.NewHandler(m, m.Config()) + } + return m.oah +} + +func (m *RegistrySQL) SubjectIdentifierAlgorithm(ctx context.Context) map[string]consent.SubjectIdentifierAlgorithm { + if m.sia == nil { + m.sia = map[string]consent.SubjectIdentifierAlgorithm{} + for _, t := range m.Config().SubjectTypesSupported(ctx) { + switch t { + case "public": + m.sia["public"] = consent.NewSubjectIdentifierAlgorithmPublic() + case "pairwise": + m.sia["pairwise"] = consent.NewSubjectIdentifierAlgorithmPairwise([]byte(m.Config().SubjectIdentifierAlgorithmSalt(ctx))) + } + } + } + return m.sia +} + +func (m *RegistrySQL) Tracer(_ context.Context) *otelx.Tracer { + if m.trc == nil { + t, err := otelx.New("Ory Hydra", m.l, m.conf.Tracing()) + if err != nil { + m.Logger().WithError(err).Error("Unable to initialize Tracer.") + } else { + // Wrap the tracer if required + if m.tracerWrapper != nil { + t = m.tracerWrapper(t) + } + + m.trc = t + } + } + if m.trc.Tracer() == nil { + m.trc = otelx.NewNoop(m.l, m.Config().Tracing()) + } + + return m.trc +} + +func (m *RegistrySQL) PrometheusManager() *prometheus.MetricsManager { + if m.pmm == nil { + m.pmm = prometheus.NewMetricsManagerWithPrefix("hydra", prometheus.HTTPMetrics, m.buildVersion, m.buildHash, m.buildDate) + } + return m.pmm +} + +func (m *RegistrySQL) Persister() persistence.Persister { + return m.persister +} + +// Config returns the configuration for the given context. It may or may not be the same as the global configuration. +func (m *RegistrySQL) Config() *config.DefaultProvider { + return m.conf +} + +// WithOAuth2Provider forces an oauth2 provider which is only used for testing. +func (m *RegistrySQL) WithOAuth2Provider(f fosite.OAuth2Provider) { + m.fop = f +} + +// WithConsentStrategy forces a consent strategy which is only used for testing. +func (m *RegistrySQL) WithConsentStrategy(c consent.Strategy) { + m.cos = c +} + +func (m *RegistrySQL) AccessRequestHooks() []oauth2.AccessRequestHook { + if m.arhs == nil { + m.arhs = []oauth2.AccessRequestHook{ + oauth2.RefreshTokenHook(m), + oauth2.TokenHook(m), + } + } + return m.arhs +} + +func (m *RegistrySQL) WithHsmContext(h hsm.Context) { + m.hsm = h +} + +func (m *RegistrySQL) HSMContext() hsm.Context { + if m.hsm == nil { + m.hsm = hsm.NewContext(m.Config(), m.l) + } + return m.hsm +} + +func (m *RegistrySQL) ClientAuthenticator() x.ClientAuthenticator { + return m.OAuth2Provider().(*fosite.Fosite) +} + +func (m *RegistrySQL) Kratos() kratos.Client { + if m.kratos == nil { + m.kratos = kratos.New(m) + } + return m.kratos +} diff --git a/driver/registry_sql_test.go b/driver/registry_sql_test.go index d4a88ef0b9d..38bc27f0746 100644 --- a/driver/registry_sql_test.go +++ b/driver/registry_sql_test.go @@ -21,8 +21,112 @@ import ( "github.com/ory/x/errorsx" "github.com/ory/x/logrusx" "github.com/ory/x/sqlcon/dockertest" + + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + + "github.com/ory/x/randx" + + "github.com/ory/x/httpx" + + "github.com/gorilla/sessions" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" ) +func TestGetJWKSFetcherStrategyHostEnforcment(t *testing.T) { + ctx := context.Background() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) + c.MustSet(ctx, config.KeyDSN, "memory") + c.MustSet(ctx, config.HSMEnabled, "false") + c.MustSet(ctx, config.KeyClientHTTPNoPrivateIPRanges, true) + + registry, err := NewRegistryWithoutInit(c, l) + require.NoError(t, err) + + _, err = registry.GetJWKSFetcherStrategy().Resolve(ctx, "http://localhost:8080", true) + require.ErrorAs(t, err, new(httpx.ErrPrivateIPAddressDisallowed)) +} + +func TestRegistrySQL_newKeyStrategy_handlesNetworkError(t *testing.T) { + // Test ensures any network specific error is logged with a + // specific message when attempting to create a new key strategy: issue #2338 + + hook := test.Hook{} // Test hook for asserting log messages + ctx := context.Background() + + l := logrusx.New("", "", logrusx.WithHook(&hook)) + l.Logrus().SetOutput(io.Discard) + l.Logrus().ExitFunc = func(int) {} // Override the exit func to avoid call to os.Exit + + // Create a config and set a valid but unresolvable DSN + c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) + c.MustSet(ctx, config.KeyDSN, "postgres://user:password@127.0.0.1:9999/postgres") + c.MustSet(ctx, config.HSMEnabled, "false") + + registry, err := NewRegistryWithoutInit(c, l) + if err != nil { + t.Errorf("Failed to create registry: %s", err) + return + } + + r := registry.(*RegistrySQL) + r.initialPing = failedPing(errors.New("snizzles")) + + _ = r.Init(context.Background(), true, false, &contextx.TestContextualizer{}, nil, nil) + + assert.Equal(t, logrus.FatalLevel, hook.LastEntry().Level) + assert.Contains(t, hook.LastEntry().Message, "snizzles") +} + +func TestRegistrySQL_CookieStore_MaxAgeZero(t *testing.T) { + // Test ensures that CookieStore MaxAge option is equal to zero after initialization + + ctx := context.Background() + r := new(RegistrySQL) + r.WithConfig(config.MustNew(context.Background(), logrusx.New("", ""), configx.WithValue(config.KeyGetSystemSecret, []string{randx.MustString(32, randx.AlphaNum)}))) + + s, err := r.CookieStore(ctx) + require.NoError(t, err) + cs := s.(*sessions.CookieStore) + + assert.Equal(t, cs.Options.MaxAge, 0) +} + +func TestRegistrySQL_HTTPClient(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) { + writer.WriteHeader(http.StatusOK) + })) + defer ts.Close() + + t.Setenv("CLIENTS_HTTP_PRIVATE_IP_EXCEPTION_URLS", fmt.Sprintf("[%q]", ts.URL+"/exception/*")) + + ctx := context.Background() + r := new(RegistrySQL) + r.WithConfig(config.MustNew( + ctx, + logrusx.New("", ""), + configx.WithValues(map[string]interface{}{ + config.KeyClientHTTPNoPrivateIPRanges: true, + }), + )) + + t.Run("case=matches exception glob", func(t *testing.T) { + res, err := r.HTTPClient(ctx).Get(ts.URL + "/exception/foo") + require.NoError(t, err) + assert.Equal(t, 200, res.StatusCode) + }) + + t.Run("case=does not match exception glob", func(t *testing.T) { + _, err := r.HTTPClient(ctx).Get(ts.URL + "/foo") + require.Error(t, err) + }) +} + func TestDefaultKeyManager_HsmDisabled(t *testing.T) { l := logrusx.New("", "") c := config.MustNew(context.Background(), l, configx.SkipValidation()) diff --git a/fositex/token_strategy.go b/fositex/token_strategy.go index 2a84822a246..116a904c7ef 100644 --- a/fositex/token_strategy.go +++ b/fositex/token_strategy.go @@ -18,12 +18,12 @@ var _ foauth2.CoreStrategy = (*TokenStrategy)(nil) // TokenStrategy uses the correct token strategy (jwt, opaque) depending on the configuration. type TokenStrategy struct { c *config.DefaultProvider - hmac *foauth2.HMACSHAStrategy - jwt *foauth2.DefaultJWTStrategy + hmac foauth2.CoreStrategy + jwt foauth2.CoreStrategy } // NewTokenStrategy returns a new TokenStrategy. -func NewTokenStrategy(c *config.DefaultProvider, hmac *foauth2.HMACSHAStrategy, jwt *foauth2.DefaultJWTStrategy) *TokenStrategy { +func NewTokenStrategy(c *config.DefaultProvider, hmac foauth2.CoreStrategy, jwt *foauth2.DefaultJWTStrategy) *TokenStrategy { return &TokenStrategy{c: c, hmac: hmac, jwt: jwt} } diff --git a/fositex/token_strategy_test.go b/fositex/token_strategy_test.go index e308de58ef4..5572311346a 100644 --- a/fositex/token_strategy_test.go +++ b/fositex/token_strategy_test.go @@ -7,6 +7,8 @@ import ( "context" "testing" + "github.com/ory/fosite/token/hmac" + "github.com/stretchr/testify/assert" "github.com/ory/fosite/handler/oauth2" @@ -34,7 +36,7 @@ func TestAccessTokenSignature(t *testing.T) { } }) t.Run("strategy=HMACStrategy", func(t *testing.T) { - strategy := new(oauth2.HMACSHAStrategy) + strategy := oauth2.NewHMACSHAStrategy(&hmac.HMACStrategy{}, nil) for _, tc := range []struct{ token string }{ {""}, {"foo"}, diff --git a/go.mod b/go.mod index 68ebb6f057d..00f7ccccbe4 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/oleiade/reflections v1.0.1 github.com/ory/analytics-go/v5 v5.0.1 - github.com/ory/fosite v0.46.1 + github.com/ory/fosite v0.47.0 github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe github.com/ory/graceful v0.1.3 github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 @@ -87,9 +87,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cockroachdb/cockroach-go/v2 v2.3.5 // indirect github.com/containerd/continuity v0.4.1 // indirect - github.com/creasty/defaults v1.7.0 // indirect github.com/cristalhq/jwt/v4 v4.0.2 // indirect - github.com/dave/jennifer v1.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect @@ -99,11 +97,9 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/ecordell/optgen v0.0.9 // indirect github.com/elliotchance/orderedmap v1.5.0 // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/fatih/structtag v1.2.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect diff --git a/go.sum b/go.sum index 2be6637ec82..4afdbfad719 100644 --- a/go.sum +++ b/go.sum @@ -107,12 +107,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/creasty/defaults v1.7.0 h1:eNdqZvc5B509z18lD8yc212CAqJNvfT1Jq6L8WowdBA= -github.com/creasty/defaults v1.7.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/cristalhq/jwt/v4 v4.0.2 h1:g/AD3h0VicDamtlM70GWGElp8kssQEv+5wYd7L9WOhU= github.com/cristalhq/jwt/v4 v4.0.2/go.mod h1:HnYraSNKDRag1DZP92rYHyrjyQHnVEHPNqesmzs+miQ= -github.com/dave/jennifer v1.7.0 h1:uRbSBH9UTS64yXbh4FrMHfgfY762RD+C7bUPKODpSJE= -github.com/dave/jennifer v1.7.0/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -135,8 +131,6 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/ecordell/optgen v0.0.9 h1:kmRMqOkbNsWayOnZSk2m5SeGaOTOc7amfi+MAnaMOeI= -github.com/ecordell/optgen v0.0.9/go.mod h1:+YZ4tk5pNGMoeH+Y4F4HeDDj0SLOlIgMMNae7az4h5g= github.com/elliotchance/orderedmap v1.5.0 h1:1IsExUsjv5XNBD3ZdC7jkAAqLWOOKdbPTmkHx63OsBg= github.com/elliotchance/orderedmap v1.5.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -152,8 +146,6 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -622,8 +614,8 @@ github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBp github.com/ory/analytics-go/v5 v5.0.1/go.mod h1:lWCiCjAaJkKfgR/BN5DCLMol8BjKS1x+4jxBxff/FF0= github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= -github.com/ory/fosite v0.46.1 h1:VC8h83cbWx7K5r/VToDldSC+317sKFqJjLOPB4Ns4AY= -github.com/ory/fosite v0.46.1/go.mod h1:fkMPsnm/UjiefE9dE9CdZQGOH48TWJLIzUcdGIXg8Kk= +github.com/ory/fosite v0.47.0 h1:Iqu5uhx54JqZQPn2hRhqjESrmRRyQb00uJjfEi1a1QI= +github.com/ory/fosite v0.47.0/go.mod h1:5U6c9nOLxyTdD/qrFv7N88TSxkdk5Wq8NzvB7UViDP0= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8= diff --git a/hsm/manager_hsm_test.go b/hsm/manager_hsm_test.go index 186fcc0d295..17f4be0dfc9 100644 --- a/hsm/manager_hsm_test.go +++ b/hsm/manager_hsm_test.go @@ -48,12 +48,10 @@ func TestDefaultKeyManager_HSMEnabled(t *testing.T) { c := config.MustNew(context.Background(), l, configx.SkipValidation()) c.MustSet(context.Background(), config.KeyDSN, "memory") c.MustSet(context.Background(), config.HSMEnabled, "true") - reg := driver.NewRegistrySQL() - reg.WithLogger(l) - reg.WithConfig(c) + reg, err := driver.NewRegistryWithoutInit(c, l) + require.NoError(t, err) reg.WithHsmContext(mockHsmContext) - err := reg.Init(context.Background(), false, true, &contextx.TestContextualizer{}, nil, nil) - assert.NoError(t, err) + assert.NoError(t, reg.Init(context.Background(), false, true, &contextx.TestContextualizer{}, nil, nil)) assert.IsType(t, &jwk.ManagerStrategy{}, reg.KeyManager()) assert.IsType(t, &sql.Persister{}, reg.SoftwareKeyManager()) } diff --git a/internal/httpclient/go.sum b/internal/httpclient/go.sum index 734252e6815..3dee6d68163 100644 --- a/internal/httpclient/go.sum +++ b/internal/httpclient/go.sum @@ -1,13 +1,360 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/oauth2/helper_test.go b/oauth2/helper_test.go index 74c25bdcfb0..3a40592bfdd 100644 --- a/oauth2/helper_test.go +++ b/oauth2/helper_test.go @@ -12,7 +12,7 @@ import ( ) func Tokens(c fosite.Configurator, length int) (res [][]string) { - s := &oauth2.HMACSHAStrategy{Enigma: &hmac.HMACStrategy{Config: c}, Config: c} + s := oauth2.NewHMACSHAStrategy(&hmac.HMACStrategy{Config: c}, c) for i := 0; i < length; i++ { tok, sig, _ := s.Enigma.Generate(context.Background())