]> git.proxmox.com Git - pmg-api.git/blob - PMG/API2/LDAP.pm
PMG/API2/LDAP.pm: sync whole database after updates
[pmg-api.git] / PMG / API2 / LDAP.pm
1 package PMG::API2::LDAP;
2
3 use strict;
4 use warnings;
5 use Data::Dumper;
6
7 use PVE::SafeSyslog;
8 use PVE::Tools qw(extract_param);
9 use HTTP::Status qw(:constants);
10 use Storable qw(dclone);
11 use PVE::JSONSchema qw(get_standard_option);
12 use PVE::RESTHandler;
13 use PVE::INotify;
14
15 use PMG::LDAPConfig;
16 use PMG::LDAPCache;
17
18 use base qw(PVE::RESTHandler);
19
20 my $ldapconfigfile = "pmg-ldap.conf";
21
22 __PACKAGE__->register_method ({
23 name => 'index',
24 path => '',
25 method => 'GET',
26 description => "LDAP server list.",
27 proxyto => 'master',
28 protected => 1,
29 parameters => {
30 additionalProperties => 0,
31 properties => {},
32 },
33 returns => {
34 type => 'array',
35 items => {
36 type => "object",
37 properties => {
38 section => { type => 'string'},
39 disable => { type => 'boolean' },
40 server1 => { type => 'string'},
41 server2 => { type => 'string', optional => 1},
42 comment => { type => 'string', optional => 1},
43 mode => { type => 'string'},
44 },
45 },
46 links => [ { rel => 'child', href => "{section}" } ],
47 },
48 code => sub {
49 my ($param) = @_;
50
51 my $ldap_cfg = PVE::INotify::read_file($ldapconfigfile);
52
53 my $res = [];
54
55 if (defined($ldap_cfg)) {
56 foreach my $section (keys %{$ldap_cfg->{ids}}) {
57 my $d = $ldap_cfg->{ids}->{$section};
58 my $entry = {
59 section => $section,
60 disable => $d->{disable} ? 1 : 0,
61 server1 => $d->{server1},
62 mode => $d->{mode} // 'ldap',
63 };
64 $entry->{server2} = $d->{server2} if defined($d->{server2});
65 $entry->{comment} = $d->{comment} if defined($d->{comment});
66 push @$res, $entry;
67 }
68 }
69
70 return $res;
71 }});
72
73 my $forced_ldap_sync = sub {
74 my ($section, $config) = @_;
75
76 my $ldapcache = PMG::LDAPCache->new(
77 id => $section, syncmode => 2, %$config);
78
79 die $ldapcache->{errors} if $ldapcache->{errors};
80
81 die "unable to find valid email addresses\n"
82 if !$ldapcache->{mcount};
83 };
84
85 __PACKAGE__->register_method ({
86 name => 'create',
87 path => '',
88 method => 'POST',
89 proxyto => 'master',
90 protected => 1,
91 description => "Add LDAP server.",
92 parameters => PMG::LDAPConfig->createSchema(1),
93 returns => { type => 'null' },
94 code => sub {
95 my ($param) = @_;
96
97 my $code = sub {
98
99 my $cfg = PVE::INotify::read_file($ldapconfigfile);
100
101 $cfg->{ids} //= {};
102
103 my $ids = $cfg->{ids};
104
105 my $section = extract_param($param, 'section');
106 my $type = $param->{type};
107
108 die "LDAP entry '$section' already exists\n"
109 if $ids->{$section};
110
111 my $config = PMG::LDAPConfig->check_config($section, $param, 1, 1);
112
113 $ids->{$section} = $config;
114
115 $forced_ldap_sync->($section, $config)
116 if !$config->{disable};
117
118 PVE::INotify::write_file($ldapconfigfile, $cfg);
119 };
120
121 PMG::LDAPConfig::lock_config($code, "add LDAP entry failed");
122
123 return undef;
124 }});
125
126 __PACKAGE__->register_method ({
127 name => 'read',
128 path => '{section}',
129 method => 'GET',
130 description => "Get LDAP server configuration.",
131 proxyto => 'master',
132 protected => 1,
133 parameters => {
134 additionalProperties => 0,
135 properties => {
136 section => {
137 description => "Secion ID.",
138 type => 'string', format => 'pve-configid',
139 },
140 },
141 },
142 returns => {},
143 code => sub {
144 my ($param) = @_;
145
146 my $cfg = PVE::INotify::read_file($ldapconfigfile);
147
148 my $section = $param->{section};
149
150 my $data = $cfg->{ids}->{$section};
151 die "LDAP entry '$section' does not exist\n" if !$data;
152
153 $data->{digest} = $cfg->{digest};
154
155 return $data;
156 }});
157
158 __PACKAGE__->register_method ({
159 name => 'update',
160 path => '{section}',
161 method => 'PUT',
162 description => "Update LDAP server settings.",
163 protected => 1,
164 proxyto => 'master',
165 parameters => PMG::LDAPConfig->updateSchema(),
166 returns => { type => 'null' },
167 code => sub {
168 my ($param) = @_;
169
170 my $code = sub {
171
172 my $cfg = PVE::INotify::read_file($ldapconfigfile);
173 my $ids = $cfg->{ids};
174
175 my $digest = extract_param($param, 'digest');
176 PVE::SectionConfig::assert_if_modified($cfg, $digest);
177
178 my $section = extract_param($param, 'section');
179
180 die "LDAP entry '$section' does not exist\n"
181 if !$ids->{$section};
182
183 my $delete_str = extract_param($param, 'delete');
184 die "no options specified\n"
185 if !$delete_str && !scalar(keys %$param);
186
187 foreach my $opt (PVE::Tools::split_list($delete_str)) {
188 delete $ids->{$section}->{$opt};
189 }
190
191 my $config = PMG::LDAPConfig->check_config($section, $param, 0, 1);
192
193 foreach my $p (keys %$config) {
194 $ids->{$section}->{$p} = $config->{$p};
195 }
196
197 $forced_ldap_sync->($section, $config)
198 if !$config->{disable};
199
200 PVE::INotify::write_file($ldapconfigfile, $cfg);
201 };
202
203 PMG::LDAPConfig::lock_config($code, "update LDAP entry failed");
204
205 return undef;
206 }});
207
208 __PACKAGE__->register_method ({
209 name => 'delete',
210 path => '{section}',
211 method => 'DELETE',
212 description => "Delete an LDAP server entry.",
213 protected => 1,
214 proxyto => 'master',
215 parameters => {
216 additionalProperties => 0,
217 properties => {
218 section => {
219 description => "Secion ID.",
220 type => 'string', format => 'pve-configid',
221 },
222 }
223 },
224 returns => { type => 'null' },
225 code => sub {
226 my ($param) = @_;
227
228 my $code = sub {
229
230 my $cfg = PVE::INotify::read_file($ldapconfigfile);
231 my $ids = $cfg->{ids};
232
233 my $section = $param->{section};
234
235 die "LDAP entry '$section' does not exist\n"
236 if !$ids->{$section};
237
238 delete $ids->{$section};
239
240 PMG::LDAPCache->delete($section);
241
242 PVE::INotify::write_file($ldapconfigfile, $cfg);
243 };
244
245 PMG::LDAPConfig::lock_config($code, "delete LDAP entry failed");
246
247 return undef;
248 }});
249
250 1;