Issues (2963)

Authentication/ADAuthorizationAuthorizer.php (5 issues)

1
<?php
2
3
namespace LibreNMS\Authentication;
4
5
use LibreNMS\Config;
6
use LibreNMS\Exceptions\AuthenticationException;
7
use LibreNMS\Exceptions\LdapMissingException;
8
9
class 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) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing LibreNMS\Config::get('au...ad_check_certificates') of type mixed|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
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'),
0 ignored issues
show
It seems like LibreNMS\Config::get('auth_ad_base_dn') can also be of type null; however, parameter $base of ldap_search() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

76
            /** @scrutinizer ignore-type */ Config::get('auth_ad_base_dn'),
Loading history...
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'),
0 ignored issues
show
It seems like LibreNMS\Config::get('auth_ad_base_dn') can also be of type null; however, parameter $base of ldap_search() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

107
            /** @scrutinizer ignore-type */ Config::get('auth_ad_base_dn'),
Loading history...
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'),
0 ignored issues
show
It seems like LibreNMS\Config::get('auth_ad_base_dn') can also be of type null; however, parameter $base of ldap_search() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
            /** @scrutinizer ignore-type */ Config::get('auth_ad_base_dn'),
Loading history...
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;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $user_id also could return the type string which is incompatible with the return type mandated by LibreNMS\Interfaces\Auth...Authorizer::getUserid() of integer.
Loading history...
152
    }
153
154
    protected function getConnection()
155
    {
156
        return $this->ldap_connection;
157
    }
158
}
159