]> git.proxmox.com Git - pve-access-control.git/blame - PVE/Auth/LDAP.pm
change from dpkg-deb to dpkg-buildpackage
[pve-access-control.git] / PVE / Auth / LDAP.pm
CommitLineData
5bb4e06a
DM
1package PVE::Auth::LDAP;
2
3use strict;
7c410d63
DM
4use warnings;
5
b5040b42 6use PVE::Tools;
5bb4e06a
DM
7use PVE::Auth::Plugin;
8use Net::LDAP;
8b600c4d 9use Net::IP;
5bb4e06a
DM
10use base qw(PVE::Auth::Plugin);
11
12sub type {
13 return 'ldap';
14}
15
16sub properties {
17 return {
18 base_dn => {
19 description => "LDAP base domain name",
20 type => 'string',
21 pattern => '\w+=[^,]+(,\s*\w+=[^,]+)*',
22 optional => 1,
23 maxLength => 256,
24 },
25 user_attr => {
26 description => "LDAP user attribute name",
27 type => 'string',
28 pattern => '\S{2,}',
29 optional => 1,
30 maxLength => 256,
31 },
b5040b42
WB
32 bind_dn => {
33 description => "LDAP bind domain name",
34 type => 'string',
35 pattern => '\w+=[^,]+(,\s*\w+=[^,]+)*',
36 optional => 1,
37 maxLength => 256,
38 },
5bb4e06a
DM
39 };
40}
41
42sub options {
43 return {
44 server1 => {},
45 server2 => { optional => 1 },
46 base_dn => {},
b5040b42 47 bind_dn => { optional => 1 },
5bb4e06a
DM
48 user_attr => {},
49 port => { optional => 1 },
50 secure => { optional => 1 },
51 default => { optional => 1 },
52 comment => { optional => 1 },
96f8ebd6 53 tfa => { optional => 1 },
5bb4e06a
DM
54 };
55}
56
57my $authenticate_user_ldap = sub {
b5040b42 58 my ($config, $server, $username, $password, $realm) = @_;
5bb4e06a
DM
59
60 my $default_port = $config->{secure} ? 636: 389;
61 my $port = $config->{port} ? $config->{port} : $default_port;
62 my $scheme = $config->{secure} ? 'ldaps' : 'ldap';
8b600c4d 63 $server = "[$server]" if Net::IP::ip_is_ipv6($server);
5bb4e06a
DM
64 my $conn_string = "$scheme://${server}:$port";
65
66 my $ldap = Net::LDAP->new($conn_string, verify => 'none') || die "$@\n";
b5040b42
WB
67
68 if (my $bind_dn = $config->{bind_dn}) {
69 my $bind_pass = PVE::Tools::file_read_firstline("/etc/pve/priv/ldap/${realm}.pw");
70 die "missing password for realm $realm\n" if !defined($bind_pass);
71 my $res = $ldap->bind($bind_dn, password => $bind_pass);
72 my $code = $res->code();
73 my $err = $res->error;
74 die "failed to authenticate to ldap service: $err\n" if ($code);
75 }
76
5bb4e06a
DM
77 my $search = $config->{user_attr} . "=" . $username;
78 my $result = $ldap->search( base => "$config->{base_dn}",
79 scope => "sub",
80 filter => "$search",
81 attrs => ['dn']
82 );
83 die "no entries returned\n" if !$result->entries;
84 my @entries = $result->entries;
85 my $res = $ldap->bind($entries[0]->dn, password => $password);
86
87 my $code = $res->code();
88 my $err = $res->error;
89
90 $ldap->unbind();
91
92 die "$err\n" if ($code);
93};
94
95sub authenticate_user {
96 my ($class, $config, $realm, $username, $password) = @_;
97
b5040b42 98 eval { &$authenticate_user_ldap($config, $config->{server1}, $username, $password, $realm); };
5bb4e06a
DM
99 my $err = $@;
100 return 1 if !$err;
101 die $err if !$config->{server2};
102 &$authenticate_user_ldap($config, $config->{server2}, $username, $password);
103}
104
1051;