Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 01:00 UTC
httpcaddyfile: reject conflicting client_auth when merging TLS policies (#8306)
* httpcaddyfile: reject conflicting client_auth when merging TLS policies * httpcaddyfile: use host and host:port site addresses in client auth conflict test * httpcaddyfile: enhance client auth consolidation test to handle conflicting configurations * httpcaddyfile: remove unnecessary blank line in conflict error handling
sam-kota committed
Nov 4, 2026 at 12:09 UTC
c1c0ee5dadc902b298c81036141cd8d15b0f85e3
2 files changed
+61
-2
caddyconfig/httpcaddyfile/httptype.go
+1
-2
@@ -1288,8 +1288,7 @@ func consolidateConnPolicies(cps caddytls.ConnectionPolicies) (caddytls.Connecti
1288
return nil, fmt.Errorf("two policies with same match criteria have conflicting cipher suites: %v vs. %v",
1289
cps[i].CipherSuites, cps[j].CipherSuites)
1290
}
1291
- if cps[i].ClientAuthentication == nil &&
1292
- cps[j].ClientAuthentication != nil &&
1291
+ if cps[i].ClientAuthentication != nil && cps[j].ClientAuthentication != nil &&
1292
!reflect.DeepEqual(cps[i].ClientAuthentication, cps[j].ClientAuthentication) {
1293
return nil, fmt.Errorf("two policies with same match criteria have conflicting client auth configuration: %+v vs. %+v",
1294
cps[i].ClientAuthentication, cps[j].ClientAuthentication)
caddyconfig/httpcaddyfile/httptype_test.go
+60
@@ -2,6 +2,7 @@ package httpcaddyfile
2
3
import (
4
"encoding/json"
5
+ "fmt"
6
"slices"
7
"strings"
8
"testing"
@@ -403,3 +404,62 @@ func TestTLSConnectionPoliciesAreIsolatedAcrossListeners(t *testing.T) {
404
}
405
}
406
}
407
+
408
+func TestClientAuthConsolidation(t *testing.T) {
409
+ const requestAuth = `client_auth {
410
+ mode request
411
+ }`
412
+ const verifyAuth = `client_auth {
413
+ mode require_and_verify
414
+ trust_pool file /tmp/root.crt
415
+ }`
416
+
417
+ tlsBlock := func(auth string) string {
418
+ if auth == "" {
419
+ return ""
420
+ }
421
+ return fmt.Sprintf("tls {\n\t\t\t%s\n\t\t}", auth)
422
+ }
423
+
424
+ for _, tc := range []struct {
425
+ name string
426
+ firstAuth string
427
+ secondAuth string
428
+ wantErr bool
429
+ }{
430
+ {"conflicting, laxer policy first", requestAuth, verifyAuth, true},
431
+ {"conflicting, stricter policy first", verifyAuth, requestAuth, true},
432
+ {"only first sets client auth", verifyAuth, "", false},
433
+ {"only second sets client auth", "", verifyAuth, false},
434
+ {"identical client auth", verifyAuth, verifyAuth, false},
435
+ } {
436
+ t.Run(tc.name, func(t *testing.T) {
437
+ caddyfileStr := fmt.Sprintf(`example.com {
438
+ %s
439
+ handle /public/* {
440
+ respond "public"
441
+ }
442
+ }
443
+
444
+ example.com:443 {
445
+ %s
446
+ handle /admin* {
447
+ respond "admin"
448
+ }
449
+ }`, tlsBlock(tc.firstAuth), tlsBlock(tc.secondAuth))
450
+
451
+ adapter := caddyfile.Adapter{ServerType: ServerType{}}
452
+ result, _, err := adapter.Adapt([]byte(caddyfileStr), nil)
453
+ if tc.wantErr {
454
+ if err == nil {
455
+ t.Fatalf("expected conflicting client auth to be rejected, got: %s", result)
456
+ }
457
+ if !strings.Contains(err.Error(), "conflicting client auth configuration") {
458
+ t.Fatalf("expected conflicting client auth error, got: %v", err)
459
+ }
460
+ } else if err != nil {
461
+ t.Fatalf("expected adapt to succeed, got: %v", err)
462
+ }
463
+ })
464
+ }
465
+}