feat: Add per-route OIDC client ID and secret support (#145)

This commit is contained in:
DeAndre Harris
2025-09-08 02:16:30 +02:00
committed by GitHub
parent 577169d03c
commit 41ce784a7f
5 changed files with 130 additions and 14 deletions

View File

@@ -3,6 +3,7 @@ package middleware
import (
"errors"
"net/http"
"strings"
"sync"
"sync/atomic"
@@ -13,6 +14,9 @@ import (
type oidcMiddleware struct {
AllowedUsers []string `json:"allowed_users"`
AllowedGroups []string `json:"allowed_groups"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
Scopes string `json:"scopes"`
auth *auth.OIDCProvider
@@ -49,11 +53,28 @@ func (amw *oidcMiddleware) initSlow() error {
amw.initMu.Unlock()
}()
// Always start with the global OIDC provider (for issuer discovery)
authProvider, err := auth.NewOIDCProviderFromEnv()
if err != nil {
return err
}
// Check if custom client credentials are provided
if amw.ClientID != "" && amw.ClientSecret != "" {
// Use custom client credentials
customProvider, err := auth.NewOIDCProviderWithCustomClient(
authProvider,
amw.ClientID,
amw.ClientSecret,
)
if err != nil {
return err
}
authProvider = customProvider
}
// If no custom credentials, authProvider remains the global one
// Apply per-route user/group restrictions (these always override global)
if len(amw.AllowedUsers) > 0 {
authProvider.SetAllowedUsers(amw.AllowedUsers)
}
@@ -61,6 +82,11 @@ func (amw *oidcMiddleware) initSlow() error {
authProvider.SetAllowedGroups(amw.AllowedGroups)
}
// Apply custom scopes if provided
if amw.Scopes != "" {
authProvider.SetScopes(strings.Split(amw.Scopes, ","))
}
amw.auth = authProvider
return nil
}

View File

@@ -0,0 +1,35 @@
package middleware
import (
"testing"
. "github.com/yusing/go-proxy/internal/utils/testing"
)
func TestOIDCMiddlewarePerRouteConfig(t *testing.T) {
t.Run("middleware struct has correct fields", func(t *testing.T) {
middleware := &oidcMiddleware{
AllowedUsers: []string{"custom-user"},
AllowedGroups: []string{"custom-group"},
ClientID: "custom-client-id",
ClientSecret: "custom-client-secret",
Scopes: "openid,profile,email,groups",
}
ExpectEqual(t, middleware.AllowedUsers, []string{"custom-user"})
ExpectEqual(t, middleware.AllowedGroups, []string{"custom-group"})
ExpectEqual(t, middleware.ClientID, "custom-client-id")
ExpectEqual(t, middleware.ClientSecret, "custom-client-secret")
ExpectEqual(t, middleware.Scopes, "openid,profile,email,groups")
})
t.Run("middleware struct handles empty values", func(t *testing.T) {
middleware := &oidcMiddleware{}
ExpectEqual(t, middleware.AllowedUsers, nil)
ExpectEqual(t, middleware.AllowedGroups, nil)
ExpectEqual(t, middleware.ClientID, "")
ExpectEqual(t, middleware.ClientSecret, "")
ExpectEqual(t, middleware.Scopes, "")
})
}