[pve-devel] r5752 - in pve-manager/pve2: . lib/PVE www/manager www/manager/window

svn-commits at proxmox.com svn-commits at proxmox.com
Thu Mar 24 11:20:01 CET 2011


Author: dietmar
Date: 2011-03-24 11:20:01 +0100 (Thu, 24 Mar 2011)
New Revision: 5752

Modified:
   pve-manager/pve2/ChangeLog
   pve-manager/pve2/lib/PVE/APIDaemon.pm
   pve-manager/pve2/lib/PVE/REST.pm
   pve-manager/pve2/www/manager/PVEUtils.js
   pve-manager/pve2/www/manager/index.pl
   pve-manager/pve2/www/manager/window/LoginWindow.js
Log:
include the CSRF prevention token


Modified: pve-manager/pve2/ChangeLog
===================================================================
--- pve-manager/pve2/ChangeLog	2011-03-24 09:03:09 UTC (rev 5751)
+++ pve-manager/pve2/ChangeLog	2011-03-24 10:20:01 UTC (rev 5752)
@@ -1,3 +1,13 @@
+2011-03-24  Proxmox Support Team  <support at proxmox.com>
+
+	* www/manager/index.pl: include the CSRF prevention token in the
+	generated page if there is a valid ticket inside the cookie (the
+	JS variable is called 'PVECSRFPreventionToken')
+
+	* lib/PVE/REST.pm (rest_handler): add CSRF prevention Logic. You
+	need to pass the CSRF prevention token in the
+	'CSRFPreventionToken' header for POST, PUT and DELETE request.
+
 2011-03-23  Proxmox Support Team  <support at proxmox.com>
 
 	* lib/PVE/REST.pm (cookie_string): set 'secure' for auth cookie

Modified: pve-manager/pve2/lib/PVE/APIDaemon.pm
===================================================================
--- pve-manager/pve2/lib/PVE/APIDaemon.pm	2011-03-24 09:03:09 UTC (rev 5751)
+++ pve-manager/pve2/lib/PVE/APIDaemon.pm	2011-03-24 10:20:01 UTC (rev 5752)
@@ -269,7 +269,8 @@
 
 			my $clientip = $headers->header('PVEClientIP');
 
-			my $res = PVE::REST::rest_handler($clientip, $method, $uri, $rel_uri, $ticket, $params);
+			my $res = PVE::REST::rest_handler($clientip, $method, $uri, $rel_uri, 
+							  $ticket, undef, $params);
 
 			if ($res->{proxy}) {
 

Modified: pve-manager/pve2/lib/PVE/REST.pm
===================================================================
--- pve-manager/pve2/lib/PVE/REST.pm	2011-03-24 09:03:09 UTC (rev 5751)
+++ pve-manager/pve2/lib/PVE/REST.pm	2011-03-24 10:20:01 UTC (rev 5752)
@@ -11,6 +11,7 @@
 use CGI;
 use mod_perl2;
 use JSON;
+use Digest::SHA;
 use LWP::UserAgent;
 use HTTP::Request::Common;
 use HTTP::Status qw(:constants :is status_message);
@@ -177,7 +178,7 @@
 }
 
 sub proxy_handler {
-    my($r, $clientip, $host, $method, $abs_uri, $ticket, $params) = @_;
+    my($r, $clientip, $host, $method, $abs_uri, $ticket, $token, $params) = @_;
 
     syslog('info', "proxy start $method $host:$abs_uri");
 
@@ -187,7 +188,7 @@
 	);
 
     $ua->default_header('cookie' => "${cookie_name}=$ticket") if $ticket;
-
+    $ua->default_header('CSRFPreventionToken' => $token) if $token;
     $ua->default_header('PVEDisableProxy' => 'true');
     $ua->default_header('PVEClientIP' => $clientip);
 
@@ -264,16 +265,16 @@
 	my $path = PVE::Tools::template_replace($perm->{path}, $param);
 	if (!$rpcenv->check($username, $path, $perm->{privs})) {
 	    my $privstr = join(',', @{$perm->{privs}});
-	    die "permission check failed ($path, $privstr)\n";
+	    die "Permission check failed ($path, $privstr)\n";
 	}
 	return 1;
     }
 
-    die "permission check failed\n";
+    die "Permission check failed\n";
 };
 
 sub rest_handler {
-    my ($clientip, $method, $abs_uri, $rel_uri, $ticket, $params) = @_;
+    my ($clientip, $method, $abs_uri, $rel_uri, $ticket, $token, $params) = @_;
 
     my $rpcenv = PVE::RPCEnvironment::get();
 
@@ -297,17 +298,20 @@
 
     if ($require_auth) {
 
-	return { 
-	    status => HTTP_UNAUTHORIZED, 
-	    message => "No ticket",
-	} if !$ticket;
+	eval {
+	    die "No ticket\n" if !$ticket;
 
-	($username, $age) = PVE::AccessControl::verify_ticket($ticket, 1);
+	    ($username, $age) = PVE::AccessControl::verify_ticket($ticket);
 
-	return { 
-	    status => HTTP_UNAUTHORIZED, 
-	    message => "Ticket verify failed",
-	} if !$username;
+	    PVE::AccessControl::verify_csrf_prevention_token($ticket, $token)
+		if ($euid != 0) && ($method ne 'GET');
+	};
+	if (my $err = $@) {
+	    return { 
+		status => HTTP_UNAUTHORIZED, 
+		message => $err,
+	    };
+	}
     }
     
     my $uri_param = {};
@@ -441,6 +445,7 @@
      my $params = $cgi->Vars();
 
      my $cookie = $r->headers_in->{Cookie};
+     my $token = $r->headers_in->{CSRFPreventionToken};
 
      my $ticket = extract_auth_cookie($cookie);
 
@@ -450,7 +455,8 @@
      my ($rel_uri, $format) = split_abs_uri($abs_uri);
      return HTTP_NOT_IMPLEMENTED if !$format;
 
-     my $res = rest_handler($clientip, $method, $abs_uri, $rel_uri, $ticket, $params);
+     my $res = rest_handler($clientip, $method, $abs_uri, $rel_uri, 
+			    $ticket, $token, $params);
 
      if ($res->{proxy}) {
 	 if ($r->headers_in->{'PVEDisableProxy'}) {
@@ -460,7 +466,7 @@
 	     return $res->{status};	     
 	 } 
 	 return proxy_handler($r, $clientip, $res->{proxy}, $method, 
-			      $abs_uri, $ticket, $params);
+			      $abs_uri, $ticket, $token, $params);
      }
 
      prepare_response_data($format, $res);

Modified: pve-manager/pve2/www/manager/PVEUtils.js
===================================================================
--- pve-manager/pve2/www/manager/PVEUtils.js	2011-03-24 09:03:09 UTC (rev 5751)
+++ pve-manager/pve2/www/manager/PVEUtils.js	2011-03-24 10:20:01 UTC (rev 5752)
@@ -12,6 +12,14 @@
     'Accept': 'application/json'
 };
 
+Ext.Ajax.on('beforerequest', function(conn, options) {
+    if (PVECSRFPreventionToken) {
+	if (!options.headers) 
+	    options.headers = {};
+	options.headers['CSRFPreventionToken'] = PVECSRFPreventionToken;
+    }
+});
+
 // do not send '_dc' parameter
 Ext.Ajax.disableCaching = false;
 

Modified: pve-manager/pve2/www/manager/index.pl
===================================================================
--- pve-manager/pve2/www/manager/index.pl	2011-03-24 09:03:09 UTC (rev 5751)
+++ pve-manager/pve2/www/manager/index.pl	2011-03-24 10:20:01 UTC (rev 5752)
@@ -4,6 +4,8 @@
 use mod_perl2 '1.9922';
 use Encode;
 use CGI;
+use PVE::AccessControl;
+use PVE::REST;
 
 sub send_output {
     my ($r, $data) = @_;
@@ -22,6 +24,15 @@
 # so we must be very careful here 
 
 my $r = Apache2::RequestUtil->request();
+
+my $token = 'null';
+if (my $cookie = $r->headers_in->{Cookie}) {
+    my $ticket = PVE::REST::extract_auth_cookie($cookie);
+    if (PVE::AccessControl::verify_ticket($ticket, 1)) {
+	$token = PVE::AccessControl::assemble_csrf_prevention_token($ticket);
+    }
+}
+
 my $cgi = CGI->new($r);
 my %args =  $cgi->Vars();
 
@@ -38,6 +49,7 @@
 }
 
 my $jssrc = <<_EOJS;
+PVECSRFPreventionToken = '$token';
 Ext.onReady(PVE.Workspace.init, PVE.Workspace);
 _EOJS
 

Modified: pve-manager/pve2/www/manager/window/LoginWindow.js
===================================================================
--- pve-manager/pve2/www/manager/window/LoginWindow.js	2011-03-24 09:03:09 UTC (rev 5751)
+++ pve-manager/pve2/www/manager/window/LoginWindow.js	2011-03-24 10:20:01 UTC (rev 5752)
@@ -20,6 +20,10 @@
 		},
 		success: function(f, resp){
 		    self.el.unmask();
+
+		    if (resp.result && resp.result.data)
+			PVECSRFPreventionToken = resp.result.data.CSRFPreventionToken;
+
 		    var handler = self.handler || Ext.emptyFn;
 		    handler.call(self);
 		    self.close();



More information about the pve-devel mailing list