]> git.proxmox.com Git - pmg-api.git/blame - PMG/API2/LDAP.pm
fix bux #1776: set http_proxy for sa-update
[pmg-api.git] / PMG / API2 / LDAP.pm
CommitLineData
be6d6ffc
DM
1package PMG::API2::LDAP;
2
3use strict;
4use warnings;
5use Data::Dumper;
6
7use PVE::SafeSyslog;
8use PVE::Tools qw(extract_param);
9use HTTP::Status qw(:constants);
10use Storable qw(dclone);
11use PVE::JSONSchema qw(get_standard_option);
12use PVE::RESTHandler;
2fdba966 13use PVE::INotify;
be6d6ffc
DM
14
15use PMG::LDAPConfig;
b183e761 16use PMG::LDAPCache;
21fb7eb2 17use PMG::LDAPSet;
be6d6ffc
DM
18
19use base qw(PVE::RESTHandler);
20
21__PACKAGE__->register_method ({
22 name => 'index',
23 path => '',
24 method => 'GET',
c2ef4490 25 description => "List configured LDAP profiles.",
be6d6ffc 26 proxyto => 'master',
6aa82c72 27 permissions => { check => [ 'admin', 'audit' ] },
be6d6ffc
DM
28 parameters => {
29 additionalProperties => 0,
30 properties => {},
31 },
32 returns => {
33 type => 'array',
34 items => {
35 type => "object",
36 properties => {
c2ef4490 37 profile => { type => 'string'},
9722e9bf 38 disable => { type => 'boolean' },
be6d6ffc 39 server1 => { type => 'string'},
bfed5777
DM
40 server2 => { type => 'string', optional => 1},
41 comment => { type => 'string', optional => 1},
dc7a750c
DM
42 gcount => { type => 'integer', optional => 1},
43 mcount => { type => 'integer', optional => 1},
44 ucount => { type => 'integer', optional => 1},
be6d6ffc
DM
45 mode => { type => 'string'},
46 },
47 },
c2ef4490 48 links => [ { rel => 'child', href => "{profile}" } ],
be6d6ffc
DM
49 },
50 code => sub {
51 my ($param) = @_;
52
d8fff1a9 53 my $ldap_cfg = PMG::LDAPConfig->new();
2fdba966 54
21fb7eb2
DM
55 my $ldap_set = PMG::LDAPSet->new_from_ldap_cfg($ldap_cfg, 1);
56
be6d6ffc
DM
57 my $res = [];
58
59 if (defined($ldap_cfg)) {
c2ef4490
DM
60 foreach my $profile (keys %{$ldap_cfg->{ids}}) {
61 my $d = $ldap_cfg->{ids}->{$profile};
bfed5777 62 my $entry = {
c2ef4490 63 profile => $profile,
9722e9bf 64 disable => $d->{disable} ? 1 : 0,
be6d6ffc
DM
65 server1 => $d->{server1},
66 mode => $d->{mode} // 'ldap',
67 };
bfed5777
DM
68 $entry->{server2} = $d->{server2} if defined($d->{server2});
69 $entry->{comment} = $d->{comment} if defined($d->{comment});
21fb7eb2 70
c2ef4490 71 if (my $d = $ldap_set->{$profile}) {
94a59215 72 foreach my $k (qw(gcount mcount ucount)) {
21fb7eb2 73 my $v = $d->{$k};
94a59215 74 $entry->{$k} = $v if defined($v);
21fb7eb2
DM
75 }
76 }
77
bfed5777 78 push @$res, $entry;
be6d6ffc
DM
79 }
80 }
2fdba966 81
be6d6ffc
DM
82 return $res;
83 }});
84
c88aa2fe 85my $forced_ldap_sync = sub {
c2ef4490 86 my ($profile, $config) = @_;
c88aa2fe
DM
87
88 my $ldapcache = PMG::LDAPCache->new(
c2ef4490 89 id => $profile, syncmode => 2, %$config);
c88aa2fe
DM
90
91 die $ldapcache->{errors} if $ldapcache->{errors};
92
93 die "unable to find valid email addresses\n"
94 if !$ldapcache->{mcount};
95};
2fdba966
DM
96
97__PACKAGE__->register_method ({
98 name => 'create',
99 path => '',
100 method => 'POST',
101 proxyto => 'master',
bdbc2bc5 102 permissions => { check => [ 'admin' ] },
2fdba966 103 protected => 1,
c2ef4490 104 description => "Add LDAP profile.",
2fdba966
DM
105 parameters => PMG::LDAPConfig->createSchema(1),
106 returns => { type => 'null' },
107 code => sub {
108 my ($param) = @_;
109
110 my $code = sub {
111
d8fff1a9 112 my $cfg = PMG::LDAPConfig->new();
98afc5ae
DM
113
114 $cfg->{ids} //= {};
115
2fdba966
DM
116 my $ids = $cfg->{ids};
117
c2ef4490 118 my $profile = extract_param($param, 'profile');
2fdba966
DM
119 my $type = $param->{type};
120
c2ef4490
DM
121 die "LDAP profile '$profile' already exists\n"
122 if $ids->{$profile};
2fdba966 123
c2ef4490 124 my $config = PMG::LDAPConfig->check_config($profile, $param, 1, 1);
2fdba966 125
c2ef4490 126 $ids->{$profile} = $config;
2fdba966 127
c2ef4490 128 $forced_ldap_sync->($profile, $config)
c88aa2fe 129 if !$config->{disable};
b183e761 130
d8fff1a9 131 $cfg->write();
2fdba966
DM
132 };
133
c2ef4490 134 PMG::LDAPConfig::lock_config($code, "add LDAP profile failed");
2fdba966
DM
135
136 return undef;
137 }});
138
139__PACKAGE__->register_method ({
03f6ea0e 140 name => 'profile_index',
c2ef4490 141 path => '{profile}',
2fdba966 142 method => 'GET',
03f6ea0e 143 description => "Directory index",
bdbc2bc5
DM
144 permissions => {
145 user => 'all',
146 },
03f6ea0e
DM
147 parameters => {
148 additionalProperties => 0,
149 properties => {
150 profile => {
151 description => "Profile ID.",
152 type => 'string', format => 'pve-configid',
153 },
154 },
155 },
156 returns => {
157 type => 'array',
158 items => {
159 type => "object",
160 properties => {
161 subdir => { type => 'string'},
162 },
163 },
164 links => [ { rel => 'child', href => "{subdir}" } ],
165 },
166 code => sub {
167 my ($param) = @_;
168
169 return [
170 { subdir => 'config' },
171 { subdir => 'sync' },
c2670481
DM
172 { subdir => 'users' },
173 { subdir => 'groups' },
03f6ea0e
DM
174 ];
175 }});
176
177__PACKAGE__->register_method ({
178 name => 'read_config',
179 path => '{profile}/config',
180 method => 'GET',
c2ef4490 181 description => "Get LDAP profile configuration.",
2fdba966 182 proxyto => 'master',
6aa82c72 183 permissions => { check => [ 'admin', 'audit' ] },
2fdba966
DM
184 parameters => {
185 additionalProperties => 0,
186 properties => {
c2ef4490 187 profile => {
03f6ea0e 188 description => "Profile ID.",
2fdba966
DM
189 type => 'string', format => 'pve-configid',
190 },
191 },
192 },
193 returns => {},
194 code => sub {
195 my ($param) = @_;
196
d8fff1a9 197 my $cfg = PMG::LDAPConfig->new();
2fdba966 198
c2ef4490 199 my $profile = $param->{profile};
2fdba966 200
c2ef4490
DM
201 my $data = $cfg->{ids}->{$profile};
202 die "LDAP profile '$profile' does not exist\n" if !$data;
2fdba966 203
10861aa8
DC
204 # we do not want to get the password over the api
205 delete $data->{bindpw};
206
2fdba966
DM
207 $data->{digest} = $cfg->{digest};
208
209 return $data;
210 }});
211
212__PACKAGE__->register_method ({
03f6ea0e
DM
213 name => 'update_config',
214 path => '{profile}/config',
2fdba966 215 method => 'PUT',
c2ef4490 216 description => "Update LDAP profile settings.",
bdbc2bc5 217 permissions => { check => [ 'admin' ] },
2fdba966
DM
218 protected => 1,
219 proxyto => 'master',
220 parameters => PMG::LDAPConfig->updateSchema(),
221 returns => { type => 'null' },
222 code => sub {
223 my ($param) = @_;
224
225 my $code = sub {
226
d8fff1a9 227 my $cfg = PMG::LDAPConfig->new();
2fdba966
DM
228 my $ids = $cfg->{ids};
229
230 my $digest = extract_param($param, 'digest');
231 PVE::SectionConfig::assert_if_modified($cfg, $digest);
232
c2ef4490 233 my $profile = extract_param($param, 'profile');
2fdba966 234
c2ef4490
DM
235 die "LDAP profile '$profile' does not exist\n"
236 if !$ids->{$profile};
2fdba966
DM
237
238 my $delete_str = extract_param($param, 'delete');
239 die "no options specified\n"
240 if !$delete_str && !scalar(keys %$param);
241
242 foreach my $opt (PVE::Tools::split_list($delete_str)) {
c2ef4490 243 delete $ids->{$profile}->{$opt};
2fdba966
DM
244 }
245
c2ef4490 246 my $config = PMG::LDAPConfig->check_config($profile, $param, 0, 1);
2fdba966
DM
247
248 foreach my $p (keys %$config) {
c2ef4490 249 $ids->{$profile}->{$p} = $config->{$p};
2fdba966
DM
250 }
251
c2ef4490 252 $forced_ldap_sync->($profile, $config)
c88aa2fe 253 if !$config->{disable};
b183e761 254
d8fff1a9 255 $cfg->write();
2fdba966
DM
256 };
257
c2ef4490 258 PMG::LDAPConfig::lock_config($code, "update LDAP profile failed");
2fdba966
DM
259
260 return undef;
261 }});
262
5a76fa30 263__PACKAGE__->register_method ({
03f6ea0e
DM
264 name => 'sync_profile',
265 path => '{profile}/sync',
5a76fa30
DM
266 method => 'POST',
267 description => "Synchronice LDAP users to local database.",
bdbc2bc5 268 permissions => { check => [ 'admin' ] },
5a76fa30
DM
269 protected => 1,
270 proxyto => 'master',
271 parameters => {
272 additionalProperties => 0,
273 properties => {
c2ef4490
DM
274 profile => {
275 description => "Profile ID.",
5a76fa30
DM
276 type => 'string', format => 'pve-configid',
277 },
278 },
279 },
280 returns => { type => 'null' },
281 code => sub {
282 my ($param) = @_;
283
d8fff1a9 284 my $cfg = PMG::LDAPConfig->new();
5a76fa30
DM
285 my $ids = $cfg->{ids};
286
c2ef4490 287 my $profile = extract_param($param, 'profile');
5a76fa30 288
c2ef4490
DM
289 die "LDAP profile '$profile' does not exist\n"
290 if !$ids->{$profile};
5a76fa30 291
c2ef4490 292 my $config = $ids->{$profile};
5a76fa30
DM
293
294 if ($config->{disable}) {
c2ef4490 295 die "LDAP profile '$profile' is disabled\n";
5a76fa30 296 } else {
c2ef4490 297 $forced_ldap_sync->($profile, $config)
5a76fa30
DM
298 }
299
300 return undef;
301 }});
302
2fdba966
DM
303__PACKAGE__->register_method ({
304 name => 'delete',
c2ef4490 305 path => '{profile}',
2fdba966 306 method => 'DELETE',
c2ef4490 307 description => "Delete an LDAP profile",
bdbc2bc5 308 permissions => { check => [ 'admin' ] },
2fdba966
DM
309 protected => 1,
310 proxyto => 'master',
311 parameters => {
312 additionalProperties => 0,
313 properties => {
c2ef4490
DM
314 profile => {
315 description => "Profile ID.",
2fdba966
DM
316 type => 'string', format => 'pve-configid',
317 },
318 }
319 },
320 returns => { type => 'null' },
321 code => sub {
322 my ($param) = @_;
323
324 my $code = sub {
325
d8fff1a9 326 my $cfg = PMG::LDAPConfig->new();
2fdba966
DM
327 my $ids = $cfg->{ids};
328
c2ef4490 329 my $profile = $param->{profile};
2fdba966 330
c2ef4490
DM
331 die "LDAP profile '$profile' does not exist\n"
332 if !$ids->{$profile};
2fdba966 333
c2ef4490 334 delete $ids->{$profile};
2fdba966 335
c2ef4490 336 PMG::LDAPCache->delete($profile);
200f41ef 337
d8fff1a9 338 $cfg->write();
2fdba966
DM
339 };
340
c2ef4490 341 PMG::LDAPConfig::lock_config($code, "delete LDAP profile failed");
2fdba966
DM
342
343 return undef;
344 }});
345
c2670481
DM
346__PACKAGE__->register_method ({
347 name => 'profile_list_users',
348 path => '{profile}/users',
349 method => 'GET',
350 description => "List LDAP users.",
6aa82c72 351 permissions => { check => [ 'admin', 'audit' ] },
c2670481
DM
352 protected => 1,
353 proxyto => 'master',
354 parameters => {
355 additionalProperties => 0,
356 properties => {
357 profile => {
358 description => "Profile ID.",
359 type => 'string', format => 'pve-configid',
360 },
361 },
362 },
363 returns => {
364 type => 'array',
365 items => {
366 type => "object",
367 properties => {
368 dn => { type => 'string'},
369 account => { type => 'string'},
370 pmail => { type => 'string'},
371 },
372 },
55e05031 373 links => [ { rel => 'child', href => "{pmail}" } ],
c2670481
DM
374 },
375 code => sub {
376 my ($param) = @_;
377
d8fff1a9 378 my $cfg = PMG::LDAPConfig->new();
c2670481
DM
379 my $ids = $cfg->{ids};
380
381 my $profile = $param->{profile};
382
383 die "LDAP profile '$profile' does not exist\n"
384 if !$ids->{$profile};
385
386 my $config = $ids->{$profile};
387
388 return [] if $config->{disable};
389
390 my $ldapcache = PMG::LDAPCache->new(
391 id => $profile, syncmode => 1, %$config);
392
393 return $ldapcache->list_users();
394 }});
395
396__PACKAGE__->register_method ({
397 name => 'address_list',
398 path => '{profile}/users/{email}',
399 method => 'GET',
400 description => "Get all email addresses for the specified user.",
6aa82c72 401 permissions => { check => [ 'admin', 'audit' ] },
c2670481
DM
402 protected => 1,
403 proxyto => 'master',
404 parameters => {
405 additionalProperties => 0,
406 properties => {
407 profile => {
408 description => "Profile ID.",
409 type => 'string', format => 'pve-configid',
410 },
411 email => {
412 description => "Email address.",
413 type => 'string', format => 'email',
414 },
415 },
416 },
417 returns => {
418 type => 'array',
419 items => {
420 type => "object",
421 properties => {
422 primary => { type => 'boolean'},
423 email => { type => 'string'},
424 },
425 },
426 },
427 code => sub {
428 my ($param) = @_;
429
d8fff1a9 430 my $cfg = PMG::LDAPConfig->new();
c2670481
DM
431 my $ids = $cfg->{ids};
432
433 my $profile = $param->{profile};
434
435 die "LDAP profile '$profile' does not exist\n"
436 if !$ids->{$profile};
437
438 my $config = $ids->{$profile};
439
440 die "profile '$profile' is disabled\n" if $config->{disable};
441
442 my $ldapcache = PMG::LDAPCache->new(
443 id => $profile, syncmode => 1, %$config);
444
445 my $res = $ldapcache->list_addresses($param->{email});
446
447 die "unable to find ldap user with email address '$param->{email}'\n"
448 if !$res;
449
450 return $res;
451
452 }});
453
454__PACKAGE__->register_method ({
455 name => 'profile_list_groups',
456 path => '{profile}/groups',
457 method => 'GET',
458 description => "List LDAP groups.",
6aa82c72 459 permissions => { check => [ 'admin', 'audit' ] },
c2670481
DM
460 protected => 1,
461 proxyto => 'master',
462 parameters => {
463 additionalProperties => 0,
464 properties => {
465 profile => {
466 description => "Profile ID.",
467 type => 'string', format => 'pve-configid',
468 },
469 },
470 },
471 returns => {
472 type => 'array',
473 items => {
474 type => "object",
475 properties => {
476 dn => { type => 'string'},
1d8a50bb 477 gid => { type => 'number' },
c2670481
DM
478 },
479 },
1d8a50bb 480 links => [ { rel => 'child', href => "{gid}" } ],
c2670481
DM
481 },
482 code => sub {
483 my ($param) = @_;
484
d8fff1a9 485 my $cfg = PMG::LDAPConfig->new();
c2670481
DM
486 my $ids = $cfg->{ids};
487
488 my $profile = $param->{profile};
489
490 die "LDAP profile '$profile' does not exist\n"
491 if !$ids->{$profile};
492
493 my $config = $ids->{$profile};
494
495 return [] if $config->{disable};
496
497 my $ldapcache = PMG::LDAPCache->new(
498 id => $profile, syncmode => 1, %$config);
499
500 return $ldapcache->list_groups();
501 }});
502
1d8a50bb
DC
503__PACKAGE__->register_method ({
504 name => 'profile_list_group_members',
505 path => '{profile}/groups/{gid}',
506 method => 'GET',
507 description => "List LDAP group members.",
6aa82c72 508 permissions => { check => [ 'admin', 'audit' ] },
1d8a50bb
DC
509 protected => 1,
510 proxyto => 'master',
511 parameters => {
512 additionalProperties => 0,
513 properties => {
514 profile => {
515 description => "Profile ID.",
516 type => 'string', format => 'pve-configid',
517 },
518 gid => {
519 description => "Group ID",
520 type => 'number',
521 },
522 },
523 },
524 returns => {
525 type => 'array',
526 items => {
527 type => "object",
528 properties => {
529 dn => { type => 'string'},
530 account => { type => 'string' },
531 pmail => { type => 'string' },
532 },
533 },
534 },
535 code => sub {
536 my ($param) = @_;
537
538 my $cfg = PMG::LDAPConfig->new();
539 my $ids = $cfg->{ids};
540
541 my $profile = $param->{profile};
542
543 die "LDAP profile '$profile' does not exist\n"
544 if !$ids->{$profile};
545
546 my $config = $ids->{$profile};
547
548 return [] if $config->{disable};
549
550 my $ldapcache = PMG::LDAPCache->new(
551 id => $profile, syncmode => 1, %$config);
552
553 return $ldapcache->list_users($param->{gid});
554 }});
555
be6d6ffc 5561;