und die restlichen .pm Module.
[kivitendo-erp.git] / SL / Auth / LDAP.pm
1 package SL::Auth::LDAP;
2
3 use English '-no_match_vars';
4
5 #use SL::Auth;
6
7 use strict;
8
9 sub new {
10   $main::lxdebug->enter_sub();
11
12   if (!defined eval "require Net::LDAP;") {
13     die 'The module "Net::LDAP" is not installed.';
14   }
15
16   my $type = shift;
17   my $self = {};
18
19   $self->{auth} = shift;
20
21   bless $self, $type;
22
23   $main::lxdebug->leave_sub();
24
25   return $self;
26 }
27
28 sub _connect {
29   $main::lxdebug->enter_sub();
30
31   my $self = shift;
32   my $cfg  = $self->{auth}->{LDAP_config};
33
34   if ($self->{ldap}) {
35     $main::lxdebug->leave_sub();
36
37     return $self->{ldap};
38   }
39
40   my $port      = $cfg->{port} || 389;
41   $self->{ldap} = Net::LDAP->new($cfg->{host}, 'port' => $port);
42
43   if (!$self->{ldap}) {
44     $main::form->error($main::locale->text('The LDAP server "#1:#2" is unreachable. Please check config/authentication.pl.', $cfg->{host}, $port));
45   }
46
47   if ($cfg->{tls}) {
48     my $mesg = $self->{ldap}->start_tls('verify' => 'none');
49     if ($mesg->is_error()) {
50       $main::form->error($main::locale->text('The connection to the LDAP server cannot be encrypted (SSL/TLS startup failure). Please check config/authentication.pl.'));
51     }
52   }
53
54   if ($cfg->{bind_dn}) {
55     my $mesg = $self->{ldap}->bind($cfg->{bind_dn}, 'password' => $cfg->{bind_password});
56     if ($mesg->is_error()) {
57       $main::form->error($main::locale->text('Binding to the LDAP server as "#1" failed. Please check config/authentication.pl.', $cfg->{bind_dn}));
58     }
59   }
60
61   $main::lxdebug->leave_sub();
62
63   return $self->{ldap};
64 }
65
66 sub _get_filter {
67   $main::lxdebug->enter_sub();
68
69   my $self   = shift;
70   my $login  = shift;
71
72   my ($cfg, $filter);
73
74   $cfg    =  $self->{auth}->{LDAP_config};
75
76   $filter =  "$cfg->{filter}";
77   $filter =~ s|^\s+||;
78   $filter =~ s|\s+$||;
79
80   $login  =~ s|\\|\\\\|g;
81   $login  =~ s|\(|\\\(|g;
82   $login  =~ s|\)|\\\)|g;
83   $login  =~ s|\*|\\\*|g;
84   $login  =~ s|\x00|\\00|g;
85
86   if ($filter =~ m|<\%login\%>|) {
87     substr($filter, $LAST_MATCH_START[0], $LAST_MATCH_END[0] - $LAST_MATCH_START[0]) = $login;
88
89   } elsif ($filter) {
90     if ((substr($filter, 0, 1) ne '(') || (substr($filter, -1, 1) ne ')')) {
91       $filter = "($filter)";
92     }
93
94     $filter = "(&${filter}($cfg->{attribute}=${login}))";
95
96   } else {
97     $filter = "$cfg->{attribute}=${login}";
98
99   }
100
101   $main::lxdebug->leave_sub();
102
103   return $filter;
104 }
105
106 sub _get_user_dn {
107   $main::lxdebug->enter_sub();
108
109   my $self   = shift;
110   my $ldap   = shift;
111   my $login  = shift;
112
113   $self->{dn_cache} ||= { };
114
115   if ($self->{dn_cache}->{$login}) {
116     $main::lxdebug->leave_sub();
117     return $self->{dn_cache}->{$login};
118   }
119
120   my $cfg    = $self->{auth}->{LDAP_config};
121
122   my $filter = $self->_get_filter($login);
123
124   my $mesg   = $ldap->search('base' => $cfg->{base_dn}, 'scope' => 'sub', 'filter' => $filter);
125
126   if ($mesg->is_error() || (0 == $mesg->count())) {
127     $main::lxdebug->leave_sub();
128     return undef;
129   }
130
131   my $entry                   = $mesg->entry(0);
132   $self->{dn_cache}->{$login} = $entry->dn();
133
134   $main::lxdebug->leave_sub();
135
136   return $self->{dn_cache}->{$login};
137 }
138
139 sub authenticate {
140   $main::lxdebug->enter_sub();
141
142   my $self       = shift;
143   my $login      = shift;
144   my $password   = shift;
145   my $is_crypted = shift;
146
147   if ($is_crypted) {
148     $main::lxdebug->leave_sub();
149     return SL::Auth->ERR_BACKEND();
150   }
151
152   my $ldap = $self->_connect();
153
154   if (!$ldap) {
155     $main::lxdebug->leave_sub();
156     return SL::Auth->ERR_BACKEND();
157   }
158
159   my $dn = $self->_get_user_dn($ldap, $login);
160
161   $main::lxdebug->message(LXDebug->DEBUG2(), "LDAP authenticate: dn $dn");
162
163   if (!$dn) {
164     $main::lxdebug->leave_sub();
165     return SL::Auth->ERR_BACKEND();
166   }
167
168   my $mesg = $ldap->bind($dn, 'password' => $password);
169
170   $main::lxdebug->message(LXDebug->DEBUG2(), "LDAP authenticate: bind mesg " . $mesg->error());
171
172   $main::lxdebug->leave_sub();
173
174   return $mesg->is_error() ? SL::Auth->ERR_PASSWORD() : SL::Auth->OK();
175 }
176
177 sub can_change_password {
178   return 0;
179 }
180
181 sub change_password {
182   return SL::Auth->ERR_BACKEND();
183 }
184
185 sub verify_config {
186   $main::lxdebug->enter_sub();
187
188   my $form   = $main::form;
189   my $locale = $main::locale;
190
191   my $self = shift;
192   my $cfg  = $self->{auth}->{LDAP_config};
193
194   if (!$cfg) {
195     $form->error($locale->text('config/authentication.pl: Key "LDAP_config" is missing.'));
196   }
197
198   if (!$cfg->{host} || !$cfg->{attribute} || !$cfg->{base_dn}) {
199     $form->error($locale->text('config/authentication.pl: Missing parameters in "LDAP_config". Required parameters are "host", "attribute" and "base_dn".'));
200   }
201
202   $main::lxdebug->leave_sub();
203 }
204
205 1;