]> git.proxmox.com Git - pmg-api.git/blame - src/PMG/RuleDB/LDAP.pm
fix #2071: RuleDB: ignore duplicate entries for Who objects
[pmg-api.git] / src / PMG / RuleDB / LDAP.pm
CommitLineData
10621236
DM
1package PMG::RuleDB::LDAP;
2
3use strict;
4use warnings;
5use DBI;
6
2aeda4ac
DM
7use PVE::Exception qw(raise_param_exc);
8
10621236
DM
9use PMG::Utils;
10use PMG::RuleDB::Object;
11use PMG::LDAPCache;
12use PMG::LDAPSet;
13
14use base qw(PMG::RuleDB::Object);
15
16sub otype {
17 return 1005;
18}
19
20sub oclass {
21 return 'who';
22}
23
24sub otype_text {
25 return 'LDAP Group';
26}
27
10621236
DM
28sub new {
29 my ($type, $ldapgroup, $profile, $ogroup) = @_;
30
31 my $class = ref($type) || $type;
32
33 my $self = $class->SUPER::new($class->otype(), $ogroup);
34
35 $self->{ldapgroup} = $ldapgroup // '';
36 $self->{profile} = $profile // '';
37
38 return $self;
39}
40
41sub load_attr {
42 my ($type, $ruledb, $id, $ogroup, $value) = @_;
43
44 my $class = ref($type) || $type;
45
46 defined($value) || die "undefined value: ERROR";
47
48 my $obj;
49 if ($value =~ m/^([^:]*):(.*)$/) {
50 $obj = $class->new($2, $1, $ogroup);
2aeda4ac 51 $obj->{digest} = Digest::SHA::sha1_hex($id, $2, $1, $ogroup);
10621236 52 } else {
2aeda4ac
DM
53 $obj = $class->new($value, '', $ogroup);
54 $obj->{digest} = Digest::SHA::sha1_hex($id, $value, '#', $ogroup);
10621236
DM
55 }
56
57 $obj->{id} = $id;
58
59 return $obj;
60}
61
62sub save {
63 my ($self, $ruledb) = @_;
64
65 defined($self->{ogroup}) || die "undefined ogroup: ERROR";
66 defined($self->{ldapgroup}) || die "undefined ldap group: ERROR";
67 defined($self->{profile}) || die "undefined ldap profile: ERROR";
68
69 my $grp = $self->{ldapgroup};
70 my $profile = $self->{profile};
71
72 my $confdata = "$profile:$grp";
73
74 if (defined ($self->{id})) {
75 # update
76
77 $ruledb->{dbh}->do(
78 "UPDATE Object SET Value = ? WHERE ID = ?",
79 undef, $confdata, $self->{id});
80
81 } else {
82 # insert
83
736b986f
DC
84 # check if it exists first
85 if (my $id = PMG::Utils::get_existing_object_id(
86 $ruledb->{dbh},
87 $self->{ogroup},
88 $self->otype(),
89 $confdata
90 )) {
91 return $id;
92 }
93
10621236
DM
94 my $sth = $ruledb->{dbh}->prepare(
95 "INSERT INTO Object (Objectgroup_ID, ObjectType, Value) " .
96 "VALUES (?, ?, ?);");
97
98 $sth->execute($self->{ogroup}, $self->otype, $confdata);
99
100 $self->{id} = PMG::Utils::lastid($ruledb->{dbh}, 'object_id_seq');
101 }
102
103 return $self->{id};
104}
105
106sub test_ldap {
107 my ($ldap, $addr, $group, $profile) = @_;
108
109 if ($group eq '') {
110 return $ldap->mail_exists($addr, $profile);
111 } elsif ($group eq '-') {
112 return !$ldap->mail_exists($addr, $profile);
2aeda4ac 113 } elsif ($profile) {
10621236 114 return $ldap->user_in_group ($addr, $group, $profile);
2aeda4ac
DM
115 } else {
116 # fail if we have a real $group without $profile
117 return 0;
10621236
DM
118 }
119}
120
121sub who_match {
122 my ($self, $addr, $ip, $ldap) = @_;
123
124 return 0 if !$ldap;
125
126 return test_ldap($ldap, $addr, $self->{ldapgroup}, $self->{profile});
127}
128
2aeda4ac
DM
129sub short_desc {
130 my ($self) = @_;
131
132 my $desc;
133
134 my $profile = $self->{profile};
135 my $group = $self->{ldapgroup};
136
137 if ($group eq '') {
138 $desc = "Existing LDAP address";
687306ad
DM
139 if ($profile) {
140 $desc .= ", profile '$profile'";
141 } else {
142 $desc .= ", any profile";
143 }
2aeda4ac
DM
144 } elsif ($group eq '-') {
145 $desc = "Unknown LDAP address";
687306ad
DM
146 if ($profile) {
147 $desc .= ", profile '$profile'";
148 } else {
149 $desc .= ", any profile";
150 }
2aeda4ac 151 } elsif ($profile) {
f76f331a 152 $desc = "LDAP group '$group', profile '$profile'";
2aeda4ac
DM
153 } else {
154 $desc = "LDAP group without profile - fail always";
155 }
156
157 return $desc;
158}
159
160sub properties {
161 my ($class) = @_;
162
163 return {
164 mode => {
165 description => "Operational mode. You can either match 'any' user, match when no such user exists with 'none', or match when the user is member of a specific group.",
166 type => 'string',
167 enum => ['any', 'none', 'group'],
168 },
169 profile => {
170 description => "Profile ID.",
171 type => 'string', format => 'pve-configid',
172 optional => 1,
173 },
174 group => {
175 description => "LDAP Group DN",
176 type => 'string',
177 maxLength => 1024,
178 minLength => 1,
179 optional => 1,
180 },
181 };
182}
183
184sub get {
185 my ($self) = @_;
186
187 my $group = $self->{ldapgroup};
188 my $profile = $self->{profile},
189
190 my $data = {};
191
192 if ($group eq '') {
193 $data->{mode} = 'any';
194 } elsif ($group eq '-') {
195 $data->{mode} = 'none';
196 } else {
197 $data->{mode} = 'group';
198 $data->{group} = $group;
199 }
200
201 $data->{profile} = $profile if $profile ne '';
202
203 return $data;
204 }
205
206sub update {
207 my ($self, $param) = @_;
208
209 my $mode = $param->{mode};
210
d974ca19
DM
211 if (defined(my $profile = $param->{profile})) {
212 my $cfg = PVE::INotify::read_file("pmg-ldap.conf");
213 my $config = $cfg->{ids}->{$profile};
214 die "LDAP profile '$profile' does not exist\n" if !$config;
215
216 if (defined(my $group = $param->{group})) {
217 my $ldapcache = PMG::LDAPCache->new(
218 id => $profile, syncmode => 1, %$config);
219
220 die "LDAP group '$group' does not exist\n"
221 if !$ldapcache->group_exists($group);
222 }
223 }
224
2aeda4ac 225 if ($mode eq 'any') {
5182cea0 226 raise_param_exc({ group => "parameter not allwed with mode '$mode'"})
2aeda4ac
DM
227 if defined($param->{group});
228 $self->{ldapgroup} = '';
229 $self->{profile} = $param->{profile} // '';
230 } elsif ($mode eq 'none') {
5182cea0 231 raise_param_exc({ group => "parameter not allwed with mode '$mode'"})
2aeda4ac
DM
232 if defined($param->{group});
233 $self->{ldapgroup} = '-';
234 $self->{profile} = $param->{profile} // '';
235 } elsif ($mode eq 'group') {
5182cea0 236 raise_param_exc({ group => "parameter is required with mode '$mode'"})
2aeda4ac
DM
237 if !defined($param->{group});
238 $self->{ldapgroup} = $param->{group};
5182cea0 239 raise_param_exc({ profile => "parameter is required with mode '$mode'"})
2aeda4ac
DM
240 if !defined($param->{profile});
241 $self->{profile} = $param->{profile};
242 } else {
243 die "internal error"; # just to me sure
244 }
245}
246
10621236
DM
2471;
248
249__END__
250
251=head1 PMG::RuleDB::LDAP
252
253A WHO object to check LDAP groups
254
1359baef 255=head2 Attributes
10621236
DM
256
257=head3 ldapgroup
258
259An LDAP group (ignore case).
260
261=head3 profile
262
263The LDAP profile name
264
265=head2 Examples
266
267 $obj = PMG::RuleDB::LDAP>new ('groupname', 'profile_name');