allow user to see his own entry
[pve-access-control.git] / PVE / API2 / User.pm
1 package PVE::API2::User;
2
3 use strict;
4 use warnings;
5 use PVE::Cluster qw (cfs_read_file cfs_write_file);
6 use PVE::Tools qw(split_list);
7 use PVE::AccessControl;
8 use PVE::JSONSchema qw(get_standard_option);
9
10 use PVE::SafeSyslog;
11
12 use Data::Dumper; # fixme: remove
13
14 use PVE::RESTHandler;
15
16 use base qw(PVE::RESTHandler);
17
18 my $extract_user_data = sub {
19     my ($data, $full) = @_;
20
21     my $res = {};
22
23     foreach my $prop (qw(enable expire firstname lastname email comment)) {
24         $res->{$prop} = $data->{$prop} if defined($data->{$prop});
25     }
26
27     return $res if !$full;
28
29     $res->{groups} = $data->{groups} ? [ keys %{$data->{groups}} ] : [];
30
31     return $res;
32 };
33
34 __PACKAGE__->register_method ({
35     name => 'index', 
36     path => '', 
37     method => 'GET',
38     description => "User index.",
39     permissions => { user => 'all' },
40     parameters => {
41         additionalProperties => 0,
42         properties => {
43             enabled => {
44                 type => 'boolean',
45                 description => "Optional filter for enable property.",
46                 optional => 1,
47             }
48         },
49     },
50     returns => {
51         type => 'array',
52         items => {
53             type => "object",
54             properties => {
55                 userid => { type => 'string' },
56             },
57         },
58         links => [ { rel => 'child', href => "{userid}" } ],
59     },
60     code => sub {
61         my ($param) = @_;
62     
63         my $rpcenv = PVE::RPCEnvironment::get();
64         my $authuser = $rpcenv->get_user();
65
66         my $res = [];
67
68         my $usercfg = cfs_read_file("user.cfg");
69  
70         foreach my $user (keys %{$usercfg->{users}}) {
71             # root sees all entries, a user only sees its own entry
72             next if $authuser ne 'root@pam' && $user ne $authuser;
73
74             my $entry = &$extract_user_data($usercfg->{users}->{$user});
75
76             if (defined($param->{enabled})) {
77                 next if $entry->{enable} && !$param->{enabled};
78                 next if !$entry->{enable} && $param->{enabled};
79             }
80
81             $entry->{userid} = $user;
82             push @$res, $entry;
83         }
84
85         return $res;
86     }});
87
88 __PACKAGE__->register_method ({
89     name => 'create_user', 
90     protected => 1,
91     path => '', 
92     method => 'POST',
93     description => "Create new user.",
94     parameters => {
95         additionalProperties => 0,
96         properties => {
97             userid => get_standard_option('userid'),
98             password => { type => 'string', optional => 1, minLength => 5, maxLength => 64 },
99             groups => { type => 'string', optional => 1, format => 'pve-groupid-list'},
100             firstname => { type => 'string', optional => 1 },
101             lastname => { type => 'string', optional => 1 },
102             email => { type => 'string', optional => 1, format => 'email-opt' },
103             comment => { type => 'string', optional => 1 },
104             expire => { 
105                 description => "Account expiration date (seconds since epoch). '0' means no expiration date.",
106                 type => 'integer', 
107                 minimum => 0,
108                 optional => 1,
109             },
110             enable => {
111                 description => "Enable the account (default). You can set this to '0' to disable the accout",
112                 type => 'boolean',
113                 optional => 1,
114                 default => 1,
115             },
116         },
117     },
118     returns => { type => 'null' },
119     code => sub {
120         my ($param) = @_;
121
122         PVE::AccessControl::lock_user_config(
123             sub {
124                         
125                 my ($username, $ruid, $realm) = PVE::AccessControl::verify_username($param->{userid});
126         
127                 my $usercfg = cfs_read_file("user.cfg");
128
129                 die "user '$username' already exists\n" 
130                     if $usercfg->{users}->{$username};
131                          
132                 PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password})
133                     if defined($param->{password});
134
135                 my $enable = defined($param->{enable}) ? $param->{enable} : 1;
136                 $usercfg->{users}->{$username} = { enable => $enable };
137                 $usercfg->{users}->{$username}->{expire} = $param->{expire} if $param->{expire};
138
139                 if ($param->{groups}) {
140                     foreach my $group (split_list($param->{groups})) {
141                         if ($usercfg->{groups}->{$group}) {
142                             PVE::AccessControl::add_user_group($username, $usercfg, $group);
143                         } else {
144                             die "no such group '$group'\n";
145                         }
146                     }
147                 }
148
149                 $usercfg->{users}->{$username}->{firstname} = $param->{firstname} if $param->{firstname};
150                 $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if $param->{lastname};
151                 $usercfg->{users}->{$username}->{email} = $param->{email} if $param->{email};
152                 $usercfg->{users}->{$username}->{comment} = $param->{comment} if $param->{comment};
153
154                 cfs_write_file("user.cfg", $usercfg);
155             }, "create user failed");
156
157         return undef;
158     }});
159
160 __PACKAGE__->register_method ({
161     name => 'read_user', 
162     path => '{userid}', 
163     method => 'GET',
164     description => "Get user configuration.",
165     parameters => {
166         additionalProperties => 0,
167         properties => {
168             userid => get_standard_option('userid'),
169         },
170     },
171     returns => {
172         additionalProperties => 0,
173         properties => {
174             enable => { type => 'boolean' },
175             expire => { type => 'integer', optional => 1 },
176             firstname => { type => 'string', optional => 1 },
177             lastname => { type => 'string', optional => 1 },
178             email => { type => 'string', optional => 1 },
179             comment => { type => 'string', optional => 1 },    
180             groups => { type => 'array' },
181         }
182     },
183     code => sub {
184         my ($param) = @_;
185
186         my ($username, undef, $domain) = 
187             PVE::AccessControl::verify_username($param->{userid});
188
189         my $usercfg = cfs_read_file("user.cfg");
190  
191         my $data = $usercfg->{users}->{$username};
192
193         die "user '$username' does not exist\n" if !$data;
194
195         return &$extract_user_data($data, 1);
196     }});
197
198 __PACKAGE__->register_method ({
199     name => 'update_user', 
200     protected => 1,
201     path => '{userid}', 
202     method => 'PUT',
203     description => "Update user configuration.",
204     parameters => {
205         additionalProperties => 0,
206         properties => {
207             userid => get_standard_option('userid'),
208             password => { type => 'string', optional => 1, minLength => 5, maxLength => 64 },
209             groups => { type => 'string', optional => 1,  format => 'pve-groupid-list'  },
210             append => { 
211                 type => 'boolean', 
212                 optional => 1,
213                 requires => 'groups',
214             },
215             enable => {
216                 description => "Enable/disable the account.",
217                 type => 'boolean',
218                 optional => 1,
219             },
220             firstname => { type => 'string', optional => 1 },
221             lastname => { type => 'string', optional => 1 },
222             email => { type => 'string', optional => 1, format => 'email-opt' },
223             comment => { type => 'string', optional => 1 },
224             expire => { 
225                 description => "Account expiration date (seconds since epoch). '0' means no expiration date.",
226                 type => 'integer', 
227                 minimum => 0,
228                 optional => 1 
229             },
230         },
231     },
232     returns => { type => 'null' },
233     code => sub {
234         my ($param) = @_;
235         
236         PVE::AccessControl::lock_user_config(
237             sub {
238
239                 my ($username, $ruid, $realm) = 
240                     PVE::AccessControl::verify_username($param->{userid});
241         
242                 my $usercfg = cfs_read_file("user.cfg");
243
244                 die "user '$username' does not exist\n" 
245                     if !$usercfg->{users}->{$username};
246
247                 PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password})
248                     if defined($param->{password});
249
250                 $usercfg->{users}->{$username}->{enable} = $param->{enable} if defined($param->{enable});
251
252                 $usercfg->{users}->{$username}->{expire} = $param->{expire} if defined($param->{expire});
253
254                 PVE::AccessControl::delete_user_group($username, $usercfg) 
255                     if (!$param->{append} && defined($param->{groups}));
256
257                 if ($param->{groups}) {
258                     foreach my $group (split_list($param->{groups})) {
259                         if ($usercfg->{groups}->{$group}) {
260                             PVE::AccessControl::add_user_group($username, $usercfg, $group);
261                         } else {
262                             die "no such group '$group'\n";
263                         }
264                     }
265                 }
266
267                 $usercfg->{users}->{$username}->{firstname} = $param->{firstname} if defined($param->{firstname});
268                 $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if defined($param->{lastname});
269                 $usercfg->{users}->{$username}->{email} = $param->{email} if defined($param->{email});
270                 $usercfg->{users}->{$username}->{comment} = $param->{comment} if defined($param->{comment});
271
272                 cfs_write_file("user.cfg", $usercfg);
273             }, "update user failed");
274         
275         return undef;
276     }});
277
278 __PACKAGE__->register_method ({
279     name => 'delete_user', 
280     protected => 1,
281     path => '{userid}', 
282     method => 'DELETE',
283     description => "Delete user.",
284     parameters => {
285         additionalProperties => 0,
286         properties => {
287             userid => get_standard_option('userid'),
288         }
289     },
290     returns => { type => 'null' },
291     code => sub {
292         my ($param) = @_;
293
294         PVE::AccessControl::lock_user_config(
295             sub {
296
297                 my ($username, $ruid, $realm) = 
298                     PVE::AccessControl::verify_username($param->{userid});
299
300                 my $usercfg = cfs_read_file("user.cfg");
301
302                 die "user '$username' does not exist\n" 
303                     if !$usercfg->{users}->{$username};
304
305                 delete ($usercfg->{users}->{$username});
306
307                 PVE::AccessControl::delete_shadow_password($ruid) if $realm eq 'pve';
308                 PVE::AccessControl::delete_user_group($username, $usercfg);
309                 PVE::AccessControl::delete_user_acl($username, $usercfg);
310
311                 cfs_write_file("user.cfg", $usercfg);
312             }, "delete user failed");
313         
314         return undef;
315     }});
316
317 1;