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

svn-commits at proxmox.com svn-commits at proxmox.com
Wed Feb 23 09:59:02 CET 2011


Author: dietmar
Date: 2011-02-23 09:59:02 +0100 (Wed, 23 Feb 2011)
New Revision: 5591

Modified:
   pve-manager/pve2/ChangeLog
   pve-manager/pve2/lib/PVE/APIDaemon.pm
   pve-manager/pve2/lib/PVE/REST.pm
   pve-manager/pve2/www/manager/window/LoginWindow.js
Log:
2011-02-23  Proxmox Support Team  <support at proxmox.com>

	* lib/PVE/REST.pm (rest_handler): use standard framework to create
	tickets.

	* www/manager/window/LoginWindow.js: use new URIs (/access/ticket)

	* lib/PVE/REST.pm (proxy_handler): set 'PVEClientIP' header - that
	way we can log auth failures with client IP (can be use by
	fail2ban)



Modified: pve-manager/pve2/ChangeLog
===================================================================
--- pve-manager/pve2/ChangeLog	2011-02-23 08:30:06 UTC (rev 5590)
+++ pve-manager/pve2/ChangeLog	2011-02-23 08:59:02 UTC (rev 5591)
@@ -1,3 +1,14 @@
+2011-02-23  Proxmox Support Team  <support at proxmox.com>
+
+	* lib/PVE/REST.pm (rest_handler): use standard framework to create
+	tickets.
+
+	* www/manager/window/LoginWindow.js: use new URIs (/access/ticket)
+
+	* lib/PVE/REST.pm (proxy_handler): set 'PVEClientIP' header - that
+	way we can log auth failures with client IP (can be use by
+	fail2ban)
+
 2011-02-16  Proxmox Support Team  <support at proxmox.com>
 
 	* lib/PVE/REST.pm (rest_handler): use new PVE::RPCEnvironment

Modified: pve-manager/pve2/lib/PVE/APIDaemon.pm
===================================================================
--- pve-manager/pve2/lib/PVE/APIDaemon.pm	2011-02-23 08:30:06 UTC (rev 5590)
+++ pve-manager/pve2/lib/PVE/APIDaemon.pm	2011-02-23 08:59:02 UTC (rev 5591)
@@ -267,8 +267,10 @@
 			my $parser = HTTP::Request::Params->new({req => $r});
 			my $params = $parser->params;
 
-			my $res = PVE::REST::rest_handler($method, $uri, $rel_uri, $ticket, $params);
+			my $clientip = $headers->header('PVEClientIP');
 
+			my $res = PVE::REST::rest_handler($clientip, $method, $uri, $rel_uri, $ticket, $params);
+
 			if ($res->{proxy}) {
 
 			    $res->{status} = 500;

Modified: pve-manager/pve2/lib/PVE/REST.pm
===================================================================
--- pve-manager/pve2/lib/PVE/REST.pm	2011-02-23 08:30:06 UTC (rev 5590)
+++ pve-manager/pve2/lib/PVE/REST.pm	2011-02-23 08:59:02 UTC (rev 5591)
@@ -35,34 +35,6 @@
     return $cookie;
 }
 
-sub create_ticket {
-    my ($user, $pw) = @_;
-
-    # NOTE: $pw is allowed to be a ticket
-
-    my $euid = $>;
-
-    my $ticket;
-    eval {
-	my $tmp;
-	if (($tmp = PVE::AccessControl::verify_ticket($pw, 1)) &&
-	    ($tmp eq $user)) {
-	    # got valid ticket
-	} else {
-	    $user = PVE::AccessControl::authenticate_user($user, $pw);
-	}
-	$ticket = PVE::AccessControl::assemble_ticket($user);
-    };
-    my $err = $@;
-
-    if ($err) {
-	syslog('err', $err);
-	return undef;
-    }
-
-    return $ticket;
-}
-
 sub extract_auth_cookie {
     my ($cookie) = @_;
 
@@ -195,7 +167,7 @@
 }
 
 sub proxy_handler {
-    my($r, $host, $method, $abs_uri, $ticket, $params) = @_;
+    my($r, $clientip, $host, $method, $abs_uri, $ticket, $params) = @_;
 
     syslog('info', "proxy start $method $host:$abs_uri");
 
@@ -207,6 +179,7 @@
     $ua->default_header('cookie' => "${cookie_name}=$ticket") if $ticket;
 
     $ua->default_header('PVEDisableProxy' => 'true');
+    $ua->default_header('PVEClientIP' => $clientip);
 
     my $uri = URI->new();
 
@@ -266,6 +239,8 @@
 my $check_permissions = sub {
     my ($rpcenv, $perm, $username, $param) = @_;
 
+    return 1 if !$username && $perm->{user} eq 'world';
+
     return 1 if $username eq 'root at pam';
 
     die "permission check failed (user != root)\n" if !$perm;
@@ -288,7 +263,7 @@
 };
 
 sub rest_handler {
-    my ($method, $abs_uri, $rel_uri, $ticket, $params) = @_;
+    my ($clientip, $method, $abs_uri, $rel_uri, $ticket, $params) = @_;
 
     my $rpcenv = PVE::RPCEnvironment::get();
 
@@ -299,60 +274,31 @@
     }
  
     my $euid = $>;
-   
-    if ($rel_uri eq '/realms' && $method eq 'GET') {
 
-	return { status => HTTP_OK, 
-		 data => $rpcenv->realm_list() };
+    my $require_auth = 1;
 
-    } elsif ($rel_uri eq '/ticket') {
-	my $user = $params->{username} || '';
-	my $pw = $params->{password} || '';
+    # explicitly allow some calls without auth
+    if (($rel_uri eq '/access/domains' && $method eq 'GET') ||
+	($rel_uri eq '/access/ticket' && $method eq 'POST')) {
+	$require_auth = 0;
+    }
 
-	$user .= "\@$params->{realm}" if $params->{realm};
+    my ($username, $age);
 
-	if (!$rpcenv->user_enabled($user)) {
-	    return { 
-		status => HTTP_FORBIDDEN,
-		message => "No such user (user not enabled).",
-	    };
-	}
+    if ($require_auth) {
 
-	return { proxy => 'localhost' } if ($euid != 0);
+	return { 
+	    status => HTTP_UNAUTHORIZED, 
+	    message => "No ticket",
+	} if !$ticket;
 
-	#syslog('info', "ticket auth $user $pw");
+	($username, $age) = PVE::AccessControl::verify_ticket($ticket, 1);
 
-	if (!($ticket = create_ticket($user, $pw))) {
-	    return { 
-		status => HTTP_FORBIDDEN,
-		message => "Unable to verify credentials.",
-	    };
-	}
-	 
-	if (defined($params->{path}) || defined($params->{permissions})) {
-	    my @privs = PVE::Tools::split_list($params->{permissions});
-	    my $path = PVE::AccessControl::normalize_path($params->{path});
-	    if (!($path && scalar(@privs) && $rpcenv->check($user, $path, \@privs))) {
-		my $msg = "permission check failed ($params->{path}, $params->{permissions})";
-		syslog('info', $msg);
-		return { 
-		    status => HTTP_FORBIDDEN,
-		    message => $msg,
-		};
-	    }
-	}
-
-	PVE::Cluster::log_msg('info', 'root at pam', "successful auth for user '$user'");
-	return { status => HTTP_OK, ticket => $ticket, 
-		 data => { ticket => $ticket }};
+	return { 
+	    status => HTTP_UNAUTHORIZED, 
+	    message => "Ticket verify failed",
+	} if !$username;
     }
-
-    my ($username, $age);
-    ($username, $age) = PVE::AccessControl::verify_ticket($ticket, 1) if $ticket;
-
-    return { status => HTTP_UNAUTHORIZED } if !($ticket && $username);
-
-    #syslog ('info', "GOT $method $abs_uri VALID TICKET $ticket");
     
     my $uri_param = {};
     my ($handler, $info) = PVE::API2->find_handler($method, $rel_uri, $uri_param);
@@ -412,6 +358,7 @@
     # set environment variables
     $rpcenv->set_language('C'); # fixme:
     $rpcenv->set_user($username);
+    $rpcenv->set_client_ip($clientip);
 
     my $resp = { 
 	info => $info, # useful to format output
@@ -433,6 +380,12 @@
 	}
     }
 
+    $rpcenv->set_user(undef);
+
+    if ($rel_uri eq '/access/ticket') {
+	$resp->{ticket} = $resp->{data}->{ticket};
+    }
+
     # fixme: update ticket if too old
     # $resp->{ticket} = update_ticket($ticket);
 
@@ -461,6 +414,7 @@
      #syslog('info', "perl handler called");
 
      my $method = $r->method;
+     my $clientip = $r->connection->remote_ip();
 
      return HTTP_NOT_IMPLEMENTED
 	 if !$known_methods->{$method};
@@ -479,7 +433,7 @@
      my ($rel_uri, $format) = split_abs_uri($abs_uri);
      return HTTP_NOT_IMPLEMENTED if !$format;
 
-     my $res = rest_handler($method, $abs_uri, $rel_uri, $ticket, $params);
+     my $res = rest_handler($clientip, $method, $abs_uri, $rel_uri, $ticket, $params);
 
      if ($res->{proxy}) {
 	 if ($r->headers_in->{'PVEDisableProxy'}) {
@@ -488,7 +442,8 @@
 	     $r->status_line("$code proxy loop detected - aborted");
 	     return $res->{status};	     
 	 } 
-	 return proxy_handler($r, $res->{proxy}, $method, $abs_uri, $ticket, $params);
+	 return proxy_handler($r, $clientip, $res->{proxy}, $method, 
+			      $abs_uri, $ticket, $params);
      }
 
      prepare_response_data($format, $res);

Modified: pve-manager/pve2/www/manager/window/LoginWindow.js
===================================================================
--- pve-manager/pve2/www/manager/window/LoginWindow.js	2011-02-23 08:30:06 UTC (rev 5590)
+++ pve-manager/pve2/www/manager/window/LoginWindow.js	2011-02-23 08:59:02 UTC (rev 5591)
@@ -32,7 +32,7 @@
 	var self = this;
 
 	var realmstore = new Ext.data.JsonStore({
-	    url: "/api2/json/realms",
+	    url: "/api2/json/access/domains",
 	    autoDestory: true,
 	    root: 'data',
 	    restful: true, // use GET, not POST
@@ -85,7 +85,7 @@
 	    items: [{
 		xtype: 'form',
 		frame: true,
-		url: '/api2/extjs/ticket',
+		url: '/api2/extjs/access/ticket',
 
 		labelWidth: 70,
 		labelAlign  : 'right',




More information about the pve-devel mailing list