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