From f00829fd606b2d3f15828125527a7b6bfda6ba7f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fabian=20Gr=C3=BCnbichler?= Date: Fri, 17 Apr 2020 09:39:50 +0200 Subject: [PATCH] plugins: refactor setup/teardown signatures MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit and move handling of tokens/key_auths to plugins, since it's not bound to be identical for all challenge types forever. Signed-off-by: Fabian Grünbichler --- src/PVE/ACME/Challenge.pm | 13 ++++++-- src/PVE/ACME/DNSChallenge.pm | 62 +++++++++++++++++++----------------- src/PVE/ACME/StandAlone.pm | 10 +++--- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/PVE/ACME/Challenge.pm b/src/PVE/ACME/Challenge.pm index 3fb8ab9..0137cf2 100644 --- a/src/PVE/ACME/Challenge.pm +++ b/src/PVE/ACME/Challenge.pm @@ -70,14 +70,23 @@ sub get_subplugins { return []; } +# acme => PVE::ACME instance +# auth => authorization object returned by ACME server +# $data => { +# plugin => plugin config data +# alias => optional domain alias +# } +# needs to set $data->{url} to URL of the challenge which has been set up +# can set other $data keys needed by teardown sub sub setup { - my ($class, $acme, $authorization) = @_; + my ($self, $acme, $auth, $data) = @_; die "implement me\n"; } +# see setup sub teardown { - my ($self) = @_; + my ($self, $acme, $auth, $data) = @_; die "implement me\n"; } diff --git a/src/PVE/ACME/DNSChallenge.pm b/src/PVE/ACME/DNSChallenge.pm index 98a183e..041bc79 100644 --- a/src/PVE/ACME/DNSChallenge.pm +++ b/src/PVE/ACME/DNSChallenge.pm @@ -143,11 +143,6 @@ sub options { }; } -my $outfunc = sub { - my $line = shift; - print "$line\n"; -}; - sub extract_challenge { my ($self, $challenge) = @_; @@ -158,44 +153,53 @@ sub get_subplugins { return $api_name_list; } -# The order of the parameters passed to proxmox-acme is important -# proxmox-acme setup $plugin [$domain|$alias] $txtvalue $plugin_conf_string -sub setup { - my ($self, $data) = @_; +my $proxmox_acme_command = sub { + my ($self, $acme, $auth, $data, $action) = @_; die "No plugin data for DNSChallenge\n" if !defined($data->{plugin}); - my $domain = $data->{plugin}->{alias} ? $data->{plugin}->{alias} : $data->{domain}; - my $txtvalue = PVE::ACME::encode(sha256($data->{key_authorization})); + + my $alias = $data->{alias}; + my $domain = $auth->{identifier}->{value}; + + my $challenge = $self->extract_challenge($auth->{challenges}); + my $key_auth = $acme->key_authorization($challenge->{token}); + + my $txtvalue = PVE::ACME::encode(sha256($key_auth)); my $dnsplugin = $data->{plugin}->{api}; my $plugin_conf_string = $data->{plugin}->{data}; # for security reasons, we execute the command as nobody # we can't verify that the code of the DNSPlugins are harmless. my $cmd = ["setpriv", "--reuid", "nobody", "--regid", "nogroup", "--clear-groups", "--"]; - push @$cmd, "/bin/bash", $ACME_PATH, "setup", $dnsplugin, $domain; - push @$cmd, $txtvalue, $plugin_conf_string; - PVE::Tools::run_command($cmd, outfunc => $outfunc); + # The order of the parameters passed to proxmox-acme is important + # proxmox-acme $plugin <$domain|$alias> $txtvalue [$plugin_conf_string] + push @$cmd, "/bin/bash", $ACME_PATH, $action, $dnsplugin; + if ($alias) { + push @$cmd, $alias; + } else { + push @$cmd, $domain; + } + push @$cmd, $txtvalue, $plugin_conf_string; + + PVE::Tools::run_command($cmd); + + $data->{url} = $challenge->{url}; + + return $domain; +}; + +sub setup { + my ($self, $acme, $auth, $data) = @_; + + my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'setup'); print "Add TXT record: _acme-challenge.$domain\n"; } -# The order of the parameters passed to proxmox-acme is important -# proxmox-acme teardown $plugin [$domain|$alias] $txtvalue $plugin_conf_string sub teardown { - my ($self, $data) = @_; + my ($self, $acme, $auth, $data) = @_; - die "No plugin data for DNSChallenge\n" if !defined($data->{plugin}); - my $domain = $data->{plugin}->{alias} ? $data->{plugin}->{alias} : $data->{domain}; - my $txtvalue = PVE::ACME::encode(sha256($data->{key_authorization})); - my $dnsplugin = $data->{plugin}->{api}; - my $plugin_conf_string = $data->{plugin}->{data}; - - # for security reasons, we execute the command as nobody - # we can't verify that the code of the DNSPlugins are harmless. - my $cmd = ["setpriv", "--reuid", "nobody", "--regid", "nogroup", "--clear-groups", "--"]; - push @$cmd, "/bin/bash", "$ACME_PATH", "teardown", $dnsplugin, $domain ; - push @$cmd, $txtvalue, $plugin_conf_string; - PVE::Tools::run_command($cmd, outfunc => $outfunc); + my $domain = $proxmox_acme_command->($self, $acme, $auth, $data, 'teardown'); print "Remove TXT record: _acme-challenge.$domain\n"; } diff --git a/src/PVE/ACME/StandAlone.pm b/src/PVE/ACME/StandAlone.pm index 310e627..b47a927 100644 --- a/src/PVE/ACME/StandAlone.pm +++ b/src/PVE/ACME/StandAlone.pm @@ -38,11 +38,12 @@ sub get_subplugins { } sub setup { - my ($class, $data) = @_; + my ($self, $acme, $auth, $data) = @_; print "Setting up webserver\n"; - my $key_auth = $data->{key_authorization}; + my $challenge = $self->extract_challenge($auth->{challenges}); + my $key_auth = $acme->key_authorization($challenge->{token}); my $server = HTTP::Daemon->new( LocalPort => 80, @@ -52,11 +53,12 @@ sub setup { if ($pid) { $data->{server} = $server; $data->{pid} = $pid; + $data->{url} = $challenge->{url}; } else { while (my $c = $server->accept()) { while (my $r = $c->get_request()) { if ($r->method() eq 'GET' and - $r->uri->path eq "/.well-known/acme-challenge/$data->{token}") { + $r->uri->path eq "/.well-known/acme-challenge/$challenge->{token}") { my $resp = HTTP::Response->new(200, 'OK', undef, $key_auth); $resp->request($r); $c->send_response($resp); @@ -71,7 +73,7 @@ sub setup { } sub teardown { - my ($self, $data) = @_; + my ($self, $acme, $auth, $data) = @_; eval { $data->{server}->close() }; kill('KILL', $data->{pid}); -- 2.39.2