Completed
Push — master ( f22a46...046041 )
by Patrick
02:27 queued 12s
created

LDAPUser::validate_password()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Flipside\Auth;
3
4
class LDAPUser extends User
5
{
6
    use LDAPCachableObject;
7
    use LDAPGettableObject;
8
    use LDAPSettableObject;
9
10
    private $ldapObj;
11
    private $server;
12
13
    /**
14
     * Initialize a LDAPUser object
15
     *
16
     * @param boolean|array|object $data The data to initialize the LDAPUser with or false for an empty User
17
     *
18
     * @SuppressWarnings("StaticAccess")
19
     */
20
    public function __construct($data = false)
21
    {
22
        $this->server = \Flipside\LDAP\LDAPServer::getInstance();
23
        $this->initialize($data);
24
    }
25
26
    private function checkChildGroup($array)
27
    {
28
        $res = false;
29
        for($i = 0; $i < $array['count']; $i++)
30
        {
31
            if(strpos($array[$i], $this->server->group_base) !== false)
32
            {
33
                $dn = explode(',', $array[$i]);
34
                $res = $this->isInGroupNamed(substr($dn[0], 3));
35
                if($res)
36
                {
37
                    return $res;
38
                }
39
            }
40
        }
41
        return $res;
42
    }
43
44
    /**
45
     * @param string $listName The name of the list to search
46
     * @param Group $group The group to search inside
47
     * @param string $dn The distringuished name to search for
48
     */
49
    private function isInListOrChild($listName, $group, $dn)
50
    {
51
        if(!isset($group[$listName]))
52
        {
53
            return false;
54
        }
55
        if(in_array($dn, $group[$listName]))
56
        {
57
            return true;
58
        }
59
        return $this->checkChildGroup($group[$listName]);
60
    }
61
62
    private function uidInMemberUid($group, $uid)
63
    {
64
        return (isset($group['memberUid']) && in_array($uid, $group['memberUid']));
65
    }
66
67
    public function isInGroupNamed($name)
68
    {
69
        $filter = new \Flipside\Data\Filter('cn eq '.$name);
70
71
        $auth = \Flipside\AuthProvider::getInstance();
72
        $ldap = $auth->getMethodByName('Flipside\Auth\LDAPAuthenticator');
73
        if($ldap !== false)
74
        {
75
            $this->server = $ldap->getAndBindServer(false);
76
        }
77
        $group = $this->server->read($this->server->group_base, $filter);
78
79
        if(!empty($group))
80
        {
81
            $group = $group[0];
82
            $dn  = $this->ldapObj->dn;
83
            $uid = $this->ldapObj->uid[0];
84
            $ret = $this->isInListOrChild('member', $group, $dn);
85
            if($ret === false)
86
            {
87
                $ret = $this->isInListOrChild('uniquemember', $group, $dn);
88
            }
89
            if($ret === false && $this->uidInMemberUid($group, $uid))
90
            {
91
                return true;
92
            }
93
            return $ret;
94
        }
95
        return false;
96
    }
97
98
    protected $valueDefaults = array(
99
        'o' => 'Volunteer'
100
    );
101
102
    protected $multiValueProps = array(
103
        'title',
104
        'ou',
105
        'host'
106
    );
107
108
    protected $cachedOnlyProps = array(
109
        'uid'
110
    );
111
112
    /**
113
     * LDAP does not allow anonymous read
114
     *
115
     * @SuppressWarnings("StaticAccess")
116
     */
117 View Code Duplication
    protected function enableRead()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
    {
119
        //Make sure we are bound in read mode
120
        $auth = \Flipside\AuthProvider::getInstance();
121
        $ldap = $auth->getMethodByName('\Flipside\Auth\LDAPAuthenticator');
122
        if($ldap !== false)
123
        {
124
            $this->server = $ldap->getAndBindServer(false);
125
        }
126
    }
127
128
    /**
129
     * Allow write for the user
130
     *
131
     * @SuppressWarnings("StaticAccess")
132
     */
133 View Code Duplication
    protected function enableReadWrite()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
134
    {
135
        //Make sure we are bound in write mode
136
        $auth = \Flipside\AuthProvider::getInstance();
137
        $ldap = $auth->getMethodByName('Flipside\Auth\LDAPAuthenticator');
138
        if($ldap !== false)
139
        {
140
            $this->server = $ldap->getAndBindServer(true);
141
        }
142
    }
143
144
    public function getGroups()
145
    {
146
        $this->enableRead();
147
        $res = array();
148
        $groups = $this->server->read($this->server->group_base);
149
        if(!empty($groups))
150
        {
151
            $count = count($groups);
152
            for($i = 0; $i < $count; $i++)
153
            {
154
                if($this->isInGroupNamed($groups[$i]['cn'][0]))
155
                {
156
                    array_push($res, new LDAPGroup($groups[$i]));
157
                }
158
            }
159
            return $res;
160
        }
161
        return false;
162
    }
163
164
    public function addLoginProvider($provider)
165
    {
166
        return $this->appendField('host', $provider);
167
    }
168
169
    private function generateLDAPPass($pass)
170
    {
171
        mt_srand((double)microtime() * 1000000);
172
        $salt = pack("CCCC", mt_rand(), mt_rand(), mt_rand(), mt_rand());
173
        $hash = base64_encode(pack('H*', sha1($pass.$salt)).$salt);
174
        return '{SSHA}'.$hash;
175
    }
176
177
    public function setPass($password)
178
    {
179
        $password = $this->generateLDAPPass($password);
180
        if(!is_object($this->ldapObj))
181
        {
182
            return $this->setFieldLocal('userPassword', $password);
183
        }
184
        $obj = array('dn'=>$this->ldapObj->dn);
185
        $obj['userPassword'] = $password;
186
        if(isset($this->ldapObj->uniqueidentifier))
187
        {
188
            $obj['uniqueIdentifier'] = null;
189
        }
190
        //Make sure we are bound in write mode
191
        $this->enableReadWrite();
192
        return $this->update($obj);
193
    }
194
195
    public function validate_password($password)
196
    {
197
        return $this->server->bind($this->ldapObj->dn, $password) !== false;
198
    }
199
200
    public function validate_reset_hash($hash)
201
    {
202
        if(isset($this->ldapObj->uniqueidentifier) && strcmp($this->ldapObj->uniqueidentifier[0], $hash) === 0)
203
        {
204
            return true;
205
        }
206
        return false;
207
    }
208
209
    public static function from_name($name, $data)
210
    {
211
        if($data === false)
212
        {
213
            throw new \Exception('data must be set for LDAPUser');
214
        }
215
        $filter = new \Data\Filter("uid eq $name");
216
        $user = $data->read($data->user_base, $filter);
217
        if(empty($user))
218
        {
219
            return false;
220
        }
221
        return new static($user[0]);
222
    }
223
224
    public function flushUser()
225
    {
226
        if(is_object($this->ldapObj))
227
        {
228
            //In this mode we are always up to date
229
            return true;
230
        }
231
        $obj = $this->ldapObj;
232
        $obj['objectClass'] = array('top', 'inetOrgPerson', 'extensibleObject');
233
        $obj['dn'] = 'uid='.$this->ldapObj['uid'].','.$this->server->user_base;
234
        if(!isset($obj['sn']))
235
        {
236
            $obj['sn'] = $obj['uid'];
237
        }
238
        if(!isset($obj['cn']))
239
        {
240
            $obj['cn'] = $obj['uid'];
241
        }
242
        //Make sure we are bound in write mode
243
        $this->enableReadWrite();
244
        $ret = $this->server->create($obj);
245
        return $ret;
246
    }
247
248
    private function getHashFromUser($ldapObj)
249
    {
250
        if(isset($ldapObj->userpassword))
251
        {
252
            return hash('sha512', $ldapObj->dn.';'.$ldapObj->userpassword[0].';'.$ldapObj->mail[0]);
253
        }
254
        return hash('sha512', $ldapObj->dn.';'.openssl_random_pseudo_bytes(10).';'.$ldapObj->mail[0]);
255
    }
256
257
    public function getPasswordResetHash()
258
    {
259
        $ldapObj = $this->server->read($this->server->user_base, new \Data\Filter('uid eq '.$this->uid));
260
        $ldapObj = $ldapObj[0];
261
        $hash = $this->getHashFromUser($ldapObj);
262
        $obj = array('dn'=>$this->ldapObj->dn);
263
        $obj['uniqueIdentifier'] = $hash;
264
        //Make sure we are bound in write mode
265
        $this->enableReadWrite();
266
        if($this->server->update($obj) === false)
267
        {
268
            throw new \Exception('Unable to create hash in LDAP object!');
269
        }
270
        return $hash;
271
    }
272
273
    public function removeEmail($email)
274
    {
275
        $mail = $this->ldapObj->mail;
276
        if(($key = array_search($email, $mail)) !== false)
277
        {
278
            unset($mail[$key]);
279
            if(isset($mail['count']))
280
            {
281
                $mail['count']--;
282
            }
283
        }
284
        $count = count($mail);
285
        if(isset($mail['count']))
286
        {
287
            $count = $mail['count'];
288
            unset($mail['count']);
289
        }
290
        $obj = array('dn'=>$this->ldapObj->dn);
291
        $obj['mail'] = $mail;
292
        if($count === 1)
293
        {
294
            $obj['labeleduri'] = null;
295
        }
296
        //Make sure we are bound in write mode
297
        $this->enableReadWrite();
298
        if($this->server->update($obj) === false)
299
        {
300
            throw new \Exception('Unable to change mail properties in LDAP object!');
301
        }
302
        $this->ldapObj = $this->server->read($this->server->user_base, new \Data\Filter('uid eq '.$this->uid));
303
        return true;
304
    }
305
306
    public function delete()
307
    {
308
        //Make sure we are bound in write mode
309
        $this->enableReadWrite();
310
        return $this->server->delete($this->ldapObj->dn);
311
    }
312
}
313
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
314