traefik plugin 0.7.7 (#73)

* Automatic discovery of the scopes.

Issue #61 raised very valid concerns about users configuring scopes that are not supported by the provider.
This change introduces automatic discovery of supported scopes by fetching the provider's discovery document and filtering out unsupported scopes.

Before:
User configures: scopes: ["openid", "profile", "email", "offline_access"]
Self-hosted GitLab: "The requested scope is invalid, unknown, or malformed"
Authentication: ❌ FAILS

After:
User configures: scopes: ["openid", "profile", "email", "offline_access"]
Middleware checks discovery doc → offline_access not supported
Automatically filters to: ["openid", "profile", "email"]
Authentication: ✅ SUCCEEDS

* Resolves issue #74 by enabling user to specify expected audience in the configuration.

* Fix flaky tests.
This commit is contained in:
2025-10-08 11:44:00 +01:00
committed by GitHub
parent 79d34ea4c9
commit bde1db1c3b
29 changed files with 3214 additions and 85 deletions
+18 -1
View File
@@ -10,6 +10,7 @@ import (
"net/http/httptest"
"net/url"
"strings"
"sync/atomic"
"testing"
"time"
)
@@ -37,6 +38,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -82,6 +84,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
enablePKCE: true,
tokenHTTPClient: &http.Client{
@@ -116,6 +119,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/invalid",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -146,6 +150,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/expired",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -176,6 +181,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/timeout",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 100 * time.Millisecond,
@@ -206,6 +212,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/error",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -236,6 +243,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/malformed",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -266,6 +274,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/incomplete",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -299,6 +308,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/slow",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -329,6 +339,7 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
return &TraefikOidc{
tokenURL: server.URL + "/token/ratelimit",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -482,13 +493,17 @@ func TestExchangeCodeForToken_Comprehensive(t *testing.T) {
// TestExchangeCodeForToken_Integration tests integration scenarios
func TestExchangeCodeForToken_Integration(t *testing.T) {
t.Run("multiple concurrent exchanges", func(t *testing.T) {
// Use atomic counter for unique token generation to handle race detector slowdown
var tokenCounter int64
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Add small delay to test concurrency
time.Sleep(10 * time.Millisecond)
// Generate unique token using atomic counter
tokenID := atomic.AddInt64(&tokenCounter, 1)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TokenResponse{
AccessToken: fmt.Sprintf("token_%d", time.Now().UnixNano()),
AccessToken: fmt.Sprintf("token_%d", tokenID),
IDToken: "test_id_token",
RefreshToken: "test_refresh_token",
TokenType: "Bearer",
@@ -500,6 +515,7 @@ func TestExchangeCodeForToken_Integration(t *testing.T) {
oidc := &TraefikOidc{
tokenURL: server.URL + "/token",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,
@@ -586,6 +602,7 @@ func TestExchangeCodeForToken_Integration(t *testing.T) {
oidc := &TraefikOidc{
tokenURL: server.URL + "/token",
clientID: "test_client",
audience: "test_client",
clientSecret: "test_secret",
tokenHTTPClient: &http.Client{
Timeout: 10 * time.Second,