diff --git a/idp/dex/connector.go b/idp/dex/connector.go index 0c0f93ea1..6505c8853 100644 --- a/idp/dex/connector.go +++ b/idp/dex/connector.go @@ -119,12 +119,17 @@ func (p *Provider) UpdateConnector(ctx context.Context, cfg *ConnectorConfig) er name = old.Name } + grantTypes := old.GrantTypes + if len(grantTypes) == 0 { + grantTypes = slices.Clone(DefaultGrantTypes) + } + return storage.Connector{ ID: cfg.ID, Type: old.Type, Name: name, Config: configData, - GrantTypes: old.GrantTypes, + GrantTypes: grantTypes, }, nil }); err != nil { return fmt.Errorf("failed to update connector: %w", err) diff --git a/idp/dex/connector_test.go b/idp/dex/connector_test.go index 56a177388..563bf40be 100644 --- a/idp/dex/connector_test.go +++ b/idp/dex/connector_test.go @@ -252,6 +252,28 @@ func TestConnectorGrantTypes(t *testing.T) { "an empty list would re-enable token exchange for this connector") }) + t.Run("updating a connector stored without an allowlist sets the default", func(t *testing.T) { + p, cleanup := newTestProvider(t) + defer cleanup() + + // Mimic a connector written by an older release. + require.NoError(t, p.storage.CreateConnector(ctx, storage.Connector{ + ID: "legacy-oidc", + Type: "oidc", + Name: "Legacy", + Config: []byte(`{"issuer":"https://accounts.example.com","clientID":"client-id"}`), + })) + + require.NoError(t, p.UpdateConnector(ctx, &ConnectorConfig{ + ID: "legacy-oidc", + ClientSecret: "new-secret", + })) + + conn, err := p.storage.GetConnector(ctx, "legacy-oidc") + require.NoError(t, err) + assert.Equal(t, DefaultGrantTypes, conn.GrantTypes) + }) + t.Run("backfills connectors stored without an allowlist", func(t *testing.T) { p, cleanup := newTestProvider(t) defer cleanup() diff --git a/idp/dex/provider.go b/idp/dex/provider.go index 5cda3e93d..44576de72 100644 --- a/idp/dex/provider.go +++ b/idp/dex/provider.go @@ -12,6 +12,7 @@ import ( "net/http" "os" "path/filepath" + "slices" "strings" "sync" "time" @@ -123,7 +124,7 @@ func NewProvider(ctx context.Context, config *Config) (*Provider, error) { Storage: stor, SkipApprovalScreen: true, SupportedResponseTypes: []string{"code"}, - AllowedGrantTypes: DefaultGrantTypes, + AllowedGrantTypes: slices.Clone(DefaultGrantTypes), ContinueOnConnectorFailure: true, Logger: logger, PrometheusRegistry: prometheus.NewRegistry(), diff --git a/management/server/idp/embedded.go b/management/server/idp/embedded.go index 08f3be79d..722fcf8c5 100644 --- a/management/server/idp/embedded.go +++ b/management/server/idp/embedded.go @@ -9,6 +9,7 @@ import ( "net/url" "os" "path" + "slices" "strings" "github.com/dexidp/dex/storage" @@ -173,7 +174,7 @@ func (c *EmbeddedIdPConfig) ToYAMLConfig() (*dex.YAMLConfig, error) { // the minimal set instead. Operators can still opt in to more by setting it. grantTypes := c.GrantTypes if len(grantTypes) == 0 { - grantTypes = dex.DefaultGrantTypes + grantTypes = slices.Clone(dex.DefaultGrantTypes) } cfg := &dex.YAMLConfig{