[pve-devel] [PATCH v2 http-server 2/2] api-server: extract, set and handle API token header

Fabian Grünbichler f.gruenbichler at proxmox.com
Thu Nov 21 15:43:43 CET 2019


Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---

Notes:
    versioned breaks/depends with pve-manager and part of PMG?

 PVE/APIServer/AnyEvent.pm            | 25 ++++++++++++++++++-------
 PVE/APIServer/Formatter.pm           |  9 +++++++++
 PVE/APIServer/Formatter/Bootstrap.pm |  1 +
 3 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/PVE/APIServer/AnyEvent.pm b/PVE/APIServer/AnyEvent.pm
index 1e5c180..3ce948f 100644
--- a/PVE/APIServer/AnyEvent.pm
+++ b/PVE/APIServer/AnyEvent.pm
@@ -544,7 +544,7 @@ sub websocket_proxy {
 }
 
 sub proxy_request {
-    my ($self, $reqstate, $clientip, $host, $node, $method, $uri, $ticket, $token, $params) = @_;
+    my ($self, $reqstate, $clientip, $host, $node, $method, $uri, $auth, $params) = @_;
 
     eval {
 	my $target;
@@ -564,8 +564,12 @@ sub proxy_request {
 	    PVEClientIP => $clientip,
 	};
 
-	$headers->{'cookie'} = PVE::APIServer::Formatter::create_auth_cookie($ticket, $self->{cookie_name}) if $ticket;
-	$headers->{'CSRFPreventionToken'} = $token if $token;
+	$headers->{'cookie'} = PVE::APIServer::Formatter::create_auth_cookie($auth->{ticket}, $self->{cookie_name})
+	    if $auth->{ticket};
+	$headers->{'Authorization'} = PVE::APIServer::Formatter::create_auth_header($auth->{api_token}, $self->{apitoken_name})
+	    if $auth->{api_token};
+	$headers->{'CSRFPreventionToken'} = $auth->{token}
+	    if $auth->{token};
 	$headers->{'Accept-Encoding'} = 'gzip' if ($reqstate->{accept_gzip} && $self->{compression});
 
 	if (defined(my $host = $reqstate->{request}->header('Host'))) {
@@ -744,7 +748,7 @@ sub handle_api2_request {
 	    $res->{proxy_params}->{tmpfilename} = $reqstate->{tmpfilename} if $upload_state;
 
 	    $self->proxy_request($reqstate, $clientip, $host, $res->{proxynode}, $method,
-				 $r->uri, $auth->{ticket}, $auth->{token}, $res->{proxy_params});
+				 $r->uri, $auth, $res->{proxy_params});
 	    return;
 
 	} elsif ($upgrade && ($method eq 'GET') && ($path =~ m|websocket$|)) {
@@ -1238,6 +1242,11 @@ sub unshift_read_header {
 		    $ticket = PVE::APIServer::Formatter::extract_auth_value($auth_header, $self->{cookie_name})
 			if !$ticket;
 
+		    # finally, fallback to API token if no ticket has been provided so far
+		    my $api_token;
+		    $api_token = PVE::APIServer::Formatter::extract_auth_value($auth_header, $self->{apitoken_name})
+			if !$ticket;
+
 		    my ($rel_uri, $format) = &$split_abs_uri($path, $self->{base_uri});
 		    if (!$format) {
 			$self->error($reqstate, HTTP_NOT_IMPLEMENTED, "no such uri");
@@ -1245,7 +1254,7 @@ sub unshift_read_header {
 		    }
 
 		    eval {
-			$auth = $self->auth_handler($method, $rel_uri, $ticket, $token,
+			$auth = $self->auth_handler($method, $rel_uri, $ticket, $token, $api_token,
 						    $reqstate->{peer_host});
 		    };
 		    if (my $err = $@) {
@@ -1639,6 +1648,7 @@ sub new {
     my $self = bless { %args }, $class;
 
     $self->{cookie_name} //= 'PVEAuthCookie';
+    $self->{apitoken_name} //= 'PVEAPIToken';
     $self->{base_uri} //= "/api2";
     $self->{dirs} //= {};
     $self->{title} //= 'API Inspector';
@@ -1646,7 +1656,7 @@ sub new {
 
     # formatter_config: we pass some configuration values to the Formatter
     $self->{formatter_config} = {};
-    foreach my $p (qw(cookie_name base_uri title)) {
+    foreach my $p (qw(apitoken_name cookie_name base_uri title)) {
 	$self->{formatter_config}->{$p} = $self->{$p};
     }
     $self->{formatter_config}->{csrfgen_func} =
@@ -1781,7 +1791,7 @@ sub generate_csrf_prevention_token {
 }
 
 sub auth_handler {
-    my ($self, $method, $rel_uri, $ticket, $token, $peer_host) = @_;
+    my ($self, $method, $rel_uri, $ticket, $token, $api_token, $peer_host) = @_;
 
     die "implement me";
 
@@ -1791,6 +1801,7 @@ sub auth_handler {
     #    userid => $username,
     #    age => $age,
     #    isUpload => $isUpload,
+    #    api_token => $api_token,
     #};
 }
 
diff --git a/PVE/APIServer/Formatter.pm b/PVE/APIServer/Formatter.pm
index def1932..20455a0 100644
--- a/PVE/APIServer/Formatter.pm
+++ b/PVE/APIServer/Formatter.pm
@@ -95,4 +95,13 @@ sub create_auth_cookie {
     return "${cookie_name}=$encticket; path=/; secure;";
 }
 
+sub create_auth_header {
+    my ($value, $key) = @_;
+
+    return undef if !$key;
+
+    my $encoded = uri_escape($value);
+    return "${key} ${encoded}";
+}
+
 1;
diff --git a/PVE/APIServer/Formatter/Bootstrap.pm b/PVE/APIServer/Formatter/Bootstrap.pm
index d61f982..e67554a 100644
--- a/PVE/APIServer/Formatter/Bootstrap.pm
+++ b/PVE/APIServer/Formatter/Bootstrap.pm
@@ -65,6 +65,7 @@ sub new {
 	url => $url,
 	title => $config->{title},
 	cookie_name => $config->{cookie_name},
+	apitoken_name => $config->{apitoken_name},
 	js => '',
     };
 
-- 
2.20.1





More information about the pve-devel mailing list