Completed
Push — master ( 99c28a...4c4331 )
by Robin
47:48
created

Wizard   D

Complexity

Total Complexity 228

Size/Duplication

Total Lines 1328
Duplicated Lines 9.04 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 19.2%
Metric Value
wmc 228
lcom 1
cbo 11
dl 120
loc 1328
ccs 148
cts 771
cp 0.192
rs 4

40 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A __destruct() 0 5 2
B countEntries() 0 23 6
A formatCountResult() 0 7 3
B countGroups() 0 22 4
A countUsers() 0 8 1
A countInBaseDN() 0 9 2
A countUsersWithAttribute() 7 18 3
C detectUserDisplayNameAttribute() 7 35 7
C detectEmailAttribute() 7 42 8
B determineAttributes() 7 23 4
B getUserAttributes() 7 28 5
A determineGroupsForGroups() 0 5 1
A determineGroupsForUsers() 0 4 1
B determineGroups() 0 24 5
D fetchGroups() 6 46 10
A determineGroupMemberAssoc() 0 16 3
A determineGroupObjectClasses() 0 21 3
B determineUserObjectClasses() 0 25 3
A getGroupFilter() 19 19 3
A getUserListFilter() 21 21 4
A getUserLoginFilter() 7 17 3
B testLoginName() 7 28 5
C guessPortAndTLS() 0 48 7
C guessBaseDN() 0 39 8
A applyFind() 0 4 1
A checkHost() 0 12 3
C detectGroupMemberAssoc() 0 36 8
A testBaseDN() 0 19 4
A testMemberOf() 0 11 4
D composeLdapFilter() 16 145 35
C connectAndBind() 0 71 15
A checkAgentRequirements() 0 7 4
A checkRequirements() 0 10 3
C cumulativeSearchOnAttribute() 0 63 20
D determineFeature() 9 41 9
C getAttributeValuesFromEntry() 0 24 8
B getConnection() 0 29 5
A getDefaultLdapPortSettings() 0 11 1
B getPortSettingsToTry() 0 25 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Wizard often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Wizard, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @author Alexander Bergolth <[email protected]>
4
 * @author Arthur Schiwon <[email protected]>
5
 * @author Bart Visscher <[email protected]>
6
 * @author Jean-Louis Dupond <[email protected]>
7
 * @author Jörn Friedrich Dreyer <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Nicolas Grekas <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Robin McCorkell <[email protected]>
13
 * @author Scrutinizer Auto-Fixer <[email protected]>
14
 * @author Victor Dubiniuk <[email protected]>
15
 *
16
 * @copyright Copyright (c) 2015, ownCloud, Inc.
17
 * @license AGPL-3.0
18
 *
19
 * This code is free software: you can redistribute it and/or modify
20
 * it under the terms of the GNU Affero General Public License, version 3,
21
 * as published by the Free Software Foundation.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
 * GNU Affero General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU Affero General Public License, version 3,
29
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
30
 *
31
 */
32
33
namespace OCA\user_ldap\lib;
34
35
use OC\ServerNotAvailableException;
36
37
class Wizard extends LDAPUtility {
38
	static protected $l;
39
	protected $access;
40
	protected $cr;
41
	protected $configuration;
42
	protected $result;
43
	protected $resultCache = array();
44
45
	const LRESULT_PROCESSED_OK = 2;
46
	const LRESULT_PROCESSED_INVALID = 3;
47
	const LRESULT_PROCESSED_SKIP = 4;
48
49
	const LFILTER_LOGIN      = 2;
50
	const LFILTER_USER_LIST  = 3;
51
	const LFILTER_GROUP_LIST = 4;
52
53
	const LFILTER_MODE_ASSISTED = 2;
54
	const LFILTER_MODE_RAW = 1;
55
56
	const LDAP_NW_TIMEOUT = 4;
57
58
	/**
59
	 * Constructor
60
	 * @param Configuration $configuration an instance of Configuration
61
	 * @param ILDAPWrapper $ldap an instance of ILDAPWrapper
62
	 */
63 7
	public function __construct(Configuration $configuration, ILDAPWrapper $ldap, Access $access) {
64 7
		parent::__construct($ldap);
65 7
		$this->configuration = $configuration;
66 7
		if(is_null(Wizard::$l)) {
67 1
			Wizard::$l = \OC::$server->getL10N('user_ldap');
68 1
		}
69 7
		$this->access = $access;
70 7
		$this->result = new WizardResult();
71 7
	}
72
73 7
	public function  __destruct() {
74 7
		if($this->result->hasChanges()) {
75 2
			$this->configuration->saveConfiguration();
76 2
		}
77 7
	}
78
79
	/**
80
	 * counts entries in the LDAP directory
81
	 *
82
	 * @param string $filter the LDAP search filter
83
	 * @param string $type a string being either 'users' or 'groups';
84
	 * @return bool|int
85
	 * @throws \Exception
86
	 */
87
	public function countEntries($filter, $type) {
88
		$reqs = array('ldapHost', 'ldapPort', 'ldapBase');
89
		if($type === 'users') {
90
			$reqs[] = 'ldapUserFilter';
91
		}
92
		if(!$this->checkRequirements($reqs)) {
93
			throw new \Exception('Requirements not met', 400);
94
		}
95
96
		$attr = array('dn'); // default
97
		$limit = 1001;
98
		if($type === 'groups') {
99
			$result =  $this->access->countGroups($filter, $attr, $limit);
100
		} else if($type === 'users') {
101
			$result = $this->access->countUsers($filter, $attr, $limit);
102
		} else if ($type === 'objects') {
103
			$result = $this->access->countObjects($limit);
104
		} else {
105
			throw new \Exception('internal error: invalid object type', 500);
106
		}
107
108
		return $result;
109
	}
110
111
	/**
112
	 * formats the return value of a count operation to the string to be
113
	 * inserted.
114
	 *
115
	 * @param bool|int $count
116
	 * @return int|string
117
	 */
118
	private function formatCountResult($count) {
119
		$formatted = ($count !== false) ? $count : 0;
120
		if($formatted > 1000) {
121
			$formatted = '> 1000';
122
		}
123
		return $formatted;
124
	}
125
126
	public function countGroups() {
127
		$filter = $this->configuration->ldapGroupFilter;
0 ignored issues
show
Documentation introduced by
The property ldapGroupFilter does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
128
129
		if(empty($filter)) {
130
			$output = self::$l->n('%s group found', '%s groups found', 0, array(0));
131
			$this->result->addChange('ldap_group_count', $output);
132
			return $this->result;
133
		}
134
135
		try {
136
			$groupsTotal = $this->formatCountResult($this->countEntries($filter, 'groups'));
137
		} catch (\Exception $e) {
138
			//400 can be ignored, 500 is forwarded
139
			if($e->getCode() === 500) {
140
				throw $e;
141
			}
142
			return false;
143
		}
144
		$output = self::$l->n('%s group found', '%s groups found', $groupsTotal, array($groupsTotal));
145
		$this->result->addChange('ldap_group_count', $output);
146
		return $this->result;
147
	}
148
149
	/**
150
	 * @return WizardResult
151
	 * @throws \Exception
152
	 */
153
	public function countUsers() {
154
		$filter = $this->access->getFilterForUserCount();
155
156
		$usersTotal = $this->formatCountResult($this->countEntries($filter, 'users'));
157
		$output = self::$l->n('%s user found', '%s users found', $usersTotal, array($usersTotal));
158
		$this->result->addChange('ldap_user_count', $output);
159
		return $this->result;
160
	}
161
162
	/**
163
	 * counts any objects in the currently set base dn
164
	 *
165
	 * @return WizardResult
166
	 * @throws \Exception
167
	 */
168
	public function countInBaseDN() {
169
		// we don't need to provide a filter in this case
170
		$total = $this->countEntries(null, 'objects');
171
		if($total === false) {
172
			throw new \Exception('invalid results received');
173
		}
174
		$this->result->addChange('ldap_test_base', $total);
175
		return $this->result;
176
	}
177
178
	/**
179
	 * counts users with a specified attribute
180
	 * @param string $attr
181
	 * @param bool $existsCheck
182
	 * @return int|bool
183
	 */
184 4
	public function countUsersWithAttribute($attr, $existsCheck = false) {
185 4 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
186 4
										   'ldapPort',
187 4
										   'ldapBase',
188 4
										   'ldapUserFilter',
189 4
										   ))) {
190
			return  false;
191
		}
192
193 4
		$filter = $this->access->combineFilterWithAnd(array(
194 4
			$this->configuration->ldapUserFilter,
0 ignored issues
show
Documentation introduced by
The property ldapUserFilter does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
195
			$attr . '=*'
196 4
		));
197
198 4
		$limit = ($existsCheck === false) ? null : 1;
199
200 4
		return $this->access->countUsers($filter, array('dn'), $limit);
201
	}
202
203
	/**
204
	 * detects the display name attribute. If a setting is already present that
205
	 * returns at least one hit, the detection will be canceled.
206
	 * @return WizardResult|bool
207
	 * @throws \Exception
208
	 */
209
	public function detectUserDisplayNameAttribute() {
210 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
211
										'ldapPort',
212
										'ldapBase',
213
										'ldapUserFilter',
214
										))) {
215
			return  false;
216
		}
217
218
		$attr = $this->configuration->ldapUserDisplayName;
0 ignored issues
show
Documentation introduced by
The property ldapUserDisplayName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
219
		if($attr !== 'displayName' && !empty($attr)) {
220
			// most likely not the default value with upper case N,
221
			// verify it still produces a result
222
			$count = intval($this->countUsersWithAttribute($attr, true));
223
			if($count > 0) {
224
				//no change, but we sent it back to make sure the user interface
225
				//is still correct, even if the ajax call was cancelled inbetween
226
				$this->result->addChange('ldap_display_name', $attr);
227
				return $this->result;
228
			}
229
		}
230
231
		// first attribute that has at least one result wins
232
		$displayNameAttrs = array('displayname', 'cn');
233
		foreach ($displayNameAttrs as $attr) {
234
			$count = intval($this->countUsersWithAttribute($attr, true));
235
236
			if($count > 0) {
237
				$this->applyFind('ldap_display_name', $attr);
238
				return $this->result;
239
			}
240
		};
241
242
		throw new \Exception(self::$l->t('Could not detect user display name attribute. Please specify it yourself in advanced ldap settings.'));
243
	}
244
245
	/**
246
	 * detects the most often used email attribute for users applying to the
247
	 * user list filter. If a setting is already present that returns at least
248
	 * one hit, the detection will be canceled.
249
	 * @return WizardResult|bool
250
	 */
251 4
	public function detectEmailAttribute() {
252 4 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
253 4
										   'ldapPort',
254 4
										   'ldapBase',
255 4
										   'ldapUserFilter',
256 4
										   ))) {
257
			return  false;
258
		}
259
260 4
		$attr = $this->configuration->ldapEmailAttribute;
0 ignored issues
show
Documentation introduced by
The property ldapEmailAttribute does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
261 4
		if(!empty($attr)) {
262 3
			$count = intval($this->countUsersWithAttribute($attr, true));
263 3
			if($count > 0) {
264 1
				return false;
265
			}
266 2
			$writeLog = true;
267 2
		} else {
268 1
			$writeLog = false;
269
		}
270
271 3
		$emailAttributes = array('mail', 'mailPrimaryAddress');
272 3
		$winner = '';
273 3
		$maxUsers = 0;
274 3
		foreach($emailAttributes as $attr) {
275 3
			$count = $this->countUsersWithAttribute($attr);
276 3
			if($count > $maxUsers) {
277 2
				$maxUsers = $count;
278 2
				$winner = $attr;
279 2
			}
280 3
		}
281
282 3
		if($winner !== '') {
283 2
			$this->applyFind('ldap_email_attr', $winner);
284 2
			if($writeLog) {
285 1
				\OCP\Util::writeLog('user_ldap', 'The mail attribute has ' .
286 1
					'automatically been reset, because the original value ' .
287 1
					'did not return any results.', \OCP\Util::INFO);
288 1
			}
289 2
		}
290
291 3
		return $this->result;
292
	}
293
294
	/**
295
	 * @return WizardResult
296
	 * @throws \Exception
297
	 */
298
	public function determineAttributes() {
299 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
300
										   'ldapPort',
301
										   'ldapBase',
302
										   'ldapUserFilter',
303
										   ))) {
304
			return  false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OCA\user_ldap\lib\Wizard::determineAttributes of type OCA\user_ldap\lib\WizardResult.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
305
		}
306
307
		$attributes = $this->getUserAttributes();
308
309
		natcasesort($attributes);
310
		$attributes = array_values($attributes);
311
312
		$this->result->addOptions('ldap_loginfilter_attributes', $attributes);
313
314
		$selected = $this->configuration->ldapLoginFilterAttributes;
0 ignored issues
show
Documentation introduced by
The property ldapLoginFilterAttributes does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
315
		if(is_array($selected) && !empty($selected)) {
316
			$this->result->addChange('ldap_loginfilter_attributes', $selected);
317
		}
318
319
		return $this->result;
320
	}
321
322
	/**
323
	 * detects the available LDAP attributes
324
	 * @return array|false The instance's WizardResult instance
325
	 * @throws \Exception
326
	 */
327
	private function getUserAttributes() {
328 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
329
										   'ldapPort',
330
										   'ldapBase',
331
										   'ldapUserFilter',
332
										   ))) {
333
			return  false;
334
		}
335
		$cr = $this->getConnection();
336
		if(!$cr) {
337
			throw new \Exception('Could not connect to LDAP');
338
		}
339
340
		$base = $this->configuration->ldapBase[0];
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
341
		$filter = $this->configuration->ldapUserFilter;
0 ignored issues
show
Documentation introduced by
The property ldapUserFilter does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
342
		$rr = $this->ldap->search($cr, $base, $filter, array(), 1, 1);
343
		if(!$this->ldap->isResource($rr)) {
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...$filter, array(), 1, 1) on line 342 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::isResource() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
344
			return false;
345
		}
346
		$er = $this->ldap->firstEntry($cr, $rr);
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...$filter, array(), 1, 1) on line 342 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::firstEntry() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
347
		$attributes = $this->ldap->getAttributes($cr, $er);
348
		$pureAttributes = array();
349
		for($i = 0; $i < $attributes['count']; $i++) {
350
			$pureAttributes[] = $attributes[$i];
351
		}
352
353
		return $pureAttributes;
354
	}
355
356
	/**
357
	 * detects the available LDAP groups
358
	 * @return WizardResult|false the instance's WizardResult instance
359
	 */
360
	public function determineGroupsForGroups() {
361
		return $this->determineGroups('ldap_groupfilter_groups',
362
									  'ldapGroupFilterGroups',
363
									  false);
364
	}
365
366
	/**
367
	 * detects the available LDAP groups
368
	 * @return WizardResult|false the instance's WizardResult instance
369
	 */
370
	public function determineGroupsForUsers() {
371
		return $this->determineGroups('ldap_userfilter_groups',
372
									  'ldapUserFilterGroups');
373
	}
374
375
	/**
376
	 * detects the available LDAP groups
377
	 * @param string $dbKey
378
	 * @param string $confKey
379
	 * @param bool $testMemberOf
380
	 * @return WizardResult|false the instance's WizardResult instance
381
	 * @throws \Exception
382
	 */
383
	private function determineGroups($dbKey, $confKey, $testMemberOf = true) {
384
		if(!$this->checkRequirements(array('ldapHost',
385
										   'ldapPort',
386
										   'ldapBase',
387
										   ))) {
388
			return  false;
389
		}
390
		$cr = $this->getConnection();
391
		if(!$cr) {
392
			throw new \Exception('Could not connect to LDAP');
393
		}
394
395
		$this->fetchGroups($dbKey, $confKey);
396
397
		if($testMemberOf) {
398
			$this->configuration->hasMemberOfFilterSupport = $this->testMemberOf();
0 ignored issues
show
Documentation introduced by
The property hasMemberOfFilterSupport does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
399
			$this->result->markChange();
400
			if(!$this->configuration->hasMemberOfFilterSupport) {
0 ignored issues
show
Documentation introduced by
The property hasMemberOfFilterSupport does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
401
				throw new \Exception('memberOf is not supported by the server');
402
			}
403
		}
404
405
		return $this->result;
406
	}
407
408
	/**
409
	 * fetches all groups from LDAP and adds them to the result object
410
	 *
411
	 * @param string $dbKey
412
	 * @param string $confKey
413
	 * @return array $groupEntries
414
	 * @throws \Exception
415
	 */
416
	public function fetchGroups($dbKey, $confKey) {
417
		$obclasses = array('posixGroup', 'group', 'zimbraDistributionList', 'groupOfNames');
418
419
		$filterParts = array();
420
		foreach($obclasses as $obclass) {
421
			$filterParts[] = 'objectclass='.$obclass;
422
		}
423
		//we filter for everything
424
		//- that looks like a group and
425
		//- has the group display name set
426
		$filter = $this->access->combineFilterWithOr($filterParts);
427
		$filter = $this->access->combineFilterWithAnd(array($filter, 'cn=*'));
428
429
		$groupNames = array();
430
		$groupEntries = array();
431
		$limit = 400;
432
		$offset = 0;
433
		do {
434
			// we need to request dn additionally here, otherwise memberOf
435
			// detection will fail later
436
			$result = $this->access->searchGroups($filter, array('cn', 'dn'), $limit, $offset);
437
			foreach($result as $item) {
438
				if(!isset($item['cn']) && !is_array($item['cn']) && !isset($item['cn'][0])) {
439
					// just in case - no issue known
440
					continue;
441
				}
442
				$groupNames[] = $item['cn'][0];
443
				$groupEntries[] = $item;
444
			}
445
			$offset += $limit;
446
		} while ($this->access->hasMoreResults());
447
448 View Code Duplication
		if(count($groupNames) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
449
			natsort($groupNames);
450
			$this->result->addOptions($dbKey, array_values($groupNames));
451
		} else {
452
			throw new \Exception(self::$l->t('Could not find the desired feature'));
453
		}
454
455
		$setFeatures = $this->configuration->$confKey;
456
		if(is_array($setFeatures) && !empty($setFeatures)) {
457
			//something is already configured? pre-select it.
458
			$this->result->addChange($dbKey, $setFeatures);
459
		}
460
		return $groupEntries;
461
	}
462
463
	public function determineGroupMemberAssoc() {
464
		if(!$this->checkRequirements(array('ldapHost',
465
										   'ldapPort',
466
										   'ldapGroupFilter',
467
										   ))) {
468
			return  false;
469
		}
470
		$attribute = $this->detectGroupMemberAssoc();
471
		if($attribute === false) {
472
			return false;
473
		}
474
		$this->configuration->setConfiguration(array('ldapGroupMemberAssocAttr' => $attribute));
475
		$this->result->addChange('ldap_group_member_assoc_attribute', $attribute);
476
477
		return $this->result;
478
	}
479
480
	/**
481
	 * Detects the available object classes
482
	 * @return WizardResult|false the instance's WizardResult instance
483
	 * @throws \Exception
484
	 */
485
	public function determineGroupObjectClasses() {
486
		if(!$this->checkRequirements(array('ldapHost',
487
										   'ldapPort',
488
										   'ldapBase',
489
										   ))) {
490
			return  false;
491
		}
492
		$cr = $this->getConnection();
493
		if(!$cr) {
494
			throw new \Exception('Could not connect to LDAP');
495
		}
496
497
		$obclasses = array('groupOfNames', 'group', 'posixGroup', '*');
498
		$this->determineFeature($obclasses,
499
								'objectclass',
500
								'ldap_groupfilter_objectclass',
501
								'ldapGroupFilterObjectclass',
502
								false);
503
504
		return $this->result;
505
	}
506
507
	/**
508
	 * detects the available object classes
509
	 * @return WizardResult
510
	 * @throws \Exception
511
	 */
512
	public function determineUserObjectClasses() {
513
		if(!$this->checkRequirements(array('ldapHost',
514
										   'ldapPort',
515
										   'ldapBase',
516
										   ))) {
517
			return  false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by OCA\user_ldap\lib\Wizard...ermineUserObjectClasses of type OCA\user_ldap\lib\WizardResult.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
518
		}
519
		$cr = $this->getConnection();
520
		if(!$cr) {
521
			throw new \Exception('Could not connect to LDAP');
522
		}
523
524
		$obclasses = array('inetOrgPerson', 'person', 'organizationalPerson',
525
						   'user', 'posixAccount', '*');
526
		$filter = $this->configuration->ldapUserFilter;
0 ignored issues
show
Documentation introduced by
The property ldapUserFilter does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
527
		//if filter is empty, it is probably the first time the wizard is called
528
		//then, apply suggestions.
529
		$this->determineFeature($obclasses,
530
								'objectclass',
531
								'ldap_userfilter_objectclass',
532
								'ldapUserFilterObjectclass',
533
								empty($filter));
534
535
		return $this->result;
536
	}
537
538
	/**
539
	 * @return WizardResult|false
540
	 * @throws \Exception
541
	 */
542 View Code Duplication
	public function getGroupFilter() {
543
		if(!$this->checkRequirements(array('ldapHost',
544
										   'ldapPort',
545
										   'ldapBase',
546
										   ))) {
547
			return false;
548
		}
549
		//make sure the use display name is set
550
		$displayName = $this->configuration->ldapGroupDisplayName;
0 ignored issues
show
Documentation introduced by
The property ldapGroupDisplayName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
551
		if(empty($displayName)) {
552
			$d = $this->configuration->getDefaults();
553
			$this->applyFind('ldap_group_display_name',
554
							 $d['ldap_group_display_name']);
555
		}
556
		$filter = $this->composeLdapFilter(self::LFILTER_GROUP_LIST);
557
558
		$this->applyFind('ldap_group_filter', $filter);
559
		return $this->result;
560
	}
561
562
	/**
563
	 * @return WizardResult|false
564
	 * @throws \Exception
565
	 */
566 View Code Duplication
	public function getUserListFilter() {
567
		if(!$this->checkRequirements(array('ldapHost',
568
										   'ldapPort',
569
										   'ldapBase',
570
										   ))) {
571
			return false;
572
		}
573
		//make sure the use display name is set
574
		$displayName = $this->configuration->ldapUserDisplayName;
0 ignored issues
show
Documentation introduced by
The property ldapUserDisplayName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
575
		if(empty($displayName)) {
576
			$d = $this->configuration->getDefaults();
577
			$this->applyFind('ldap_display_name', $d['ldap_display_name']);
578
		}
579
		$filter = $this->composeLdapFilter(self::LFILTER_USER_LIST);
580
		if(!$filter) {
581
			throw new \Exception('Cannot create filter');
582
		}
583
584
		$this->applyFind('ldap_userlist_filter', $filter);
585
		return $this->result;
586
	}
587
588
	/**
589
	 * @return bool|WizardResult
590
	 * @throws \Exception
591
	 */
592
	public function getUserLoginFilter() {
593 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
594
										   'ldapPort',
595
										   'ldapBase',
596
										   'ldapUserFilter',
597
										   ))) {
598
			return false;
599
		}
600
601
		$filter = $this->composeLdapFilter(self::LFILTER_LOGIN);
602
		if(!$filter) {
603
			throw new \Exception('Cannot create filter');
604
		}
605
606
		$this->applyFind('ldap_login_filter', $filter);
607
		return $this->result;
608
	}
609
610
	/**
611
	 * @return bool|WizardResult
612
	 * @param string $loginName
613
	 * @throws \Exception
614
	 */
615
	public function testLoginName($loginName) {
616 View Code Duplication
		if(!$this->checkRequirements(array('ldapHost',
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
617
			'ldapPort',
618
			'ldapBase',
619
			'ldapLoginFilter',
620
		))) {
621
			return false;
622
		}
623
624
		$cr = $this->access->connection->getConnectionResource();
625
		if(!$this->ldap->isResource($cr)) {
626
			throw new \Exception('connection error');
627
		}
628
629
		if(mb_strpos($this->access->connection->ldapLoginFilter, '%uid', 0, 'UTF-8')
0 ignored issues
show
Documentation introduced by
The property ldapLoginFilter does not exist on object<OCA\user_ldap\lib\Connection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
630
			=== false) {
631
			throw new \Exception('missing placeholder');
632
		}
633
634
		$users = $this->access->countUsersByLoginName($loginName);
635
		if($this->ldap->errno($cr) !== 0) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison !== seems to always evaluate to true as the types of $this->ldap->errno($cr) (string) and 0 (integer) can never be identical. Maybe you want to use a loose comparison != instead?
Loading history...
636
			throw new \Exception($this->ldap->error($cr));
637
		}
638
		$filter = str_replace('%uid', $loginName, $this->access->connection->ldapLoginFilter);
0 ignored issues
show
Documentation introduced by
The property ldapLoginFilter does not exist on object<OCA\user_ldap\lib\Connection>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
639
		$this->result->addChange('ldap_test_loginname', $users);
640
		$this->result->addChange('ldap_test_effective_filter', $filter);
641
		return $this->result;
642
	}
643
644
	/**
645
	 * Tries to determine the port, requires given Host, User DN and Password
646
	 * @return WizardResult|false WizardResult on success, false otherwise
647
	 * @throws \Exception
648
	 */
649
	public function guessPortAndTLS() {
650
		if(!$this->checkRequirements(array('ldapHost',
651
										   ))) {
652
			return false;
653
		}
654
		$this->checkHost();
655
		$portSettings = $this->getPortSettingsToTry();
656
657
		if(!is_array($portSettings)) {
658
			throw new \Exception(print_r($portSettings, true));
659
		}
660
661
		//proceed from the best configuration and return on first success
662
		foreach($portSettings as $setting) {
663
			$p = $setting['port'];
664
			$t = $setting['tls'];
665
			\OCP\Util::writeLog('user_ldap', 'Wiz: trying port '. $p . ', TLS '. $t, \OCP\Util::DEBUG);
666
			//connectAndBind may throw Exception, it needs to be catched by the
667
			//callee of this method
668
669
			try {
670
				$settingsFound = $this->connectAndBind($p, $t);
671
			} catch (\Exception $e) {
672
				// any reply other than -1 (= cannot connect) is already okay,
673
				// because then we found the server
674
				// unavailable startTLS returns -11
675
				if($e->getCode() > 0) {
676
					$settingsFound = true;
677
				} else {
678
					throw $e;
679
				}
680
			}
681
682
			if ($settingsFound === true) {
683
				$config = array(
684
					'ldapPort' => $p,
685
					'ldapTLS' => intval($t)
686
				);
687
				$this->configuration->setConfiguration($config);
688
				\OCP\Util::writeLog('user_ldap', 'Wiz: detected Port ' . $p, \OCP\Util::DEBUG);
689
				$this->result->addChange('ldap_port', $p);
690
				return $this->result;
691
			}
692
		}
693
694
		//custom port, undetected (we do not brute force)
695
		return false;
696
	}
697
698
	/**
699
	 * tries to determine a base dn from User DN or LDAP Host
700
	 * @return WizardResult|false WizardResult on success, false otherwise
701
	 */
702
	public function guessBaseDN() {
703
		if(!$this->checkRequirements(array('ldapHost',
704
										   'ldapPort',
705
										   ))) {
706
			return false;
707
		}
708
709
		//check whether a DN is given in the agent name (99.9% of all cases)
710
		$base = null;
711
		$i = stripos($this->configuration->ldapAgentName, 'dc=');
0 ignored issues
show
Documentation introduced by
The property ldapAgentName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
712
		if($i !== false) {
713
			$base = substr($this->configuration->ldapAgentName, $i);
0 ignored issues
show
Documentation introduced by
The property ldapAgentName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
714
			if($this->testBaseDN($base)) {
715
				$this->applyFind('ldap_base', $base);
716
				return $this->result;
717
			}
718
		}
719
720
		//this did not help :(
721
		//Let's see whether we can parse the Host URL and convert the domain to
722
		//a base DN
723
		$helper = new Helper();
724
		$domain = $helper->getDomainFromURL($this->configuration->ldapHost);
0 ignored issues
show
Documentation introduced by
The property ldapHost does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
725
		if(!$domain) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $domain of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
726
			return false;
727
		}
728
729
		$dparts = explode('.', $domain);
730
		while(count($dparts) > 0) {
731
			$base2 = 'dc=' . implode(',dc=', $dparts);
732
			if ($base !== $base2 && $this->testBaseDN($base2)) {
733
				$this->applyFind('ldap_base', $base2);
734
				return $this->result;
735
			}
736
			array_shift($dparts);
737
		}
738
739
		return false;
740
	}
741
742
	/**
743
	 * sets the found value for the configuration key in the WizardResult
744
	 * as well as in the Configuration instance
745
	 * @param string $key the configuration key
746
	 * @param string $value the (detected) value
747
	 *
748
	 */
749 2
	private function applyFind($key, $value) {
750 2
		$this->result->addChange($key, $value);
751 2
		$this->configuration->setConfiguration(array($key => $value));
752 2
	}
753
754
	/**
755
	 * Checks, whether a port was entered in the Host configuration
756
	 * field. In this case the port will be stripped off, but also stored as
757
	 * setting.
758
	 */
759
	private function checkHost() {
760
		$host = $this->configuration->ldapHost;
0 ignored issues
show
Documentation introduced by
The property ldapHost does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
761
		$hostInfo = parse_url($host);
762
763
		//removes Port from Host
764
		if(is_array($hostInfo) && isset($hostInfo['port'])) {
765
			$port = $hostInfo['port'];
766
			$host = str_replace(':'.$port, '', $host);
767
			$this->applyFind('ldap_host', $host);
768
			$this->applyFind('ldap_port', $port);
769
		}
770
	}
771
772
	/**
773
	 * tries to detect the group member association attribute which is
774
	 * one of 'uniqueMember', 'memberUid', 'member'
775
	 * @return string|false, string with the attribute name, false on error
0 ignored issues
show
Documentation introduced by
The doc-type string|false, could not be parsed: Expected "|" or "end of type", but got "," at position 12. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
776
	 * @throws \Exception
777
	 */
778
	private function detectGroupMemberAssoc() {
779
		$possibleAttrs = array('uniqueMember', 'memberUid', 'member');
780
		$filter = $this->configuration->ldapGroupFilter;
0 ignored issues
show
Documentation introduced by
The property ldapGroupFilter does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
781
		if(empty($filter)) {
782
			return false;
783
		}
784
		$cr = $this->getConnection();
785
		if(!$cr) {
786
			throw new \Exception('Could not connect to LDAP');
787
		}
788
		$base = $this->configuration->ldapBase[0];
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
789
		$rr = $this->ldap->search($cr, $base, $filter, $possibleAttrs, 0, 1000);
790
		if(!$this->ldap->isResource($rr)) {
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...possibleAttrs, 0, 1000) on line 789 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::isResource() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
791
			return false;
792
		}
793
		$er = $this->ldap->firstEntry($cr, $rr);
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...possibleAttrs, 0, 1000) on line 789 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::firstEntry() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
794
		while(is_resource($er)) {
795
			$this->ldap->getDN($cr, $er);
796
			$attrs = $this->ldap->getAttributes($cr, $er);
797
			$result = array();
798
			$possibleAttrsCount = count($possibleAttrs);
799
			for($i = 0; $i < $possibleAttrsCount; $i++) {
800
				if(isset($attrs[$possibleAttrs[$i]])) {
801
					$result[$possibleAttrs[$i]] = $attrs[$possibleAttrs[$i]]['count'];
802
				}
803
			}
804
			if(!empty($result)) {
805
				natsort($result);
806
				return key($result);
807
			}
808
809
			$er = $this->ldap->nextEntry($cr, $er);
810
		}
811
812
		return false;
813
	}
814
815
	/**
816
	 * Checks whether for a given BaseDN results will be returned
817
	 * @param string $base the BaseDN to test
818
	 * @return bool true on success, false otherwise
819
	 * @throws \Exception
820
	 */
821
	private function testBaseDN($base) {
822
		$cr = $this->getConnection();
823
		if(!$cr) {
824
			throw new \Exception('Could not connect to LDAP');
825
		}
826
827
		//base is there, let's validate it. If we search for anything, we should
828
		//get a result set > 0 on a proper base
829
		$rr = $this->ldap->search($cr, $base, 'objectClass=*', array('dn'), 0, 1);
830
		if(!$this->ldap->isResource($rr)) {
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...=*', array('dn'), 0, 1) on line 829 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::isResource() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
831
			$errorNo  = $this->ldap->errno($cr);
832
			$errorMsg = $this->ldap->error($cr);
833
			\OCP\Util::writeLog('user_ldap', 'Wiz: Could not search base '.$base.
834
							' Error '.$errorNo.': '.$errorMsg, \OCP\Util::INFO);
835
			return false;
836
		}
837
		$entries = $this->ldap->countEntries($cr, $rr);
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...=*', array('dn'), 0, 1) on line 829 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::countEntries() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
838
		return ($entries !== false) && ($entries > 0);
839
	}
840
841
	/**
842
	 * Checks whether the server supports memberOf in LDAP Filter.
843
	 * Note: at least in OpenLDAP, availability of memberOf is dependent on
844
	 * a configured objectClass. I.e. not necessarily for all available groups
845
	 * memberOf does work.
846
	 *
847
	 * @return bool true if it does, false otherwise
848
	 * @throws \Exception
849
	 */
850
	private function testMemberOf() {
851
		$cr = $this->getConnection();
852
		if(!$cr) {
853
			throw new \Exception('Could not connect to LDAP');
854
		}
855
		$result = $this->access->countUsers('memberOf=*', array('memberOf'), 1);
856
		if(is_int($result) &&  $result > 0) {
857
			return true;
858
		}
859
		return false;
860
	}
861
862
	/**
863
	 * creates an LDAP Filter from given configuration
864
	 * @param integer $filterType int, for which use case the filter shall be created
865
	 * can be any of self::LFILTER_USER_LIST, self::LFILTER_LOGIN or
866
	 * self::LFILTER_GROUP_LIST
867
	 * @return string|false string with the filter on success, false otherwise
868
	 * @throws \Exception
869
	 */
870
	private function composeLdapFilter($filterType) {
871
		$filter = '';
872
		$parts = 0;
873
		switch ($filterType) {
874
			case self::LFILTER_USER_LIST:
875
				$objcs = $this->configuration->ldapUserFilterObjectclass;
0 ignored issues
show
Documentation introduced by
The property ldapUserFilterObjectclass does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
876
				//glue objectclasses
877 View Code Duplication
				if(is_array($objcs) && count($objcs) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
878
					$filter .= '(|';
879
					foreach($objcs as $objc) {
880
						$filter .= '(objectclass=' . $objc . ')';
881
					}
882
					$filter .= ')';
883
					$parts++;
884
				}
885
				//glue group memberships
886
				if($this->configuration->hasMemberOfFilterSupport) {
0 ignored issues
show
Documentation introduced by
The property hasMemberOfFilterSupport does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
887
					$cns = $this->configuration->ldapUserFilterGroups;
0 ignored issues
show
Documentation introduced by
The property ldapUserFilterGroups does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
888
					if(is_array($cns) && count($cns) > 0) {
889
						$filter .= '(|';
890
						$cr = $this->getConnection();
891
						if(!$cr) {
892
							throw new \Exception('Could not connect to LDAP');
893
						}
894
						$base = $this->configuration->ldapBase[0];
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
895
						foreach($cns as $cn) {
896
							$rr = $this->ldap->search($cr, $base, 'cn=' . $cn, array('dn', 'primaryGroupToken'));
897
							if(!$this->ldap->isResource($rr)) {
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,..., 'primaryGroupToken')) on line 896 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::isResource() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
898
								continue;
899
							}
900
							$er = $this->ldap->firstEntry($cr, $rr);
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,..., 'primaryGroupToken')) on line 896 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::firstEntry() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
901
							$attrs = $this->ldap->getAttributes($cr, $er);
902
							$dn = $this->ldap->getDN($cr, $er);
903
							if(empty($dn)) {
904
								continue;
905
							}
906
							$filterPart = '(memberof=' . $dn . ')';
907
							if(isset($attrs['primaryGroupToken'])) {
908
								$pgt = $attrs['primaryGroupToken'][0];
909
								$primaryFilterPart = '(primaryGroupID=' . $pgt .')';
910
								$filterPart = '(|' . $filterPart . $primaryFilterPart . ')';
911
							}
912
							$filter .= $filterPart;
913
						}
914
						$filter .= ')';
915
					}
916
					$parts++;
917
				}
918
				//wrap parts in AND condition
919
				if($parts > 1) {
920
					$filter = '(&' . $filter . ')';
921
				}
922
				if(empty($filter)) {
923
					$filter = '(objectclass=*)';
924
				}
925
				break;
926
927
			case self::LFILTER_GROUP_LIST:
928
				$objcs = $this->configuration->ldapGroupFilterObjectclass;
0 ignored issues
show
Documentation introduced by
The property ldapGroupFilterObjectclass does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
929
				//glue objectclasses
930 View Code Duplication
				if(is_array($objcs) && count($objcs) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
931
					$filter .= '(|';
932
					foreach($objcs as $objc) {
933
						$filter .= '(objectclass=' . $objc . ')';
934
					}
935
					$filter .= ')';
936
					$parts++;
937
				}
938
				//glue group memberships
939
				$cns = $this->configuration->ldapGroupFilterGroups;
0 ignored issues
show
Documentation introduced by
The property ldapGroupFilterGroups does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
940
				if(is_array($cns) && count($cns) > 0) {
941
					$filter .= '(|';
942
					$base = $this->configuration->ldapBase[0];
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Unused Code introduced by
$base is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
943
					foreach($cns as $cn) {
944
						$filter .= '(cn=' . $cn . ')';
945
					}
946
					$filter .= ')';
947
				}
948
				$parts++;
949
				//wrap parts in AND condition
950
				if($parts > 1) {
951
					$filter = '(&' . $filter . ')';
952
				}
953
				break;
954
955
			case self::LFILTER_LOGIN:
956
				$ulf = $this->configuration->ldapUserFilter;
0 ignored issues
show
Documentation introduced by
The property ldapUserFilter does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
957
				$loginpart = '=%uid';
958
				$filterUsername = '';
959
				$userAttributes = $this->getUserAttributes();
960
				$userAttributes = array_change_key_case(array_flip($userAttributes));
961
				$parts = 0;
962
963
				if($this->configuration->ldapLoginFilterUsername === '1') {
0 ignored issues
show
Documentation introduced by
The property ldapLoginFilterUsername does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
964
					$attr = '';
965
					if(isset($userAttributes['uid'])) {
966
						$attr = 'uid';
967
					} else if(isset($userAttributes['samaccountname'])) {
968
						$attr = 'samaccountname';
969
					} else if(isset($userAttributes['cn'])) {
970
						//fallback
971
						$attr = 'cn';
972
					}
973
					if(!empty($attr)) {
974
						$filterUsername = '(' . $attr . $loginpart . ')';
975
						$parts++;
976
					}
977
				}
978
979
				$filterEmail = '';
980
				if($this->configuration->ldapLoginFilterEmail === '1') {
0 ignored issues
show
Documentation introduced by
The property ldapLoginFilterEmail does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
981
					$filterEmail = '(|(mailPrimaryAddress=%uid)(mail=%uid))';
982
					$parts++;
983
				}
984
985
				$filterAttributes = '';
986
				$attrsToFilter = $this->configuration->ldapLoginFilterAttributes;
0 ignored issues
show
Documentation introduced by
The property ldapLoginFilterAttributes does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
987
				if(is_array($attrsToFilter) && count($attrsToFilter) > 0) {
988
					$filterAttributes = '(|';
989
					foreach($attrsToFilter as $attribute) {
990
						$filterAttributes .= '(' . $attribute . $loginpart . ')';
991
					}
992
					$filterAttributes .= ')';
993
					$parts++;
994
				}
995
996
				$filterLogin = '';
997
				if($parts > 1) {
998
					$filterLogin = '(|';
999
				}
1000
				$filterLogin .= $filterUsername;
1001
				$filterLogin .= $filterEmail;
1002
				$filterLogin .= $filterAttributes;
1003
				if($parts > 1) {
1004
					$filterLogin .= ')';
1005
				}
1006
1007
				$filter = '(&'.$ulf.$filterLogin.')';
1008
				break;
1009
		}
1010
1011
		\OCP\Util::writeLog('user_ldap', 'Wiz: Final filter '.$filter, \OCP\Util::DEBUG);
1012
1013
		return $filter;
1014
	}
1015
1016
	/**
1017
	 * Connects and Binds to an LDAP Server
1018
	 * @param int $port the port to connect with
1019
	 * @param bool $tls whether startTLS is to be used
1020
	 * @param bool $ncc
1021
	 * @return bool
1022
	 * @throws \Exception
1023
	 */
1024
	private function connectAndBind($port = 389, $tls = false, $ncc = false) {
1025
		if($ncc) {
1026
			//No certificate check
1027
			//FIXME: undo afterwards
1028
			putenv('LDAPTLS_REQCERT=never');
1029
		}
1030
1031
		//connect, does not really trigger any server communication
1032
		\OCP\Util::writeLog('user_ldap', 'Wiz: Checking Host Info ', \OCP\Util::DEBUG);
1033
		$host = $this->configuration->ldapHost;
0 ignored issues
show
Documentation introduced by
The property ldapHost does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1034
		$hostInfo = parse_url($host);
1035
		if(!$hostInfo) {
1036
			throw new \Exception($this->l->t('Invalid Host'));
1037
		}
1038
		if(isset($hostInfo['scheme'])) {
1039
			if(isset($hostInfo['port'])) {
1040
				//problem
1041
			} else {
1042
				$host .= ':' . $port;
1043
			}
1044
		}
1045
		\OCP\Util::writeLog('user_ldap', 'Wiz: Attempting to connect ', \OCP\Util::DEBUG);
1046
		$cr = $this->ldap->connect($host, $port);
1047
		if(!is_resource($cr)) {
1048
			throw new \Exception($this->l->t('Invalid Host'));
1049
		}
1050
1051
		\OCP\Util::writeLog('user_ldap', 'Wiz: Setting LDAP Options ', \OCP\Util::DEBUG);
1052
		//set LDAP options
1053
		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1054
		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1055
		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1056
1057
		try {
1058
			if($tls) {
1059
				$isTlsWorking = @$this->ldap->startTls($cr);
1060
				if(!$isTlsWorking) {
1061
					return false;
1062
				}
1063
			}
1064
1065
			\OCP\Util::writeLog('user_ldap', 'Wiz: Attemping to Bind ', \OCP\Util::DEBUG);
1066
			//interesting part: do the bind!
1067
			$login = $this->ldap->bind($cr,
1068
				$this->configuration->ldapAgentName,
0 ignored issues
show
Documentation introduced by
The property ldapAgentName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1069
				$this->configuration->ldapAgentPassword
0 ignored issues
show
Documentation introduced by
The property ldapAgentPassword does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1070
			);
1071
			$errNo = $this->ldap->errno($cr);
1072
			$error = ldap_error($cr);
1073
			$this->ldap->unbind($cr);
1074
		} catch(ServerNotAvailableException $e) {
1075
			return false;
1076
		}
1077
1078
		if($login === true) {
1079
			$this->ldap->unbind($cr);
1080
			if($ncc) {
1081
				throw new \Exception('Certificate cannot be validated.');
1082
			}
1083
			\OCP\Util::writeLog('user_ldap', 'Wiz: Bind successful to Port '. $port . ' TLS ' . intval($tls), \OCP\Util::DEBUG);
1084
			return true;
1085
		}
1086
1087
		if($errNo === -1 || ($errNo === 2 && $ncc)) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $errNo (string) and -1 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $errNo (string) and 2 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1088
			//host, port or TLS wrong
1089
			return false;
1090
		} else if ($errNo === 2) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $errNo (string) and 2 (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
1091
			return $this->connectAndBind($port, $tls, true);
1092
		}
1093
		throw new \Exception($error, $errNo);
1094
	}
1095
1096
	/**
1097
	 * checks whether a valid combination of agent and password has been
1098
	 * provided (either two values or nothing for anonymous connect)
1099
	 * @return bool, true if everything is fine, false otherwise
0 ignored issues
show
Documentation introduced by
The doc-type bool, could not be parsed: Expected "|" or "end of type", but got "," at position 4. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1100
	 */
1101 4
	private function checkAgentRequirements() {
1102 4
		$agent = $this->configuration->ldapAgentName;
0 ignored issues
show
Documentation introduced by
The property ldapAgentName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1103 4
		$pwd = $this->configuration->ldapAgentPassword;
0 ignored issues
show
Documentation introduced by
The property ldapAgentPassword does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1104
1105 4
		return ( (!empty($agent) && !empty($pwd))
1106 4
		       || (empty($agent) &&  empty($pwd)));
1107
	}
1108
1109
	/**
1110
	 * @param array $reqs
1111
	 * @return bool
1112
	 */
1113 4
	private function checkRequirements($reqs) {
1114 4
		$this->checkAgentRequirements();
0 ignored issues
show
Unused Code introduced by
The call to the method OCA\user_ldap\lib\Wizard::checkAgentRequirements() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
1115 4
		foreach($reqs as $option) {
1116 4
			$value = $this->configuration->$option;
1117 4
			if(empty($value)) {
1118
				return false;
1119
			}
1120 4
		}
1121 4
		return true;
1122
	}
1123
1124
	/**
1125
	 * does a cumulativeSearch on LDAP to get different values of a
1126
	 * specified attribute
1127
	 * @param string[] $filters array, the filters that shall be used in the search
1128
	 * @param string $attr the attribute of which a list of values shall be returned
1129
	 * @param int $dnReadLimit the amount of how many DNs should be analyzed.
1130
	 * The lower, the faster
1131
	 * @param string $maxF string. if not null, this variable will have the filter that
1132
	 * yields most result entries
1133
	 * @return array|false an array with the values on success, false otherwise
1134
	 */
1135 3
	public function cumulativeSearchOnAttribute($filters, $attr, $dnReadLimit = 3, &$maxF = null) {
1136 3
		$dnRead = array();
1137 3
		$foundItems = array();
1138 3
		$maxEntries = 0;
1139 3
		if(!is_array($this->configuration->ldapBase)
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1140 3
		   || !isset($this->configuration->ldapBase[0])) {
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1141
			return false;
1142
		}
1143 3
		$base = $this->configuration->ldapBase[0];
0 ignored issues
show
Documentation introduced by
The property ldapBase does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1144 3
		$cr = $this->getConnection();
1145 3
		if(!$this->ldap->isResource($cr)) {
1146
			return false;
1147
		}
1148 3
		$lastFilter = null;
1149 3
		if(isset($filters[count($filters)-1])) {
1150 3
			$lastFilter = $filters[count($filters)-1];
1151 3
		}
1152 3
		foreach($filters as $filter) {
1153 3
			if($lastFilter === $filter && count($foundItems) > 0) {
1154
				//skip when the filter is a wildcard and results were found
1155 3
				continue;
1156
			}
1157
			// 20k limit for performance and reason
1158 3
			$rr = $this->ldap->search($cr, $base, $filter, array($attr), 0, 20000);
1159 3
			if(!$this->ldap->isResource($rr)) {
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...array($attr), 0, 20000) on line 1158 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::isResource() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1160
				continue;
1161
			}
1162 3
			$entries = $this->ldap->countEntries($cr, $rr);
0 ignored issues
show
Security Bug introduced by
It seems like $rr defined by $this->ldap->search($cr,...array($attr), 0, 20000) on line 1158 can also be of type false; however, OCA\user_ldap\lib\ILDAPWrapper::countEntries() does only seem to accept resource, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1163 3
			$getEntryFunc = 'firstEntry';
1164 3
			if(($entries !== false) && ($entries > 0)) {
1165 3
				if(!is_null($maxF) && $entries > $maxEntries) {
1166
					$maxEntries = $entries;
1167
					$maxF = $filter;
1168
				}
1169 3
				$dnReadCount = 0;
1170
				do {
1171 3
					$entry = $this->ldap->$getEntryFunc($cr, $rr);
1172 3
					$getEntryFunc = 'nextEntry';
1173 3
					if(!$this->ldap->isResource($entry)) {
1174 2
						continue 2;
1175
					}
1176 3
					$rr = $entry; //will be expected by nextEntry next round
1177 3
					$attributes = $this->ldap->getAttributes($cr, $entry);
1178 3
					$dn = $this->ldap->getDN($cr, $entry);
1179 3
					if($dn === false || in_array($dn, $dnRead)) {
1180 1
						continue;
1181
					}
1182 3
					$newItems = array();
1183 3
					$state = $this->getAttributeValuesFromEntry($attributes,
0 ignored issues
show
Documentation introduced by
$attributes is of type array, but the function expects a resource.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1184 3
																$attr,
1185 3
																$newItems);
1186 3
					$dnReadCount++;
1187 3
					$foundItems = array_merge($foundItems, $newItems);
1188 3
					$this->resultCache[$dn][$attr] = $newItems;
1189 3
					$dnRead[] = $dn;
1190
				} while(($state === self::LRESULT_PROCESSED_SKIP
0 ignored issues
show
Bug introduced by
The variable $state does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1191 3
						|| $this->ldap->isResource($entry))
1192 3
						&& ($dnReadLimit === 0 || $dnReadCount < $dnReadLimit));
1193 1
			}
1194 3
		}
1195
1196 3
		return array_unique($foundItems);
1197
	}
1198
1199
	/**
1200
	 * determines if and which $attr are available on the LDAP server
1201
	 * @param string[] $objectclasses the objectclasses to use as search filter
1202
	 * @param string $attr the attribute to look for
1203
	 * @param string $dbkey the dbkey of the setting the feature is connected to
1204
	 * @param string $confkey the confkey counterpart for the $dbkey as used in the
1205
	 * Configuration class
1206
	 * @param bool $po whether the objectClass with most result entries
1207
	 * shall be pre-selected via the result
1208
	 * @return array|false list of found items.
1209
	 * @throws \Exception
1210
	 */
1211
	private function determineFeature($objectclasses, $attr, $dbkey, $confkey, $po = false) {
1212
		$cr = $this->getConnection();
1213
		if(!$cr) {
1214
			throw new \Exception('Could not connect to LDAP');
1215
		}
1216
		$p = 'objectclass=';
1217
		foreach($objectclasses as $key => $value) {
1218
			$objectclasses[$key] = $p.$value;
1219
		}
1220
		$maxEntryObjC = '';
1221
1222
		//how deep to dig?
1223
		//When looking for objectclasses, testing few entries is sufficient,
1224
		$dig = 3;
1225
1226
		$availableFeatures =
1227
			$this->cumulativeSearchOnAttribute($objectclasses, $attr,
1228
											   $dig, $maxEntryObjC);
1229 View Code Duplication
		if(is_array($availableFeatures)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
1230
		   && count($availableFeatures) > 0) {
1231
			natcasesort($availableFeatures);
1232
			//natcasesort keeps indices, but we must get rid of them for proper
1233
			//sorting in the web UI. Therefore: array_values
1234
			$this->result->addOptions($dbkey, array_values($availableFeatures));
1235
		} else {
1236
			throw new \Exception(self::$l->t('Could not find the desired feature'));
1237
		}
1238
1239
		$setFeatures = $this->configuration->$confkey;
1240
		if(is_array($setFeatures) && !empty($setFeatures)) {
1241
			//something is already configured? pre-select it.
1242
			$this->result->addChange($dbkey, $setFeatures);
1243
		} else if($po && !empty($maxEntryObjC)) {
1244
			//pre-select objectclass with most result entries
1245
			$maxEntryObjC = str_replace($p, '', $maxEntryObjC);
1246
			$this->applyFind($dbkey, $maxEntryObjC);
1247
			$this->result->addChange($dbkey, $maxEntryObjC);
1248
		}
1249
1250
		return $availableFeatures;
1251
	}
1252
1253
	/**
1254
	 * appends a list of values fr
1255
	 * @param resource $result the return value from ldap_get_attributes
1256
	 * @param string $attribute the attribute values to look for
1257
	 * @param array &$known new values will be appended here
1258
	 * @return int, state on of the class constants LRESULT_PROCESSED_OK,
0 ignored issues
show
Documentation introduced by
The doc-type int, could not be parsed: Expected "|" or "end of type", but got "," at position 3. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1259
	 * LRESULT_PROCESSED_INVALID or LRESULT_PROCESSED_SKIP
1260
	 */
1261 3
	private function getAttributeValuesFromEntry($result, $attribute, &$known) {
1262 3
		if(!is_array($result)
1263 3
		   || !isset($result['count'])
1264 3
		   || !$result['count'] > 0) {
1265
			return self::LRESULT_PROCESSED_INVALID;
1266
		}
1267
1268
		// strtolower on all keys for proper comparison
1269 3
		$result = \OCP\Util::mb_array_change_key_case($result);
1270 3
		$attribute = strtolower($attribute);
1271 3
		if(isset($result[$attribute])) {
1272 3
			foreach($result[$attribute] as $key => $val) {
1273 3
				if($key === 'count') {
1274
					continue;
1275
				}
1276 3
				if(!in_array($val, $known)) {
1277 3
					$known[] = $val;
1278 3
				}
1279 3
			}
1280 3
			return self::LRESULT_PROCESSED_OK;
1281
		} else {
1282
			return self::LRESULT_PROCESSED_SKIP;
1283
		}
1284
	}
1285
1286
	/**
1287
	 * @return bool|mixed
1288
	 */
1289 3
	private function getConnection() {
1290 3
		if(!is_null($this->cr)) {
1291
			return $this->cr;
1292
		}
1293
1294 3
		$host = $this->configuration->ldapHost;
0 ignored issues
show
Documentation introduced by
The property ldapHost does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1295 3
		if(strpos($host, '://') !== false) {
1296
			//ldap_connect ignores port parameter when URLs are passed
1297
			$host .= ':' . $this->configuration->ldapPort;
0 ignored issues
show
Documentation introduced by
The property ldapPort does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1298
		}
1299 3
		$cr = $this->ldap->connect($host, $this->configuration->ldapPort);
0 ignored issues
show
Documentation introduced by
The property ldapPort does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1300
1301 3
		$this->ldap->setOption($cr, LDAP_OPT_PROTOCOL_VERSION, 3);
1302 3
		$this->ldap->setOption($cr, LDAP_OPT_REFERRALS, 0);
1303 3
		$this->ldap->setOption($cr, LDAP_OPT_NETWORK_TIMEOUT, self::LDAP_NW_TIMEOUT);
1304 3
		if($this->configuration->ldapTLS === 1) {
0 ignored issues
show
Documentation introduced by
The property ldapTLS does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1305
			$this->ldap->startTls($cr);
1306
		}
1307
1308 3
		$lo = @$this->ldap->bind($cr,
1309 3
								 $this->configuration->ldapAgentName,
0 ignored issues
show
Documentation introduced by
The property ldapAgentName does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1310 3
								 $this->configuration->ldapAgentPassword);
0 ignored issues
show
Documentation introduced by
The property ldapAgentPassword does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1311 3
		if($lo === true) {
1312 3
			$this->$cr = $cr;
1313 3
			return $cr;
1314
		}
1315
1316
		return false;
1317
	}
1318
1319
	/**
1320
	 * @return array
1321
	 */
1322
	private function getDefaultLdapPortSettings() {
1323
		static $settings = array(
1324
								array('port' => 7636, 'tls' => false),
1325
								array('port' =>  636, 'tls' => false),
1326
								array('port' => 7389, 'tls' => true),
1327
								array('port' =>  389, 'tls' => true),
1328
								array('port' => 7389, 'tls' => false),
1329
								array('port' =>  389, 'tls' => false),
1330
						  );
1331
		return $settings;
1332
	}
1333
1334
	/**
1335
	 * @return array
1336
	 */
1337
	private function getPortSettingsToTry() {
1338
		//389 ← LDAP / Unencrypted or StartTLS
1339
		//636 ← LDAPS / SSL
1340
		//7xxx ← UCS. need to be checked first, because both ports may be open
1341
		$host = $this->configuration->ldapHost;
0 ignored issues
show
Documentation introduced by
The property ldapHost does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1342
		$port = intval($this->configuration->ldapPort);
0 ignored issues
show
Documentation introduced by
The property ldapPort does not exist on object<OCA\user_ldap\lib\Configuration>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1343
		$portSettings = array();
1344
1345
		//In case the port is already provided, we will check this first
1346
		if($port > 0) {
1347
			$hostInfo = parse_url($host);
1348
			if(!(is_array($hostInfo)
1349
				&& isset($hostInfo['scheme'])
1350
				&& stripos($hostInfo['scheme'], 'ldaps') !== false)) {
1351
				$portSettings[] = array('port' => $port, 'tls' => true);
1352
			}
1353
			$portSettings[] =array('port' => $port, 'tls' => false);
1354
		}
1355
1356
		//default ports
1357
		$portSettings = array_merge($portSettings,
1358
		                            $this->getDefaultLdapPortSettings());
1359
1360
		return $portSettings;
1361
	}
1362
1363
1364
}
1365