1<?php
2
3namespace LibreNMS\Authentication;
4
5use LibreNMS\Config;
6use LibreNMS\Exceptions\AuthenticationException;
7use LibreNMS\Exceptions\LdapMissingException;
8
9class ADAuthorizationAuthorizer extends MysqlAuthorizer
10{
11    use LdapSessionCache;
12    use ActiveDirectoryCommon;
13
14    protected static $AUTH_IS_EXTERNAL = true;
15    protected static $CAN_UPDATE_PASSWORDS = false;
16
17    protected $ldap_connection;
18
19    public function __construct()
20    {
21        if (! function_exists('ldap_connect')) {
22            throw new LdapMissingException();
23        }
24
25        // Disable certificate checking before connect if required
26        if (Config::has('auth_ad_check_certificates') &&
27            Config::get('auth_ad_check_certificates') == 0) {
28            putenv('LDAPTLS_REQCERT=never');
29        }
30
31        // Set up connection to LDAP server
32        $this->ldap_connection = @ldap_connect(Config::get('auth_ad_url'));
33        if (! $this->ldap_connection) {
34            throw new AuthenticationException('Fatal error while connecting to AD url ' . Config::get('auth_ad_url') . ': ' . ldap_error($this->ldap_connection));
35        }
36
37        // disable referrals and force ldap version to 3
38        ldap_set_option($this->ldap_connection, LDAP_OPT_REFERRALS, 0);
39        ldap_set_option($this->ldap_connection, LDAP_OPT_PROTOCOL_VERSION, 3);
40
41        // Bind to AD
42        if (Config::has('auth_ad_binduser') && Config::has('auth_ad_bindpassword')) {
43            // With specified bind user
44            if (! ldap_bind($this->ldap_connection, Config::get('auth_ad_binduser') . '@' . Config::get('auth_ad_domain'), Config::get('auth_ad_bindpassword'))) {
45                echo ldap_error($this->ldap_connection);
46            }
47        } else {
48            // Anonymous
49            if (! ldap_bind($this->ldap_connection)) {
50                echo ldap_error($this->ldap_connection);
51            }
52        }
53    }
54
55    public function authenticate($credentials)
56    {
57        if (isset($credentials['username']) && $this->userExists($credentials['username'])) {
58            return true;
59        }
60
61        if (Config::get('http_auth_guest')) {
62            return true;
63        }
64
65        throw new AuthenticationException();
66    }
67
68    public function userExists($username, $throw_exception = false)
69    {
70        if ($this->authLdapSessionCacheGet('user_exists')) {
71            return true;
72        }
73
74        $search = ldap_search(
75            $this->ldap_connection,
76            Config::get('auth_ad_base_dn'),
77            $this->userFilter($username),
78            ['samaccountname']
79        );
80        $entries = ldap_get_entries($this->ldap_connection, $search);
81
82        if ($entries['count']) {
83            /*
84             * Cache positiv result as this will result in more queries which we
85             * want to speed up.
86             */
87            $this->authLdapSessionCacheSet('user_exists', 1);
88
89            return true;
90        }
91
92        return false;
93    }
94
95    public function getUserlevel($username)
96    {
97        $userlevel = $this->authLdapSessionCacheGet('userlevel');
98        if ($userlevel) {
99            return $userlevel;
100        } else {
101            $userlevel = 0;
102        }
103
104        // Find all defined groups $username is in
105        $search = ldap_search(
106            $this->ldap_connection,
107            Config::get('auth_ad_base_dn'),
108            $this->userFilter($username),
109            ['memberOf']
110        );
111        $entries = ldap_get_entries($this->ldap_connection, $search);
112
113        // Loop the list and find the highest level
114        foreach ($entries[0]['memberof'] as $entry) {
115            $group_cn = $this->getCn($entry);
116            $auth_ad_groups = Config::get('auth_ad_groups');
117            if ($auth_ad_groups[$group_cn]['level'] > $userlevel) {
118                $userlevel = $auth_ad_groups[$group_cn]['level'];
119            }
120        }
121
122        $this->authLdapSessionCacheSet('userlevel', $userlevel);
123
124        return $userlevel;
125    }
126
127    public function getUserid($username)
128    {
129        $user_id = $this->authLdapSessionCacheGet('userid');
130        if (isset($user_id)) {
131            return $user_id;
132        } else {
133            $user_id = -1;
134        }
135
136        $attributes = ['objectsid'];
137        $search = ldap_search(
138            $this->ldap_connection,
139            Config::get('auth_ad_base_dn'),
140            $this->userFilter($username),
141            $attributes
142        );
143        $entries = ldap_get_entries($this->ldap_connection, $search);
144
145        if ($entries['count']) {
146            $user_id = $this->getUseridFromSid($this->sidFromLdap($entries[0]['objectsid'][0]));
147        }
148
149        $this->authLdapSessionCacheSet('userid', $user_id);
150
151        return $user_id;
152    }
153
154    protected function getConnection()
155    {
156        return $this->ldap_connection;
157    }
158}
159