Completed
Pull Request — master (#628)
by Richard
19:02 queued 04:58
created

Ldap   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 228
Duplicated Lines 0 %

Test Coverage

Coverage 12.9%

Importance

Changes 0
Metric Value
eloc 79
dl 0
loc 228
rs 10
c 0
b 0
f 0
ccs 8
cts 62
cp 0.129
wmc 17

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getUserDN() 0 31 4
A loadXoopsUser() 0 13 2
A getFilter() 0 9 2
A authenticate() 0 31 6
A __construct() 0 13 3
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
namespace Xoops\Auth;
13
14
use Xoops\Core\Database\Connection;
15
16
/**
17
 * Authentication class for standard LDAP Server V3
18
 *
19
 * @category  Xoops\Auth
20
 * @package   Ldap
21
 * @author    Pierre-Eric MENUET <[email protected]>
22
 * @copyright 2000-2014 XOOPS Project (http://xoops.org)
23
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
24
 * @link      http://xoops.org
25
 * @since     2.0
26
 */
27
class Ldap extends AuthAbstract
28
{
29
30
    /**
31
     * @var
32
     */
33
    public $ldap_server;
34
35
    /**
36
     * @var string
37
     */
38
39
    public $ldap_port = '389';
40
    /**
41
     * @var string
42
     */
43
    public $ldap_version = '3';
44
45
    /**
46
     * @var
47
     */
48
    public $ldap_base_dn;
49
50
    /**
51
     * @var
52
     */
53
    public $ldap_loginname_asdn;
54
55
    /**
56
     * @var
57
     */
58
    public $ldap_loginldap_attr;
59
60
    /**
61
     * @var
62
     */
63
    public $ldap_mail_attr;
64
65
    /**
66
     * @var
67
     */
68
    public $ldap_name_attr;
69
70
    /**
71
     * @var
72
     */
73
    public $ldap_surname_attr;
74
75
    /**
76
     * @var
77
     */
78
    public $ldap_givenname_attr;
79
80
    /**
81
     * @var
82
     */
83
    public $ldap_manager_dn;
84
85
    /**
86
     * @var
87
     */
88
    public $ldap_manager_pass;
89
90
    /**
91
     * @var
92
     */
93
    public $ds;
94
95
    /**
96
     * @var
97
     */
98
    public $ldap_use_TLS;
99
100
    /**
101
     * @var
102
     */
103
    public $ldap_domain_name;
104
105
    /**
106
     * @var
107
     */
108
    public $ldap_filter_person;
109
110
    /**
111
     * Authentication Service constructor
112
     *
113
     * @param Connection|null $dao databse
114
     */
115 4
    public function __construct(Connection $dao = null)
116
    {
117 4
        if (!extension_loaded('ldap')) {
118
            trigger_error(sprintf(\XoopsLocale::F_EXTENSION_PHP_NOT_LOADED, 'LDAP'), E_USER_ERROR);
119
            return;
120
        }
121
122 4
        $xoops = \Xoops::getInstance();
123 4
        $this->dao = $dao;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dao can also be of type Xoops\Core\Database\Connection. However, the property $dao is declared as type Xoops\Auth\use. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
124
        //Configuration options that are stored in the database
125 4
        $configs = $xoops->getConfigs();
126 4
        foreach ($configs as $key => $val) {
127 4
            $this->$key = $val;
128
        }
129 4
    }
130
131
    /**
132
     * Authenticate  user again LDAP directory (Bind)
133
     *               2 options :
134
     *         Authenticate directly with uname in the DN
135
     *         Authenticate with manager, search the dn
136
     *
137
     * @param string $uname Username
138
     * @param string $pwd   Password
139
     *
140
     * @return bool
141
     */
142
    public function authenticate($uname, $pwd = null)
143
    {
144
        $authenticated = false;
145
        $this->ds = ldap_connect($this->ldap_server, $this->ldap_port);
0 ignored issues
show
Bug introduced by
$this->ldap_port of type string is incompatible with the type integer expected by parameter $port of ldap_connect(). ( Ignorable by Annotation )

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

145
        $this->ds = ldap_connect($this->ldap_server, /** @scrutinizer ignore-type */ $this->ldap_port);
Loading history...
146
        if ($this->ds) {
147
            ldap_set_option($this->ds, LDAP_OPT_PROTOCOL_VERSION, $this->ldap_version);
148
            if ($this->ldap_use_TLS) { // We use TLS secure connection
149
                if (!ldap_start_tls($this->ds)) {
150
                    $this->setErrors(0, \XoopsLocale::E_TLS_CONNECTION_NOT_OPENED);
151
                }
152
            }
153
            // If the uid is not in the DN we proceed to a search
154
            // The uid is not always in the dn
155
            $userDN = $this->getUserDN($uname);
156
            if (!(is_string($userDN))) {
157
                return false;
158
            }
159
            // We bind as user to test the credentials
160
            $authenticated = ldap_bind($this->ds, $userDN, stripslashes($pwd));
161
            if ($authenticated) {
162
                // We load the Xoops User database
163
                return $this->loadXoopsUser($userDN, $uname, $pwd);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->loadXoopsU...($userDN, $uname, $pwd) also could return the type Xoops\Auth\XoopsUser which is incompatible with the documented return type boolean.
Loading history...
164
            } else {
165
                $this->setErrors(ldap_errno($this->ds), ldap_err2str(ldap_errno($this->ds)) . '(' . $userDN . ')');
166
            }
167
        } else {
168
            $this->setErrors(0, \XoopsLocale::E_CANNOT_CONNECT_TO_SERVER);
169
        }
170
        @ldap_close($this->ds);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for ldap_close(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

170
        /** @scrutinizer ignore-unhandled */ @ldap_close($this->ds);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
171
172
        return $authenticated;
173
    }
174
175
    /**
176
     * Compose the user DN with the configuration.
177
     *
178
     * @param string $uname username
179
     *
180
     * @return bool|string userDN or false
181
     */
182
    public function getUserDN($uname)
183
    {
184
        $userDN = false;
185
        if (!$this->ldap_loginname_asdn) {
186
            // Bind with the manager
187
            if (!ldap_bind($this->ds, $this->ldap_manager_dn, stripslashes($this->ldap_manager_pass))) {
188
                $this->setErrors(
189
                    ldap_errno($this->ds),
190
                    ldap_err2str(ldap_errno($this->ds)) . '(' . $this->ldap_manager_dn . ')'
191
                );
192
193
                return false;
194
            }
195
            $filter = $this->getFilter($uname);
196
            $sr = ldap_search($this->ds, $this->ldap_base_dn, $filter);
197
            $info = ldap_get_entries($this->ds, $sr);
198
            if ($info['count'] > 0) {
199
                $userDN = $info[0]['dn'];
200
            } else {
201
                $this->setErrors(0, sprintf(
202
                    \XoopsLocale::EF_USER_NOT_FOUND_IN_DIRECTORY_SERVER,
203
                    $uname,
204
                    $filter,
205
                    $this->ldap_base_dn
206
                ));
207
            }
208
        } else {
209
            $userDN = $this->ldap_loginldap_attr . '=' . $uname . ',' . $this->ldap_base_dn;
210
        }
211
212
        return $userDN;
213
    }
214
215
    /**
216
     * Load user from XOOPS Database
217
     *
218
     * @param string $uname username
219
     *
220
     * @return mixed|string
221
     */
222
    public function getFilter($uname)
223
    {
224
        if ($this->ldap_filter_person != '') {
225
            $filter = str_replace('@@loginname@@', $uname, $this->ldap_filter_person);
226
        } else {
227
            $filter = $this->ldap_loginldap_attr . '=' . $uname;
228
        }
229
230
        return $filter;
231
    }
232
233
    /**
234
     * loadXoopsUser
235
     *
236
     * @param string $userdn base DN for the directory
237
     * @param string $uname  username
238
     * @param string $pwd    pasword
239
     *
240
     * @return bool|XoopsUser
0 ignored issues
show
Bug introduced by
The type Xoops\Auth\XoopsUser was not found. Did you mean XoopsUser? If so, make sure to prefix the type with \.
Loading history...
241
     */
242
    public function loadXoopsUser($userdn, $uname, $pwd = null)
243
    {
244
        $xoopsUser = false;
245
        $provisHandler = Provisioning::getInstance($this);
246
        $sr = ldap_read($this->ds, $userdn, '(objectclass=*)');
247
        $entries = ldap_get_entries($this->ds, $sr);
248
        if ($entries['count'] > 0) {
249
            $xoopsUser = $provisHandler->sync($entries[0], $uname, $pwd);
250
        } else {
251
            $this->setErrors(0, sprintf('loadXoopsUser - ' . \XoopsLocale::EF_ENTRY_NOT_READ, $userdn));
252
        }
253
254
        return $xoopsUser;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $xoopsUser also could return the type Xoops\Core\Kernel\Handlers\XoopsUser which is incompatible with the documented return type Xoops\Auth\XoopsUser|boolean.
Loading history...
255
    }
256
}
257