aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag')
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php39
-rw-r--r--src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php4
-rw-r--r--src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php40
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig58
-rw-r--r--src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php8
-rw-r--r--src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php48
-rw-r--r--src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php94
-rw-r--r--src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php8
-rw-r--r--src/Wallabag/CoreBundle/Tests/WallabagTestCase.php2
9 files changed, 267 insertions, 34 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
index f48a9cb1..7540f756 100644
--- a/src/Wallabag/CoreBundle/Controller/ConfigController.php
+++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php
@@ -7,6 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 7use Symfony\Component\HttpFoundation\Request;
8use Wallabag\CoreBundle\Entity\Config; 8use Wallabag\CoreBundle\Entity\Config;
9use Wallabag\CoreBundle\Form\Type\ConfigType; 9use Wallabag\CoreBundle\Form\Type\ConfigType;
10use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
10 11
11class ConfigController extends Controller 12class ConfigController extends Controller
12{ 13{
@@ -14,19 +15,18 @@ class ConfigController extends Controller
14 * @param Request $request 15 * @param Request $request
15 * 16 *
16 * @Route("/config", name="config") 17 * @Route("/config", name="config")
17 *
18 * @return \Symfony\Component\HttpFoundation\Response
19 */ 18 */
20 public function indexAction(Request $request) 19 public function indexAction(Request $request)
21 { 20 {
21 $em = $this->getDoctrine()->getManager();
22 $config = $this->getConfig(); 22 $config = $this->getConfig();
23 23
24 $form = $this->createForm(new ConfigType(), $config); 24 // handle basic config detail
25 $configForm = $this->createForm(new ConfigType(), $config);
26 $configForm->handleRequest($request);
25 27
26 $form->handleRequest($request); 28 if ($configForm->isValid()) {
27 29
28 if ($form->isValid()) {
29 $em = $this->getDoctrine()->getManager();
30 $em->persist($config); 30 $em->persist($config);
31 $em->flush(); 31 $em->flush();
32 32
@@ -38,11 +38,36 @@ class ConfigController extends Controller
38 return $this->redirect($this->generateUrl('config')); 38 return $this->redirect($this->generateUrl('config'));
39 } 39 }
40 40
41 // handle changing password
42 $pwdForm = $this->createForm(new ChangePasswordType());
43 $pwdForm->handleRequest($request);
44
45 if ($pwdForm->isValid()) {
46 $user = $this->getUser();
47 $user->setPassword($pwdForm->get('new_password')->getData());
48 $em->persist($user);
49 $em->flush();
50
51 $this->get('session')->getFlashBag()->add(
52 'notice',
53 'Password updated'
54 );
55
56 return $this->redirect($this->generateUrl('config'));
57 }
58
41 return $this->render('WallabagCoreBundle:Config:index.html.twig', array( 59 return $this->render('WallabagCoreBundle:Config:index.html.twig', array(
42 'form' => $form->createView(), 60 'configForm' => $configForm->createView(),
61 'pwdForm' => $pwdForm->createView(),
43 )); 62 ));
44 } 63 }
45 64
65 /**
66 * Retrieve config for the current user.
67 * If no config were found, create a new one.
68 *
69 * @return Wallabag\CoreBundle\Entity\Config
70 */
46 private function getConfig() 71 private function getConfig()
47 { 72 {
48 $config = $this->getDoctrine() 73 $config = $this->getDoctrine()
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
index e4751f20..d99412f4 100644
--- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
+++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
@@ -18,7 +18,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
18 $userAdmin->setName('Big boss'); 18 $userAdmin->setName('Big boss');
19 $userAdmin->setEmail('bigboss@wallabag.org'); 19 $userAdmin->setEmail('bigboss@wallabag.org');
20 $userAdmin->setUsername('admin'); 20 $userAdmin->setUsername('admin');
21 $userAdmin->setPassword('test'); 21 $userAdmin->setPassword('mypassword');
22 22
23 $manager->persist($userAdmin); 23 $manager->persist($userAdmin);
24 24
@@ -28,7 +28,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
28 $bobUser->setName('Bobby'); 28 $bobUser->setName('Bobby');
29 $bobUser->setEmail('bobby@wallabag.org'); 29 $bobUser->setEmail('bobby@wallabag.org');
30 $bobUser->setUsername('bob'); 30 $bobUser->setUsername('bob');
31 $bobUser->setPassword('test'); 31 $bobUser->setPassword('mypassword');
32 32
33 $manager->persist($bobUser); 33 $manager->persist($bobUser);
34 34
diff --git a/src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php b/src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php
new file mode 100644
index 00000000..8bf4ca1e
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php
@@ -0,0 +1,40 @@
1<?php
2namespace Wallabag\CoreBundle\Form\Type;
3
4use Symfony\Component\Form\AbstractType;
5use Symfony\Component\Form\FormBuilderInterface;
6use Symfony\Component\OptionsResolver\OptionsResolverInterface;
7use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
8use Symfony\Component\Validator\Constraints;
9
10class ChangePasswordType extends AbstractType
11{
12 public function buildForm(FormBuilderInterface $builder, array $options)
13 {
14 $builder
15 ->add('old_password', 'password', array(
16 'constraints' => new UserPassword(array('message' => 'Wrong value for your current password')),
17 ))
18 ->add('new_password', 'repeated', array(
19 'type' => 'password',
20 'invalid_message' => 'The password fields must match.',
21 'required' => true,
22 'first_options' => array('label' => 'New password'),
23 'second_options' => array('label' => 'Repeat new password'),
24 'constraints' => array(
25 new Constraints\Length(array(
26 'min' => 6,
27 'minMessage' => 'Password should by at least 6 chars long'
28 )),
29 new Constraints\NotBlank()
30 )
31 ))
32 ->add('save', 'submit')
33 ;
34 }
35
36 public function getName()
37 {
38 return 'change_passwd';
39 }
40}
diff --git a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig
index 9c04ff20..94145177 100644
--- a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig
+++ b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig
@@ -7,35 +7,67 @@
7{% endblock %} 7{% endblock %}
8 8
9{% block content %} 9{% block content %}
10 <h2>Basic config</h2> 10 <h2>{% trans %}Basic config{% endtrans %}</h2>
11 11
12 <form action="{{ path('config') }}" method="post" {{ form_enctype(form) }}> 12 <form action="{{ path('config') }}" method="post" {{ form_enctype(configForm) }}>
13 {{ form_errors(form) }} 13 {{ form_errors(configForm) }}
14 14
15 <fieldset class="w500p inline"> 15 <fieldset class="w500p inline">
16 <div class="row"> 16 <div class="row">
17 {{ form_label(form.theme) }} 17 {{ form_label(configForm.theme) }}
18 {{ form_errors(form.theme) }} 18 {{ form_errors(configForm.theme) }}
19 {{ form_widget(form.theme) }} 19 {{ form_widget(configForm.theme) }}
20 </div> 20 </div>
21 </fieldset> 21 </fieldset>
22 22
23 <fieldset class="w500p inline"> 23 <fieldset class="w500p inline">
24 <div class="row"> 24 <div class="row">
25 {{ form_label(form.items_per_page) }} 25 {{ form_label(configForm.items_per_page) }}
26 {{ form_errors(form.items_per_page) }} 26 {{ form_errors(configForm.items_per_page) }}
27 {{ form_widget(form.items_per_page) }} 27 {{ form_widget(configForm.items_per_page) }}
28 </div> 28 </div>
29 </fieldset> 29 </fieldset>
30 30
31 <fieldset class="w500p inline"> 31 <fieldset class="w500p inline">
32 <div class="row"> 32 <div class="row">
33 {{ form_label(form.language) }} 33 {{ form_label(configForm.language) }}
34 {{ form_errors(form.language) }} 34 {{ form_errors(configForm.language) }}
35 {{ form_widget(form.language) }} 35 {{ form_widget(configForm.language) }}
36 </div> 36 </div>
37 </fieldset> 37 </fieldset>
38 38
39 {{ form_rest(form) }} 39 {{ form_rest(configForm) }}
40 </form>
41
42 <h2>{% trans %}Change your password{% endtrans %}</h2>
43
44 <form action="{{ path('config') }}" method="post" {{ form_enctype(pwdForm) }}>
45 {{ form_errors(pwdForm) }}
46
47 <fieldset class="w500p inline">
48 <div class="row">
49 {{ form_label(pwdForm.old_password) }}
50 {{ form_errors(pwdForm.old_password) }}
51 {{ form_widget(pwdForm.old_password) }}
52 </div>
53 </fieldset>
54
55 <fieldset class="w500p inline">
56 <div class="row">
57 {{ form_label(pwdForm.new_password.first) }}
58 {{ form_errors(pwdForm.new_password.first) }}
59 {{ form_widget(pwdForm.new_password.first) }}
60 </div>
61 </fieldset>
62
63 <fieldset class="w500p inline">
64 <div class="row">
65 {{ form_label(pwdForm.new_password.second) }}
66 {{ form_errors(pwdForm.new_password.second) }}
67 {{ form_widget(pwdForm.new_password.second) }}
68 </div>
69 </fieldset>
70
71 {{ form_rest(pwdForm) }}
40 </form> 72 </form>
41{% endblock %} 73{% endblock %}
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php b/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php
index 56f1affe..fcfe418b 100644
--- a/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php
+++ b/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php
@@ -41,10 +41,6 @@ class WallabagPasswordEncoder extends BasePasswordEncoder
41 */ 41 */
42 public function encodePassword($raw, $salt) 42 public function encodePassword($raw, $salt)
43 { 43 {
44 if (null === $this->username) {
45 throw new \LogicException('We can not check the password without a username.');
46 }
47
48 if ($this->isPasswordTooLong($raw)) { 44 if ($this->isPasswordTooLong($raw)) {
49 throw new BadCredentialsException('Invalid password.'); 45 throw new BadCredentialsException('Invalid password.');
50 } 46 }
@@ -71,6 +67,10 @@ class WallabagPasswordEncoder extends BasePasswordEncoder
71 */ 67 */
72 protected function mergePasswordAndSalt($password, $salt) 68 protected function mergePasswordAndSalt($password, $salt)
73 { 69 {
70 if (null === $this->username) {
71 throw new \LogicException('We can not check the password without a username.');
72 }
73
74 if (empty($salt)) { 74 if (empty($salt)) {
75 return $password; 75 return $password;
76 } 76 }
diff --git a/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php b/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php
new file mode 100644
index 00000000..5586f976
--- /dev/null
+++ b/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php
@@ -0,0 +1,48 @@
1<?php
2
3namespace Wallabag\CoreBundle\Security\Validator;
4
5use Symfony\Component\Security\Core\User\UserInterface;
6use Symfony\Component\Security\Core\SecurityContextInterface;
7use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
8use Symfony\Component\Validator\Constraint;
9use Symfony\Component\Validator\ConstraintValidator;
10use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
11use Symfony\Component\Validator\Exception\UnexpectedTypeException;
12use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
13
14class WallabagUserPasswordValidator extends ConstraintValidator
15{
16 private $securityContext;
17 private $encoderFactory;
18
19 public function __construct(SecurityContextInterface $securityContext, EncoderFactoryInterface $encoderFactory)
20 {
21 $this->securityContext = $securityContext;
22 $this->encoderFactory = $encoderFactory;
23 }
24
25 /**
26 * {@inheritdoc}
27 */
28 public function validate($password, Constraint $constraint)
29 {
30 if (!$constraint instanceof UserPassword) {
31 throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword');
32 }
33
34 $user = $this->securityContext->getToken()->getUser();
35
36 if (!$user instanceof UserInterface) {
37 throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.');
38 }
39
40 // give username, it's used to hash the password
41 $encoder = $this->encoderFactory->getEncoder($user);
42 $encoder->setUsername($user->getUsername());
43
44 if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
45 $this->context->addViolation($constraint->message);
46 }
47 }
48}
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php
index 30809a04..4aceed15 100644
--- a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php
+++ b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php
@@ -26,7 +26,8 @@ class ConfigControllerTest extends WallabagTestCase
26 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 26 $this->assertEquals(200, $client->getResponse()->getStatusCode());
27 27
28 $this->assertCount(1, $crawler->filter('input[type=number]')); 28 $this->assertCount(1, $crawler->filter('input[type=number]'));
29 $this->assertCount(1, $crawler->filter('button[type=submit]')); 29 $this->assertCount(1, $crawler->filter('button[id=config_save]'));
30 $this->assertCount(1, $crawler->filter('button[id=change_passwd_save]'));
30 } 31 }
31 32
32 public function testUpdate() 33 public function testUpdate()
@@ -38,7 +39,7 @@ class ConfigControllerTest extends WallabagTestCase
38 39
39 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 40 $this->assertEquals(200, $client->getResponse()->getStatusCode());
40 41
41 $form = $crawler->filter('button[type=submit]')->form(); 42 $form = $crawler->filter('button[id=config_save]')->form();
42 43
43 $data = array( 44 $data = array(
44 'config[theme]' => 'baggy', 45 'config[theme]' => 'baggy',
@@ -84,7 +85,7 @@ class ConfigControllerTest extends WallabagTestCase
84 85
85 $this->assertEquals(200, $client->getResponse()->getStatusCode()); 86 $this->assertEquals(200, $client->getResponse()->getStatusCode());
86 87
87 $form = $crawler->filter('button[type=submit]')->form(); 88 $form = $crawler->filter('button[id=config_save]')->form();
88 89
89 $crawler = $client->submit($form, $data); 90 $crawler = $client->submit($form, $data);
90 91
@@ -93,4 +94,91 @@ class ConfigControllerTest extends WallabagTestCase
93 $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text'))); 94 $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text')));
94 $this->assertContains('This value should not be blank', $alert[0]); 95 $this->assertContains('This value should not be blank', $alert[0]);
95 } 96 }
97
98 public function dataForChangePasswordFailed()
99 {
100 return array(
101 array(
102 array(
103 'change_passwd[old_password]' => 'baggy',
104 'change_passwd[new_password][first]' => '',
105 'change_passwd[new_password][second]' => '',
106 ),
107 'Wrong value for your current password'
108 ),
109 array(
110 array(
111 'change_passwd[old_password]' => 'mypassword',
112 'change_passwd[new_password][first]' => '',
113 'change_passwd[new_password][second]' => '',
114 ),
115 'This value should not be blank'
116 ),
117 array(
118 array(
119 'change_passwd[old_password]' => 'mypassword',
120 'change_passwd[new_password][first]' => 'hop',
121 'change_passwd[new_password][second]' => '',
122 ),
123 'The password fields must match'
124 ),
125 array(
126 array(
127 'change_passwd[old_password]' => 'mypassword',
128 'change_passwd[new_password][first]' => 'hop',
129 'change_passwd[new_password][second]' => 'hop',
130 ),
131 'Password should by at least 6 chars long'
132 ),
133 );
134 }
135
136 /**
137 * @dataProvider dataForChangePasswordFailed
138 */
139 public function testChangePasswordFailed($data, $expectedMessage)
140 {
141 $this->logInAs('admin');
142 $client = $this->getClient();
143
144 $crawler = $client->request('GET', '/config');
145
146 $this->assertEquals(200, $client->getResponse()->getStatusCode());
147
148 $form = $crawler->filter('button[id=change_passwd_save]')->form();
149
150 $crawler = $client->submit($form, $data);
151
152 $this->assertEquals(200, $client->getResponse()->getStatusCode());
153
154 $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text')));
155 $this->assertContains($expectedMessage, $alert[0]);
156 }
157
158 public function testChangePassword()
159 {
160 $this->logInAs('admin');
161 $client = $this->getClient();
162
163 $crawler = $client->request('GET', '/config');
164
165 $this->assertEquals(200, $client->getResponse()->getStatusCode());
166
167 $form = $crawler->filter('button[id=change_passwd_save]')->form();
168
169 $data = array(
170 'change_passwd[old_password]' => 'mypassword',
171 'change_passwd[new_password][first]' => 'mypassword',
172 'change_passwd[new_password][second]' => 'mypassword',
173 );
174
175 $client->submit($form, $data);
176
177 $this->assertEquals(302, $client->getResponse()->getStatusCode());
178
179 $crawler = $client->followRedirect();
180
181 $this->assertGreaterThan(1, $alert = $crawler->filter('div.flash-notice')->extract(array('_text')));
182 $this->assertContains('Password updated', $alert[0]);
183 }
96} 184}
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php
index d77e2303..fcfa8ccf 100644
--- a/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php
+++ b/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php
@@ -47,7 +47,7 @@ class WallabagRestControllerTest extends WallabagTestCase
47 $client->request('GET', '/api/salts/admin.json'); 47 $client->request('GET', '/api/salts/admin.json');
48 $salt = json_decode($client->getResponse()->getContent()); 48 $salt = json_decode($client->getResponse()->getContent());
49 49
50 $headers = $this->generateHeaders('admin', 'test', $salt[0]); 50 $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
51 51
52 $entry = $client->getContainer() 52 $entry = $client->getContainer()
53 ->get('doctrine.orm.entity_manager') 53 ->get('doctrine.orm.entity_manager')
@@ -73,7 +73,7 @@ class WallabagRestControllerTest extends WallabagTestCase
73 $client->request('GET', '/api/salts/admin.json'); 73 $client->request('GET', '/api/salts/admin.json');
74 $salt = json_decode($client->getResponse()->getContent()); 74 $salt = json_decode($client->getResponse()->getContent());
75 75
76 $headers = $this->generateHeaders('admin', 'test', $salt[0]); 76 $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
77 77
78 $entry = $client->getContainer() 78 $entry = $client->getContainer()
79 ->get('doctrine.orm.entity_manager') 79 ->get('doctrine.orm.entity_manager')
@@ -101,7 +101,7 @@ class WallabagRestControllerTest extends WallabagTestCase
101 $client->request('GET', '/api/salts/admin.json'); 101 $client->request('GET', '/api/salts/admin.json');
102 $salt = json_decode($client->getResponse()->getContent()); 102 $salt = json_decode($client->getResponse()->getContent());
103 103
104 $headers = $this->generateHeaders('admin', 'test', $salt[0]); 104 $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
105 105
106 $client->request('GET', '/api/entries', array(), array(), $headers); 106 $client->request('GET', '/api/entries', array(), array(), $headers);
107 107
@@ -125,7 +125,7 @@ class WallabagRestControllerTest extends WallabagTestCase
125 $client->request('GET', '/api/salts/admin.json'); 125 $client->request('GET', '/api/salts/admin.json');
126 $salt = json_decode($client->getResponse()->getContent()); 126 $salt = json_decode($client->getResponse()->getContent());
127 127
128 $headers = $this->generateHeaders('admin', 'test', $salt[0]); 128 $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
129 129
130 $entry = $client->getContainer() 130 $entry = $client->getContainer()
131 ->get('doctrine.orm.entity_manager') 131 ->get('doctrine.orm.entity_manager')
diff --git a/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php b/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php
index 39794545..22016d8e 100644
--- a/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php
+++ b/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php
@@ -24,7 +24,7 @@ abstract class WallabagTestCase extends WebTestCase
24 $form = $crawler->filter('button[type=submit]')->form(); 24 $form = $crawler->filter('button[type=submit]')->form();
25 $data = array( 25 $data = array(
26 '_username' => $username, 26 '_username' => $username,
27 '_password' => 'test', 27 '_password' => 'mypassword',
28 ); 28 );
29 29
30 $this->client->submit($form, $data); 30 $this->client->submit($form, $data);