@marcel91200 / caddy Mirror · read-only
Fork 0

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

master
go 207 lines 5.04 KB
Raw
1 package integration
2
3 import (
4 "context"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "log/slog"
9 "strings"
10 "testing"
11
12 "github.com/mholt/acmez/v3"
13 "github.com/mholt/acmez/v3/acme"
14 "go.uber.org/zap"
15 "go.uber.org/zap/exp/zapslog"
16
17 "github.com/caddyserver/caddy/v2/caddytest"
18 )
19
20 func TestACMEServerDirectory(t *testing.T) {
21 tester := caddytest.NewTester(t)
22 tester.InitServer(`
23 {
24 skip_install_trust
25 local_certs
26 admin localhost:2999
27 http_port 9080
28 https_port 9443
29 pki {
30 ca local {
31 name "Caddy Local Authority"
32 }
33 }
34 }
35 acme.localhost:9443 {
36 acme_server
37 }
38 `, "caddyfile")
39 tester.AssertGetResponse(
40 "https://acme.localhost:9443/acme/local/directory",
41 200,
42 `{"newNonce":"https://acme.localhost:9443/acme/local/new-nonce","newAccount":"https://acme.localhost:9443/acme/local/new-account","newOrder":"https://acme.localhost:9443/acme/local/new-order","revokeCert":"https://acme.localhost:9443/acme/local/revoke-cert","keyChange":"https://acme.localhost:9443/acme/local/key-change"}
43 `)
44 }
45
46 func TestACMEServerAllowPolicy(t *testing.T) {
47 tester := caddytest.NewTester(t)
48 tester.InitServer(`
49 {
50 skip_install_trust
51 local_certs
52 admin localhost:2999
53 http_port 9080
54 https_port 9443
55 pki {
56 ca local {
57 name "Caddy Local Authority"
58 }
59 }
60 }
61 acme.localhost {
62 acme_server {
63 challenges http-01
64 allow {
65 domains localhost
66 }
67 }
68 }
69 `, "caddyfile")
70
71 ctx := context.Background()
72 logger, err := zap.NewDevelopment()
73 if err != nil {
74 t.Error(err)
75 return
76 }
77
78 client := acmez.Client{
79 Client: &acme.Client{
80 Directory: "https://acme.localhost:9443/acme/local/directory",
81 HTTPClient: tester.Client,
82 Logger: slog.New(zapslog.NewHandler(logger.Core())),
83 },
84 ChallengeSolvers: map[string]acmez.Solver{
85 acme.ChallengeTypeHTTP01: &naiveHTTPSolver{logger: logger},
86 },
87 }
88
89 accountPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
90 if err != nil {
91 t.Errorf("generating account key: %v", err)
92 }
93 account := acme.Account{
94 Contact: []string{"mailto:you@example.com"},
95 TermsOfServiceAgreed: true,
96 PrivateKey: accountPrivateKey,
97 }
98 account, err = client.NewAccount(ctx, account)
99 if err != nil {
100 t.Errorf("new account: %v", err)
101 return
102 }
103
104 // Every certificate needs a key.
105 certPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
106 if err != nil {
107 t.Errorf("generating certificate key: %v", err)
108 return
109 }
110 {
111 certs, err := client.ObtainCertificateForSANs(ctx, account, certPrivateKey, []string{"localhost"})
112 if err != nil {
113 t.Errorf("obtaining certificate for allowed domain: %v", err)
114 return
115 }
116
117 // ACME servers should usually give you the entire certificate chain
118 // in PEM format, and sometimes even alternate chains! It's up to you
119 // which one(s) to store and use, but whatever you do, be sure to
120 // store the certificate and key somewhere safe and secure, i.e. don't
121 // lose them!
122 for _, cert := range certs {
123 t.Logf("Certificate %q:\n%s\n\n", cert.URL, cert.ChainPEM)
124 }
125 }
126 {
127 _, err := client.ObtainCertificateForSANs(ctx, account, certPrivateKey, []string{"not-matching.localhost"})
128 if err == nil {
129 t.Errorf("obtaining certificate for 'not-matching.localhost' domain")
130 } else if !strings.Contains(err.Error(), "urn:ietf:params:acme:error:rejectedIdentifier") {
131 t.Logf("unexpected error: %v", err)
132 }
133 }
134 }
135
136 func TestACMEServerDenyPolicy(t *testing.T) {
137 tester := caddytest.NewTester(t)
138 tester.InitServer(`
139 {
140 skip_install_trust
141 local_certs
142 admin localhost:2999
143 http_port 9080
144 https_port 9443
145 pki {
146 ca local {
147 name "Caddy Local Authority"
148 }
149 }
150 }
151 acme.localhost {
152 acme_server {
153 deny {
154 domains deny.localhost
155 }
156 }
157 }
158 `, "caddyfile")
159
160 ctx := context.Background()
161 logger, err := zap.NewDevelopment()
162 if err != nil {
163 t.Error(err)
164 return
165 }
166
167 client := acmez.Client{
168 Client: &acme.Client{
169 Directory: "https://acme.localhost:9443/acme/local/directory",
170 HTTPClient: tester.Client,
171 Logger: slog.New(zapslog.NewHandler(logger.Core())),
172 },
173 ChallengeSolvers: map[string]acmez.Solver{
174 acme.ChallengeTypeHTTP01: &naiveHTTPSolver{logger: logger},
175 },
176 }
177
178 accountPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
179 if err != nil {
180 t.Errorf("generating account key: %v", err)
181 }
182 account := acme.Account{
183 Contact: []string{"mailto:you@example.com"},
184 TermsOfServiceAgreed: true,
185 PrivateKey: accountPrivateKey,
186 }
187 account, err = client.NewAccount(ctx, account)
188 if err != nil {
189 t.Errorf("new account: %v", err)
190 return
191 }
192
193 // Every certificate needs a key.
194 certPrivateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
195 if err != nil {
196 t.Errorf("generating certificate key: %v", err)
197 return
198 }
199 {
200 _, err := client.ObtainCertificateForSANs(ctx, account, certPrivateKey, []string{"deny.localhost"})
201 if err == nil {
202 t.Errorf("obtaining certificate for 'deny.localhost' domain")
203 } else if !strings.Contains(err.Error(), "urn:ietf:params:acme:error:rejectedIdentifier") {
204 t.Logf("unexpected error: %v", err)
205 }
206 }
207 }