Completed
Push — master ( 9f2169...fd3a03 )
by Patrick
03:30
created

LDAPUser::flushUser()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 2
Metric Value
cc 4
eloc 12
c 5
b 0
f 2
nc 5
nop 0
dl 0
loc 21
rs 9.0534
1
<?php
2
namespace 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 = \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 \Data\Filter('cn eq '.$name);
70
        $group = $this->server->read($this->server->group_base, $filter);
71
        if(!empty($group))
72
        {
73
            $group = $group[0];
74
            $dn  = $this->ldapObj->dn;
75
            $uid = $this->ldapObj->uid[0];
76
            $ret = $this->isInListOrChild('member', $group, $dn);
77
            if($ret === false)
78
            {
79
                $ret = $this->isInListOrChild('uniquemember', $group, $dn);
80
            }
81
            if($ret === false && $this->uidInMemberUid($group, $uid))
82
            {
83
                return true;
84
            }
85
            return $ret;
86
        }
87
        return false;
88
    }
89
90
    protected $valueDefaults = array(
91
        'o' => 'Volunteer'
92
    );
93
94
    protected $multiValueProps = array(
95
        'title',
96
        'ou',
97
        'host'
98
    );
99
100
    protected $cachedOnlyProps = array(
101
        'uid'
102
    );
103
104
    /**
105
     * Allow write for the user
106
     *
107
     * @SuppressWarnings("StaticAccess")
108
     */
109
    protected function enableReadWrite()
110
    {
111
        //Make sure we are bound in write mode
112
        $auth = \AuthProvider::getInstance();
113
        $ldap = $auth->getMethodByName('Auth\LDAPAuthenticator');
114
        if($ldap !== false)
115
        {
116
            $ldap->getAndBindServer(true);
117
        }
118
    }
119
120
    public function getGroups()
121
    {
122
        $res = array();
123
        $groups = $this->server->read($this->server->group_base);
124
        if(!empty($groups))
125
        {
126
            $count = count($groups);
127
            for($i = 0; $i < $count; $i++)
128
            {
129
                if($this->isInGroupNamed($groups[$i]['cn'][0]))
130
                {
131
                    array_push($res, new LDAPGroup($groups[$i]));
132
                }
133
            }
134
            return $res;
135
        }
136
        return false;
137
    }
138
139
    public function addLoginProvider($provider)
140
    {
141
        return $this->appendField('host', $provider);
142
    }
143
144
    private function generateLDAPPass($pass)
145
    {
146
        mt_srand((double)microtime() * 1000000);
147
        $salt = pack("CCCC", mt_rand(), mt_rand(), mt_rand(), mt_rand());
148
        $hash = base64_encode(pack('H*', sha1($pass.$salt)).$salt);
149
        return '{SSHA}'.$hash;
150
    }
151
152
    public function setPass($password)
153
    {
154
        if(!is_object($this->ldapObj))
155
        {
156
            return $this->setFieldLocal('userPassword', $this->generateLDAPPass($password));
157
        }
158
        $obj = array('dn'=>$this->ldapObj->dn);
159
        $obj['userPassword'] = $this->generateLDAPPass($password);
160
        if(isset($this->ldapObj->uniqueidentifier))
161
        {
162
            $obj['uniqueIdentifier'] = null;
163
        }
164
        //Make sure we are bound in write mode
165
        $this->enableReadWrite();
166
        return $this->update($obj);
167
    }
168
169
    public function validate_password($password)
170
    {
171
        return $this->server->bind($this->ldapObj->dn, $password) !== false;
172
    }
173
174
    public function validate_reset_hash($hash)
175
    {
176
        if(isset($this->ldapObj->uniqueidentifier) && strcmp($this->ldapObj->uniqueidentifier[0], $hash) === 0)
177
        {
178
            return true;
179
        }
180
        return false;
181
    }
182
183
    public static function from_name($name, $data)
184
    {
185
        if($data === false)
186
        {
187
            throw new \Exception('data must be set for LDAPUser');
188
        }
189
        $filter = new \Data\Filter("uid eq $name");
190
        $user = $data->read($data->user_base, $filter);
191
        if(empty($user))
192
        {
193
            return false;
194
        }
195
        return new static($user[0]);
196
    }
197
198
    public function flushUser()
199
    {
200
        if(is_object($this->ldapObj))
201
        {
202
            //In this mode we are always up to date
203
            return true;
204
        }
205
        $obj = $this->ldapObj;
206
        $obj['objectClass'] = array('top', 'inetOrgPerson', 'extensibleObject');
207
        $obj['dn'] = 'uid='.$this->ldapObj['uid'].','.$this->server->user_base;
208
        if(!isset($obj['sn']))
209
        {
210
            $obj['sn'] = $obj['uid'];
211
        }
212
        if(!isset($obj['cn']))
213
        {
214
            $obj['cn'] = $obj['uid'];
215
        }
216
        $ret = $this->server->create($obj);
217
        return $ret;
218
    }
219
220
    private function getHashFromUser($ldapObj)
221
    {
222
        if(isset($ldapObj->userpassword))
223
        {
224
            return hash('sha512', $ldapObj->dn.';'.$ldapObj->userpassword[0].';'.$ldapObj->mail[0]);
225
        }
226
        return hash('sha512', $ldapObj->dn.';'.openssl_random_pseudo_bytes(10).';'.$ldapObj->mail[0]);
227
    }
228
229
    public function getPasswordResetHash()
230
    {
231
        //Make sure we are bound in write mode
232
        $this->enableReadWrite();
233
        $ldapObj = $this->server->read($this->server->user_base, new \Data\Filter('uid eq '.$this->uid));
234
        $ldapObj = $ldapObj[0];
235
        $hash = $this->getHashFromUser($ldapObj);
236
        $obj = array('dn'=>$this->ldapObj->dn);
237
        $obj['uniqueIdentifier'] = $hash;
238
        if($this->server->update($obj) === false)
239
        {
240
            throw new \Exception('Unable to create hash in LDAP object!');
241
        }
242
        return $hash;
243
    }
244
245
    public function delete()
246
    {
247
        //Make sure we are bound in write mode
248
        $this->enableReadWrite();
249
        return $this->server->delete($this->ldapObj->dn);
250
    }
251
}
252
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
253