Add exec value source type (#5050)

* config: introduce ExecSource value source

* auth: introduce OidcTokenSourceAuthProvider

* auth: use OidcTokenSourceAuthProvider if tokenSource config is present on the client

* cmd: allow exec token source only if CLI flag was passed
This commit is contained in:
Krzysztof Bogacki
2025-11-17 17:20:21 +01:00
committed by GitHub
parent f736d171ac
commit 66973a03db
10 changed files with 179 additions and 20 deletions

View File

@@ -77,7 +77,9 @@ func NewProxyCommand(name string, c v1.ProxyConfigurer, clientCfg *v1.ClientComm
fmt.Println(err)
os.Exit(1)
}
if _, err := validation.ValidateClientCommonConfig(clientCfg); err != nil {
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)}
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
fmt.Println(err)
os.Exit(1)
}
@@ -88,7 +90,7 @@ func NewProxyCommand(name string, c v1.ProxyConfigurer, clientCfg *v1.ClientComm
fmt.Println(err)
os.Exit(1)
}
err := startService(clientCfg, []v1.ProxyConfigurer{c}, nil, "")
err := startService(clientCfg, []v1.ProxyConfigurer{c}, nil, unsafeFeatures, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -106,7 +108,8 @@ func NewVisitorCommand(name string, c v1.VisitorConfigurer, clientCfg *v1.Client
fmt.Println(err)
os.Exit(1)
}
if _, err := validation.ValidateClientCommonConfig(clientCfg); err != nil {
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)}
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
fmt.Println(err)
os.Exit(1)
}
@@ -117,7 +120,7 @@ func NewVisitorCommand(name string, c v1.VisitorConfigurer, clientCfg *v1.Client
fmt.Println(err)
os.Exit(1)
}
err := startService(clientCfg, nil, []v1.VisitorConfigurer{c}, "")
err := startService(clientCfg, nil, []v1.VisitorConfigurer{c}, unsafeFeatures, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@@ -21,6 +21,7 @@ import (
"os"
"os/signal"
"path/filepath"
"slices"
"sync"
"syscall"
"time"
@@ -36,11 +37,18 @@ import (
"github.com/fatedier/frp/pkg/util/version"
)
type UnsafeFeature = string
const (
TokenSourceExec UnsafeFeature = "TokenSourceExec"
)
var (
cfgFile string
cfgDir string
showVersion bool
strictConfigMode bool
allowUnsafe []UnsafeFeature
)
func init() {
@@ -48,6 +56,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory")
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors")
rootCmd.PersistentFlags().StringSliceVarP(&allowUnsafe, "allow_unsafe", "", []string{}, "allowed unsafe features, one or more of: TokenSourceExec")
}
var rootCmd = &cobra.Command{
@@ -59,15 +68,17 @@ var rootCmd = &cobra.Command{
return nil
}
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)}
// If cfgDir is not empty, run multiple frpc service for each config file in cfgDir.
// Note that it's only designed for testing. It's not guaranteed to be stable.
if cfgDir != "" {
_ = runMultipleClients(cfgDir)
_ = runMultipleClients(cfgDir, unsafeFeatures)
return nil
}
// Do not show command usage here.
err := runClient(cfgFile)
err := runClient(cfgFile, unsafeFeatures)
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -76,7 +87,7 @@ var rootCmd = &cobra.Command{
},
}
func runMultipleClients(cfgDir string) error {
func runMultipleClients(cfgDir string, unsafeFeatures v1.UnsafeFeatures) error {
var wg sync.WaitGroup
err := filepath.WalkDir(cfgDir, func(path string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
@@ -86,7 +97,7 @@ func runMultipleClients(cfgDir string) error {
time.Sleep(time.Millisecond)
go func() {
defer wg.Done()
err := runClient(path)
err := runClient(path, unsafeFeatures)
if err != nil {
fmt.Printf("frpc service error for config file [%s]\n", path)
}
@@ -111,7 +122,7 @@ func handleTermSignal(svr *client.Service) {
svr.GracefulClose(500 * time.Millisecond)
}
func runClient(cfgFilePath string) error {
func runClient(cfgFilePath string, unsafeFeatures v1.UnsafeFeatures) error {
cfg, proxyCfgs, visitorCfgs, isLegacyFormat, err := config.LoadClientConfig(cfgFilePath, strictConfigMode)
if err != nil {
return err
@@ -127,20 +138,21 @@ func runClient(cfgFilePath string) error {
}
}
warning, err := validation.ValidateAllClientConfig(cfg, proxyCfgs, visitorCfgs)
warning, err := validation.ValidateAllClientConfig(cfg, proxyCfgs, visitorCfgs, unsafeFeatures)
if warning != nil {
fmt.Printf("WARNING: %v\n", warning)
}
if err != nil {
return err
}
return startService(cfg, proxyCfgs, visitorCfgs, cfgFilePath)
return startService(cfg, proxyCfgs, visitorCfgs, unsafeFeatures, cfgFilePath)
}
func startService(
cfg *v1.ClientCommonConfig,
proxyCfgs []v1.ProxyConfigurer,
visitorCfgs []v1.VisitorConfigurer,
unsafeFeatures v1.UnsafeFeatures,
cfgFile string,
) error {
log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
@@ -153,6 +165,7 @@ func startService(
Common: cfg,
ProxyCfgs: proxyCfgs,
VisitorCfgs: visitorCfgs,
UnsafeFeatures: unsafeFeatures,
ConfigFilePath: cfgFile,
})
if err != nil {

View File

@@ -17,10 +17,12 @@ package sub
import (
"fmt"
"os"
"slices"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/config/v1/validation"
)
@@ -42,7 +44,8 @@ var verifyCmd = &cobra.Command{
fmt.Println(err)
os.Exit(1)
}
warning, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs)
unsafeFeatures := v1.UnsafeFeatures{TokenSourceExec: slices.Contains(allowUnsafe, TokenSourceExec)}
warning, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs, unsafeFeatures)
if warning != nil {
fmt.Printf("WARNING: %v\n", warning)
}