]> git.proxmox.com Git - pve-access-control.git/blob - PVE/API2/User.pm
set minimal and maximal password length
[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 enabled => {
43 type => 'boolean',
44 description => "Optional filter for enable property.",
45 optional => 1,
46 }
47 },
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';
68
69 my $entry = &$extract_user_data($usercfg->{users}->{$user});
70
71 if (defined($param->{enabled})) {
72 next if $entry->{enable} && !$param->{enabled};
73 next if !$entry->{enable} && $param->{enabled};
74 }
75
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, minLength => 5, maxLength => 64 },
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 defined($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, minLength => 5, maxLength => 64 },
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 defined($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)
250 if (!$param->{append} && defined($param->{groups}));
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;