Skip to content

Commit 7311a79

Browse files
authored
chore: reduce registry code bloat and improve DI (#3794)
1 parent 28f139f commit 7311a79

17 files changed

+1178
-804
lines changed

client/handler.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -818,13 +818,26 @@ func (h *Handler) ValidDynamicAuth(r *http.Request, ps httprouter.Params) (fosit
818818
}
819819

820820
token := strings.TrimPrefix(fosite.AccessTokenFromRequest(r), "ory_at_")
821-
if err := h.r.OAuth2HMACStrategy().Enigma.Validate(r.Context(), token); err != nil {
821+
if err := h.r.OAuth2HMACStrategy().ValidateAccessToken(
822+
r.Context(),
823+
// The strategy checks the expiry time of the token. Registration tokens don't expire (we don't have a way of
824+
// rotating them) so we set the expiry time to a time in the future.
825+
&fosite.Request{
826+
Session: &fosite.DefaultSession{
827+
ExpiresAt: map[fosite.TokenType]time.Time{
828+
fosite.AccessToken: time.Now().Add(time.Hour),
829+
},
830+
},
831+
RequestedAt: time.Now(),
832+
},
833+
token,
834+
); err != nil {
822835
return nil, herodot.ErrUnauthorized.
823836
WithTrace(err).
824837
WithReason("The requested OAuth 2.0 client does not exist or you provided incorrect credentials.").WithDebug(err.Error())
825838
}
826839

827-
signature := h.r.OAuth2HMACStrategy().Enigma.Signature(token)
840+
signature := h.r.OAuth2EnigmaStrategy().Signature(token)
828841
if subtle.ConstantTimeCompare([]byte(c.RegistrationAccessTokenSignature), []byte(signature)) == 0 {
829842
return nil, errors.WithStack(herodot.ErrUnauthorized.
830843
WithReason("The requested OAuth 2.0 client does not exist or you provided incorrect credentials.").WithDebug("Registration access tokens do not match."))

client/registry.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/ory/fosite"
1010
foauth2 "github.com/ory/fosite/handler/oauth2"
11+
enigma "github.com/ory/fosite/token/hmac"
1112
"github.com/ory/hydra/v2/jwk"
1213
"github.com/ory/hydra/v2/x"
1314
)
@@ -22,6 +23,7 @@ type Registry interface {
2223
ClientManager() Manager
2324
ClientHasher() fosite.Hasher
2425
OpenIDJWTStrategy() jwk.JWTSigner
25-
OAuth2HMACStrategy() *foauth2.HMACSHAStrategy
26+
OAuth2HMACStrategy() foauth2.CoreStrategy
27+
OAuth2EnigmaStrategy() *enigma.HMACStrategy
2628
config.Provider
2729
}

consent/strategy_logout_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func TestLogoutFlows(t *testing.T) {
4040
reg := internal.NewMockedRegistry(t, &contextx.Default{})
4141
reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque")
4242
reg.Config().MustSet(ctx, config.KeyConsentRequestMaxAge, time.Hour)
43+
4344
reg.WithKratos(fakeKratos)
4445

4546
defaultRedirectedMessage := "redirected to default server"

driver/di.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright © 2024 Ory Corp
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package driver
5+
6+
import (
7+
"github.com/pkg/errors"
8+
"go.opentelemetry.io/otel/trace"
9+
10+
"github.com/ory/fosite"
11+
"github.com/ory/fosite/handler/oauth2"
12+
"github.com/ory/hydra/v2/consent"
13+
"github.com/ory/hydra/v2/driver/config"
14+
"github.com/ory/hydra/v2/fositex"
15+
"github.com/ory/hydra/v2/hsm"
16+
"github.com/ory/hydra/v2/internal/kratos"
17+
"github.com/ory/x/contextx"
18+
"github.com/ory/x/logrusx"
19+
)
20+
21+
// WritableRegistry is a deprecated interface that should not be used anymore.
22+
//
23+
// Deprecate this at some point.
24+
type WritableRegistry interface {
25+
// WithBuildInfo(v, h, d string) Registry
26+
27+
WithConfig(c *config.DefaultProvider) Registry
28+
WithContextualizer(ctxer contextx.Contextualizer) Registry
29+
WithLogger(l *logrusx.Logger) Registry
30+
WithTracer(t trace.Tracer) Registry
31+
WithTracerWrapper(TracerWrapper) Registry
32+
WithKratos(k kratos.Client) Registry
33+
WithExtraFositeFactories(f []fositex.Factory) Registry
34+
ExtraFositeFactories() []fositex.Factory
35+
WithOAuth2Provider(f fosite.OAuth2Provider)
36+
WithConsentStrategy(c consent.Strategy)
37+
WithHsmContext(h hsm.Context)
38+
}
39+
40+
type RegistryModifier func(r Registry) error
41+
42+
func WithRegistryModifiers(f ...RegistryModifier) OptionsModifier {
43+
return func(o *Options) {
44+
o.registryModifiers = f
45+
}
46+
}
47+
48+
func RegistryWithHMACSHAStrategy(s func(r Registry) oauth2.CoreStrategy) RegistryModifier {
49+
return func(r Registry) error {
50+
switch rt := r.(type) {
51+
case *RegistrySQL:
52+
rt.hmacs = s(r)
53+
default:
54+
return errors.Errorf("unable to set HMAC strategy on registry of type %T", r)
55+
}
56+
return nil
57+
}
58+
}
59+
60+
func RegistryWithHsmContext(h hsm.Context) RegistryModifier {
61+
return func(r Registry) error {
62+
switch rt := r.(type) {
63+
case *RegistrySQL:
64+
rt.hsm = h
65+
default:
66+
return errors.Errorf("unable to set HMAC strategy on registry of type %T", r)
67+
}
68+
return nil
69+
}
70+
}

driver/factory.go

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,45 @@ import (
1919
)
2020

2121
type (
22-
options struct {
22+
Options struct {
2323
preload bool
2424
validate bool
2525
opts []configx.OptionModifier
2626
config *config.DefaultProvider
2727
// 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.
28-
skipNetworkInit bool
29-
tracerWrapper TracerWrapper
30-
extraMigrations []fs.FS
31-
goMigrations []popx.Migration
32-
fositexFactories []fositex.Factory
33-
inspect func(Registry) error
28+
skipNetworkInit bool
29+
tracerWrapper TracerWrapper
30+
extraMigrations []fs.FS
31+
goMigrations []popx.Migration
32+
fositexFactories []fositex.Factory
33+
registryModifiers []RegistryModifier
34+
inspect func(Registry) error
3435
}
35-
OptionsModifier func(*options)
36+
OptionsModifier func(*Options)
3637

3738
TracerWrapper func(*otelx.Tracer) *otelx.Tracer
3839
)
3940

40-
func newOptions() *options {
41-
return &options{
41+
func NewOptions(opts []OptionsModifier) *Options {
42+
o := &Options{
4243
validate: true,
4344
preload: true,
4445
opts: []configx.OptionModifier{},
4546
}
47+
for _, f := range opts {
48+
f(o)
49+
}
50+
return o
4651
}
4752

4853
func WithConfig(config *config.DefaultProvider) OptionsModifier {
49-
return func(o *options) {
54+
return func(o *Options) {
5055
o.config = config
5156
}
5257
}
5358

5459
func WithOptions(opts ...configx.OptionModifier) OptionsModifier {
55-
return func(o *options) {
60+
return func(o *Options) {
5661
o.opts = append(o.opts, opts...)
5762
}
5863
}
@@ -61,61 +66,58 @@ func WithOptions(opts ...configx.OptionModifier) OptionsModifier {
6166
//
6267
// This does not affect schema validation!
6368
func DisableValidation() OptionsModifier {
64-
return func(o *options) {
69+
return func(o *Options) {
6570
o.validate = false
6671
}
6772
}
6873

6974
// DisablePreloading will not preload the config.
7075
func DisablePreloading() OptionsModifier {
71-
return func(o *options) {
76+
return func(o *Options) {
7277
o.preload = false
7378
}
7479
}
7580

7681
func SkipNetworkInit() OptionsModifier {
77-
return func(o *options) {
82+
return func(o *Options) {
7883
o.skipNetworkInit = true
7984
}
8085
}
8186

8287
// WithTracerWrapper sets a function that wraps the tracer.
8388
func WithTracerWrapper(wrapper TracerWrapper) OptionsModifier {
84-
return func(o *options) {
89+
return func(o *Options) {
8590
o.tracerWrapper = wrapper
8691
}
8792
}
8893

8994
// WithExtraMigrations specifies additional database migration.
9095
func WithExtraMigrations(m ...fs.FS) OptionsModifier {
91-
return func(o *options) {
96+
return func(o *Options) {
9297
o.extraMigrations = append(o.extraMigrations, m...)
9398
}
9499
}
95100

96101
func WithGoMigrations(m ...popx.Migration) OptionsModifier {
97-
return func(o *options) {
102+
return func(o *Options) {
98103
o.goMigrations = append(o.goMigrations, m...)
99104
}
100105
}
101106

102107
func WithExtraFositeFactories(f ...fositex.Factory) OptionsModifier {
103-
return func(o *options) {
108+
return func(o *Options) {
104109
o.fositexFactories = append(o.fositexFactories, f...)
105110
}
106111
}
107112

108113
func Inspect(f func(Registry) error) OptionsModifier {
109-
return func(o *options) {
114+
return func(o *Options) {
110115
o.inspect = f
111116
}
112117
}
113118

114119
func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifier) (Registry, error) {
115-
o := newOptions()
116-
for _, f := range opts {
117-
f(o)
118-
}
120+
o := NewOptions(opts)
119121

120122
l := sl.Logger()
121123
if l == nil {
@@ -151,6 +153,12 @@ func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifie
151153

152154
r.WithExtraFositeFactories(o.fositexFactories)
153155

156+
for _, f := range o.registryModifiers {
157+
if err := f(r); err != nil {
158+
return nil, err
159+
}
160+
}
161+
154162
if err = r.Init(ctx, o.skipNetworkInit, false, ctxter, o.extraMigrations, o.goMigrations); err != nil {
155163
l.WithError(err).Error("Unable to initialize service registry.")
156164
return nil, err

driver/registry.go

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,16 @@ import (
88
"io/fs"
99
"net/http"
1010

11-
"go.opentelemetry.io/otel/trace"
12-
13-
"github.com/ory/hydra/v2/fositex"
14-
"github.com/ory/hydra/v2/internal/kratos"
15-
"github.com/ory/x/httprouterx"
11+
enigma "github.com/ory/fosite/token/hmac"
1612
"github.com/ory/x/popx"
1713

1814
"github.com/ory/hydra/v2/aead"
19-
"github.com/ory/hydra/v2/hsm"
15+
"github.com/ory/hydra/v2/internal/kratos"
2016
"github.com/ory/x/contextx"
17+
"github.com/ory/x/httprouterx"
2118

2219
"github.com/ory/hydra/v2/oauth2/trust"
2320

24-
"github.com/pkg/errors"
25-
26-
"github.com/ory/x/errorsx"
27-
2821
"github.com/ory/fosite"
2922
foauth2 "github.com/ory/fosite/handler/oauth2"
3023

@@ -47,22 +40,13 @@ import (
4740

4841
type Registry interface {
4942
dbal.Driver
43+
WritableRegistry
5044

5145
Init(ctx context.Context, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer, extraMigrations []fs.FS, goMigrations []popx.Migration) error
5246

53-
WithBuildInfo(v, h, d string) Registry
54-
WithConfig(c *config.DefaultProvider) Registry
55-
WithContextualizer(ctxer contextx.Contextualizer) Registry
56-
WithLogger(l *logrusx.Logger) Registry
57-
WithTracer(t trace.Tracer) Registry
58-
WithTracerWrapper(TracerWrapper) Registry
59-
WithKratos(k kratos.Client) Registry
6047
x.HTTPClientProvider
6148
GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy
6249

63-
WithExtraFositeFactories(f []fositex.Factory) Registry
64-
ExtraFositeFactories() []fositex.Factory
65-
6650
contextx.Provider
6751
config.Provider
6852
persistence.Provider
@@ -86,35 +70,37 @@ type Registry interface {
8670
ConsentHandler() *consent.Handler
8771
OAuth2Handler() *oauth2.Handler
8872
HealthHandler() *healthx.Handler
73+
OAuth2EnigmaStrategy() *enigma.HMACStrategy
8974
OAuth2AwareMiddleware() func(h http.Handler) http.Handler
9075

91-
OAuth2HMACStrategy() *foauth2.HMACSHAStrategy
92-
WithOAuth2Provider(f fosite.OAuth2Provider)
93-
WithConsentStrategy(c consent.Strategy)
94-
WithHsmContext(h hsm.Context)
76+
OAuth2HMACStrategy() foauth2.CoreStrategy
9577
}
9678

9779
func NewRegistryFromDSN(ctx context.Context, c *config.DefaultProvider, l *logrusx.Logger, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer) (Registry, error) {
9880
registry, err := NewRegistryWithoutInit(c, l)
9981
if err != nil {
10082
return nil, err
10183
}
84+
10285
if err := registry.Init(ctx, skipNetworkInit, migrate, ctxer, nil, nil); err != nil {
10386
return nil, err
10487
}
88+
10589
return registry, nil
10690
}
10791

10892
func NewRegistryWithoutInit(c *config.DefaultProvider, l *logrusx.Logger) (Registry, error) {
109-
driver, err := dbal.GetDriverFor(c.DSN())
110-
if err != nil {
111-
return nil, errorsx.WithStack(err)
112-
}
113-
registry, ok := driver.(Registry)
114-
if !ok {
115-
return nil, errors.Errorf("driver of type %T does not implement interface Registry", driver)
93+
registry := NewRegistrySQL(
94+
c, l, config.Version, config.Commit, config.Date,
95+
)
96+
97+
if !registry.CanHandle(c.DSN()) {
98+
if dbal.IsSQLite(c.DSN()) {
99+
return nil, dbal.ErrSQLiteSupportMissing
100+
}
101+
102+
return nil, dbal.ErrNoResponsibleDriverFound
116103
}
117-
registry = registry.WithLogger(l).WithConfig(c).WithBuildInfo(config.Version, config.Commit, config.Date)
118104

119105
return registry, nil
120106
}

0 commit comments

Comments
 (0)