]> git.proxmox.com Git - pve-access-control.git/blobdiff - PVE/API2/User.pm
Remove unused Dumper uses
[pve-access-control.git] / PVE / API2 / User.pm
index 0637f765fda580392562bdfd35a175aa098e2a1e..602e3f030ba4bc990adf7717e659f1007cf1b7f5 100644 (file)
@@ -2,6 +2,7 @@ package PVE::API2::User;
 
 use strict;
 use warnings;
+use PVE::Exception qw(raise raise_perm_exc);
 use PVE::Cluster qw (cfs_read_file cfs_write_file);
 use PVE::Tools qw(split_list);
 use PVE::AccessControl;
@@ -9,8 +10,6 @@ use PVE::JSONSchema qw(get_standard_option);
 
 use PVE::SafeSyslog;
 
-use Data::Dumper; # fixme: remove
-
 use PVE::RESTHandler;
 
 use base qw(PVE::RESTHandler);
@@ -20,7 +19,7 @@ my $extract_user_data = sub {
 
     my $res = {};
 
-    foreach my $prop (qw(enable expire firstname lastname email comment)) {
+    foreach my $prop (qw(enable expire firstname lastname email comment keys)) {
        $res->{$prop} = $data->{$prop} if defined($data->{$prop});
     }
 
@@ -36,9 +35,19 @@ __PACKAGE__->register_method ({
     path => '', 
     method => 'GET',
     description => "User index.",
+    permissions => { 
+       description => "The returned list is restricted to users where you have 'User.Modify' or 'Sys.Audit' permissions on '/access/groups' or on a group the user belongs too. But it always includes the current (authenticated) user.",
+       user => 'all',
+    },
     parameters => {
        additionalProperties => 0,
-       properties => {},
+       properties => {
+           enabled => {
+               type => 'boolean',
+               description => "Optional filter for enable property.",
+               optional => 1,
+           }
+       },
     },
     returns => {
        type => 'array',
@@ -53,14 +62,30 @@ __PACKAGE__->register_method ({
     code => sub {
        my ($param) = @_;
     
+       my $rpcenv = PVE::RPCEnvironment::get();
+       my $usercfg = $rpcenv->{user_cfg};
+       my $authuser = $rpcenv->get_user();
+
        my $res = [];
 
-       my $usercfg = cfs_read_file("user.cfg");
+       my $privs = [ 'User.Modify', 'Sys.Audit' ];
+       my $canUserMod = $rpcenv->check_any($authuser, "/access/groups", $privs, 1);
+       my $groups = $rpcenv->filter_groups($authuser, $privs, 1);
+       my $allowed_users = $rpcenv->group_member_join([keys %$groups]);      
+
        foreach my $user (keys %{$usercfg->{users}}) {
-           next if $user eq 'root';
+
+           if (!($canUserMod || $user eq $authuser)) {
+               next if !$allowed_users->{$user};
+           }
 
            my $entry = &$extract_user_data($usercfg->{users}->{$user});
+
+           if (defined($param->{enabled})) {
+               next if $entry->{enable} && !$param->{enabled};
+               next if !$entry->{enable} && $param->{enabled};
+           }
+
            $entry->{userid} = $user;
            push @$res, $entry;
        }
@@ -73,17 +98,39 @@ __PACKAGE__->register_method ({
     protected => 1,
     path => '', 
     method => 'POST',
+    permissions => { 
+       description => "You need 'Realm.AllocateUser' on '/access/realm/<realm>' on the realm of user <userid>, and 'User.Modify' permissions to '/access/groups/<group>' for any group specified (or 'User.Modify' on '/access/groups' if you pass no groups.",
+       check => [ 'and',
+                  [ 'userid-param', 'Realm.AllocateUser'],
+                  [ 'userid-group', ['User.Modify'], groups_param => 1],
+           ],
+    },
     description => "Create new user.",
     parameters => {
        additionalProperties => 0,
        properties => {
            userid => get_standard_option('userid'),
-           password => { type => 'string', optional => 1 },
-           groups => { type => 'string', optional => 1, format => 'pve-groupid-list'},
+           password => {
+               description => "Initial password.",
+               type => 'string', 
+               optional => 1, 
+               minLength => 5, 
+               maxLength => 64 
+           },
+           groups => {
+               type => 'string', format => 'pve-groupid-list',
+               optional => 1,
+               completion => \&PVE::AccessControl::complete_group,
+           },
            firstname => { type => 'string', optional => 1 },
            lastname => { type => 'string', optional => 1 },
            email => { type => 'string', optional => 1, format => 'email-opt' },
            comment => { type => 'string', optional => 1 },
+           keys => {
+               description => "Keys for two factor auth (yubico).",
+               type => 'string', 
+               optional => 1,
+           },
            expire => { 
                description => "Account expiration date (seconds since epoch). '0' means no expiration date.",
                type => 'integer', 
@@ -113,7 +160,7 @@ __PACKAGE__->register_method ({
                    if $usercfg->{users}->{$username};
                         
                PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password})
-                   if $param->{password};
+                   if defined($param->{password});
 
                my $enable = defined($param->{enable}) ? $param->{enable} : 1;
                $usercfg->{users}->{$username} = { enable => $enable };
@@ -133,6 +180,7 @@ __PACKAGE__->register_method ({
                $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if $param->{lastname};
                $usercfg->{users}->{$username}->{email} = $param->{email} if $param->{email};
                $usercfg->{users}->{$username}->{comment} = $param->{comment} if $param->{comment};
+               $usercfg->{users}->{$username}->{keys} = $param->{keys} if $param->{keys};
 
                cfs_write_file("user.cfg", $usercfg);
            }, "create user failed");
@@ -145,6 +193,9 @@ __PACKAGE__->register_method ({
     path => '{userid}', 
     method => 'GET',
     description => "Get user configuration.",
+    permissions => { 
+       check => ['userid-group', ['User.Modify', 'Sys.Audit']],
+    },
     parameters => {
        additionalProperties => 0,
        properties => {
@@ -160,6 +211,7 @@ __PACKAGE__->register_method ({
            lastname => { type => 'string', optional => 1 },
            email => { type => 'string', optional => 1 },
            comment => { type => 'string', optional => 1 },    
+           keys => { type => 'string', optional => 1 },    
            groups => { type => 'array' },
        }
     },
@@ -170,11 +222,9 @@ __PACKAGE__->register_method ({
            PVE::AccessControl::verify_username($param->{userid});
 
        my $usercfg = cfs_read_file("user.cfg");
-       my $data = $usercfg->{users}->{$username};
-
-       die "user '$username' does not exist\n" if !$data;
 
+       my $data = PVE::AccessControl::check_user_exist($usercfg, $username);
        return &$extract_user_data($data, 1);
     }});
 
@@ -183,13 +233,21 @@ __PACKAGE__->register_method ({
     protected => 1,
     path => '{userid}', 
     method => 'PUT',
+    permissions => { 
+       check => ['userid-group', ['User.Modify'], groups_param => 1 ],
+    },
     description => "Update user configuration.",
     parameters => {
        additionalProperties => 0,
        properties => {
-           userid => get_standard_option('userid'),
-           password => { type => 'string', optional => 1 },
-           groups => { type => 'string', optional => 1,  format => 'pve-groupid-list'  },
+           userid => get_standard_option('userid', {
+               completion => \&PVE::AccessControl::complete_username,
+           }),
+           groups => {
+               type => 'string', format => 'pve-groupid-list',
+               optional => 1,
+               completion => \&PVE::AccessControl::complete_group,
+           },
            append => { 
                type => 'boolean', 
                optional => 1,
@@ -204,6 +262,11 @@ __PACKAGE__->register_method ({
            lastname => { type => 'string', optional => 1 },
            email => { type => 'string', optional => 1, format => 'email-opt' },
            comment => { type => 'string', optional => 1 },
+           keys => {
+               description => "Keys for two factor auth (yubico).",
+               type => 'string', 
+               optional => 1,
+           },
            expire => { 
                description => "Account expiration date (seconds since epoch). '0' means no expiration date.",
                type => 'integer', 
@@ -215,27 +278,23 @@ __PACKAGE__->register_method ({
     returns => { type => 'null' },
     code => sub {
        my ($param) = @_;
+
+       my ($username, $ruid, $realm) = 
+           PVE::AccessControl::verify_username($param->{userid});
        
        PVE::AccessControl::lock_user_config(
            sub {
-
-               my ($username, $ruid, $realm) = 
-                   PVE::AccessControl::verify_username($param->{userid});
        
                my $usercfg = cfs_read_file("user.cfg");
 
-               die "user '$username' does not exist\n" 
-                   if !$usercfg->{users}->{$username};
-
-               PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password})
-                   if $param->{password};
+               PVE::AccessControl::check_user_exist($usercfg, $username);
 
                $usercfg->{users}->{$username}->{enable} = $param->{enable} if defined($param->{enable});
 
                $usercfg->{users}->{$username}->{expire} = $param->{expire} if defined($param->{expire});
 
                PVE::AccessControl::delete_user_group($username, $usercfg) 
-                   if (!$param->{append} && $param->{groups});
+                   if (!$param->{append} && defined($param->{groups}));
 
                if ($param->{groups}) {
                    foreach my $group (split_list($param->{groups})) {
@@ -251,6 +310,7 @@ __PACKAGE__->register_method ({
                $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if defined($param->{lastname});
                $usercfg->{users}->{$username}->{email} = $param->{email} if defined($param->{email});
                $usercfg->{users}->{$username}->{comment} = $param->{comment} if defined($param->{comment});
+               $usercfg->{users}->{$username}->{keys} = $param->{keys} if defined($param->{keys});
 
                cfs_write_file("user.cfg", $usercfg);
            }, "update user failed");
@@ -264,32 +324,45 @@ __PACKAGE__->register_method ({
     path => '{userid}', 
     method => 'DELETE',
     description => "Delete user.",
+    permissions => { 
+       check => [ 'and',
+                  [ 'userid-param', 'Realm.AllocateUser'],
+                  [ 'userid-group', ['User.Modify']],
+           ],
+    },
     parameters => {
        additionalProperties => 0,
        properties => {
-           userid => get_standard_option('userid'),
+           userid => get_standard_option('userid', {
+               completion => \&PVE::AccessControl::complete_username,
+           }),
        }
     },
     returns => { type => 'null' },
     code => sub {
        my ($param) = @_;
+       
+       my $rpcenv = PVE::RPCEnvironment::get();
+       my $authuser = $rpcenv->get_user();
+
+       my ($userid, $ruid, $realm) = 
+           PVE::AccessControl::verify_username($param->{userid});
 
        PVE::AccessControl::lock_user_config(
            sub {
 
-               my ($username, $ruid, $realm) = 
-                   PVE::AccessControl::verify_username($param->{userid});
-
                my $usercfg = cfs_read_file("user.cfg");
 
-               die "user '$username' does not exist\n" 
-                   if !$usercfg->{users}->{$username};
+               my $domain_cfg = cfs_read_file('domains.cfg');
+               if (my $cfg = $domain_cfg->{ids}->{$realm}) {
+                   my $plugin = PVE::Auth::Plugin->lookup($cfg->{type});
+                   $plugin->delete_user($cfg, $realm, $ruid);
+               }
 
-               delete ($usercfg->{users}->{$username});
+               delete $usercfg->{users}->{$userid};
 
-               PVE::AccessControl::delete_shadow_password($ruid) if $realm eq 'pve';
-               PVE::AccessControl::delete_user_group($username, $usercfg);
-               PVE::AccessControl::delete_user_acl($username, $usercfg);
+               PVE::AccessControl::delete_user_group($userid, $usercfg);
+               PVE::AccessControl::delete_user_acl($userid, $usercfg);
 
                cfs_write_file("user.cfg", $usercfg);
            }, "delete user failed");