Skip to content

Commit 68b50d1

Browse files
committed
Added a command to encode a password
1 parent 5ada72e commit 68b50d1

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bundle\SecurityBundle\Command;
13+
14+
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
use Symfony\Component\Console\Question\Question;
18+
use Symfony\Component\Console\Input\InputOption;
19+
use Symfony\Component\Console\Helper\Table;
20+
21+
/**
22+
* Encode a user's password
23+
*
24+
* @author Sarah Khalil <mkhalil.sarah@gmail.com>
25+
*/
26+
class UserPasswordEncoderCommand extends ContainerAwareCommand
27+
{
28+
/**
29+
* {@inheritdoc}
30+
*/
31+
protected function configure()
32+
{
33+
$this
34+
->setName('security:encode-password')
35+
->setDescription('Encode a password.')
36+
->addOption('show-password', null, InputOption::VALUE_NONE, 'Show raw password.')
37+
->setHelp(<<<EOF
38+
The <info>%command.name%</info> command allows to encode a password using encoders
39+
that are configured in the application security.yml file.
40+
41+
EOF
42+
)
43+
;
44+
}
45+
46+
/**
47+
* {@inheritdoc}
48+
*/
49+
protected function execute(InputInterface $input, OutputInterface $output)
50+
{
51+
$passwordQuestion = $this->createPasswordQuestion($input, $output);
52+
$saltQuestion = $this->createSaltQuestion($input, $output);
53+
$userClassQuestion = $this->createUserClassQuestion($input, $output);
54+
55+
$helper = $this->getHelper('question');
56+
$password = $helper->ask($input, $output, $passwordQuestion);
57+
$salt = $helper->ask($input, $output, $saltQuestion);
58+
$output->writeln("\n <info>Encoders are configured by user type in the security.yml file.</info>");
59+
$userClass = $helper->ask($input, $output, $userClassQuestion);
60+
61+
$encoder = $this->getContainer()->get('security.encoder_factory')->getEncoder($userClass);
62+
$encodedPassword = $encoder->encodePassword($password, $salt);
63+
64+
$table = new Table($output);
65+
$table
66+
->setHeaders(array('Key', 'Value'))
67+
->addRow(array('Raw password', $input->getOption('show-password') ? $password : str_repeat('*', mb_strlen($password))))
68+
->addRow(array('Salt', $salt))
69+
->addRow(array('Encoded password', $encodedPassword))
70+
;
71+
72+
$table->render();
73+
}
74+
75+
/**
76+
* Create the password question to ask the user for the password to be encoded.
77+
*
78+
* @param InputInterface $input
79+
* @param OutputInterface $output
80+
*
81+
* @return Question
82+
*/
83+
private function createPasswordQuestion(InputInterface $input, OutputInterface $output)
84+
{
85+
$passwordQuestion = new Question('<question>Type the password you want to encode please:</question> ');
86+
87+
$passwordQuestion->setValidator(function ($value) {
88+
if (trim($value) == '') {
89+
throw new \Exception('The password must not be empty.');
90+
}
91+
92+
return $value;
93+
});
94+
$passwordQuestion->setHidden(true);
95+
$passwordQuestion->setMaxAttempts(20);
96+
97+
return $passwordQuestion;
98+
}
99+
100+
/**
101+
* Create the question that asks for the salt to perform the encoding.
102+
* If there is no provided salt, a random one is automatically generated.
103+
*
104+
* @param InputInterface $input
105+
* @param OutputInterface $output
106+
*
107+
* @return Question
108+
*/
109+
private function createSaltQuestion(InputInterface $input, OutputInterface $output)
110+
{
111+
$saltQuestion = new Question('<question>Provide a salt (if none, a salt will be generated):</question> ');
112+
113+
$saltQuestion->setValidator(function ($value) use ($output) {
114+
if (trim($value) == '') {
115+
$value = hash('sha512', $this->getContainer()->get('security.secure_random')->nextBytes(30));
116+
117+
$output->writeln("\n<comment>The salt has been generated: </comment>".$value);
118+
$output->writeln(sprintf("<comment>Make sure that your salt storage field fits this salt length: %s chars.</comment>\n", strlen($value)));
119+
}
120+
121+
return $value;
122+
});
123+
124+
return $saltQuestion;
125+
}
126+
127+
/**
128+
* Create the question that asks for the configured user class.
129+
*
130+
* @param InputInterface $input
131+
* @param OutputInterface $output
132+
*
133+
* @return Question
134+
*/
135+
private function createUserClassQuestion(InputInterface $input, OutputInterface $output)
136+
{
137+
$userClassQuestion = new Question('<question>Provide your configured user class:</question> ');
138+
$userClassQuestion->setAutocompleterValues(array('Symfony\Component\Security\Core\User\User'));
139+
$userClassQuestion->setValidator(function ($value) use ($output) {
140+
if (trim($value) == '') {
141+
$value = 'Symfony\Component\Security\Core\User\User';
142+
$output->writeln('<info>You did not provide any user class.</info> <comment>The user class used is: Symfony\Component\Security\Core\User\User</comment>');
143+
}
144+
145+
return $value;
146+
});
147+
148+
return $userClassQuestion;
149+
}
150+
}

0 commit comments

Comments
 (0)