e03d04c8b367b83ad2cc33bbdcc7767675f53154
[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     };
76 }
77
78 my $authenticate_user_ad = sub {
79     my ($config, $server, $username, $password) = @_;
80
81     my $default_port = $config->{secure} ? 636: 389;
82     my $port = $config->{port} ? $config->{port} : $default_port;
83     my $scheme = $config->{secure} ? 'ldaps' : 'ldap';
84     $server = "[$server]" if Net::IP::ip_is_ipv6($server);
85     my $conn_string = "$scheme://${server}:$port";
86     
87     my $ldap = Net::LDAP->new($conn_string) || die "$@\n";
88
89     $username = "$username\@$config->{domain}" 
90         if $username !~ m/@/ && $config->{domain};
91
92     my $res = $ldap->bind($username, password => $password);
93
94     my $code = $res->code();
95     my $err = $res->error;
96
97     $ldap->unbind();
98
99     die "$err\n" if ($code);
100 };
101
102 sub authenticate_user {
103     my ($class, $config, $realm, $username, $password) = @_;
104
105     eval { &$authenticate_user_ad($config, $config->{server1}, $username, $password); };
106     my $err = $@;
107     return 1 if !$err;
108     die $err if !$config->{server2};
109     &$authenticate_user_ad($config, $config->{server2}, $username, $password);
110     return 1;
111 }
112
113 1;