]> git.proxmox.com Git - pve-access-control.git/blob - PVE/API2/User.pm
8b063641178197feecb376ecd42041e2675feca9
[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;