Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make cache service work with authenticated asset downloads #6120

Merged
merged 4 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/OpenQA/CacheService/Model/Cache.pm
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ sub get_asset ($self, $host, $job, $type, $asset) {
# Keep temporary files on the same partition as the cache
my $log = $self->log;
my $downloader = $self->downloader->log($log)->tmpdir($self->_realpath->child('tmp')->to_string);
$downloader->ua->configure_credentials($url->host);

my $start;
my $options = {
Expand Down
4 changes: 2 additions & 2 deletions lib/OpenQA/Downloader.pm
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ package OpenQA::Downloader;
use Mojo::Base -base, -signatures;

use Mojo::Loader 'load_class';
use Mojo::UserAgent;
use Mojo::File 'path';
use Mojo::URL;
use OpenQA::UserAgent;
use OpenQA::Utils 'human_readable_size';
use Try::Tiny;
use Time::HiRes 'sleep';

has attempts => 5;
has [qw(log tmpdir)];
has sleep_time => 5;
has ua => sub { Mojo::UserAgent->new(max_redirects => 5, max_response_size => 0) };
has ua => sub { OpenQA::UserAgent->new(max_redirects => 5, max_response_size => 0) };
has res => undef;

sub download ($self, $url, $target, $options = {}) {
Expand Down
3 changes: 2 additions & 1 deletion lib/OpenQA/Shared/Controller/Auth.pm
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ sub _key_auth ($self, $reason, $key) {
if (my $api_key = $self->schema->resultset('ApiKeys')->find({key => $key})) {
$log->trace(sprintf 'Key is for user "%s"', $api_key->user->username);

my $msg = $self->req->url->to_string;
my $headers = $self->req->headers;
my $url = $self->req->url;
my $msg = $url->path eq '/api/v1/auth' ? ($headers->header('X-Original-URI') // $url) : $url;
my $hash = $headers->header('X-API-Hash');
my $remote_timestamp = $headers->header('X-API-Microtime');
my $our_timestamp = time;
Expand Down
73 changes: 32 additions & 41 deletions lib/OpenQA/UserAgent.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later

package OpenQA::UserAgent;
use Mojo::Base 'Mojo::UserAgent';
use Mojo::Base 'Mojo::UserAgent', -signatures;

use Mojo::Util 'hmac_sha1_sum';
use Config::IniFiles;
Expand All @@ -14,65 +14,56 @@ has [qw(apikey apisecret base_url)];
sub new {
my $self = shift->SUPER::new(@_);
my %args = @_;

for my $i (qw(apikey apisecret)) {
next unless $args{$i};
$self->$i($args{$i});
$self->$i($args{$i}) if $args{$i};
}

if ($args{api}) {
my @cfgpaths = ($ENV{OPENQA_CONFIG} // glob('~/.config/openqa'), '/etc/openqa');
for my $path (@cfgpaths) {
my $file = $path . '/client.conf';
next unless $file && -r $file;
my $cfg = Config::IniFiles->new(-file => $file) || last;
last unless $cfg->SectionExists($args{api});
for my $i (qw(key secret)) {
my $attr = "api$i";
next if $self->$attr;
# Fetch all the values in the file and keep the last one
my @values = $cfg->val($args{api}, $i);
next unless my $val = $values[-1];
$val =~ s/\s+$//; # remove trailing whitespace
$self->$attr($val);
}
last;
}
}
$self->configure_credentials($args{api});

# Scheduling a couple of hundred jobs takes quite some time - so we better wait a couple of minutes
# (default is 20 seconds)
$self->inactivity_timeout(600);

# Some urls might redirect to https and then there are internal redirects for assets
$self->max_redirects(3);

$self->on(
start => sub {
$self->_add_auth_headers(@_);
});
$self->on(start => sub ($ua, $tx) { $self->_add_auth_headers($ua, $tx) });

#read proxy environment variables
$self->proxy->detect;

return $self;
}

sub _add_auth_headers {
my ($self, $ua, $tx) = @_;
sub configure_credentials ($self, $host) {
return undef unless $host;
my @cfgpaths = ($ENV{OPENQA_CONFIG} // glob('~/.config/openqa'), '/etc/openqa');
for my $path (@cfgpaths) {
my $file = $path . '/client.conf';
next unless $file && -r $file;
my $cfg = Config::IniFiles->new(-file => $file) || last;
last unless $cfg->SectionExists($host);
for my $i (qw(key secret)) {
my $attr = "api$i";
next if $self->$attr;
# Fetch all the values in the file and keep the last one
my @values = $cfg->val($host, $i);
next unless my $val = $values[-1];
$val =~ s/\s+$//; # remove trailing whitespace
$self->$attr($val);
}
last;
}
}

sub _add_auth_headers ($self, $ua, $tx) {
my $timestamp = time;
my %headers = (
Accept => 'application/json',
'X-API-Microtime' => $timestamp,
);
my $headers = $tx->req->headers;
$headers->accept('application/json') unless defined $headers->accept;
$headers->header('X-API-Microtime', $timestamp);
if ($self->apisecret && $self->apikey) {
$headers{'X-API-Key'} = $self->apikey;
$headers{'X-API-Hash'} = hmac_sha1_sum($self->_path_query($tx) . $timestamp, $self->apisecret);
}

my $set_headers = $tx->req->headers;
foreach my $key (keys %headers) {
# don't overwrite headers that were set manually
$set_headers->header($key, $headers{$key}) unless defined $set_headers->header($key);
$headers->header('X-API-Key', $self->apikey);
$headers->header('X-API-Hash', hmac_sha1_sum($self->_path_query($tx) . $timestamp, $self->apisecret));
}
}

Expand Down
Loading