Completed
Push — master ( fb3d48...947961 )
by Chad
02:22
created

ConfigCommand::verifyCredentials()   D

Complexity

Conditions 10
Paths 12

Size

Total Lines 42
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 4.8196
c 0
b 0
f 0
cc 10
eloc 25
nc 12
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the LdapToolsBundle package.
4
 *
5
 * (c) Chad Sikorra <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace LdapTools\Bundle\LdapToolsBundle\Command;
12
13
use LdapTools\Bundle\LdapToolsBundle\Factory\LdapFactory;
14
use LdapTools\Connection\LdapConnection;
15
use LdapTools\Connection\LdapServerPool;
16
use LdapTools\DomainConfiguration;
17
use LdapTools\Exception\LdapConnectionException;
18
use LdapTools\Operation\AuthenticationOperation;
19
use LdapTools\Operation\AuthenticationResponse;
20
use LdapTools\Utilities\LdapUtilities;
21
use Symfony\Component\Console\Command\Command;
22
use Symfony\Component\Console\Helper\QuestionHelper;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Input\InputOption;
25
use Symfony\Component\Console\Output\OutputInterface;
26
use Symfony\Component\Console\Question\ChoiceQuestion;
27
use Symfony\Component\Console\Question\ConfirmationQuestion;
28
use Symfony\Component\Console\Question\Question;
29
use Symfony\Component\Yaml\Yaml;
30
31
/**
32
 * Assists in generating the LdapTools configuration for the bundle.
33
 *
34
 * @author Chad Sikorra <[email protected]>
35
 */
36
class ConfigCommand extends Command
37
{
38
    /**
39
     * @var OutputInterface
40
     */
41
    protected $output;
42
43
    /**
44
     * @var InputInterface
45
     */
46
    protected $input;
47
48
    /**
49
     * @var QuestionHelper
50
     */
51
    protected $helper;
52
53
    /**
54
     * @var bool
55
     */
56
    protected $silent = false;
57
58
    /**
59
     * @var bool
60
     */
61
    protected $interactive = true;
62
63
    /**
64
     * @var LdapServerPool
65
     */
66
    protected $serverPool;
67
68
    /**
69
     * @var LdapFactory
70
     */
71
    protected $factory;
72
73
    /**
74
     * @param null|string $name
75
     */
76
    public function __construct($name = null)
77
    {
78
        $this->factory = new LdapFactory();
79
        parent::__construct($name);
80
    }
81
82
    /**
83
     * @param LdapServerPool $serverPool
84
     */
85
    public function setLdapServerPool(LdapServerPool $serverPool)
86
    {
87
        $this->serverPool = $serverPool;
88
    }
89
90
    /**
91
     * @param LdapFactory $factory
92
     */
93
    public function setConnectionFactory(LdapFactory $factory)
94
    {
95
        $this->factory = $factory;
96
    }
97
98
    /**
99
     * {@inheritDoc}
100
     */
101
    protected function configure()
102
    {
103
        $this
104
            ->setName('ldaptools:generate:config')
105
            ->addOption('domain', null, InputOption::VALUE_OPTIONAL, 'The LDAP domain name (ie. domain.local).')
106
            ->addOption('username', null, InputOption::VALUE_OPTIONAL, 'The LDAP username.')
107
            ->addOption('password', null, InputOption::VALUE_OPTIONAL, 'The LDAP password.')
108
            ->addOption('server', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The LDAP server to use.')
109
            ->addOption('port', null, InputOption::VALUE_OPTIONAL, 'The LDAP server port to use.', 389)
110
            ->addOption('use-tls', null, InputOption::VALUE_NONE, 'Whether or not TLS should be used for the connection.')
111
            ->addOption('use-ssl', null, InputOption::VALUE_NONE, 'Whether or not to use SSL (TLS over port 636).')
112
            ->addOption('silent', null, InputOption::VALUE_NONE, 'Only the YAML config will be displayed.')
113
            ->addOption('non-interactive', null, InputOption::VALUE_NONE, 'No prompts or questions. Requires: server/domain, username, password')
114
            ->addOption('show-config', null, InputOption::VALUE_NONE, 'Show the config at the end without prompting.')
115
            ->setDescription('Assists in generating the base LDAP YAML configuration needed for the bundle.');
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function execute(InputInterface $input, OutputInterface $output)
122
    {
123
        $config = null;
124
        $connection = null;
125
126
        $this->input = $input;
127
        $this->output = $output;
128
        $this->helper = $this->getHelper('question');
129
        $this->silent = $input->getOption('silent');
130
        $this->interactive = !$input->getOption('non-interactive');
131
        $this->serverPool = $this->serverPool ?: new LdapServerPool(new DomainConfiguration(''));
132
133
        $domain = trim($input->getOption('domain'));
134
        $server = $input->getOption('server');
135
        $port = (int) $input->getOption('port');
136
        $username = trim($input->getOption('username'));
137
        $password = $input->getOption('password');
138
        $useTls = $input->getOption('use-tls');
139
        $useSsl = $input->getOption('use-ssl');
140
        $this->validateOptions($server, $domain, $username, $password, $useTls, $useSsl);
141
142
        while (!$connection) {
143
            $config = $this->getConfigForDomain($server, $domain, $port, $useTls, $useSsl);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $config is correct as $this->getConfigForDomai...port, $useTls, $useSsl) (which targets LdapTools\Bundle\LdapToo...d::getConfigForDomain()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
144
            if (!$config && (!$this->interactive || !$this->confirm('<question>Try again? [Y/n]: </question>'))) {
145
                return 1;
146
            } elseif (!$config) {
147
                continue;
148
            }
149
            $connection = $this->getLdapConnection($config);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $connection is correct as $this->getLdapConnection($config) (which targets LdapTools\Bundle\LdapToo...nd::getLdapConnection()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
150
            if (!$connection && (!$this->interactive || !$this->confirm('<question>Try again? [Y/n]: </question>'))) {
151
                return 1;
152
            }
153
        }
154
        if (!$useTls && !$useSsl && $this->interactive) {
155
            while (!$this->chooseEncryption($connection)) {
156
                if ($this->confirm('<question>Continue without encryption? [Y/n]: </question>')) {
157
                    break;
158
                }
159
            }
160
        }
161
162
        while (!$this->verifyCredentials($connection, $username, $password)) {
163
            if (!$this->confirm('<question>Try a different username/password? [Y/n]: </question>')) {
164
                return 1;
165
            }
166
            $username = null;
167
            $password = null;
168
        }
169
170
        $this->askAndShowConfig($config, $input, $output);
0 ignored issues
show
Documentation introduced by
$config is of type null, but the function expects a object<LdapTools\DomainConfiguration>.

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...
171
172
        return 0;
173
    }
174
175
    /**
176
     * @param string $server
177
     * @param string $domain
178
     * @param string $username
179
     * @param string $password
180
     * @param bool $useTls
181
     * @param bool $useSsl
182
     */
183
    protected function validateOptions($server, $domain, $username, $password, $useTls, $useSsl)
184
    {
185
        if ($useTls && $useSsl) {
186
            throw new \LogicException('You cannot use both the ssl and tls option. Generally you want --use-tls.');
187
        }
188
        if (!$this->interactive && !$server && !$domain) {
189
            throw new \LogicException('You must enter a server or domain when not in interactive mode.');
190
        }
191
        if (!$this->interactive && (!$username || !$password)) {
192
            throw new \LogicException('You must enter a username and password when not in interactive mode.');
193
        }
194
    }
195
196
    /**
197
     * @param string|null $server
198
     * @param string|null $domain
199
     * @param int|null $port
200
     * @param bool $useTls
201
     * @param bool $useSsl
202
     * @return DomainConfiguration|null
203
     */
204
    protected function getConfigForDomain($server, $domain, $port, $useTls, $useSsl)
205
    {
206
        $config = ($this->factory->getConfig($domain))
207
            ->setLazyBind(true)
208
            ->setUseTls($useTls)
209
            ->setUseSsl($useSsl);
210
        $config = $this->setServerOrDomain($config, $server, $domain);
211
        if ($port) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $port of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

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

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
212
            $config->setPort($port);
213
        }
214
        $this->serverPool->setConfig($config);
0 ignored issues
show
Bug introduced by
It seems like $config defined by $this->setServerOrDomain...nfig, $server, $domain) on line 210 can be null; however, LdapTools\Connection\LdapServerPool::setConfig() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
215
216
        try {
217
            $config->setServers([$this->serverPool->getServer()]);
218
        } catch (LdapConnectionException $e) {
219
            if (!empty($config->getServers())) {
220
                $this->writeln(sprintf('<error>Cannot connect to LDAP server %s on port %s.</error>', $config->getServers()[0], $config->getPort()));
221
            } else {
222
                $this->writeln(sprintf('<error>Cannot find any LDAP severs for domain: %s</error>', $domain));
223
            }
224
225
            return null;
226
        }
227
        $this->writeln(sprintf('<info>Server %s is responding on port %s.</info>', $config->getServers()[0], $config->getPort()));
228
229
        return $config;
230
    }
231
232
    /**
233
     * @param DomainConfiguration $config
234
     * @param string|null $server
235
     * @param string|null $domain
236
     * @return DomainConfiguration|null
237
     */
238
    protected function setServerOrDomain(DomainConfiguration $config, $server, $domain)
239
    {
240
        while (!$domain && !$server) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $domain of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
Bug Best Practice introduced by
The expression $server of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
241
            if (!$server && $this->interactive) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $server of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
242
                $defaultServer = $this->getDefaultServerName();
243
                $server = $this->promptForResponse(
244
                    'Enter a server name '
245
                    . ($defaultServer ? "[$defaultServer]" : '(Leave empty to attempt lookup via domain name)') . ': ',
246
                    $defaultServer
247
                );
248
            }
249
            if (!$server && !$domain && $this->interactive) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $server of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
Bug Best Practice introduced by
The expression $domain of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
250
                $defaultDomain = $this->getDefaultDomainName();
251
                $domain = $this->promptForResponse('Enter a domain name' . ($defaultDomain ? " [$defaultDomain]" : '') . ': ', $defaultDomain);
252
            }
253
            if (!$domain && !$server) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $domain of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
Bug Best Practice introduced by
The expression $server of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
254
                $this->writeln('<error>You must enter a domain name or server name.</error>');
255
                if (!$this->interactive) {
256
                    return null;
257
                }
258
            }
259
        }
260
261
        if ($server) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $server of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
262
            $config->setServers(is_array($server) ? $server : [$server]);
263
        }
264
        if ($domain) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $domain of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null 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...
265
            $config->setDomainName($domain);
266
        }
267
268
        return $config;
269
    }
270
271
    /**
272
     * @param DomainConfiguration $config
273
     * @return LdapConnection|null
274
     */
275
    protected function getLdapConnection(DomainConfiguration $config)
276
    {
277
        $connection = $this->factory->getConnection($config);
278
279
        try {
280
            $rootDse = $connection->getRootDse();
281
        } catch (\Exception $e) {
282
            $this->writeln(sprintf(
283
                '<error>Unable to query the RootDSE. %s</error>',
284
                $e->getMessage()
285
            ));
286
287
            return null;
288
        }
289
290
        $baseDn = null;
0 ignored issues
show
Unused Code introduced by
$baseDn 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...
291
        if ($rootDse->has('defaultNamingContext')) {
292
            $baseDn = $rootDse->get('defaultNamingContext');
293
        } else {
294
            $contexts = $rootDse->get('namingContexts');
295
            $baseDn = is_array($contexts) ? $contexts[0] : $contexts;
296
        }
297
        $config->setBaseDn($baseDn)->setDomainName(implode('.', LdapUtilities::explodeDn($baseDn)));
298
        $this->writeln(sprintf('<info>Successfully connected to: %s</info>', $config->getDomainName()));
299
300
        return $connection;
301
    }
302
303
    /**
304
     * @param LdapConnection $connection
305
     * @param string|null $username
306
     * @param string|null $password
307
     * @return bool
308
     */
309
    protected function verifyCredentials(LdapConnection $connection, $username, $password)
310
    {
311
        if (!$username && $this->interactive) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $username of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
312
            $defaultUser = $this->getDefaultUsername();
313
            $username = $this->promptForResponse('Enter the LDAP username' . ($defaultUser ? " [$defaultUser]" : '') . ': ', $defaultUser, false, function ($value) {
314
                if (trim($value) === '') {
315
                    throw new \Exception('The username cannot be empty.');
316
                }
317
318
                return $value;
319
            });
320
        }
321
322
        $validatePassword = function ($value) {
323
            if (empty($value)) {
324
                throw new \InvalidArgumentException('The password cannot be empty.');
325
            }
326
327
            return $value;
328
        };
329
        while (!$password && $this->interactive) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $password of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null 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...
330
            $original = $this->promptForResponse(sprintf('Enter the LDAP password for %s: ', $username), null, true, $validatePassword);
331
            $verified = $this->promptForResponse('Enter the password again to confirm: ', null, true, $validatePassword);
332
            if ($original !== $verified) {
333
                $this->writeln('<error>Passwords do not match. Please enter them again.</error>');
334
            } else {
335
                $password = $verified;
336
            }
337
        }
338
        /** @var AuthenticationResponse $response */
339
        $response = $connection->execute(new AuthenticationOperation($username, $password));
340
341
        if ($response->isAuthenticated()) {
342
            $this->writeln(sprintf('<info>Successfully authenticated with user: %s</info>', $username));
343
            $connection->getConfig()->setUsername($username)->setPassword($password);
344
345
            return true;
346
        }
347
        $this->writeln(sprintf('<error>Unable to authenticate to LDAP: %s</error>', $response->getErrorMessage()));
348
349
        return false;
350
    }
351
352
    /**
353
     * @param LdapConnection $connection
354
     * @return bool
355
     */
356
    protected function chooseEncryption(LdapConnection $connection)
357
    {
358
        $question = new ChoiceQuestion(
359
            'Encryption is currently not enabled for this connection. Please make a selection [TLS]: ',
360
            ['TLS', 'SSL', 'None'],
361
            '0'
362
        );
363
        $answer = $this->helper->ask($this->input, $this->output, $question);
364
365
        if ($answer === 'None') {
366
            return true;
367
        }
368
        $useSsl = $connection->getConfig()->getUseSsl();
369
        $useTls = $connection->getConfig()->getUseTls();
370
371
        if ($answer === 'TLS') {
372
            $connection->getConfig()->setUseTls(true);
373
        } else {
374
            $connection->getConfig()->setUseSsl(true);
375
        }
376
377
        $success = false;
378
        try {
379
            // RootDSE is cached in the connection initially. Make sure to use a new connection...
380
            $success = (bool) $this->factory->getConnection($connection->getConfig())->getRootDse();
381
            $this->writeln(sprintf('<info>Connected to LDAP via %s.</info>', $answer));
382
        } catch (\Exception $e) {
383
            $this->writeln(sprintf('<error>Error connecting via %s. %s</error>', $answer, $e->getMessage()));
384
        } finally {
385
            if (!$success) {
386
                $connection->getConfig()->setUseSsl($useSsl);
387
                $connection->getConfig()->setUseTls($useTls);
388
            }
389
        }
390
391
        return $success;
392
    }
393
394
    protected function askAndShowConfig(DomainConfiguration $config, InputInterface $input, OutputInterface $output)
395
    {
396
        if ($input->getOption('show-config') || $this->confirm('<question>Show the generated config (includes password)? [Y/n]: </question>')) {
397
            $this->writeln('');
398
            $output->writeln(Yaml::dump($this->getYamlArrayFromConfig($config), 4));
399
        }
400
    }
401
402
    /**
403
     * @param DomainConfiguration $config
404
     * @return array
405
     */
406
    protected function getAllLdapServersForDomain(DomainConfiguration $config)
407
    {
408
        $server = strtolower($config->getServers()[0]);
409
        // Slice the array to 5, as it's possible for a large amount of LDAP servers...
410
        $servers = array_map('strtolower', array_slice(
411
            LdapUtilities::getLdapServersForDomain($config->getDomainName()),
412
            0,
413
            5
414
        ));
415
416
        // We want to make sure to pop the tested server to the front...
417
        $pos = array_search($server, $servers);
418
        if ($pos !== false) {
419
            unset($servers[$pos]);
420
        }
421
        // But if we have a FQDN version, prefer that...
422
        $pos = array_search($server.'.'.strtolower($config->getDomainName()), $servers);
423
        if ($pos !== false) {
424
            unset($servers[$pos]);
425
            $server .= '.'.$config->getDomainName();
426
        }
427
        array_unshift($servers, $server);
428
429
        return $servers;
430
    }
431
432
    /**
433
     * @return string|null
434
     */
435
    protected function getDefaultDomainName()
436
    {
437
        return isset($_SERVER['USERDNSDOMAIN']) ? $_SERVER['USERDNSDOMAIN'] : null;
438
    }
439
440
    /**
441
     * @return string|null
442
     */
443
    protected function getDefaultServerName()
444
    {
445
        return isset($_SERVER['LOGONSERVER']) ? ltrim($_SERVER['LOGONSERVER'], '\\') : null;
446
    }
447
448
    /**
449
     * @return string|null
450
     */
451
    protected function getDefaultUsername()
452
    {
453
        $user = null;
454
455
        if (isset($_SERVER['USERNAME'])) {
456
            $user = $_SERVER['USERNAME'];
457
        } elseif ($_SERVER['USER']) {
458
            $user = $_SERVER['USER'];
459
        }
460
461
        return $user;
462
    }
463
464
    /**
465
     * @param DomainConfiguration $config
466
     * @return array
467
     */
468
    protected function getYamlArrayFromConfig(DomainConfiguration $config)
469
    {
470
        $domainCfg = [
471
            'domain_name' => $config->getDomainName(),
472
            'base_dn' => $config->getBaseDn(),
473
            'username' => $config->getUsername(),
474
            'password' => $config->getPassword(),
475
            'servers' => $this->getAllLdapServersForDomain($config),
476
        ];
477
        if ($config->getPort() !== 389) {
478
            $domainCfg['port'] = $config->getPort();
479
        }
480
        if ($config->getUseTls()) {
481
            $domainCfg['use_tls'] = true;
482
        }
483
        if ($config->getUseSsl()) {
484
            $domainCfg['use_ssl'] = true;
485
        }
486
487
        return [
488
            'ldap_tools' => [
489
                'domains' => [
490
                    $config->getDomainName() => $domainCfg
491
                ]
492
            ]
493
        ];
494
    }
495
496
    /**
497
     * @param string $message
498
     * @param bool $default
499
     * @return bool
500
     */
501
    protected function confirm($message, $default = true)
502
    {
503
        if (!$this->interactive) {
504
            return false;
505
        }
506
507
        return $this->helper->ask($this->input, $this->output, new ConfirmationQuestion($message, $default));
508
    }
509
510
    /**
511
     * @param string $message
512
     * @param null|string $default
513
     * @param bool $hide
514
     * @param null|callable $validator
515
     * @return string
516
     */
517
    protected function promptForResponse($message, $default = null, $hide = false, $validator = null)
518
    {
519
        $question =  (new Question($message, $default))->setHidden($hide);
520
        if ($validator) {
521
            $question->setValidator($validator);
522
        }
523
524
        return $this->helper->ask($this->input, $this->output, $question);
525
    }
526
527
    /**
528
     * @param $message
529
     */
530
    protected function writeln($message)
531
    {
532
        if (!$this->silent) {
533
            $this->output->writeln($message);
534
        }
535
    }
536
}
537