From 8b80a3201fcddda3fcf125116d33555cb385a803 Mon Sep 17 00:00:00 2001 From: Ye Zhihao Date: Tue, 4 Aug 2020 03:44:38 +0800 Subject: [PATCH] httpcaddyfile: Bring `enforce_origin` and `origins` to admin config (#3595) * Bring `ensure_origin` and `origins` to caddyfile admin config * Add unit test for caddyfile admin config update * Add caddyfile adapt test for typical admin setup * httpcaddyfile: Replace admin config error message when there's more arguments than needed Replace d.Err() to d.ArgErr() since the latter provides similarly informative error message Co-authored-by: Matt Holt Co-authored-by: Matt Holt --- caddyconfig/httpcaddyfile/httptype.go | 8 +- caddyconfig/httpcaddyfile/httptype_test.go | 52 ++++++++++++ caddyconfig/httpcaddyfile/options.go | 38 +++++++-- .../caddyfile_adapt/global_options_admin.txt | 80 +++++++++++++++++++ 4 files changed, 164 insertions(+), 14 deletions(-) create mode 100644 caddytest/integration/caddyfile_adapt/global_options_admin.txt diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 3f37f024..130067da 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -261,12 +261,8 @@ func (st ServerType) Setup(inputServerBlocks []caddyfile.ServerBlock, storageCvtr.(caddy.Module).CaddyModule().ID.Name(), &warnings) } - if adminConfig, ok := options["admin"].(string); ok && adminConfig != "" { - if adminConfig == "off" { - cfg.Admin = &caddy.AdminConfig{Disabled: true} - } else { - cfg.Admin = &caddy.AdminConfig{Listen: adminConfig} - } + if adminConfig, ok := options["admin"].(*caddy.AdminConfig); ok && adminConfig != nil { + cfg.Admin = adminConfig } if len(customLogs) > 0 { if cfg.Logging == nil { diff --git a/caddyconfig/httpcaddyfile/httptype_test.go b/caddyconfig/httpcaddyfile/httptype_test.go index b0ee3ac0..233e3749 100644 --- a/caddyconfig/httpcaddyfile/httptype_test.go +++ b/caddyconfig/httpcaddyfile/httptype_test.go @@ -164,6 +164,58 @@ func TestGlobalOptions(t *testing.T) { expectWarn: false, expectError: true, }, + { + input: ` + { + admin { + enforce_origin + origins 192.168.1.1:2020 127.0.0.1:2020 + } + } + :80 + `, + expectWarn: false, + expectError: false, + }, + { + input: ` + { + admin 127.0.0.1:2020 { + enforce_origin + origins 192.168.1.1:2020 127.0.0.1:2020 + } + } + :80 + `, + expectWarn: false, + expectError: false, + }, + { + input: ` + { + admin 192.168.1.1:2020 127.0.0.1:2020 { + enforce_origin + origins 192.168.1.1:2020 127.0.0.1:2020 + } + } + :80 + `, + expectWarn: false, + expectError: true, + }, + { + input: ` + { + admin off { + enforce_origin + origins 192.168.1.1:2020 127.0.0.1:2020 + } + } + :80 + `, + expectWarn: false, + expectError: true, + }, } { adapter := caddyfile.Adapter{ diff --git a/caddyconfig/httpcaddyfile/options.go b/caddyconfig/httpcaddyfile/options.go index f69ca3ec..613bbc60 100644 --- a/caddyconfig/httpcaddyfile/options.go +++ b/caddyconfig/httpcaddyfile/options.go @@ -223,17 +223,39 @@ func parseOptSingleString(d *caddyfile.Dispenser) (interface{}, error) { } func parseOptAdmin(d *caddyfile.Dispenser) (interface{}, error) { - if d.Next() { - var listenAddress string - if !d.AllArgs(&listenAddress) { - return "", d.ArgErr() + adminCfg := new(caddy.AdminConfig) + for d.Next() { + if d.NextArg() { + listenAddress := d.Val() + if listenAddress == "off" { + adminCfg.Disabled = true + if d.Next() { // Do not accept any remaining options including block + return nil, d.Err("No more option is allowed after turning off admin config") + } + } else { + adminCfg.Listen = listenAddress + if d.NextArg() { // At most 1 arg is allowed + return nil, d.ArgErr() + } + } } - if listenAddress == "" { - listenAddress = caddy.DefaultAdminListen + for nesting := d.Nesting(); d.NextBlock(nesting); { + switch d.Val() { + case "enforce_origin": + adminCfg.EnforceOrigin = true + + case "origins": + adminCfg.Origins = d.RemainingArgs() + + default: + return nil, d.Errf("unrecognized parameter '%s'", d.Val()) + } } - return listenAddress, nil } - return "", nil + if adminCfg.Listen == "" && !adminCfg.Disabled { + adminCfg.Listen = caddy.DefaultAdminListen + } + return adminCfg, nil } func parseOptOnDemand(d *caddyfile.Dispenser) (interface{}, error) { diff --git a/caddytest/integration/caddyfile_adapt/global_options_admin.txt b/caddytest/integration/caddyfile_adapt/global_options_admin.txt new file mode 100644 index 00000000..14bee216 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/global_options_admin.txt @@ -0,0 +1,80 @@ +{ + debug + http_port 8080 + https_port 8443 + default_sni localhost + order root first + storage file_system { + root /data + } + acme_ca https://example.com + acme_ca_root /path/to/ca.crt + + email test@example.com + admin { + origins localhost:2019 [::1]:2019 127.0.0.1:2019 192.168.10.128 + } + on_demand_tls { + ask https://example.com + interval 30s + burst 20 + } + local_certs + key_type ed25519 +} + +:80 +---------- +{ + "admin": { + "listen": "localhost:2019", + "origins": [ + "localhost:2019", + "[::1]:2019", + "127.0.0.1:2019", + "192.168.10.128" + ] + }, + "logging": { + "logs": { + "default": { + "level": "DEBUG" + } + } + }, + "storage": { + "module": "file_system", + "root": "/data" + }, + "apps": { + "http": { + "http_port": 8080, + "https_port": 8443, + "servers": { + "srv0": { + "listen": [ + ":80" + ] + } + } + }, + "tls": { + "automation": { + "policies": [ + { + "issuer": { + "module": "internal" + } + } + ], + "on_demand": { + "rate_limit": { + "interval": 30000000000, + "burst": 20 + }, + "ask": "https://example.com" + } + } + } + } +}