Skip to content

Commit

Permalink
[backend] support bearer auth in dod container downloads
Browse files Browse the repository at this point in the history
  • Loading branch information
mlschroe committed May 17, 2021
1 parent 52164aa commit 1929ae8
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 3 deletions.
12 changes: 12 additions & 0 deletions src/backend/BSRepServer/DoD.pm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use BSHandoff;
use BSContar;
use BSStdServer;
use BSUtil;
use BSBearer;

use BSRepServer::Containertar;
use BSRepServer::Containerinfo;
Expand Down Expand Up @@ -80,6 +81,14 @@ sub blob_matches_digest {
return (split(':', $digest, 2))[1] eq $ctx->hexdigest() ? 1 : 0;
}

my %registry_authenticators;

sub doauthrpc {
my ($param, $xmlargs, @args) = @_;
$param = { %$param, 'resulthook' => sub { $xmlargs->($_[0]) } };
return BSWatcher::rpc($param, $xmlargs, @args);
}

sub fetchdodcontainer {
my ($gdst, $pool, $repo, $p, $handoff) = @_;
my $container = $pool->pkg2name($p);
Expand Down Expand Up @@ -109,9 +118,12 @@ sub fetchdodcontainer {
my $tmp = "$dir/._blob.$blob.$$";
my $url = $repo->dodurl();
$url .= '/' unless $url =~ /\/$/;
my $authenticator = $registry_authenticators{"$url$regrepo"};
$authenticator = $registry_authenticators{"$url$regrepo"} = BSBearer::generate_authenticator(undef, 'verbose' => 1, 'rpccall' => \&doauthrpc) unless $authenticator;
$url .= "v2/$regrepo/blobs/$blob";
print "fetching: $url\n";
my $param = {'uri' => $url, 'filename' => $tmp, 'receiver' => \&BSHTTP::file_receiver, 'proxy' => $proxy};
$param->{'authenticator'} = $authenticator;
$param->{'maxredirects'} = $maxredirects if defined $maxredirects;
my $r;
eval { $r = BSWatcher::rpc($param); };
Expand Down
77 changes: 74 additions & 3 deletions src/backend/BSWatcher.pm
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,32 @@ sub rpc_error {
}
}

sub rpc_error_job {
my ($jev, $uri, $err) = @_;
chomp $err;
$jev->{'rpcdone'} = $jev->{'rpcoriguri'} || $uri;
$jev->{'rpcerror'} = $err;
redo_request($jev);
delete $jev->{'rpcdone'};
delete $jev->{'rpcresult'};
delete $jev->{'rpcoriguri'};
}

sub rpc_result_hook {
my ($ev, $res, $hook) = @_;
my @jobs = @{$ev->{'joblist'} || []};
my $uri = $ev->{'rpcuri'};
for my $jev (@jobs) {
local $BSServerEvents::gev = $jev;
eval { $hook->($res, $ev->{'param'}) };
if ($@) {
rpc_error_job($jev, $uri, $@);
} else {
redo_request($jev);
}
}
}

sub rpc_result {
my ($ev, $res) = @_;
$ev->{'rpcstate'} = 'done';
Expand All @@ -289,6 +315,7 @@ sub rpc_result {
delete $rpcs{$uri};
close $ev->{'fd'} if $ev->{'fd'};
delete $ev->{'fd'};
return rpc_result_hook($ev, $res, $ev->{'param'}->{'resulthook'}) if $ev->{'param'}->{'resulthook'};
my @jobs = @{$ev->{'joblist'} || []};
for my $jev (@jobs) {
$jev->{'rpcdone'} = $jev->{'rpcoriguri'} || $uri;
Expand Down Expand Up @@ -318,12 +345,45 @@ sub rpc_redirect {
delete $rpcs{$ev->{'rpcuri'}};
close $ev->{'fd'} if $ev->{'fd'};
delete $ev->{'fd'};
my $host = $ev->{'rpcdest'};
$host =~ s/:\d+$//;
#print "redirecting to: $location\n";
my @jobs = @{$ev->{'joblist'} || []};
for my $jev (@jobs) {
$jev->{'rpcoriguri'} ||= $ev->{'rpcuri'};
local $BSServerEvents::gev = $jev;
rpc({%$param, 'uri' => $location, 'maxredirects' => $param->{'maxredirects'} - 1});
eval {
rpc({%$param, 'uri' => $location, 'maxredirects' => $param->{'maxredirects'} - 1, '_stripauthhost' => $host, 'verbatim_uri' => 1});
};
rpc_error_job($jev, $ev->{'rpcuri'}, $@) if $@;
}
}

sub rpc_authenticate {
my ($ev, $status, $authenticator, $headers) = @_;

delete $rpcs{$ev->{'rpcuri'}};
close $ev->{'fd'} if $ev->{'fd'};
delete $ev->{'fd'};
my @jobs = @{$ev->{'joblist'} || []};
my $param = $ev->{'param'};
for my $jev (@jobs) {
$jev->{'rpcoriguri'} ||= $ev->{'rpcuri'};
local $BSServerEvents::gev = $jev;
my $auth;
eval {
$auth = $param->{'authenticator'}->($param, $headers->{'www-authenticate'}, $headers);
if ($auth) {
my %myparam = ( %{$ev->{'param'}}, 'authenticator' => undef );
$myparam{'headers'} = [ grep {!/^authorization:/i} @{$myparam{'headers'} || []} ];
push @{$myparam{'headers'}}, "Authorization: $auth";
rpc(\%myparam);
} elsif (defined($auth)) {
die("$1 remote error: $2\n") if $status =~ /^(\d+) +(.*?)$/;
die("remote error: $status\n");
}
};
rpc_error_job($jev, $ev->{'rpcuri'}, $@) if $@;
}
}

Expand Down Expand Up @@ -797,9 +857,11 @@ sub rpc_recv_null {
sub rpc_tossl {
my ($ev) = @_;
# print "switching to https\n";
my $sni;
$sni = $1 if $ev->{'rpcdest'} && $ev->{'rpcdest'} =~ /^(.+):\d+$/;
fcntl($ev->{'fd'}, F_SETFL, 0); # in danger honor...
eval {
($ev->{'param'}->{'https'} || $tossl)->($ev->{'fd'}, $ev->{'param'}->{'ssl_keyfile'}, $ev->{'param'}->{'ssl_certfile'}, 1);
($ev->{'param'}->{'https'} || $tossl)->($ev->{'fd'}, $ev->{'param'}->{'ssl_keyfile'}, $ev->{'param'}->{'ssl_certfile'}, 1, $sni);
if ($ev->{'param'}->{'sslpeerfingerprint'}) {
die("bad sslpeerfingerprint '$ev->{'param'}->{'sslpeerfingerprint'}'\n") unless $ev->{'param'}->{'sslpeerfingerprint'} =~ /^(.*?):(.*)$/s;
my $pfp = tied($ev->{'fd'})->peerfingerprint($1);
Expand Down Expand Up @@ -862,7 +924,11 @@ sub rpc_recv_handler {
$ans = $2;
my %headers;
BSHTTP::gethead(\%headers, $headers);
if ($status =~ /^302[^\d]/) {
if ($status =~ /^401[^\d]/ && $ev->{'param'}->{'authenticator'} && $headers{'www-authenticate'}) {
rpc_authenticate($ev, $status, $ev->{'param'}->{'authenticator'}, \%headers);
return undef;
}
if ($status =~ /^30[27][^\d]/) {
rpc_redirect($ev, $headers{'location'});
return;
} elsif ($status !~ /^200[^\d]/) {
Expand Down Expand Up @@ -1086,6 +1152,11 @@ sub rpc {
push @xhdrs, 'Content-Type: application/x-www-form-urlencoded';
push @xhdrs, "Content-Length: ".length($data);
}
if ($param->{'authenticator'} && !grep {/^authorization:/i} @xhdrs) {
# ask authenticator for cached authorization
my $auth = $param->{'authenticator'}->($param);
push @xhdrs, "Authorization: $auth" if $auth;
}

my $proxy = $param->{'proxy'};
my ($proto, $host, $port, $req, $proxytunnel) = BSRPC::createreq($param, $uri, $proxy, \%cookiestore, @xhdrs);
Expand Down

0 comments on commit 1929ae8

Please sign in to comment.