@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 293 lines 7.96 KB
Raw
1 package httpcaddyfile
2
3 import (
4 "encoding/json"
5 "testing"
6 "time"
7
8 "github.com/caddyserver/caddy/v2"
9 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
10 "github.com/caddyserver/caddy/v2/modules/caddytls"
11 _ "github.com/caddyserver/caddy/v2/modules/logging"
12 )
13
14 func TestGlobalLogOptionSyntax(t *testing.T) {
15 for i, tc := range []struct {
16 input string
17 output string
18 expectError bool
19 }{
20 // NOTE: Additional test cases of successful Caddyfile parsing
21 // are present in: caddytest/integration/caddyfile_adapt/
22 {
23 input: `{
24 log default
25 }
26 `,
27 output: `{}`,
28 expectError: false,
29 },
30 {
31 input: `{
32 log example {
33 output file foo.log
34 }
35 log example {
36 format json
37 }
38 }
39 `,
40 expectError: true,
41 },
42 {
43 input: `{
44 log example /foo {
45 output file foo.log
46 }
47 }
48 `,
49 expectError: true,
50 },
51 } {
52
53 adapter := caddyfile.Adapter{
54 ServerType: ServerType{},
55 }
56
57 out, _, err := adapter.Adapt([]byte(tc.input), nil)
58
59 if err != nil != tc.expectError {
60 t.Errorf("Test %d error expectation failed Expected: %v, got %v", i, tc.expectError, err)
61 continue
62 }
63
64 if string(out) != tc.output {
65 t.Errorf("Test %d error output mismatch Expected: %s, got %s", i, tc.output, out)
66 }
67 }
68 }
69
70 func TestGlobalResolversOption(t *testing.T) {
71 tests := []struct {
72 name string
73 input string
74 expectResolvers []string
75 expectError bool
76 }{
77 {
78 name: "single resolver",
79 input: `{
80 tls_resolvers 1.1.1.1
81 }
82 example.com {
83 }`,
84 expectResolvers: []string{"1.1.1.1"},
85 expectError: false,
86 },
87 {
88 name: "two resolvers",
89 input: `{
90 tls_resolvers 1.1.1.1 8.8.8.8
91 }
92 example.com {
93 }`,
94 expectResolvers: []string{"1.1.1.1", "8.8.8.8"},
95 expectError: false,
96 },
97 {
98 name: "multiple resolvers",
99 input: `{
100 tls_resolvers 1.1.1.1 8.8.8.8 9.9.9.9
101 }
102 example.com {
103 }`,
104 expectResolvers: []string{"1.1.1.1", "8.8.8.8", "9.9.9.9"},
105 expectError: false,
106 },
107 {
108 name: "no resolvers specified",
109 input: `{
110 }
111 example.com {
112 }`,
113 expectResolvers: nil,
114 expectError: false,
115 },
116 }
117
118 for _, tc := range tests {
119 t.Run(tc.name, func(t *testing.T) {
120 adapter := caddyfile.Adapter{
121 ServerType: ServerType{},
122 }
123
124 out, _, err := adapter.Adapt([]byte(tc.input), nil)
125
126 if (err != nil) != tc.expectError {
127 t.Errorf("error expectation failed. Expected error: %v, got: %v", tc.expectError, err)
128 return
129 }
130
131 if tc.expectError {
132 return
133 }
134
135 // Parse the output JSON to check resolvers
136 var config struct {
137 Apps struct {
138 TLS *caddytls.TLS `json:"tls"`
139 } `json:"apps"`
140 }
141
142 if err := json.Unmarshal(out, &config); err != nil {
143 t.Errorf("failed to unmarshal output: %v", err)
144 return
145 }
146
147 // Check if resolvers match expected
148 if config.Apps.TLS == nil {
149 if tc.expectResolvers != nil {
150 t.Errorf("Expected TLS config with resolvers %v, but TLS config is nil", tc.expectResolvers)
151 }
152 return
153 }
154
155 actualResolvers := config.Apps.TLS.Resolvers
156 if len(tc.expectResolvers) == 0 && len(actualResolvers) == 0 {
157 return // Both empty, ok
158 }
159 if len(actualResolvers) != len(tc.expectResolvers) {
160 t.Errorf("Expected %d resolvers, got %d. Expected: %v, got: %v", len(tc.expectResolvers), len(actualResolvers), tc.expectResolvers, actualResolvers)
161 return
162 }
163 for j, expected := range tc.expectResolvers {
164 if actualResolvers[j] != expected {
165 t.Errorf("Resolver %d mismatch. Expected: %s, got: %s", j, expected, actualResolvers[j])
166 }
167 }
168 })
169 }
170 }
171
172 func TestGlobalCertIssuerAppliesToImplicitACMEIssuer(t *testing.T) {
173 adapter := caddyfile.Adapter{
174 ServerType: ServerType{},
175 }
176
177 input := `{
178 cert_issuer acme {
179 disable_tlsalpn_challenge
180 }
181 }
182 report.company.intern {
183 tls {
184 ca https://deglacme01.company.intern/acme/acme/directory
185 ca_root /etc/certs/company_root2.crt
186 }
187 respond "ok"
188 }`
189
190 out, _, err := adapter.Adapt([]byte(input), nil)
191 if err != nil {
192 t.Fatalf("adapting caddyfile: %v", err)
193 }
194
195 var config struct {
196 Apps struct {
197 TLS *caddytls.TLS `json:"tls"`
198 } `json:"apps"`
199 }
200 if err := json.Unmarshal(out, &config); err != nil {
201 t.Fatalf("unmarshaling adapted config: %v", err)
202 }
203 if config.Apps.TLS == nil || config.Apps.TLS.Automation == nil {
204 t.Fatal("expected tls automation config")
205 }
206
207 var subjectPolicy *caddytls.AutomationPolicy
208 for _, ap := range config.Apps.TLS.Automation.Policies {
209 if len(ap.SubjectsRaw) == 1 && ap.SubjectsRaw[0] == "report.company.intern" {
210 subjectPolicy = ap
211 break
212 }
213 }
214 if subjectPolicy == nil {
215 t.Fatal("expected subject-specific automation policy")
216 }
217 if len(subjectPolicy.IssuersRaw) != 1 {
218 t.Fatalf("expected one issuer for subject-specific policy, got %d", len(subjectPolicy.IssuersRaw))
219 }
220
221 var issuer caddytls.ACMEIssuer
222 if err := json.Unmarshal(subjectPolicy.IssuersRaw[0], &issuer); err != nil {
223 t.Fatalf("unmarshaling issuer: %v", err)
224 }
225 if issuer.CA != "https://deglacme01.company.intern/acme/acme/directory" {
226 t.Fatalf("expected custom ACME CA, got %q", issuer.CA)
227 }
228 if len(issuer.TrustedRootsPEMFiles) != 1 || issuer.TrustedRootsPEMFiles[0] != "/etc/certs/company_root2.crt" {
229 t.Fatalf("expected trusted roots to include site CA root, got %v", issuer.TrustedRootsPEMFiles)
230 }
231 if issuer.Challenges == nil || issuer.Challenges.TLSALPN == nil || !issuer.Challenges.TLSALPN.Disabled {
232 t.Fatalf("expected tls-alpn challenge to be disabled, got %#v", issuer.Challenges)
233 }
234 }
235
236 func TestMergeACMEIssuers(t *testing.T) {
237 base := &caddytls.ACMEIssuer{
238 Email: "ops@example.com",
239 Challenges: &caddytls.ChallengesConfig{
240 HTTP: &caddytls.HTTPChallengeConfig{
241 AlternatePort: 8080,
242 },
243 TLSALPN: &caddytls.TLSALPNChallengeConfig{
244 Disabled: true,
245 AlternatePort: 8443,
246 },
247 DNS: &caddytls.DNSChallengeConfig{
248 Resolvers: []string{"1.1.1.1"},
249 OverrideDomain: "_acme-challenge.example.net",
250 },
251 },
252 TrustedRootsPEMFiles: []string{"global.pem"},
253 }
254 overrides := &caddytls.ACMEIssuer{
255 CA: "https://deglacme01.company.intern/acme/acme/directory",
256 Challenges: &caddytls.ChallengesConfig{
257 HTTP: &caddytls.HTTPChallengeConfig{
258 Disabled: true,
259 },
260 DNS: &caddytls.DNSChallengeConfig{
261 PropagationTimeout: caddy.Duration(time.Minute),
262 },
263 },
264 TrustedRootsPEMFiles: []string{"site.pem"},
265 }
266
267 merged := mergeACMEIssuers(base, overrides)
268 if merged.CA != overrides.CA {
269 t.Fatalf("expected merged CA %q, got %q", overrides.CA, merged.CA)
270 }
271 if merged.Email != base.Email {
272 t.Fatalf("expected merged email %q, got %q", base.Email, merged.Email)
273 }
274 if len(merged.TrustedRootsPEMFiles) != 2 || merged.TrustedRootsPEMFiles[0] != "global.pem" || merged.TrustedRootsPEMFiles[1] != "site.pem" {
275 t.Fatalf("expected merged roots [global.pem site.pem], got %v", merged.TrustedRootsPEMFiles)
276 }
277 if merged.Challenges == nil || merged.Challenges.HTTP == nil || !merged.Challenges.HTTP.Disabled || merged.Challenges.HTTP.AlternatePort != 8080 {
278 t.Fatalf("expected merged HTTP challenge config to preserve alternate port and apply disable flag, got %#v", merged.Challenges)
279 }
280 if merged.Challenges.TLSALPN == nil || !merged.Challenges.TLSALPN.Disabled || merged.Challenges.TLSALPN.AlternatePort != 8443 {
281 t.Fatalf("expected merged TLS-ALPN challenge config to preserve global settings, got %#v", merged.Challenges)
282 }
283 if merged.Challenges.DNS == nil || merged.Challenges.DNS.PropagationTimeout != caddy.Duration(time.Minute) || len(merged.Challenges.DNS.Resolvers) != 1 || merged.Challenges.DNS.Resolvers[0] != "1.1.1.1" || merged.Challenges.DNS.OverrideDomain != "_acme-challenge.example.net" {
284 t.Fatalf("expected merged DNS challenge config to preserve global values and apply overrides, got %#v", merged.Challenges)
285 }
286
287 if base.CA != "" {
288 t.Fatalf("expected base issuer to remain unchanged, got CA %q", base.CA)
289 }
290 if len(base.TrustedRootsPEMFiles) != 1 || base.TrustedRootsPEMFiles[0] != "global.pem" {
291 t.Fatalf("expected base roots to remain unchanged, got %v", base.TrustedRootsPEMFiles)
292 }
293 }