]> git.proxmox.com Git - pve-access-control.git/blob - PVE/Auth/AD.pm
b9db568c912f6a9b683bb11fdebb5d18dfc0b9e6
[pve-access-control.git] / PVE / Auth / AD.pm
1 package PVE::Auth::AD;
2
3 use strict;
4 use warnings;
5 use PVE::Auth::Plugin;
6 use Net::LDAP;
7 use Net::IP;
8
9 use base qw(PVE::Auth::Plugin);
10
11 sub type {
12 return 'ad';
13 }
14
15 sub properties {
16 return {
17 server1 => {
18 description => "Server IP address (or DNS name)",
19 type => 'string',
20 format => 'address',
21 maxLength => 256,
22 },
23 server2 => {
24 description => "Fallback Server IP address (or DNS name)",
25 type => 'string',
26 optional => 1,
27 format => 'address',
28 maxLength => 256,
29 },
30 secure => {
31 description => "Use secure LDAPS protocol.",
32 type => 'boolean',
33 optional => 1,
34
35 },
36 default => {
37 description => "Use this as default realm",
38 type => 'boolean',
39 optional => 1,
40 },
41 comment => {
42 description => "Description.",
43 type => 'string',
44 optional => 1,
45 maxLength => 4096,
46 },
47 port => {
48 description => "Server port.",
49 type => 'integer',
50 minimum => 1,
51 maximum => 65535,
52 optional => 1,
53 },
54 domain => {
55 description => "AD domain name",
56 type => 'string',
57 pattern => '\S+',
58 optional => 1,
59 maxLength => 256,
60 },
61 tfa => PVE::JSONSchema::get_standard_option('tfa'),
62 };
63 }
64
65 sub options {
66 return {
67 server1 => {},
68 server2 => { optional => 1 },
69 domain => {},
70 port => { optional => 1 },
71 secure => { optional => 1 },
72 default => { optional => 1 },,
73 comment => { optional => 1 },
74 tfa => { optional => 1 },
75 verify => { optional => 1 },
76 capath => { optional => 1 },
77 cert => { optional => 1 },
78 certkey => { optional => 1 },
79 };
80 }
81
82 my $authenticate_user_ad = sub {
83 my ($config, $server, $username, $password) = @_;
84
85 my $default_port = $config->{secure} ? 636: 389;
86 my $port = $config->{port} ? $config->{port} : $default_port;
87 my $scheme = $config->{secure} ? 'ldaps' : 'ldap';
88 $server = "[$server]" if Net::IP::ip_is_ipv6($server);
89 my $conn_string = "$scheme://${server}:$port";
90
91 my %ad_args;
92 if ($config->{verify}) {
93 $ad_args{verify} = 'require';
94 if (defined(my $cert = $config->{cert})) {
95 $ad_args{clientcert} = $cert;
96 }
97 if (defined(my $key = $config->{certkey})) {
98 $ad_args{clientkey} = $key;
99 }
100 if (defined(my $capath = $config->{capath})) {
101 if (-d $capath) {
102 $ad_args{capath} = $capath;
103 } else {
104 $ad_args{cafile} = $capath;
105 }
106 }
107 } elsif (defined($config->{verify})) {
108 $ad_args{verify} = 'none';
109 }
110
111 my $ldap = Net::LDAP->new($conn_string, %ad_args) || die "$@\n";
112
113 $username = "$username\@$config->{domain}"
114 if $username !~ m/@/ && $config->{domain};
115
116 my $res = $ldap->bind($username, password => $password);
117
118 my $code = $res->code();
119 my $err = $res->error;
120
121 $ldap->unbind();
122
123 die "$err\n" if ($code);
124 };
125
126 sub authenticate_user {
127 my ($class, $config, $realm, $username, $password) = @_;
128
129 eval { &$authenticate_user_ad($config, $config->{server1}, $username, $password); };
130 my $err = $@;
131 return 1 if !$err;
132 die $err if !$config->{server2};
133 &$authenticate_user_ad($config, $config->{server2}, $username, $password);
134 return 1;
135 }
136
137 1;