]> git.proxmox.com Git - pve-access-control.git/blob - PVE/API2/User.pm
use 'mv' to make targets atomic
[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 parameters => {
40 additionalProperties => 0,
41 properties => {},
42 },
43 returns => {
44 type => 'array',
45 items => {
46 type => "object",
47 properties => {
48 userid => { type => 'string' },
49 },
50 },
51 links => [ { rel => 'child', href => "{userid}" } ],
52 },
53 code => sub {
54 my ($param) = @_;
55
56 my $res = [];
57
58 my $usercfg = cfs_read_file("user.cfg");
59
60 foreach my $user (keys %{$usercfg->{users}}) {
61 next if $user eq 'root';
62
63 my $entry = &$extract_user_data($usercfg->{users}->{$user});
64 $entry->{userid} = $user;
65 push @$res, $entry;
66 }
67
68 return $res;
69 }});
70
71 __PACKAGE__->register_method ({
72 name => 'create_user',
73 protected => 1,
74 path => '',
75 method => 'POST',
76 description => "Create new user.",
77 parameters => {
78 additionalProperties => 0,
79 properties => {
80 userid => get_standard_option('userid'),
81 password => { type => 'string', optional => 1 },
82 groups => { type => 'string', optional => 1, format => 'pve-groupid-list'},
83 firstname => { type => 'string', optional => 1 },
84 lastname => { type => 'string', optional => 1 },
85 email => { type => 'string', optional => 1, format => 'email-opt' },
86 comment => { type => 'string', optional => 1 },
87 expire => {
88 description => "Account expiration date (seconds since epoch). '0' means no expiration date.",
89 type => 'integer',
90 minimum => 0,
91 optional => 1,
92 },
93 enable => {
94 description => "Enable the account (default). You can set this to '0' to disable the accout",
95 type => 'boolean',
96 optional => 1,
97 default => 1,
98 },
99 },
100 },
101 returns => { type => 'null' },
102 code => sub {
103 my ($param) = @_;
104
105 PVE::AccessControl::lock_user_config(
106 sub {
107
108 my ($username, $ruid, $realm) = PVE::AccessControl::verify_username($param->{userid});
109
110 my $usercfg = cfs_read_file("user.cfg");
111
112 die "user '$username' already exists\n"
113 if $usercfg->{users}->{$username};
114
115 PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password})
116 if $param->{password};
117
118 my $enable = defined($param->{enable}) ? $param->{enable} : 1;
119 $usercfg->{users}->{$username} = { enable => $enable };
120 $usercfg->{users}->{$username}->{expire} = $param->{expire} if $param->{expire};
121
122 if ($param->{groups}) {
123 foreach my $group (split_list($param->{groups})) {
124 if ($usercfg->{groups}->{$group}) {
125 PVE::AccessControl::add_user_group($username, $usercfg, $group);
126 } else {
127 die "no such group '$group'\n";
128 }
129 }
130 }
131
132 $usercfg->{users}->{$username}->{firstname} = $param->{firstname} if $param->{firstname};
133 $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if $param->{lastname};
134 $usercfg->{users}->{$username}->{email} = $param->{email} if $param->{email};
135 $usercfg->{users}->{$username}->{comment} = $param->{comment} if $param->{comment};
136
137 cfs_write_file("user.cfg", $usercfg);
138 }, "create user failed");
139
140 return undef;
141 }});
142
143 __PACKAGE__->register_method ({
144 name => 'read_user',
145 path => '{userid}',
146 method => 'GET',
147 description => "Get user configuration.",
148 parameters => {
149 additionalProperties => 0,
150 properties => {
151 userid => get_standard_option('userid'),
152 },
153 },
154 returns => {
155 additionalProperties => 0,
156 properties => {
157 enable => { type => 'boolean' },
158 expire => { type => 'integer', optional => 1 },
159 firstname => { type => 'string', optional => 1 },
160 lastname => { type => 'string', optional => 1 },
161 email => { type => 'string', optional => 1 },
162 comment => { type => 'string', optional => 1 },
163 groups => { type => 'array' },
164 }
165 },
166 code => sub {
167 my ($param) = @_;
168
169 my ($username, undef, $domain) =
170 PVE::AccessControl::verify_username($param->{userid});
171
172 my $usercfg = cfs_read_file("user.cfg");
173
174 my $data = $usercfg->{users}->{$username};
175
176 die "user '$username' does not exist\n" if !$data;
177
178 return &$extract_user_data($data, 1);
179 }});
180
181 __PACKAGE__->register_method ({
182 name => 'update_user',
183 protected => 1,
184 path => '{userid}',
185 method => 'PUT',
186 description => "Update user configuration.",
187 parameters => {
188 additionalProperties => 0,
189 properties => {
190 userid => get_standard_option('userid'),
191 password => { type => 'string', optional => 1 },
192 groups => { type => 'string', optional => 1, format => 'pve-groupid-list' },
193 append => {
194 type => 'boolean',
195 optional => 1,
196 requires => 'groups',
197 },
198 enable => {
199 description => "Enable/disable the account.",
200 type => 'boolean',
201 optional => 1,
202 },
203 firstname => { type => 'string', optional => 1 },
204 lastname => { type => 'string', optional => 1 },
205 email => { type => 'string', optional => 1, format => 'email-opt' },
206 comment => { type => 'string', optional => 1 },
207 expire => {
208 description => "Account expiration date (seconds since epoch). '0' means no expiration date.",
209 type => 'integer',
210 minimum => 0,
211 optional => 1
212 },
213 },
214 },
215 returns => { type => 'null' },
216 code => sub {
217 my ($param) = @_;
218
219 PVE::AccessControl::lock_user_config(
220 sub {
221
222 my ($username, $ruid, $realm) =
223 PVE::AccessControl::verify_username($param->{userid});
224
225 my $usercfg = cfs_read_file("user.cfg");
226
227 die "user '$username' does not exist\n"
228 if !$usercfg->{users}->{$username};
229
230 PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password})
231 if $param->{password};
232
233 $usercfg->{users}->{$username}->{enable} = $param->{enable} if defined($param->{enable});
234
235 $usercfg->{users}->{$username}->{expire} = $param->{expire} if defined($param->{expire});
236
237 PVE::AccessControl::delete_user_group($username, $usercfg)
238 if (!$param->{append} && $param->{groups});
239
240 if ($param->{groups}) {
241 foreach my $group (split_list($param->{groups})) {
242 if ($usercfg->{groups}->{$group}) {
243 PVE::AccessControl::add_user_group($username, $usercfg, $group);
244 } else {
245 die "no such group '$group'\n";
246 }
247 }
248 }
249
250 $usercfg->{users}->{$username}->{firstname} = $param->{firstname} if defined($param->{firstname});
251 $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if defined($param->{lastname});
252 $usercfg->{users}->{$username}->{email} = $param->{email} if defined($param->{email});
253 $usercfg->{users}->{$username}->{comment} = $param->{comment} if defined($param->{comment});
254
255 cfs_write_file("user.cfg", $usercfg);
256 }, "update user failed");
257
258 return undef;
259 }});
260
261 __PACKAGE__->register_method ({
262 name => 'delete_user',
263 protected => 1,
264 path => '{userid}',
265 method => 'DELETE',
266 description => "Delete user.",
267 parameters => {
268 additionalProperties => 0,
269 properties => {
270 userid => get_standard_option('userid'),
271 }
272 },
273 returns => { type => 'null' },
274 code => sub {
275 my ($param) = @_;
276
277 PVE::AccessControl::lock_user_config(
278 sub {
279
280 my ($username, $ruid, $realm) =
281 PVE::AccessControl::verify_username($param->{userid});
282
283 my $usercfg = cfs_read_file("user.cfg");
284
285 die "user '$username' does not exist\n"
286 if !$usercfg->{users}->{$username};
287
288 delete ($usercfg->{users}->{$username});
289
290 PVE::AccessControl::delete_shadow_password($ruid) if $realm eq 'pve';
291 PVE::AccessControl::delete_user_group($username, $usercfg);
292 PVE::AccessControl::delete_user_acl($username, $usercfg);
293
294 cfs_write_file("user.cfg", $usercfg);
295 }, "delete user failed");
296
297 return undef;
298 }});
299
300 1;