[pve-devel] [PATCH RFC 18/21] add helpers to access the API via https - needs libwww-perl
Dietmar Maurer
dietmar at proxmox.com
Mon Nov 28 08:09:10 CET 2016
Signed-off-by: Dietmar Maurer <dietmar at proxmox.com>
---
data/PVE/CLI/pvecm.pm | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++
debian/control | 2 +-
2 files changed, 144 insertions(+), 1 deletion(-)
diff --git a/data/PVE/CLI/pvecm.pm b/data/PVE/CLI/pvecm.pm
index 3a44673..5063b4e 100755
--- a/data/PVE/CLI/pvecm.pm
+++ b/data/PVE/CLI/pvecm.pm
@@ -3,6 +3,12 @@ package PVE::CLI::pvecm;
use strict;
use warnings;
use Getopt::Long;
+use Term::ReadLine;
+use IO::Socket::SSL; # important for SSL_verify_callback
+use LWP::UserAgent;
+use URI::Escape;
+use Net::SSLeay;
+use JSON;
use Socket;
use IO::File;
use Net::IP;
@@ -28,6 +34,143 @@ my $backupdir = "/var/lib/pve-cluster/backup";
my $dbfile = "$libdir/config.db";
my $authfile = "/etc/corosync/authkey";
+sub read_password {
+ my $term = new Term::ReadLine ('pvecm');
+ my $attribs = $term->Attribs;
+ $attribs->{redisplay_function} = $attribs->{shadow_redisplay};
+ my $input = $term->readline('Enter password: ');
+ return $input;
+}
+
+sub api2_post {
+ my ($agent, $host, $path, $param) = @_;
+
+ my $uri = URI->new();
+ $uri->scheme('https');
+ $uri->host($host);
+ $uri->port(8006);
+ $uri->path("/api2/json/$path");
+
+ my $response = $agent->post($uri, $param);
+
+ my $ct = $response->header('Content-Type') || '';
+
+ if ($response->is_success) {
+ die "got unexpected content type" if $ct !~ m|application/json|;
+ my $res = from_json($response->decoded_content, {utf8 => 1});
+ my $data = $res->{data};
+
+ if ($path eq "access/ticket") {
+ my $csrf = $data->{CSRFPreventionToken};
+ my $ticket = $data->{ticket};
+ my $encticket = uri_escape($ticket);
+ my $cookie = "PVEAuthCookie=$encticket; path=/; secure;";
+ $agent->default_header('CSRFPreventionToken' => $csrf);
+ $agent->default_header('Cookie', $cookie);
+ }
+
+ return $data;
+ }
+
+ my $msg = $response->status_line . "\n";
+ eval {
+ return if $ct !~ m|application/json|;
+ my $res = from_json($response->decoded_content, {utf8 => 1});
+ if (my $errors = $res->{errors}) {
+ foreach my $key (keys %$errors) {
+ my $m = $errors->{$key};
+ chomp($m);
+ $m =~s/\n/ -- /g;
+ $msg .= " $key: $m\n";
+ }
+ }
+ };
+ die $msg;
+}
+
+sub manual_verify_fingerprint {
+ my ($host, $fingerprint) = @_;
+
+ print "The authenticity of host '$host' can't be established.\n" .
+ "X509 SHA256 key fingerprint is $fingerprint.\n" .
+ "Are you sure you want to continue connecting (yes/no)? ";
+
+ my $answer = <>;
+
+ return 1 if $answer =~m/^\s*yes\s*$/i;
+
+ return 0;
+}
+
+my $fingerprint;
+my $fingerprint_verified;
+
+sub api2_connect {
+ my ($host, $password) = @_;
+
+ my $ssl_verify_callback = sub {
+ my (undef, undef, undef, undef, $cert, $depth) = @_;
+
+ # we don't care about intermediate or root certificates
+ return 1 if $depth != 0;
+
+ # check server certificate against cache of pinned FPs
+ # get fingerprint of server certificate
+ my $fp;
+ eval {
+ $fp = Net::SSLeay::X509_get_fingerprint($cert, 'sha256');
+ };
+ return 0 if $@ || !defined($fp) || $fp eq ''; # error
+
+ if ($fingerprint_verified && $fingerprint && ($fp eq $fingerprint)) {
+ return 1;
+ }
+
+ if (PVE::Cluster::check_cert_fingerprint($cert)) {
+ $fingerprint = $fp;
+ $fingerprint_verified = 1;
+ return 1;
+ }
+
+ if (!$fingerprint) {
+ $fingerprint = $fp;
+ return 0;
+ }
+ $fingerprint = $fp;
+
+ return 0;
+ };
+
+ my $agent = LWP::UserAgent->new(
+ keep_alive => 10,
+ protocols_allowed => [ 'https'],
+ ssl_opts => {
+ verify_hostname => 0,
+ SSL_verify_mode => SSL_VERIFY_PEER,
+ SSL_verify_callback => $ssl_verify_callback,
+ },
+ timeout => 60);
+
+ $agent->default_header('Accept-Encoding' => 'gzip'); # allow gzip
+
+ eval {
+ api2_post($agent, $host, "access/ticket", {
+ username => 'root at pam', password => $password });
+ };
+ if (my $err = $@) {
+ die $err if !$fingerprint || $fingerprint_verified;
+ if (manual_verify_fingerprint($host, $fingerprint)) {
+ $fingerprint_verified = 1;
+ api2_post($agent, $host, "access/ticket", {
+ username => 'root at pam', password => $password });
+ } else {
+ die $err;
+ }
+ }
+
+ return $agent;
+}
+
sub backup_database {
print "backup old database\n";
diff --git a/debian/control b/debian/control
index 73a6146..7339664 100644
--- a/debian/control
+++ b/debian/control
@@ -8,7 +8,7 @@ Standards-Version: 3.7.3
Package: pve-cluster
Architecture: any
Pre-Depends: ${misc:Pre-Depends}
-Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, perlapi-5.20.0, rsync, libsqlite3-0, sqlite3, libfuse2 (>= 2.9.2-4), fuse, corosync-pve (>= 2.3.4-1), libqb0 (>= 0.17.1-1), libpve-common-perl, libglib2.0-0 (>= 2.42.1-1), rsyslog, openssl, librrd4, librrds-perl, rrdcached, libdigest-hmac-perl, libxml-parser-perl, systemd, faketime, libcrypt-ssleay-perl
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, perlapi-5.20.0, rsync, libsqlite3-0, sqlite3, libfuse2 (>= 2.9.2-4), fuse, corosync-pve (>= 2.3.4-1), libqb0 (>= 0.17.1-1), libpve-common-perl, libglib2.0-0 (>= 2.42.1-1), rsyslog, openssl, librrd4, librrds-perl, rrdcached, libdigest-hmac-perl, libxml-parser-perl, systemd, faketime, libcrypt-ssleay-perl, libio-socket-ssl-perl, liblwp-protocol-https-perl
Description: Cluster Infrastructure for Proxmox Virtual Environment
This package contains the Cluster Infrastructure for the Proxmox
Virtual Environment, namely a distributed filesystem to store
--
2.1.4
More information about the pve-devel
mailing list