partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 4dda6fb5b103ad0544bc3c00d3214e2fa41f028e
parent 74976fcd857538feb4a49875ddad79ab2a41e75f
Author: Felicitus <felicitus@felicitus.org>
Date:   Wed,  4 Nov 2015 17:45:00 +0100

Refactored the auth system to allow changing the user's legacy password, thus creating a new FOSRest user. Added unit tests for authentication

Diffstat:
Msrc/PartKeepr/AuthBundle/Action/ChangePasswordAction.php | 38+++++++++++++++++++++++---------------
Msrc/PartKeepr/AuthBundle/Action/PostUserAction.php | 1+
Msrc/PartKeepr/AuthBundle/Action/PutUserAction.php | 1+
Msrc/PartKeepr/AuthBundle/Entity/User.php | 19+++++++++++--------
Msrc/PartKeepr/AuthBundle/Services/UserService.php | 9+++++----
Asrc/PartKeepr/AuthBundle/Tests/LegacyAuthTest.php | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/AuthBundle/Tests/UserTest.php | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/User/UserEditor.js | 9+++++----
8 files changed, 203 insertions(+), 31 deletions(-)

diff --git a/src/PartKeepr/AuthBundle/Action/ChangePasswordAction.php b/src/PartKeepr/AuthBundle/Action/ChangePasswordAction.php @@ -3,17 +3,12 @@ namespace PartKeepr\AuthBundle\Action; use Dunglas\ApiBundle\Action\ActionUtilTrait; -use Dunglas\ApiBundle\Api\ResourceInterface; -use Dunglas\ApiBundle\Exception\RuntimeException; -use Dunglas\ApiBundle\Model\DataProviderInterface; use FOS\UserBundle\Model\UserManagerInterface; use FOS\UserBundle\Util\UserManipulator; use PartKeepr\AuthBundle\Entity\User; use PartKeepr\AuthBundle\Services\UserService; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Security\Core\Encoder\EncoderFactory; -use Symfony\Component\Serializer\SerializerInterface; class ChangePasswordAction { @@ -51,7 +46,8 @@ class ChangePasswordAction $this->userManager = $userManager; } - public function __invoke (Request $request) { + public function __invoke(Request $request) + { $user = $this->userService->getUser(); if (!$request->request->has("oldpassword") && !$request->request->has("newpassword")) { @@ -60,19 +56,31 @@ class ChangePasswordAction $FOSUser = $this->userManager->findUserByUsername($user->getUsername()); - if ($FOSUser === null) { - throw new \Exception("Cannot change password for legacy or LDAP users"); - } + if ($FOSUser !== null) { + $encoder = $this->encoderFactory->getEncoder($FOSUser); + $encoded_pass = $encoder->encodePassword($request->request->get("oldpassword"), $FOSUser->getSalt()); - $encoder = $this->encoderFactory->getEncoder($FOSUser); - $encoded_pass = $encoder->encodePassword($request->request->get("oldpassword"), $FOSUser->getSalt()); + if ($FOSUser->getPassword() != $encoded_pass) { + throw new \Exception("Old password is wrong"); + } - if ($FOSUser->getPassword() != $encoded_pass) { - throw new \Exception("Old password is wrong"); - } + $this->userManipulator->changePassword($user->getUsername(), $request->request->get("newpassword")); + } else { + if ($user->isLegacy()) { + if ($user->getPassword() !== md5($request->request->get("oldpassword"))) { + throw new \Exception("Old password is wrong"); + } - $this->userManipulator->changePassword($user->getUsername(), $request->request->get("newpassword")); + $user->setNewPassword($request->request->get("newpassword")); + + $this->userService->syncData($user); + } else { + throw new \Exception("Cannot change password for LDAP users"); + } + } + $user->setPassword(""); + $user->setNewPassword(""); return $user; } diff --git a/src/PartKeepr/AuthBundle/Action/PostUserAction.php b/src/PartKeepr/AuthBundle/Action/PostUserAction.php @@ -73,6 +73,7 @@ class PostUserAction $data->setLegacy(false); $this->userService->syncData($data); + $data->setNewPassword(""); $data->setPassword(""); return $data; diff --git a/src/PartKeepr/AuthBundle/Action/PutUserAction.php b/src/PartKeepr/AuthBundle/Action/PutUserAction.php @@ -75,6 +75,7 @@ class PutUserAction ); $this->userService->syncData($data); + $data->setNewPassword(""); $data->setPassword(""); $data->setLegacy(false); diff --git a/src/PartKeepr/AuthBundle/Entity/User.php b/src/PartKeepr/AuthBundle/Entity/User.php @@ -3,6 +3,7 @@ namespace PartKeepr\AuthBundle\Entity; use Doctrine\ORM\Mapping as ORM; use PartKeepr\DoctrineReflectionBundle\Annotation\TargetService; +use PartKeepr\DoctrineReflectionBundle\Annotation\VirtualField; use PartKeepr\Util\BaseEntity; use Symfony\Component\Security\Core\User\EquatableInterface; use Symfony\Component\Security\Core\User\UserInterface; @@ -31,9 +32,11 @@ class User extends BaseEntity implements UserInterface, EquatableInterface private $password; /** + * @Groups({"default"}) + * @VirtualField(type="string") * @var string */ - private $plainPassword; + private $newPassword; /** * @Assert\Email() @@ -203,7 +206,7 @@ class User extends BaseEntity implements UserInterface, EquatableInterface */ public function getPassword() { - return $this->plainPassword; + return $this->password; } /** @@ -213,18 +216,18 @@ class User extends BaseEntity implements UserInterface, EquatableInterface */ public function setPassword($password) { - $this->plainPassword = $password; + $this->password = $password; } - public function getPlainPassword () { - return $this->plainPassword; + public function getNewPassword () { + return $this->newPassword; } /** - * Sets the plain password. Used for password changes + * Sets the new password. Used for password changes */ - public function setPlainPassword ($password) { - + public function setNewPassword ($password) { + $this->newPassword = $password; } /** diff --git a/src/PartKeepr/AuthBundle/Services/UserService.php b/src/PartKeepr/AuthBundle/Services/UserService.php @@ -97,14 +97,15 @@ class UserService if ($FOSUser === null) { - if ($user->getPlainPassword() == "") { + if ($user->getNewPassword() == "") { throw new \Exception("Password must be set"); } - $FOSUser = $this->userManipulator->create($user->getUsername(), $user->getPlainPassword(), "", true, false); + $FOSUser = $this->userManipulator->create($user->getUsername(), $user->getNewPassword(), "", true, false); + $user->setLegacy(false); } - if ($user->getPlainPassword() != "") { - $this->userManipulator->changePassword($user->getUsername(), $user->getPlainPassword()); + if ($user->getNewPassword() != "") { + $this->userManipulator->changePassword($user->getUsername(), $user->getNewPassword()); } diff --git a/src/PartKeepr/AuthBundle/Tests/LegacyAuthTest.php b/src/PartKeepr/AuthBundle/Tests/LegacyAuthTest.php @@ -0,0 +1,43 @@ +<?php +namespace PartKeepr\AuthBundle\Tests; + +use PartKeepr\AuthBundle\Entity\User; +use PartKeepr\CoreBundle\Tests\WebTestCase; + +class LegacyAuthTest extends WebTestCase +{ + public function setUp() + { + $this->loadFixtures(array()); + } + + public function testLegacyAuth () { + $user = new User("foobar"); + $user->setPassword(md5("admin")); + $user->setLegacy(true); + + $this->getContainer()->get("doctrine.orm.default_entity_manager")->persist($user); + $this->getContainer()->get("doctrine.orm.default_entity_manager")->flush($user); + + $client = static::makeClient(false, array( + 'PHP_AUTH_USER' => "foobar", + 'PHP_AUTH_PW' => "admin" + ) + ); + + $client->request("GET", "/api/system_status"); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + + $client = static::makeClient(false, array( + 'PHP_AUTH_USER' => "foobar", + 'PHP_AUTH_PW' => "admin2" + ) + ); + + $client->request("GET", "/api/system_status"); + + $this->assertEquals(401, $client->getResponse()->getStatusCode()); + + } +} diff --git a/src/PartKeepr/AuthBundle/Tests/UserTest.php b/src/PartKeepr/AuthBundle/Tests/UserTest.php @@ -0,0 +1,114 @@ +<?php +namespace PartKeepr\AuthBundle\Tests; + + +use PartKeepr\AuthBundle\Entity\User; +use PartKeepr\CoreBundle\Tests\WebTestCase; + +class UserTest extends WebTestCase +{ + public function setUp() + { + $this->loadFixtures(array()); + } + + public function testCreateUser () { + $client = static::makeClient(true); + + $data = array( + "username" => "foobartest", + "newPassword" => "1234" + ); + + $client->request("POST", "/api/users", array(), array(), array(), json_encode($data)); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertEquals(201, $client->getResponse()->getStatusCode()); + $this->assertEquals("foobartest", $response->{"username"}); + $this->assertEmpty($response->{"password"}); + $this->assertEmpty($response->{"newPassword"}); + $this->assertFalse($response->{"legacy"}); + } + + public function testChangeUserPassword () { + $builtinProvider = $this->getContainer()->get("partkeepr.userservice")->getBuiltinProvider(); + + $user = new User("bernd"); + $user->setPassword(md5("admin")); + $user->setLegacy(true); + $user->setProvider($builtinProvider); + + $this->getContainer()->get("doctrine.orm.default_entity_manager")->persist($user); + $this->getContainer()->get("doctrine.orm.default_entity_manager")->flush($user); + + $client = static::makeClient(true); + + $iriConverter = $this->getContainer()->get("api.iri_converter"); + $iri = $iriConverter->getIriFromItem($user); + + $client->request("GET", $iri); + + $response = json_decode($client->getResponse()->getContent()); + + $response->{"newPassword"} = "foobar"; + + $client->request("PUT", $iri, array(), array(), array(), json_encode($response)); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEmpty($response->{"password"}); + $this->assertEmpty($response->{"newPassword"}); + $this->assertFalse($response->{"legacy"}); + } + + public function testSelfChangeUserPassword () { + $builtinProvider = $this->getContainer()->get("partkeepr.userservice")->getBuiltinProvider(); + + $user = new User("bernd2"); + $user->setPassword(md5("admin")); + $user->setLegacy(true); + $user->setProvider($builtinProvider); + + $this->getContainer()->get("doctrine.orm.default_entity_manager")->persist($user); + $this->getContainer()->get("doctrine.orm.default_entity_manager")->flush($user); + + $client = static::makeClient(false, array( + 'PHP_AUTH_USER' => "bernd2", + 'PHP_AUTH_PW' => "admin" + ) + ); + + $iriConverter = $this->getContainer()->get("api.iri_converter"); + $iri = $iriConverter->getIriFromItem($user)."/changePassword"; + + $parameters = array( + "oldpassword" => "admin", + "newpassword" => "foobar" + ); + + $client->request("PUT", $iri, $parameters); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertFalse($response->{"legacy"}); + $this->assertEmpty($response->{"password"}); + $this->assertEmpty($response->{"newPassword"}); + + $client = static::makeClient(false, array( + 'PHP_AUTH_USER' => "bernd2", + 'PHP_AUTH_PW' => "foobar" + ) + ); + + $client->request("PUT", $iri, $parameters); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertEquals(500, $client->getResponse()->getStatusCode()); + $this->assertObjectHasAttribute("@type", $response); + $this->assertEquals("Error", $response->{"@type"}); + } +} diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/User/UserEditor.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/User/UserEditor.js @@ -20,7 +20,7 @@ Ext.define('PartKeepr.UserEditor', { }, { xtype: 'textfield', inputType: "password", - name: 'password', + name: 'newPassword', fieldLabel: i18n("Password") }, { xtype: 'displayfield', @@ -31,14 +31,15 @@ Ext.define('PartKeepr.UserEditor', { } ]; - this.on("startEdit", this.onEditStart, this, {delay: 200}); - + this.on("startEdit", this.toggleLegacyField, this, {delay: 200}); this.callParent(); }, - onEditStart: function () + toggleLegacyField: function () { if (this.record.get("legacy") === true) { this.down("#legacyField").setVisible(true); + } else { + this.down("#legacyField").setVisible(false); } } });