1
package caddytls
2
3
import (
4
+ "context"
5
+ "crypto/ecdsa"
6
+ "crypto/elliptic"
7
+ "crypto/rand"
8
+ "crypto/x509"
9
+ "net/http"
10
+ "net/http/httptest"
11
+ "sync/atomic"
12
+ "testing"
13
+ "time"
14
+
15
"github.com/caddyserver/caddy/v2"
16
+ _ "github.com/caddyserver/caddy/v2/modules/internal/network"
17
+ "github.com/caddyserver/certmagic"
18
"github.com/mholt/acmez/v3/acme"
6
- "testing"
19
+ "go.uber.org/zap"
20
)
21
22
func TestACMEIssuerExpandPlaceholders(t *testing.T) {
54
t.Errorf("ExternalAccount.MACKey: got %q, want %q", iss.ExternalAccount.MACKey, want)
55
}
56
}
57
+
58
+// The HTTP app provisions ACME issuers again to fill in its ports and then
59
+// rebuilds the CertMagic config; requests must still use the configured proxy (#8283).
60
+func TestACMEIssuerNetworkProxyAfterRebuildCertMagic(t *testing.T) {
61
+ var proxied atomic.Int32
62
+ proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
63
+ if r.Method == http.MethodConnect && r.Host == "acme.invalid:443" {
64
+ proxied.Add(1)
65
+ }
66
+ http.Error(w, "test proxy", http.StatusBadGateway)
67
+ }))
68
+ defer proxy.Close()
69
+
70
+ certCacheMu.Lock()
71
+ prevCache := certCache
72
+ certCache = certmagic.NewCache(certmagic.CacheOptions{
73
+ GetConfigForCert: func(certmagic.Certificate) (*certmagic.Config, error) { return nil, nil },
74
+ })
75
+ certCacheMu.Unlock()
76
+ defer func() {
77
+ certCacheMu.Lock()
78
+ certCache.Stop()
79
+ certCache = prevCache
80
+ certCacheMu.Unlock()
81
+ }()
82
+
83
+ caddyCtx, cancel := caddy.NewContext(caddy.Context{Context: t.Context()})
84
+ defer cancel()
85
+ tlsApp := &TLS{ctx: caddyCtx, logger: zap.NewNop()}
86
+
87
+ iss := &ACMEIssuer{
88
+ CA: "https://acme.invalid/directory",
89
+ NetworkProxyRaw: []byte(`{"from":"url","url":"` + proxy.URL + `"}`),
90
+ }
91
+ if err := iss.Provision(caddyCtx); err != nil {
92
+ t.Fatalf("provisioning issuer: %v", err)
93
+ }
94
+ ap := &AutomationPolicy{
95
+ Issuers: []certmagic.Issuer{iss},
96
+ storage: &certmagic.FileStorage{Path: t.TempDir()},
97
+ }
98
+ if err := ap.Provision(tlsApp); err != nil {
99
+ t.Fatalf("provisioning automation policy: %v", err)
100
+ }
101
+
102
+ // what the HTTP app's fillInACMEIssuer and createAutomationPolicies do
103
+ if err := iss.Provision(caddyCtx); err != nil {
104
+ t.Fatalf("re-provisioning issuer: %v", err)
105
+ }
106
+ if err := ap.RebuildCertMagic(tlsApp); err != nil {
107
+ t.Fatalf("rebuilding certmagic config: %v", err)
108
+ }
109
+
110
+ key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
111
+ if err != nil {
112
+ t.Fatal(err)
113
+ }
114
+ csrDER, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{DNSNames: []string{"example.com"}}, key)
115
+ if err != nil {
116
+ t.Fatal(err)
117
+ }
118
+ csr, err := x509.ParseCertificateRequest(csrDER)
119
+ if err != nil {
120
+ t.Fatal(err)
121
+ }
122
+
123
+ ctx, cancelIssue := context.WithTimeout(t.Context(), 10*time.Second)
124
+ defer cancelIssue()
125
+ if _, err := iss.Issue(ctx, csr); err == nil {
126
+ t.Fatal("expected issuance to fail against the test proxy")
127
+ }
128
+ if proxied.Load() == 0 {
129
+ t.Error("ACME request did not go through the configured network proxy")
130
+ }
131
+}