1 package SL::Auth::LDAP;
3 use English '-no_match_vars';
5 use SL::Auth::Constants qw(:all);
10 if (!defined eval "require Net::LDAP;") {
11 die 'The module "Net::LDAP" is not installed.';
16 $self->{config} = shift;
25 $self->{ldap} = undef;
26 $self->{dn_cache} = { };
31 my $cfg = $self->{config};
33 return $self->{ldap} if $self->{ldap};
35 my $port = $cfg->{port} || 389;
36 my $ldap = Net::LDAP->new($cfg->{host}, port => $port, timeout => $cfg->{timeout} || 10);
39 $::lxdebug->warn($main::locale->text('The LDAP server "#1:#2" is unreachable. Please check config/kivitendo.conf.', $cfg->{host}, $port));
44 my $mesg = $ldap->start_tls(verify => $cfg->{verify} // 'require');
45 if ($mesg->is_error()) {
46 $::lxdebug->warn($main::locale->text('The connection to the LDAP server cannot be encrypted (SSL/TLS startup failure). Please check config/kivitendo.conf.'));
51 if ($cfg->{bind_dn}) {
52 my $mesg = $ldap->bind($cfg->{bind_dn}, 'password' => $cfg->{bind_password});
53 if ($mesg->is_error()) {
54 $::lxdebug->warn($main::locale->text('Binding to the LDAP server as "#1" failed. Please check config/kivitendo.conf.', $cfg->{bind_dn}));
59 $self->{ldap} = $ldap;
70 $cfg = $self->{config};
72 $filter = "$cfg->{filter}";
76 $login =~ s|\\|\\\\|g;
77 $login =~ s|\(|\\\(|g;
78 $login =~ s|\)|\\\)|g;
79 $login =~ s|\*|\\\*|g;
80 $login =~ s|\x00|\\00|g;
82 if ($filter =~ m|<\%login\%>|) {
83 substr($filter, $LAST_MATCH_START[0], $LAST_MATCH_END[0] - $LAST_MATCH_START[0]) = $login;
86 if ((substr($filter, 0, 1) ne '(') || (substr($filter, -1, 1) ne ')')) {
87 $filter = "($filter)";
90 $filter = "(&${filter}($cfg->{attribute}=${login}))";
93 $filter = "$cfg->{attribute}=${login}";
105 $self->{dn_cache} ||= { };
107 return $self->{dn_cache}->{$login} if $self->{dn_cache}->{$login};
109 my $cfg = $self->{config};
111 my $filter = $self->_get_filter($login);
113 my $mesg = $ldap->search('base' => $cfg->{base_dn}, 'scope' => 'sub', 'filter' => $filter);
115 return undef if $mesg->is_error || !$mesg->count();
117 my $entry = $mesg->entry(0);
118 $self->{dn_cache}->{$login} = $entry->dn();
120 return $self->{dn_cache}->{$login};
126 my $password = shift;
127 my $is_crypted = shift;
129 return ERR_BACKEND if $is_crypted;
131 my $ldap = $self->_connect();
133 return ERR_BACKEND if !$ldap;
135 my $dn = $self->_get_user_dn($ldap, $login);
137 $main::lxdebug->message(LXDebug->DEBUG2(), "LDAP authenticate: dn $dn");
139 return ERR_BACKEND if !$dn;
141 my $mesg = $ldap->bind($dn, 'password' => $password);
143 $main::lxdebug->message(LXDebug->DEBUG2(), "LDAP authenticate: bind mesg " . $mesg->error());
145 return $mesg->is_error() ? ERR_PASSWORD : OK;
148 sub can_change_password {
152 sub requires_cleartext_password {
156 sub change_password {
161 my $form = $main::form;
162 my $locale = $main::locale;
165 my $cfg = $self->{config};
168 $form->error($locale->text('config/kivitendo.conf: Key "authentication/ldap" is missing.'));
171 if (!$cfg->{host} || !$cfg->{attribute} || !$cfg->{base_dn}) {
172 $form->error($locale->text('config/kivitendo.conf: Missing parameters in "authentication/ldap". Required parameters are "host", "attribute" and "base_dn".'));