@marcel91200 / caddy Mirror · read-only / commits / c2b91dbd
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 14, 05:15 UTC

httpcaddyfile: Support repeated use of cert_issuer global option

This changes the signature of UnmarshalGlobalFunc but this is probably OK since it's only used by this repo as far as we know. We need this change in order to "remember" the previous value in case a global option appears more than once, which is now a possibility with the cert_issuer option since Caddy now supports multiple issuers in the order defined by the user. Bonus: the issuer subdirective of tls now supports one-liner for "acme" when all you need to set is the directory: issuer acme <dir>

Matthew Holt committed Jan 7, 2021 at 11:01 UTC c2b91dbd65173d256e6fa4ddd3fec6ed2f6c87ef
5 files changed +51 -40
caddyconfig/httpcaddyfile/directives.go
+4 -3
@@ -498,9 +498,10 @@ type (
498 UnmarshalHandlerFunc func(h Helper) (caddyhttp.MiddlewareHandler, error)
499
500 // UnmarshalGlobalFunc is a function which can unmarshal Caddyfile
501 - // tokens into a global option config value using a Helper type.
502 - // These are passed in a call to RegisterGlobalOption.
503 - UnmarshalGlobalFunc func(d *caddyfile.Dispenser) (interface{}, error)
501 + // tokens from a global option. It is passed the tokens to parse and
502 + // existing value from the previous instance of this global option
503 + // (if any). It returns the value to associate with this global option.
504 + UnmarshalGlobalFunc func(d *caddyfile.Dispenser, existingVal interface{}) (interface{}, error)
505 )
506
507 var registeredDirectives = make(map[string]UnmarshalFunc)
caddyconfig/httpcaddyfile/httptype.go
+1 -1
@@ -315,7 +315,7 @@ func (ServerType) evaluateGlobalOptionsBlock(serverBlocks []serverBlock, options
315 return nil, fmt.Errorf("%s:%d: unrecognized global option: %s", tkn.File, tkn.Line, opt)
316 }
317
318 - val, err = optFunc(disp)
318 + val, err = optFunc(disp, options[opt])
319 if err != nil {
320 return nil, fmt.Errorf("parsing caddyfile tokens for '%s': %v", opt, err)
321 }
caddyconfig/httpcaddyfile/options.go
+31 -30
@@ -30,7 +30,6 @@ func init() {
30 RegisterGlobalOption("https_port", parseOptHTTPSPort)
31 RegisterGlobalOption("default_sni", parseOptSingleString)
32 RegisterGlobalOption("order", parseOptOrder)
33 - RegisterGlobalOption("experimental_http3", parseOptTrue)
33 RegisterGlobalOption("storage", parseOptStorage)
34 RegisterGlobalOption("acme_ca", parseOptSingleString)
35 RegisterGlobalOption("acme_ca_root", parseOptSingleString)
@@ -46,11 +45,9 @@ func init() {
45 RegisterGlobalOption("servers", parseServerOptions)
46 }
47
49 -func parseOptTrue(d *caddyfile.Dispenser) (interface{}, error) {
50 - return true, nil
51 -}
48 +func parseOptTrue(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) { return true, nil }
49
53 -func parseOptHTTPPort(d *caddyfile.Dispenser) (interface{}, error) {
50 +func parseOptHTTPPort(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
51 var httpPort int
52 for d.Next() {
53 var httpPortStr string
@@ -66,7 +63,7 @@ func parseOptHTTPPort(d *caddyfile.Dispenser) (interface{}, error) {
63 return httpPort, nil
64 }
65
69 -func parseOptHTTPSPort(d *caddyfile.Dispenser) (interface{}, error) {
66 +func parseOptHTTPSPort(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
67 var httpsPort int
68 for d.Next() {
69 var httpsPortStr string
@@ -82,7 +79,7 @@ func parseOptHTTPSPort(d *caddyfile.Dispenser) (interface{}, error) {
79 return httpsPort, nil
80 }
81
85 -func parseOptOrder(d *caddyfile.Dispenser) (interface{}, error) {
82 +func parseOptOrder(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
83 newOrder := directiveOrder
84
85 for d.Next() {
@@ -158,7 +155,7 @@ func parseOptOrder(d *caddyfile.Dispenser) (interface{}, error) {
155 return newOrder, nil
156 }
157
161 -func parseOptStorage(d *caddyfile.Dispenser) (interface{}, error) {
158 +func parseOptStorage(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
159 if !d.Next() { // consume option name
160 return nil, d.ArgErr()
161 }
@@ -177,7 +174,7 @@ func parseOptStorage(d *caddyfile.Dispenser) (interface{}, error) {
174 return storage, nil
175 }
176
180 -func parseOptACMEDNS(d *caddyfile.Dispenser) (interface{}, error) {
177 +func parseOptACMEDNS(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
178 if !d.Next() { // consume option name
179 return nil, d.ArgErr()
180 }
@@ -196,7 +193,7 @@ func parseOptACMEDNS(d *caddyfile.Dispenser) (interface{}, error) {
193 return prov, nil
194 }
195
199 -func parseOptACMEEAB(d *caddyfile.Dispenser) (interface{}, error) {
196 +func parseOptACMEEAB(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
197 eab := new(acme.EAB)
198 for d.Next() {
199 if d.NextArg() {
@@ -224,26 +221,30 @@ func parseOptACMEEAB(d *caddyfile.Dispenser) (interface{}, error) {
221 return eab, nil
222 }
223
227 -func parseOptCertIssuer(d *caddyfile.Dispenser) (interface{}, error) {
228 - if !d.Next() { // consume option name
229 - return nil, d.ArgErr()
230 - }
231 - if !d.Next() { // get issuer module name
232 - return nil, d.ArgErr()
224 +func parseOptCertIssuer(d *caddyfile.Dispenser, existing interface{}) (interface{}, error) {
225 + var issuers []certmagic.Issuer
226 + if existing != nil {
227 + issuers = existing.([]certmagic.Issuer)
228 }
234 - modID := "tls.issuance." + d.Val()
235 - unm, err := caddyfile.UnmarshalModule(d, modID)
236 - if err != nil {
237 - return nil, err
238 - }
239 - iss, ok := unm.(certmagic.Issuer)
240 - if !ok {
241 - return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
229 + for d.Next() { // consume option name
230 + if !d.Next() { // get issuer module name
231 + return nil, d.ArgErr()
232 + }
233 + modID := "tls.issuance." + d.Val()
234 + unm, err := caddyfile.UnmarshalModule(d, modID)
235 + if err != nil {
236 + return nil, err
237 + }
238 + iss, ok := unm.(certmagic.Issuer)
239 + if !ok {
240 + return nil, d.Errf("module %s (%T) is not a certmagic.Issuer", modID, unm)
241 + }
242 + issuers = append(issuers, iss)
243 }
243 - return iss, nil
244 + return issuers, nil
245 }
246
246 -func parseOptSingleString(d *caddyfile.Dispenser) (interface{}, error) {
247 +func parseOptSingleString(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
248 d.Next() // consume parameter name
249 if !d.Next() {
250 return "", d.ArgErr()
@@ -255,7 +256,7 @@ func parseOptSingleString(d *caddyfile.Dispenser) (interface{}, error) {
256 return val, nil
257 }
258
258 -func parseOptAdmin(d *caddyfile.Dispenser) (interface{}, error) {
259 +func parseOptAdmin(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
260 adminCfg := new(caddy.AdminConfig)
261 for d.Next() {
262 if d.NextArg() {
@@ -291,7 +292,7 @@ func parseOptAdmin(d *caddyfile.Dispenser) (interface{}, error) {
292 return adminCfg, nil
293 }
294
294 -func parseOptOnDemand(d *caddyfile.Dispenser) (interface{}, error) {
295 +func parseOptOnDemand(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
296 var ond *caddytls.OnDemandConfig
297 for d.Next() {
298 if d.NextArg() {
@@ -351,7 +352,7 @@ func parseOptOnDemand(d *caddyfile.Dispenser) (interface{}, error) {
352 return ond, nil
353 }
354
354 -func parseOptAutoHTTPS(d *caddyfile.Dispenser) (interface{}, error) {
355 +func parseOptAutoHTTPS(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
356 d.Next() // consume parameter name
357 if !d.Next() {
358 return "", d.ArgErr()
@@ -366,6 +367,6 @@ func parseOptAutoHTTPS(d *caddyfile.Dispenser) (interface{}, error) {
367 return val, nil
368 }
369
369 -func parseServerOptions(d *caddyfile.Dispenser) (interface{}, error) {
370 +func parseServerOptions(d *caddyfile.Dispenser, _ interface{}) (interface{}, error) {
371 return unmarshalCaddyfileServerOptions(d)
372 }
caddyconfig/httpcaddyfile/tlsapp.go
+5 -5
@@ -414,11 +414,11 @@ func fillInGlobalACMEDefaults(issuer certmagic.Issuer, options map[string]interf
414 // returned if there are no default/global options. However, if always is
415 // true, a non-nil value will always be returned (unless there is an error).
416 func newBaseAutomationPolicy(options map[string]interface{}, warnings []caddyconfig.Warning, always bool) (*caddytls.AutomationPolicy, error) {
417 - issuer, hasIssuer := options["cert_issuer"]
417 + issuers, hasIssuers := options["cert_issuer"]
418 _, hasLocalCerts := options["local_certs"]
419 keyType, hasKeyType := options["key_type"]
420
421 - hasGlobalAutomationOpts := hasIssuer || hasLocalCerts || hasKeyType
421 + hasGlobalAutomationOpts := hasIssuers || hasLocalCerts || hasKeyType
422
423 // if there are no global options related to automation policies
424 // set, then we can just return right away
@@ -434,12 +434,12 @@ func newBaseAutomationPolicy(options map[string]interface{}, warnings []caddycon
434 ap.KeyType = keyType.(string)
435 }
436
437 - if hasIssuer && hasLocalCerts {
437 + if hasIssuers && hasLocalCerts {
438 return nil, fmt.Errorf("global options are ambiguous: local_certs is confusing when combined with cert_issuer, because local_certs is also a specific kind of issuer")
439 }
440
441 - if hasIssuer {
442 - ap.Issuers = []certmagic.Issuer{issuer.(certmagic.Issuer)}
441 + if hasIssuers {
442 + ap.Issuers = issuers.([]certmagic.Issuer)
443 } else if hasLocalCerts {
444 ap.Issuers = []certmagic.Issuer{new(caddytls.InternalIssuer)}
445 }
modules/caddytls/acmeissuer.go
+10 -1
@@ -233,7 +233,7 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss }
233
234 // UnmarshalCaddyfile deserializes Caddyfile tokens into iss.
235 //
236 -// ... acme {
236 +// ... acme [<directory_url>] {
237 // dir <directory_url>
238 // test_dir <test_directory_url>
239 // email <email>
@@ -250,9 +250,18 @@ func (iss *ACMEIssuer) GetACMEIssuer() *ACMEIssuer { return iss }
250 //
251 func (iss *ACMEIssuer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
252 for d.Next() {
253 + if d.NextArg() {
254 + iss.CA = d.Val()
255 + if d.NextArg() {
256 + return d.ArgErr()
257 + }
258 + }
259 for nesting := d.Nesting(); d.NextBlock(nesting); {
260 switch d.Val() {
261 case "dir":
262 + if iss.CA != "" {
263 + return d.Errf("directory is already specified: %s", iss.CA)
264 + }
265 if !d.AllArgs(&iss.CA) {
266 return d.ArgErr()
267 }