From 51f7e24b1259ba11316dc2722d88d49b238c210f Mon Sep 17 00:00:00 2001 From: Sven Nierlein Date: Sun, 15 Sep 2024 21:21:34 +0200 Subject: [PATCH] unify remote.cgi and proxy.cgi --- lib/Thruk.pm | 3 +- lib/Thruk/Backend/Peer.pm | 50 ++++--- lib/Thruk/Config.pm | 2 +- lib/Thruk/Controller/proxy.pm | 16 ++- lib/Thruk/Controller/remote.pm | 26 +++- lib/Thruk/Utils.pm | 129 ++++++++++++++---- lib/Thruk/Utils/CLI.pm | 16 +++ lib/Thruk/Utils/Filter.pm | 15 +- .../editor/templates/editor.tt | 2 +- .../lib/Thruk/NodeControl/Utils.pm | 16 ++- .../node-control/templates/node_control.tt | 4 +- templates/_extinfo_type_0_blocks.tt | 8 +- templates/_extinfo_type_0_table.tt | 8 +- templates/_header.tt | 2 +- 14 files changed, 221 insertions(+), 76 deletions(-) diff --git a/lib/Thruk.pm b/lib/Thruk.pm index 0757c9fe97..bb499b631d 100644 --- a/lib/Thruk.pm +++ b/lib/Thruk.pm @@ -96,7 +96,7 @@ sub startup { $app = Plack::Middleware::Static->wrap($app, path => sub { my $p = Thruk::Context::translate_request_path($_, config()); - return if $p =~ m%^/thruk/cgi\-bin/proxy\.cgi%mx; + return if $p =~ m%^/thruk/cgi\-bin/(remote|proxy)\.cgi%mx; $p =~ /\.(css|png|js|gif|jpg|ico|html|wav|mp3|ogg|ttf|svg|woff|woff2|eot|map)$/mx; }, root => './root/', @@ -190,6 +190,7 @@ sub _build_app { [ '^/thruk/r/v1.*' ,'Thruk::Controller::rest_v1::index' ], [ '^/thruk/r/.*' ,'Thruk::Controller::rest_v1::index' ], [ '^/thruk/cgi-bin/proxy.cgi/.*' ,'Thruk::Controller::proxy::index' ], + [ '^/thruk/cgi-bin/remote.cgi/.*' ,'Thruk::Controller::remote::index' ], ]; Thruk::Utils::Status::add_view({'group' => 'Main', diff --git a/lib/Thruk/Backend/Peer.pm b/lib/Thruk/Backend/Peer.pm index 31f2608efd..4b10d0bf78 100644 --- a/lib/Thruk/Backend/Peer.pm +++ b/lib/Thruk/Backend/Peer.pm @@ -334,9 +334,13 @@ sub cmd { $background_options->{"cmd"} = $cmd; } if($self->{'type'} eq 'http') { - if($self->{'federation'} && scalar @{$self->{'fed_info'}->{'type'}} >= 2 && $self->{'fed_info'}->{'type'}->[1] eq 'http') { + # is the machine reachable by http + if($self->{'federation'} + && scalar @{$self->{'fed_info'}->{'type'}} >= 2 + && $self->{'fed_info'}->{'type'}->[1] eq 'http' + ) { require Thruk::Utils; - my $url = Thruk::Utils::get_remote_thruk_url($c, $self->{'key'}); + my $url = Thruk::Utils::get_remote_thruk_url_path($c, $self->{'key'}); my $options = { 'action' => 'raw', @@ -359,7 +363,7 @@ sub cmd { my $req = HTTP::Request->new('POST', $url.'cgi-bin/remote.cgi', $header, $postdata); require Thruk::Controller::proxy; - my $res = Thruk::Controller::proxy::proxy_request($c, $self->{'key'}, $url.'cgi-bin/remote.cgi', $req); + my $res = Thruk::Controller::proxy::proxy_request($c, $self->{'key'}, $url.'cgi-bin/remote.cgi', $req); my $result; eval { $result = Cpanel::JSON::XS::decode_json($res->content()); @@ -368,31 +372,39 @@ sub cmd { if($err) { die(Thruk::Utils::http_response_error($res)); } + if(ref $result->{'output'} ne 'ARRAY') { + $out = $result->{'output'}; + $rc = -1; + return($rc, $out); + } ($rc, $out) = @{$result->{'output'}}; if($background_options) { ($out) = @{$result->{'output'}}; } + return($rc, $out); + } + + if($background_options) { + ($out) = @{$self->{'class'}->request("Thruk::Utils::External::cmd", ['Thruk::Context', $background_options], { timeout => 120 })}; } else { - if($background_options) { - ($out) = @{$self->{'class'}->request("Thruk::Utils::External::cmd", ['Thruk::Context', $background_options], { timeout => 120 })}; - } else { - ($rc, $out) = @{$self->{'class'}->request("Thruk::Utils::IO::cmd", [$cmd], { timeout => 120 })}; - } + ($rc, $out) = @{$self->{'class'}->request("Thruk::Utils::IO::cmd", [$cmd], { timeout => 120 })}; } + return($rc, $out); - } elsif(my $http_peer = $self->get_http_fallback_peer()) { + } + + if(my $http_peer = $self->get_http_fallback_peer()) { my @args = @_; shift @args; return($http_peer->cmd(@args)); } - else { - if($background_options) { - require Thruk::Utils::External; - $out = Thruk::Utils::External::cmd($c, $background_options); - } else { - require Thruk::Utils::IO; - ($rc, $out) = Thruk::Utils::IO::cmd($cmd); - } + + if($background_options) { + require Thruk::Utils::External; + $out = Thruk::Utils::External::cmd($c, $background_options); + } else { + require Thruk::Utils::IO; + ($rc, $out) = Thruk::Utils::IO::cmd($cmd); } return($rc, $out); @@ -413,7 +425,7 @@ sub rpc { if($self->{'type'} eq 'http') { if($self->{'federation'} && scalar @{$self->{'fed_info'}->{'type'}} >= 2 && $self->{'fed_info'}->{'type'}->[1] eq 'http') { require Thruk::Utils; - my $url = Thruk::Utils::get_remote_thruk_url($c, $self->{'key'}); + my $url = Thruk::Utils::get_remote_thruk_url_path($c, $self->{'key'}); my $options = { 'action' => 'raw', @@ -480,7 +492,7 @@ sub job_data { if($self->{'type'} eq 'http') { if($self->{'federation'} && scalar @{$self->{'fed_info'}->{'type'}} >= 2 && $self->{'fed_info'}->{'type'}->[1] eq 'http') { require Thruk::Utils; - my $url = Thruk::Utils::get_remote_thruk_url($c, $self->{'key'}); + my $url = Thruk::Utils::get_remote_thruk_url_path($c, $self->{'key'}); my $options = { 'action' => 'raw', diff --git a/lib/Thruk/Config.pm b/lib/Thruk/Config.pm index 6afd2ce79d..27ade7b4a6 100644 --- a/lib/Thruk/Config.pm +++ b/lib/Thruk/Config.pm @@ -834,7 +834,7 @@ sub get_toolkit_config { 'get_broadcasts' => \&Thruk::Utils::Broadcast::get_broadcasts, 'command_disabled' => \&Thruk::Utils::command_disabled, 'proxifiy_url' => \&Thruk::Utils::proxifiy_url, - 'get_remote_thruk_url' => \&Thruk::Utils::get_remote_thruk_url, + 'get_remote_thruk_url_path' => \&Thruk::Utils::get_remote_thruk_url_path, 'basename' => \&Thruk::Base::basename, 'debug_details' => \&get_debug_details, 'format_date' => \&Thruk::Utils::format_date, diff --git a/lib/Thruk/Controller/proxy.pm b/lib/Thruk/Controller/proxy.pm index 90157c89bb..3122ae01bb 100644 --- a/lib/Thruk/Controller/proxy.pm +++ b/lib/Thruk/Controller/proxy.pm @@ -81,13 +81,21 @@ sub proxy_request { my $request_url = Thruk::Utils::absolute_url($peer->{'addr'}, $url, 1); # federated peers forward to the next hop - my $passthrough; + my($passthrough, $add_key); if($peer->{'federation'} && scalar @{$peer->{'fed_info'}->{'type'}} >= 2 && $peer->{'fed_info'}->{'type'}->[1] eq 'http') { $request_url = $peer->{'addr'}; $request_url =~ s|/cgi\-bin/remote\.cgi$||gmx; $request_url =~ s|/thruk/?$||gmx; - $request_url = $request_url.'/thruk/cgi-bin/proxy.cgi/'.$peer->{'key'}; + $request_url = $request_url.'/thruk/cgi-bin/remote.cgi/'.$peer->{'key'}; $passthrough = '/thruk/cgi-bin/proxy.cgi/'.$peer->{'key'}.$url; + } else { + # TODO: only if normal http request fails or so... + $request_url = $peer->{'addr'}; + $request_url =~ s|/cgi\-bin/remote\.cgi$||gmx; + $request_url =~ s|/thruk/?$||gmx; + $request_url = $request_url.'/thruk/cgi-bin/remote.cgi'; + $passthrough = $url; + $add_key = 1; } if($base_req->{'env'}->{'QUERY_STRING'}) { @@ -107,6 +115,10 @@ sub proxy_request { if($passthrough) { $req->header('X-Thruk-Passthrough', $passthrough); } + if($add_key) { + $req->header('X-Thruk-Auth-Key', $peer->{'class'}->{'auth'}); + $req->header('X-Thruk-Auth-User', $c->user->{'username'}) if $c->user_exists; + } my $ua = Thruk::UserAgent->new({}, $c->config); $ua->max_redirect(0); Thruk::UserAgent::disable_verify_hostname_by_url($ua, $request_url); diff --git a/lib/Thruk/Controller/remote.pm b/lib/Thruk/Controller/remote.pm index 2e8a881c0b..a915a2fd44 100644 --- a/lib/Thruk/Controller/remote.pm +++ b/lib/Thruk/Controller/remote.pm @@ -25,7 +25,31 @@ Thruk Controller. ########################################################## sub index { - my($c) = @_; + my($c, $path_info) = @_; + + # proxy request + if($c->req->header('X-Thruk-Passthrough')) { + if(!$c->user_exists) { + $c->authenticate(skip_db_access => 1); + } + if(!$c->user_exists) { + $c->res->code(401); + return $c->render("text" => 'not authorized'); + } +# TODO: check why changes constantly + $c->user->set_dynamic_attributes($c); + require Thruk::Context; + require Thruk::Utils::CLI; + my $url = Thruk::Context::translate_request_path($c->req->header('X-Thruk-Passthrough'), $c->config); + my @res = Thruk::Utils::CLI::request_url($c, $url, undef, $c->req->method, $c->req->parameters); + if($res[1] && $res[1]->{'headers'}) { + $c->res->headers($res[1]->{'headers'}->clone()); + } + $c->res->body($res[1]->{'result'} // $res[2]); + $c->res->code($res[0]); + $c->{'rendered'} = 1; + return; + } Thruk::Utils::check_pid_file($c); diff --git a/lib/Thruk/Utils.pm b/lib/Thruk/Utils.pm index 73c244ac80..0b18b30f94 100644 --- a/lib/Thruk/Utils.pm +++ b/lib/Thruk/Utils.pm @@ -1302,7 +1302,7 @@ returns url with optional proxy prepended sub proxifiy_me { my($c, $peer_id) = @_; return unless $peer_id; - my $thruk_url = get_remote_thruk_url($c, $peer_id); + my $thruk_url = get_remote_thruk_url_path($c, $peer_id); return unless $thruk_url; my $url = $c->req->uri; $url =~ s|^https?://[^/]+/|/|mx; @@ -1314,61 +1314,140 @@ sub proxifiy_me { ######################################## -=head2 get_remote_thruk_url +=head2 get_remote_thruk_url_path - get_remote_thruk_url($c, $peer_key, [$full]) + get_remote_thruk_url_path($c, $peer_key) -return url for remote thruk installation +returns path of last http address/thruk instance in chain =cut -sub get_remote_thruk_url { +sub get_remote_thruk_url_path { my($c, $id, $full) = @_; my $peer = $c->db->get_peer_by_key($id); confess("got no peer for id: ".$id) unless $peer; my $url = ""; if($peer->{'fed_info'} && $peer->{'fed_info'}->{'addr'}) { - # use last address which starts with http for my $u (reverse @{$peer->{'fed_info'}->{'addr'}}) { - if($u =~ m|^https?:|mx) { + if($u =~ m%^https?:%mx) { $url = $u; last; } } } - if($peer->{'type'} eq 'http' && (!$url || $url !~ /^https?:/mx)) { - $url = $peer->{'addr'}; + if(!$url || $url !~ m/^https?:\/\//mx) { + for my $u (reverse @{$peer->peer_list()}) { + if($u =~ m%^https?:%mx) { + $url = $u; + last; + } + } } - return($url || "") if $full; - if($url) { - if($url !~ m/^https?:\/\//mx) { - return(""); + if(!$url || $url !~ m/^https?:\/\//mx) { + return(""); + } + + $url =~ s|^https?://[^/]*/?|/|gmx; + $url =~ s|cgi-bin\/remote\.cgi$||gmx; + $url =~ s|thruk/?$||gmx; + $url =~ s|/$||gmx; + $url = $url.'/thruk/'; + + return($url); +} + +######################################## + +=head2 get_remote_thruk_hostname + + get_remote_thruk_hostname($c, $peer_key) + +returns hostname and url of last none-local address + +=cut +sub get_remote_thruk_hostname { + my($c, $id) = @_; + + my $peer = $c->db->get_peer_by_key($id); + confess("got no peer for id: ".$id) unless $peer; + + my $url = ""; + if($peer->{'fed_info'} && $peer->{'fed_info'}->{'addr'}) { + for my $u (reverse @{$peer->{'fed_info'}->{'addr'}}) { + next if $u =~ m%(127\.0\.0\.|localhost|::1|^/)%mx; + if($u =~ m%^(https?:|.*:\d+)%mx) { + $url = $u; + last; + } + } + } + + if(!$url) { + for my $u (reverse @{$peer->peer_list()}) { + next if $u =~ m%(127\.0\.0\.|localhost|::1|^/)%mx; + if($u =~ m%^(https?:|.*:\d+)%mx) { + $url = $u; + last; + } } - $url =~ s|^https?://[^/]*/?|/|gmx; - $url =~ s|cgi-bin\/remote\.cgi$||gmx; - $url =~ s|thruk/?$||gmx; - $url =~ s|/$||gmx; - $url = $url.'/thruk/'; } - return($url || ""); + + return unless $url; + + if($url =~ m|^(https?)://([^/]+)/([^/]+)/|gmx) { + return($2, $url); + } + + if($url =~ m|^(.*):(\d+)|gmx) { + return($1, $url); + } + + return; } ######################################## -=head2 get_remote_thruk_url_full +=head2 get_remote_thruk_site_name - get_remote_thruk_url_full($c, $peer_key) + get_remote_thruk_site_name($c, $peer_key) -returns ($proto, $hostname, $site) +returns site name of peer =cut -sub get_remote_thruk_url_full { +sub get_remote_thruk_site_name { my($c, $id) = @_; - my $url = get_remote_thruk_url($c, $id, 1); + + my $peer = $c->db->get_peer_by_key($id); + confess("got no peer for id: ".$id) unless $peer; + + my $url = ""; + if($peer->{'fed_info'} && $peer->{'fed_info'}->{'addr'}) { + for my $u (reverse @{$peer->{'fed_info'}->{'addr'}}) { + if($u =~ m%^(https?:|/omd/sites/)%mx) { + $url = $u; + last; + } + } + } + + if(!$url) { + for my $u (reverse @{$peer->peer_list()}) { + if($u =~ m%^(https?:|/omd/sites/)%mx) { + $url = $u; + last; + } + } + } + return unless $url; if($url =~ m|^(https?)://([^/]+)/([^/]+)/|gmx) { - return($1, $2, $3); + return($3); } + + if($url =~ m|^/omd/sites/([^/]+)/|gmx) { + return($1); + } + return; } diff --git a/lib/Thruk/Utils/CLI.pm b/lib/Thruk/Utils/CLI.pm index 67ac2c9097..47a31531e4 100644 --- a/lib/Thruk/Utils/CLI.pm +++ b/lib/Thruk/Utils/CLI.pm @@ -464,6 +464,22 @@ sub _internal_request { delete $Thruk::thruk->{'TRANSFER_USER'} if $app->{'thruk'}; $Thruk::thruk->{'TRANSFER_USER'} = $user if defined $user; + # serve static files internally + if($url =~ m%/thruk/(vendor|javascript|themes)/%mx) { + my $file = Thruk->config->{home}.'/root'.$url; + if(-f $file) { + require Plack::MIME; + my $content_type = Plack::MIME->mime_type($file) || 'text/plain'; + return(undef, undef, + HTTP::Response->new( + 200, "OK", + HTTP::Headers->new( Content_Type => $content_type ), + Thruk::Utils::IO::read($file), + ), + ); + } + } + my $request = HTTP::Request->new($method, $url); $request->method(uc($method)); if($postdata) { diff --git a/lib/Thruk/Utils/Filter.pm b/lib/Thruk/Utils/Filter.pm index 5528fbc988..0eeb4f3700 100644 --- a/lib/Thruk/Utils/Filter.pm +++ b/lib/Thruk/Utils/Filter.pm @@ -2078,13 +2078,7 @@ sub peer_address_list { my $peer = $c->db->get_peer_by_key($id); confess("got no peer for id: ".$id) unless $peer; - my $mainAddr = $peer->{'addr'}; - my($proto, $host, $site) = Thruk::Utils::get_remote_thruk_url_full($c, $id); - my $http = ""; - if($host) { - $http = CORE::sprintf('%s://%s/%s', $proto, $host, $site); - $mainAddr = $http; - } + my($host, $mainAddr) = Thruk::Utils::get_remote_thruk_hostname($c, $id); my $full = []; if($peer->{'fed_info'}) { for my $url (@{$peer->{'fed_info'}->{'addr'}}) { @@ -2094,7 +2088,12 @@ sub peer_address_list { } } - return([$mainAddr, $http, $full]); + $mainAddr = $peer->{'addr'} unless $mainAddr; + + $mainAddr =~ s|cgi-bin\/remote\.cgi$||gmx; + $mainAddr =~ s|thruk/?$||gmx; + + return([$mainAddr, $full]); } ######################################## diff --git a/plugins/plugins-available/editor/templates/editor.tt b/plugins/plugins-available/editor/templates/editor.tt index 0b2a59249b..6a6ab098e7 100644 --- a/plugins/plugins-available/editor/templates/editor.tt +++ b/plugins/plugins-available/editor/templates/editor.tt @@ -29,7 +29,7 @@