auth: enhance OIDC client with TLS and proxy configuration options (#4990)

pull/4997/head
fatedier 2025-09-25 10:19:19 +08:00 committed by GitHub
parent 7cfa546b55
commit abf4942e8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 108 additions and 8 deletions

View File

@ -1,3 +1,4 @@
## Features
* Add NAT traversal configuration options for XTCP proxies and visitors. Support disabling assisted addresses to avoid using slow VPN connections during NAT hole punching.
* Enhanced OIDC client configuration with support for custom TLS certificate verification and proxy settings. Added `trustedCaFile`, `insecureSkipVerify`, and `proxyURL` options for OIDC token endpoint connections.

View File

@ -149,9 +149,15 @@ func NewService(options ServiceOptions) (*Service, error) {
}
webServer = ws
}
authSetter, err := auth.NewAuthSetter(options.Common.Auth)
if err != nil {
return nil, err
}
s := &Service{
ctx: context.Background(),
authSetter: auth.NewAuthSetter(options.Common.Auth),
authSetter: authSetter,
webServer: webServer,
common: options.Common,
configFilePath: options.ConfigFilePath,

View File

@ -55,6 +55,20 @@ auth.token = "12345678"
# auth.oidc.additionalEndpointParams.audience = "https://dev.auth.com/api/v2/"
# auth.oidc.additionalEndpointParams.var1 = "foobar"
# OIDC TLS and proxy configuration
# Specify a custom CA certificate file for verifying the OIDC token endpoint's TLS certificate.
# This is useful when the OIDC provider uses a self-signed certificate or a custom CA.
# auth.oidc.trustedCaFile = "/path/to/ca.crt"
# Skip TLS certificate verification for the OIDC token endpoint.
# INSECURE: Only use this for debugging purposes, not recommended for production.
# auth.oidc.insecureSkipVerify = false
# Specify a proxy server for OIDC token endpoint connections.
# Supports http, https, socks5, and socks5h proxy protocols.
# If not specified, no proxy is used for OIDC connections.
# auth.oidc.proxyURL = "http://proxy.example.com:8080"
# Set admin address for control frpc's action by http api such as reload
webServer.addr = "127.0.0.1"
webServer.port = 7400

View File

@ -27,16 +27,19 @@ type Setter interface {
SetNewWorkConn(*msg.NewWorkConn) error
}
func NewAuthSetter(cfg v1.AuthClientConfig) (authProvider Setter) {
func NewAuthSetter(cfg v1.AuthClientConfig) (authProvider Setter, err error) {
switch cfg.Method {
case v1.AuthMethodToken:
authProvider = NewTokenAuth(cfg.AdditionalScopes, cfg.Token)
case v1.AuthMethodOIDC:
authProvider = NewOidcAuthSetter(cfg.AdditionalScopes, cfg.OIDC)
authProvider, err = NewOidcAuthSetter(cfg.AdditionalScopes, cfg.OIDC)
if err != nil {
return nil, err
}
default:
panic(fmt.Sprintf("wrong method: '%s'", cfg.Method))
return nil, fmt.Errorf("unsupported auth method: %s", cfg.Method)
}
return authProvider
return authProvider, nil
}
type Verifier interface {

View File

@ -16,23 +16,72 @@ package auth
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"net/url"
"os"
"slices"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/msg"
)
// createOIDCHTTPClient creates an HTTP client with custom TLS and proxy configuration for OIDC token requests
func createOIDCHTTPClient(trustedCAFile string, insecureSkipVerify bool, proxyURL string) (*http.Client, error) {
// Clone the default transport to get all reasonable defaults
transport := http.DefaultTransport.(*http.Transport).Clone()
// Configure TLS settings
if trustedCAFile != "" || insecureSkipVerify {
tlsConfig := &tls.Config{
InsecureSkipVerify: insecureSkipVerify,
}
if trustedCAFile != "" && !insecureSkipVerify {
caCert, err := os.ReadFile(trustedCAFile)
if err != nil {
return nil, fmt.Errorf("failed to read OIDC CA certificate file %q: %w", trustedCAFile, err)
}
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
return nil, fmt.Errorf("failed to parse OIDC CA certificate from file %q", trustedCAFile)
}
tlsConfig.RootCAs = caCertPool
}
transport.TLSClientConfig = tlsConfig
}
// Configure proxy settings
if proxyURL != "" {
parsedURL, err := url.Parse(proxyURL)
if err != nil {
return nil, fmt.Errorf("failed to parse OIDC proxy URL %q: %w", proxyURL, err)
}
transport.Proxy = http.ProxyURL(parsedURL)
} else {
// Explicitly disable proxy to override DefaultTransport's ProxyFromEnvironment
transport.Proxy = nil
}
return &http.Client{Transport: transport}, nil
}
type OidcAuthProvider struct {
additionalAuthScopes []v1.AuthScope
tokenGenerator *clientcredentials.Config
httpClient *http.Client
}
func NewOidcAuthSetter(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCClientConfig) *OidcAuthProvider {
func NewOidcAuthSetter(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCClientConfig) (*OidcAuthProvider, error) {
eps := make(map[string][]string)
for k, v := range cfg.AdditionalEndpointParams {
eps[k] = []string{v}
@ -50,14 +99,30 @@ func NewOidcAuthSetter(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCClien
EndpointParams: eps,
}
// Create custom HTTP client if needed
var httpClient *http.Client
if cfg.TrustedCaFile != "" || cfg.InsecureSkipVerify || cfg.ProxyURL != "" {
var err error
httpClient, err = createOIDCHTTPClient(cfg.TrustedCaFile, cfg.InsecureSkipVerify, cfg.ProxyURL)
if err != nil {
return nil, fmt.Errorf("failed to create OIDC HTTP client: %w", err)
}
}
return &OidcAuthProvider{
additionalAuthScopes: additionalAuthScopes,
tokenGenerator: tokenGenerator,
}
httpClient: httpClient,
}, nil
}
func (auth *OidcAuthProvider) generateAccessToken() (accessToken string, err error) {
tokenObj, err := auth.tokenGenerator.Token(context.Background())
ctx := context.Background()
if auth.httpClient != nil {
ctx = context.WithValue(ctx, oauth2.HTTPClient, auth.httpClient)
}
tokenObj, err := auth.tokenGenerator.Token(ctx)
if err != nil {
return "", fmt.Errorf("couldn't generate OIDC token for login: %v", err)
}

View File

@ -228,6 +228,17 @@ type AuthOIDCClientConfig struct {
// AdditionalEndpointParams specifies additional parameters to be sent
// this field will be transfer to map[string][]string in OIDC token generator.
AdditionalEndpointParams map[string]string `json:"additionalEndpointParams,omitempty"`
// TrustedCaFile specifies the path to a custom CA certificate file
// for verifying the OIDC token endpoint's TLS certificate.
TrustedCaFile string `json:"trustedCaFile,omitempty"`
// InsecureSkipVerify disables TLS certificate verification for the
// OIDC token endpoint. Only use this for debugging, not recommended for production.
InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"`
// ProxyURL specifies a proxy to use when connecting to the OIDC token endpoint.
// Supports http, https, socks5, and socks5h proxy protocols.
// If empty, no proxy is used for OIDC connections.
ProxyURL string `json:"proxyURL,omitempty"`
}
type VirtualNetConfig struct {