mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-12 04:04:26 +00:00
review fixes apr 2026 (#130)
* Multiple fixes - refresh coordinator dedup + memory pressure wire - middleware sse consolidation + timer leak + claim cache - universal cache sync backfill + isDebug gate - lazy background task race - memory monitor stw cached + refresh() api * fix(auth): suppress OIDC redirects on non-navigation requests - [x] Add isNonNavigationRequest using Sec-Fetch-Mode and Accept headers - [x] Add comprehensive TestIsNonNavigationRequest - [x] Update ServeHTTP to 401 non-navigation and AJAX requests Fixes #129 * feat(config): add custom CA and insecure skip verify for OIDC TLS - [x] Add CACertPath, CACertPEM, InsecureSkipVerify to Config - [x] Implement loadCACertPool for CA bundle loading - [x] Update HTTPClientConfig with RootCAs and InsecureSkipVerify - [x] Apply CA pool and skip verify to pooled HTTP clients - [x] Enhance configKey to distinguish TLS configs - [x] Add comprehensive ca_cert_test.go Fixes #125 * feat(oidc): add custom CA certificate support for private OIDC providers - [x] Add caCertPath, caCertPEM, insecureSkipVerify config options - [x] Update traefik.yml with new OIDC client config fields - [x] Add configuration schema descriptions for new options - [x] Update README table and add Custom CA Certificates section * Fix the documentation. * test(redis): add oversized argument rejection test - [x] Add TestRedisConn_RejectOversizedArgumentBytes - [x] Import strings package * Dependencies cleanup
This commit is contained in:
+137
@@ -0,0 +1,137 @@
|
||||
package traefikoidc
|
||||
|
||||
import (
|
||||
"encoding/pem"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// testCertPEM returns a valid PEM-encoded certificate harvested from an
|
||||
// httptest.NewTLSServer. Using httptest keeps the test free of any
|
||||
// handwritten static cert that could expire.
|
||||
func testCertPEM(t *testing.T) string {
|
||||
t.Helper()
|
||||
srv := httptest.NewTLSServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
|
||||
t.Cleanup(srv.Close)
|
||||
|
||||
cert := srv.Certificate()
|
||||
if cert == nil {
|
||||
t.Fatal("httptest.NewTLSServer did not expose a certificate")
|
||||
}
|
||||
return string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}))
|
||||
}
|
||||
|
||||
func TestLoadCACertPool_Empty(t *testing.T) {
|
||||
cfg := &Config{}
|
||||
pool, err := cfg.loadCACertPool()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if pool != nil {
|
||||
t.Errorf("expected nil pool when no CA source configured, got %v", pool)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertPool_InlinePEM(t *testing.T) {
|
||||
cfg := &Config{CACertPEM: testCertPEM(t)}
|
||||
pool, err := cfg.loadCACertPool()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if pool == nil {
|
||||
t.Fatal("expected non-nil pool for valid CACertPEM")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertPool_InlinePEM_Garbage(t *testing.T) {
|
||||
cfg := &Config{CACertPEM: "not a pem"}
|
||||
pool, err := cfg.loadCACertPool()
|
||||
if err == nil {
|
||||
t.Fatal("expected error for garbage CACertPEM, got nil")
|
||||
}
|
||||
if pool != nil {
|
||||
t.Errorf("expected nil pool on error, got %v", pool)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "caCertPEM") {
|
||||
t.Errorf("error should name the failing field, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertPool_FilePath(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "ca.pem")
|
||||
if err := os.WriteFile(path, []byte(testCertPEM(t)), 0o600); err != nil {
|
||||
t.Fatalf("writing temp PEM: %v", err)
|
||||
}
|
||||
|
||||
cfg := &Config{CACertPath: path}
|
||||
pool, err := cfg.loadCACertPool()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if pool == nil {
|
||||
t.Fatal("expected non-nil pool for valid CACertPath")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertPool_FilePath_Missing(t *testing.T) {
|
||||
cfg := &Config{CACertPath: "/does/not/exist/ca.pem"}
|
||||
pool, err := cfg.loadCACertPool()
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing CACertPath, got nil")
|
||||
}
|
||||
if pool != nil {
|
||||
t.Errorf("expected nil pool on error, got %v", pool)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCACertPool_Combined(t *testing.T) {
|
||||
// Both inline and file sources populated — certificates from both should
|
||||
// be accepted into the same pool.
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "ca.pem")
|
||||
if err := os.WriteFile(path, []byte(testCertPEM(t)), 0o600); err != nil {
|
||||
t.Fatalf("writing temp PEM: %v", err)
|
||||
}
|
||||
|
||||
cfg := &Config{CACertPath: path, CACertPEM: testCertPEM(t)}
|
||||
pool, err := cfg.loadCACertPool()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if pool == nil {
|
||||
t.Fatal("expected non-nil pool when both sources set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedTransportPool_ConfigKeyDistinguishesCAAndSkipVerify(t *testing.T) {
|
||||
p := GetGlobalTransportPool()
|
||||
cfgSystem := DefaultHTTPClientConfig()
|
||||
|
||||
cfgSkip := DefaultHTTPClientConfig()
|
||||
cfgSkip.InsecureSkipVerify = true
|
||||
|
||||
cfgCustomCA := DefaultHTTPClientConfig()
|
||||
pool, err := (&Config{CACertPEM: testCertPEM(t)}).loadCACertPool()
|
||||
if err != nil {
|
||||
t.Fatalf("loadCACertPool: %v", err)
|
||||
}
|
||||
cfgCustomCA.RootCAs = pool
|
||||
|
||||
keys := map[string]string{
|
||||
"system": p.configKey(cfgSystem),
|
||||
"skip": p.configKey(cfgSkip),
|
||||
"customCA": p.configKey(cfgCustomCA),
|
||||
}
|
||||
seen := make(map[string]string, len(keys))
|
||||
for name, key := range keys {
|
||||
if dup, ok := seen[key]; ok {
|
||||
t.Errorf("configKey collision: %s and %s share key %q", name, dup, key)
|
||||
}
|
||||
seen[key] = name
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user