mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-20 20:39:08 +02:00
[management] allow disabling device code flow when using dex (#6809)
This commit is contained in:
@@ -335,7 +335,7 @@ replace github.com/cloudflare/circl => codeberg.org/cunicu/circl v0.0.0-20230801
|
|||||||
|
|
||||||
replace github.com/pion/ice/v4 => github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51
|
replace github.com/pion/ice/v4 => github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51
|
||||||
|
|
||||||
replace github.com/dexidp/dex => github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1
|
replace github.com/dexidp/dex => github.com/netbirdio/dex v0.244.1-0.20260716205454-a163de3129e5
|
||||||
|
|
||||||
replace github.com/dexidp/dex/api/v2 => github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1
|
replace github.com/dexidp/dex/api/v2 => github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1
|
||||||
|
|
||||||
|
|||||||
@@ -476,8 +476,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
|||||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1 h1:4TaYr9O4xX0D2kszeOLclTiCbA3eHq3xWV+9ILJbIYs=
|
github.com/netbirdio/dex v0.244.1-0.20260716205454-a163de3129e5 h1:3PwQv8aR46qN2u16+Dv6udnH3sbVKX5KrGwF35CKSI0=
|
||||||
github.com/netbirdio/dex v0.244.1-0.20260512110716-8d70ad8647c1/go.mod h1:IHH+H8vK2GfqtIt5u/5OdPh18yk0oDHuj2vz5+Goetg=
|
github.com/netbirdio/dex v0.244.1-0.20260716205454-a163de3129e5/go.mod h1:IHH+H8vK2GfqtIt5u/5OdPh18yk0oDHuj2vz5+Goetg=
|
||||||
github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1 h1:neE7z+FPUkldl3faK/Jt+hJK2L+1XfQ1W33TQhU9m88=
|
github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1 h1:neE7z+FPUkldl3faK/Jt+hJK2L+1XfQ1W33TQhU9m88=
|
||||||
github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1/go.mod h1:awuTyT29CYALpEyET0S307EgNlPWrc7fFKRAyhsO45M=
|
github.com/netbirdio/dex/api/v2 v2.0.0-20260512110716-8d70ad8647c1/go.mod h1:awuTyT29CYALpEyET0S307EgNlPWrc7fFKRAyhsO45M=
|
||||||
github.com/netbirdio/easyjson v0.9.0 h1:6Nw2lghSVuy8RSkAYDhDv1thBVEmfVbKZnV7T7Z6Aus=
|
github.com/netbirdio/easyjson v0.9.0 h1:6Nw2lghSVuy8RSkAYDhDv1thBVEmfVbKZnV7T7Z6Aus=
|
||||||
|
|||||||
@@ -613,6 +613,10 @@ func (c *YAMLConfig) ToServerConfig(stor storage.Storage, logger *slog.Logger) s
|
|||||||
cfg.SupportedResponseTypes = c.OAuth2.ResponseTypes
|
cfg.SupportedResponseTypes = c.OAuth2.ResponseTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.OAuth2.GrantTypes) > 0 {
|
||||||
|
cfg.AllowedGrantTypes = c.OAuth2.GrantTypes
|
||||||
|
}
|
||||||
|
|
||||||
// Apply expiry settings
|
// Apply expiry settings
|
||||||
if c.Expiry.IDTokens != "" {
|
if c.Expiry.IDTokens != "" {
|
||||||
if d, err := parseDuration(c.Expiry.IDTokens); err == nil {
|
if d, err := parseDuration(c.Expiry.IDTokens); err == nil {
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ import (
|
|||||||
"github.com/dexidp/dex/server/signer"
|
"github.com/dexidp/dex/server/signer"
|
||||||
"github.com/dexidp/dex/storage"
|
"github.com/dexidp/dex/storage"
|
||||||
"github.com/dexidp/dex/storage/sql"
|
"github.com/dexidp/dex/storage/sql"
|
||||||
jose "github.com/go-jose/go-jose/v4"
|
"github.com/go-jose/go-jose/v4"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|||||||
@@ -595,3 +595,90 @@ enablePasswordDB: true
|
|||||||
assert.True(t, cfg.ContinueOnConnectorFailure,
|
assert.True(t, cfg.ContinueOnConnectorFailure,
|
||||||
"buildDexConfig must set ContinueOnConnectorFailure to true so management starts even if an external IdP is down")
|
"buildDexConfig must set ContinueOnConnectorFailure to true so management starts even if an external IdP is down")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToServerConfig_WiresGrantTypes(t *testing.T) {
|
||||||
|
tmpDir, err := os.MkdirTemp("", "dex-grants-*")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
stor := openTestStorage(t, tmpDir)
|
||||||
|
defer stor.Close()
|
||||||
|
|
||||||
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
||||||
|
|
||||||
|
grants := []string{"authorization_code", "refresh_token"}
|
||||||
|
cfg := &YAMLConfig{Issuer: "http://localhost:5599/oauth2", OAuth2: OAuth2{GrantTypes: grants}}
|
||||||
|
assert.Equal(t, grants, cfg.ToServerConfig(stor, logger).AllowedGrantTypes)
|
||||||
|
|
||||||
|
empty := &YAMLConfig{Issuer: "http://localhost:5599/oauth2"}
|
||||||
|
assert.Empty(t, empty.ToServerConfig(stor, logger).AllowedGrantTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDeviceGuardProvider(t *testing.T, grantTypesYAML string) *Provider {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp("", "dex-devguard-*")
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() { _ = os.RemoveAll(tmpDir) })
|
||||||
|
|
||||||
|
yamlContent := `
|
||||||
|
issuer: http://localhost:5599/oauth2
|
||||||
|
storage:
|
||||||
|
type: sqlite3
|
||||||
|
config:
|
||||||
|
file: ` + filepath.Join(tmpDir, "dex.db") + `
|
||||||
|
web:
|
||||||
|
http: 127.0.0.1:5599
|
||||||
|
enablePasswordDB: true
|
||||||
|
` + grantTypesYAML
|
||||||
|
|
||||||
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
||||||
|
require.NoError(t, os.WriteFile(configPath, []byte(yamlContent), 0644))
|
||||||
|
|
||||||
|
yamlConfig, err := LoadConfig(configPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
provider, err := NewProviderFromYAML(context.Background(), yamlConfig)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() { _ = provider.Stop(context.Background()) })
|
||||||
|
return provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_BlocksDeviceEndpointsWhenDeviceGrantDisabled(t *testing.T) {
|
||||||
|
provider := newDeviceGuardProvider(t, `
|
||||||
|
oauth2:
|
||||||
|
grantTypes:
|
||||||
|
- authorization_code
|
||||||
|
- refresh_token
|
||||||
|
`)
|
||||||
|
|
||||||
|
devicePaths := []string{
|
||||||
|
"/oauth2/device",
|
||||||
|
"/oauth2/device/code",
|
||||||
|
"/oauth2/device/token",
|
||||||
|
"/oauth2/device/auth/verify_code",
|
||||||
|
"/oauth2/device/callback",
|
||||||
|
}
|
||||||
|
for _, path := range devicePaths {
|
||||||
|
for _, method := range []string{http.MethodGet, http.MethodPost} {
|
||||||
|
req := httptest.NewRequest(method, path, nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
provider.Handler().ServeHTTP(rec, req)
|
||||||
|
assert.Equal(t, http.StatusNotFound, rec.Code, "%s %s must be blocked", method, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/oauth2/.well-known/openid-configuration", nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
provider.Handler().ServeHTTP(rec, req)
|
||||||
|
assert.Equal(t, http.StatusOK, rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_AllowsDeviceEndpointsWhenGrantsDefault(t *testing.T) {
|
||||||
|
provider := newDeviceGuardProvider(t, "")
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/oauth2/device/code", nil)
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
provider.Handler().ServeHTTP(rec, req)
|
||||||
|
assert.NotEqual(t, http.StatusNotFound, rec.Code)
|
||||||
|
}
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ type EmbeddedIdPConfig struct {
|
|||||||
DashboardPostLogoutRedirectURIs []string
|
DashboardPostLogoutRedirectURIs []string
|
||||||
// StaticConnectors are additional connectors to seed during initialization
|
// StaticConnectors are additional connectors to seed during initialization
|
||||||
StaticConnectors []dex.Connector
|
StaticConnectors []dex.Connector
|
||||||
|
// GrantTypes restricts allowed OAuth2 grants; empty means all (Dex default). Omit the
|
||||||
|
// device_code grant to disable the device flow; keep authorization_code and refresh_token.
|
||||||
|
GrantTypes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmbeddedStorageConfig holds storage configuration for the embedded IdP.
|
// EmbeddedStorageConfig holds storage configuration for the embedded IdP.
|
||||||
@@ -175,6 +178,7 @@ func (c *EmbeddedIdPConfig) ToYAMLConfig() (*dex.YAMLConfig, error) {
|
|||||||
},
|
},
|
||||||
OAuth2: dex.OAuth2{
|
OAuth2: dex.OAuth2{
|
||||||
SkipApprovalScreen: true,
|
SkipApprovalScreen: true,
|
||||||
|
GrantTypes: c.GrantTypes,
|
||||||
},
|
},
|
||||||
Frontend: dex.Frontend{
|
Frontend: dex.Frontend{
|
||||||
Issuer: "NetBird",
|
Issuer: "NetBird",
|
||||||
|
|||||||
Reference in New Issue
Block a user