mirror of
https://github.com/wallabag/wallabag.git
synced 2025-07-22 17:18:37 +00:00
* public registration
* remove WSSE implementation * add oAuth2 implementation
This commit is contained in:
parent
8a60bc4cc2
commit
fcb1fba5c2
33 changed files with 551 additions and 528 deletions
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Wallabag\ApiBundle\Controller;
|
||||
|
||||
use FOS\RestBundle\Controller\FOSRestController;
|
||||
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
|
@ -11,7 +11,7 @@ use Wallabag\CoreBundle\Entity\Tag;
|
|||
use Hateoas\Configuration\Route;
|
||||
use Hateoas\Representation\Factory\PagerfantaFactory;
|
||||
|
||||
class WallabagRestController extends Controller
|
||||
class WallabagRestController extends FOSRestController
|
||||
{
|
||||
/**
|
||||
* @param Entry $entry
|
||||
|
@ -38,31 +38,6 @@ class WallabagRestController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve salt for a giver user.
|
||||
*
|
||||
* @ApiDoc(
|
||||
* parameters={
|
||||
* {"name"="username", "dataType"="string", "required"=true, "description"="username"}
|
||||
* }
|
||||
* )
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSaltAction($username)
|
||||
{
|
||||
$user = $this
|
||||
->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByUsername($username);
|
||||
|
||||
if (is_null($user)) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
return array($user->getSalt() ?: null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all entries. It could be filtered by many options.
|
||||
*
|
||||
|
@ -122,7 +97,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function getEntryAction(Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$json = $this->get('serializer')->serialize($entry, 'json');
|
||||
|
||||
|
@ -184,7 +159,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function patchEntriesAction(Entry $entry, Request $request)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$title = $request->request->get('title');
|
||||
$isArchived = $request->request->get('is_archived');
|
||||
|
@ -228,7 +203,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function deleteEntriesAction(Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($entry);
|
||||
|
@ -250,7 +225,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function getEntriesTagsAction(Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$json = $this->get('serializer')->serialize($entry->getTags(), 'json');
|
||||
|
||||
|
@ -271,7 +246,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function postEntriesTagsAction(Request $request, Entry $entry)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$tags = $request->request->get('tags', '');
|
||||
if (!empty($tags)) {
|
||||
|
@ -299,7 +274,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function deleteEntriesTagsAction(Entry $entry, Tag $tag)
|
||||
{
|
||||
$this->validateUserAccess($entry->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$entry->removeTag($tag);
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
@ -334,7 +309,7 @@ class WallabagRestController extends Controller
|
|||
*/
|
||||
public function deleteTagAction(Tag $tag)
|
||||
{
|
||||
$this->validateUserAccess($tag->getUser()->getId(), $this->getUser()->getId());
|
||||
$this->validateUserAccess($tag->getUser()->getId());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($tag);
|
||||
|
@ -350,12 +325,12 @@ class WallabagRestController extends Controller
|
|||
* If not, throw exception. It means a user try to access information from an other user.
|
||||
*
|
||||
* @param int $requestUserId User id from the requested source
|
||||
* @param int $currentUserId User id from the retrieved source
|
||||
*/
|
||||
private function validateUserAccess($requestUserId, $currentUserId)
|
||||
private function validateUserAccess($requestUserId)
|
||||
{
|
||||
if ($requestUserId != $currentUserId) {
|
||||
throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$currentUserId);
|
||||
$user = $this->get('security.context')->getToken()->getUser();
|
||||
if ($requestUserId != $user->getId()) {
|
||||
throw $this->createAccessDeniedException('Access forbidden. Entry user id: '.$requestUserId.', logged user id: '.$user->getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
|
||||
|
||||
class WsseFactory implements SecurityFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||
{
|
||||
$providerId = 'security.authentication.provider.wsse.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new DefinitionDecorator('wsse.security.authentication.provider'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
;
|
||||
|
||||
$listenerId = 'security.authentication.listener.wsse.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('wsse.security.authentication.listener'));
|
||||
|
||||
return array($providerId, $listenerId, $defaultEntryPoint);
|
||||
}
|
||||
|
||||
public function getPosition()
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'wsse';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -13,9 +13,6 @@ class WallabagApiExtension extends Extension
|
|||
{
|
||||
$configuration = new Configuration();
|
||||
$config = $this->processConfiguration($configuration, $configs);
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
|
||||
$loader->load('services.yml');
|
||||
}
|
||||
|
||||
public function getAlias()
|
||||
|
|
31
src/Wallabag/ApiBundle/Entity/AccessToken.php
Normal file
31
src/Wallabag/ApiBundle/Entity/AccessToken.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_access_tokens")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class AccessToken extends BaseAccessToken
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Client")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\User")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
31
src/Wallabag/ApiBundle/Entity/AuthCode.php
Normal file
31
src/Wallabag/ApiBundle/Entity/AuthCode.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_auth_codes")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class AuthCode extends BaseAuthCode
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Client")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\User")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
25
src/Wallabag/ApiBundle/Entity/Client.php
Normal file
25
src/Wallabag/ApiBundle/Entity/Client.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\Client as BaseClient;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_clients")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class Client extends BaseClient
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
31
src/Wallabag/ApiBundle/Entity/RefreshToken.php
Normal file
31
src/Wallabag/ApiBundle/Entity/RefreshToken.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Entity;
|
||||
|
||||
use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Table("oauth2_refresh_tokens")
|
||||
* @ORM\Entity
|
||||
*/
|
||||
class RefreshToken extends BaseRefreshToken
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Client")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\CoreBundle\Entity\User")
|
||||
*/
|
||||
protected $user;
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
services:
|
||||
wsse.security.authentication.provider:
|
||||
class: Wallabag\ApiBundle\Security\Authentication\Provider\WsseProvider
|
||||
public: false
|
||||
arguments: ['', '%kernel.cache_dir%/security/nonces']
|
||||
|
||||
wsse.security.authentication.listener:
|
||||
class: Wallabag\ApiBundle\Security\Firewall\WsseListener
|
||||
public: false
|
||||
tags:
|
||||
- { name: monolog.logger, channel: wsse }
|
||||
arguments: ['@security.context', '@security.authentication.manager', '@logger']
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Security\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\NonceExpiredException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken;
|
||||
|
||||
class WsseProvider implements AuthenticationProviderInterface
|
||||
{
|
||||
private $userProvider;
|
||||
private $cacheDir;
|
||||
|
||||
public function __construct(UserProviderInterface $userProvider, $cacheDir)
|
||||
{
|
||||
$this->userProvider = $userProvider;
|
||||
$this->cacheDir = $cacheDir;
|
||||
|
||||
// If cache directory does not exist we create it
|
||||
if (!is_dir($this->cacheDir)) {
|
||||
mkdir($this->cacheDir, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function authenticate(TokenInterface $token)
|
||||
{
|
||||
$user = $this->userProvider->loadUserByUsername($token->getUsername());
|
||||
|
||||
if (!$user) {
|
||||
throw new AuthenticationException('Bad credentials. Did you forgot your username?');
|
||||
}
|
||||
|
||||
if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) {
|
||||
$authenticatedToken = new WsseUserToken($user->getRoles());
|
||||
$authenticatedToken->setUser($user);
|
||||
|
||||
return $authenticatedToken;
|
||||
}
|
||||
|
||||
throw new AuthenticationException('The WSSE authentication failed.');
|
||||
}
|
||||
|
||||
protected function validateDigest($digest, $nonce, $created, $secret)
|
||||
{
|
||||
// Check created time is not in the future
|
||||
if (strtotime($created) > time()) {
|
||||
throw new AuthenticationException('Back to the future...');
|
||||
}
|
||||
|
||||
// Expire timestamp after 5 minutes
|
||||
if (time() - strtotime($created) > 300) {
|
||||
throw new AuthenticationException('Too late for this timestamp... Watch your watch.');
|
||||
}
|
||||
|
||||
// Validate nonce is unique within 5 minutes
|
||||
if (file_exists($this->cacheDir.'/'.$nonce) && file_get_contents($this->cacheDir.'/'.$nonce) + 300 > time()) {
|
||||
throw new NonceExpiredException('Previously used nonce detected');
|
||||
}
|
||||
|
||||
file_put_contents($this->cacheDir.'/'.$nonce, time());
|
||||
|
||||
// Validate Secret
|
||||
$expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true));
|
||||
|
||||
if ($digest !== $expected) {
|
||||
throw new AuthenticationException('Bad credentials ! Digest is not as expected.');
|
||||
}
|
||||
|
||||
return $digest === $expected;
|
||||
}
|
||||
|
||||
public function supports(TokenInterface $token)
|
||||
{
|
||||
return $token instanceof WsseUserToken;
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Security\Authentication\Token;
|
||||
|
||||
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
|
||||
|
||||
class WsseUserToken extends AbstractToken
|
||||
{
|
||||
public $created;
|
||||
public $digest;
|
||||
public $nonce;
|
||||
|
||||
public function __construct(array $roles = array())
|
||||
{
|
||||
parent::__construct($roles);
|
||||
|
||||
$this->setAuthenticated(count($roles) > 0);
|
||||
}
|
||||
|
||||
public function getCredentials()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Security\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\SecurityContextInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Wallabag\ApiBundle\Security\Authentication\Token\WsseUserToken;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class WsseListener implements ListenerInterface
|
||||
{
|
||||
protected $securityContext;
|
||||
protected $authenticationManager;
|
||||
protected $logger;
|
||||
|
||||
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger)
|
||||
{
|
||||
$this->securityContext = $securityContext;
|
||||
$this->authenticationManager = $authenticationManager;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function handle(GetResponseEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
$wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/';
|
||||
if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$token = new WsseUserToken();
|
||||
$token->setUser($matches[1]);
|
||||
|
||||
$token->digest = $matches[2];
|
||||
$token->nonce = $matches[3];
|
||||
$token->created = $matches[4];
|
||||
|
||||
try {
|
||||
$authToken = $this->authenticationManager->authenticate($token);
|
||||
|
||||
$this->securityContext->setToken($authToken);
|
||||
|
||||
return;
|
||||
} catch (AuthenticationException $failed) {
|
||||
$failedMessage = 'WSSE Login failed for '.$token->getUsername().'. Why ? '.$failed->getMessage();
|
||||
$this->logger->err($failedMessage);
|
||||
|
||||
// Deny authentication with a '403 Forbidden' HTTP response
|
||||
$response = new Response();
|
||||
$response->setStatusCode(403);
|
||||
$response->setContent($failedMessage);
|
||||
$event->setResponse($response);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
46
src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php
Normal file
46
src/Wallabag/ApiBundle/Tests/AbstractControllerTest.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\ApiBundle\Tests;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
|
||||
abstract class AbstractControllerTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
protected $client = null;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->client = $this->createAuthorizedClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Client
|
||||
*/
|
||||
protected function createAuthorizedClient()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$container = $client->getContainer();
|
||||
|
||||
$session = $container->get('session');
|
||||
/** @var $userManager \FOS\UserBundle\Doctrine\UserManager */
|
||||
$userManager = $container->get('fos_user.user_manager');
|
||||
/** @var $loginManager \FOS\UserBundle\Security\LoginManager */
|
||||
$loginManager = $container->get('fos_user.security.login_manager');
|
||||
$firewallName = $container->getParameter('fos_user.firewall_name');
|
||||
|
||||
$user = $userManager->findUserBy(array('username' => 'admin'));
|
||||
$loginManager->loginUser($firewallName, $user);
|
||||
|
||||
// save the login token into the session and put it in a cookie
|
||||
$container->get('session')->set('_security_'.$firewallName,
|
||||
serialize($container->get('security.context')->getToken()));
|
||||
$container->get('session')->save();
|
||||
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
|
@ -2,99 +2,15 @@
|
|||
|
||||
namespace Wallabag\ApiBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Wallabag\ApiBundle\Tests\AbstractControllerTest;
|
||||
|
||||
class WallabagRestControllerTest extends WebTestCase
|
||||
class WallabagRestControllerTest extends AbstractControllerTest
|
||||
{
|
||||
protected static $salt;
|
||||
|
||||
/**
|
||||
* Grab the salt once and store it to be available for all tests.
|
||||
*/
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$client = self::createClient();
|
||||
|
||||
$user = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
self::$salt = $user->getSalt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate HTTP headers for authenticate user on API.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function generateHeaders($username, $password)
|
||||
{
|
||||
$encryptedPassword = sha1($password.$username.self::$salt);
|
||||
$nonce = substr(md5(uniqid('nonce_', true)), 0, 16);
|
||||
|
||||
$now = new \DateTime('now', new \DateTimeZone('UTC'));
|
||||
$created = (string) $now->format('Y-m-d\TH:i:s\Z');
|
||||
$digest = base64_encode(sha1(base64_decode($nonce).$created.$encryptedPassword, true));
|
||||
|
||||
return array(
|
||||
'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"',
|
||||
'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="'.$username.'", PasswordDigest="'.$digest.'", Nonce="'.$nonce.'", Created="'.$created.'"',
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetSalt()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$client->request('GET', '/api/salts/admin.json');
|
||||
|
||||
$user = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:User')
|
||||
->findOneByUsername('admin');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey(0, $content);
|
||||
$this->assertEquals($user->getSalt(), $content[0]);
|
||||
|
||||
$client->request('GET', '/api/salts/notfound.json');
|
||||
$this->assertEquals(404, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testWithBadHeaders()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
|
||||
$entry = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByIsArchived(false);
|
||||
|
||||
if (!$entry) {
|
||||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$badHeaders = array(
|
||||
'HTTP_AUTHORIZATION' => 'Authorization profile="UsernameToken"',
|
||||
'HTTP_x-wsse' => 'X-WSSE: UsernameToken Username="admin", PasswordDigest="Wr0ngDig3st", Nonce="n0Nc3", Created="2015-01-01T13:37:00Z"',
|
||||
);
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $badHeaders);
|
||||
$this->assertEquals(403, $client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testGetOneEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneBy(array('user' => 1, 'isArchived' => false));
|
||||
|
@ -103,18 +19,17 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'.json');
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertEquals($entry->getTitle(), $content['title']);
|
||||
$this->assertEquals($entry->getUrl(), $content['url']);
|
||||
$this->assertCount(count($entry->getTags()), $content['tags']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -123,10 +38,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetOneEntryWrongUser()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneBy(array('user' => 2, 'isArchived' => false));
|
||||
|
@ -135,21 +47,18 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'.json');
|
||||
|
||||
$this->assertEquals(403, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(403, $this->client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testGetEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/entries');
|
||||
|
||||
$client->request('GET', '/api/entries', array(), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
|
@ -158,7 +67,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -167,14 +76,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetStarredEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'));
|
||||
|
||||
$client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
|
@ -183,7 +89,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -192,14 +98,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetArchiveEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/entries', array('archive' => 1));
|
||||
|
||||
$client->request('GET', '/api/entries', array('archive' => 1), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
|
@ -208,7 +111,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
$this->client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
|
@ -217,10 +120,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testDeleteEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
|
@ -229,36 +129,31 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertEquals($entry->getTitle(), $content['title']);
|
||||
$this->assertEquals($entry->getUrl(), $content['url']);
|
||||
|
||||
// We'll try to delete this entry again
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('DELETE', '/api/entries/'.$entry->getId().'.json');
|
||||
|
||||
$client->request('DELETE', '/api/entries/'.$entry->getId().'.json', array(), array(), $headers);
|
||||
|
||||
$this->assertEquals(404, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(404, $this->client->getResponse()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testPostEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$client->request('POST', '/api/entries.json', array(
|
||||
$this->client->request('POST', '/api/entries.json', array(
|
||||
'url' => 'http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html',
|
||||
'tags' => 'google',
|
||||
), array(), $headers);
|
||||
));
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThan(0, $content['id']);
|
||||
$this->assertEquals('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']);
|
||||
|
@ -269,10 +164,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testPatchEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
|
@ -284,16 +176,16 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
// hydrate the tags relations
|
||||
$nbTags = count($entry->getTags());
|
||||
|
||||
$client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array(
|
||||
$this->client->request('PATCH', '/api/entries/'.$entry->getId().'.json', array(
|
||||
'title' => 'New awesome title',
|
||||
'tags' => 'new tag '.uniqid(),
|
||||
'star' => true,
|
||||
'archive' => false,
|
||||
), array(), $headers);
|
||||
));
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertEquals($entry->getId(), $content['id']);
|
||||
$this->assertEquals($entry->getUrl(), $content['url']);
|
||||
|
@ -303,10 +195,7 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetTagsEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneWithTags(1);
|
||||
|
@ -322,17 +211,14 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel());
|
||||
}
|
||||
|
||||
$client->request('GET', '/api/entries/'.$entry->getId().'/tags', array(), array(), $headers);
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'/tags');
|
||||
|
||||
$this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $client->getResponse()->getContent());
|
||||
$this->assertEquals(json_encode($tags, JSON_HEX_QUOT), $this->client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testPostTagsOnEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
|
@ -345,16 +231,16 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
$newTags = 'tag1,tag2,tag3';
|
||||
|
||||
$client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags), array(), $headers);
|
||||
$this->client->request('POST', '/api/entries/'.$entry->getId().'/tags', array('tags' => $newTags));
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('tags', $content);
|
||||
$this->assertEquals($nbTags + 3, count($content['tags']));
|
||||
|
||||
$entryDB = $client->getContainer()
|
||||
$entryDB = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->find($entry->getId());
|
||||
|
@ -369,15 +255,13 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
}
|
||||
}
|
||||
|
||||
public function testDeleteOneTagEntrie()
|
||||
public function testDeleteOneTagEntry()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$entry = $client->getContainer()
|
||||
$entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByUser(1);
|
||||
->findOneWithTags(1);
|
||||
$entry = $entry[0];
|
||||
|
||||
if (!$entry) {
|
||||
$this->markTestSkipped('No content found in db.');
|
||||
|
@ -387,11 +271,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$nbTags = count($entry->getTags());
|
||||
$tag = $entry->getTags()[0];
|
||||
|
||||
$client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json', array(), array(), $headers);
|
||||
$this->client->request('DELETE', '/api/entries/'.$entry->getId().'/tags/'.$tag->getId().'.json');
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('tags', $content);
|
||||
$this->assertEquals($nbTags - 1, count($content['tags']));
|
||||
|
@ -399,14 +283,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
|
||||
public function testGetUserTags()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('GET', '/api/tags.json');
|
||||
|
||||
$client->request('GET', '/api/tags.json', array(), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThan(0, $content);
|
||||
$this->assertArrayHasKey('id', $content[0]);
|
||||
|
@ -420,14 +301,11 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
*/
|
||||
public function testDeleteUserTag($tag)
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
$this->client->request('DELETE', '/api/tags/'.$tag['id'].'.json');
|
||||
|
||||
$client->request('DELETE', '/api/tags/'.$tag['id'].'.json', array(), array(), $headers);
|
||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
$content = json_decode($this->client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertArrayHasKey('label', $content);
|
||||
$this->assertEquals($tag['label'], $content['label']);
|
||||
|
|
|
@ -3,16 +3,7 @@
|
|||
namespace Wallabag\ApiBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Wallabag\ApiBundle\DependencyInjection\Security\Factory\WsseFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class WallabagApiBundle extends Bundle
|
||||
{
|
||||
public function build(ContainerBuilder $container)
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$extension = $container->getExtension('security');
|
||||
$extension->addSecurityListenerFactory(new WsseFactory());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ class ConfigController extends Controller
|
|||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$config = $this->getConfig();
|
||||
$userManager = $this->container->get('fos_user.user_manager');
|
||||
$user = $this->getUser();
|
||||
|
||||
// handle basic config detail (this form is defined as a service)
|
||||
|
@ -52,9 +53,8 @@ class ConfigController extends Controller
|
|||
$pwdForm->handleRequest($request);
|
||||
|
||||
if ($pwdForm->isValid()) {
|
||||
$user->setPassword($pwdForm->get('new_password')->getData());
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
$user->setPlainPassword($pwdForm->get('new_password')->getData());
|
||||
$userManager->updateUser($user, true);
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
|
@ -69,8 +69,7 @@ class ConfigController extends Controller
|
|||
$userForm->handleRequest($request);
|
||||
|
||||
if ($userForm->isValid()) {
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
$userManager->updateUser($user, true);
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
|
@ -97,14 +96,14 @@ class ConfigController extends Controller
|
|||
}
|
||||
|
||||
// handle adding new user
|
||||
$newUser = new User();
|
||||
$newUser = $userManager->createUser();
|
||||
// enable created user by default
|
||||
$newUser->setEnabled(true);
|
||||
$newUserForm = $this->createForm(new NewUserType(), $newUser, array('validation_groups' => array('Profile')));
|
||||
$newUserForm->handleRequest($request);
|
||||
|
||||
if ($newUserForm->isValid()) {
|
||||
$em->persist($newUser);
|
||||
if ($newUserForm->isValid() && $this->get('security.authorization_checker')->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$userManager->updateUser($newUser, true);
|
||||
|
||||
$config = new Config($newUser);
|
||||
$config->setTheme($this->container->getParameter('theme'));
|
||||
|
|
|
@ -18,8 +18,9 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
|
|||
$userAdmin->setName('Big boss');
|
||||
$userAdmin->setEmail('bigboss@wallabag.org');
|
||||
$userAdmin->setUsername('admin');
|
||||
$userAdmin->setPassword('mypassword');
|
||||
$userAdmin->setPlainPassword('mypassword');
|
||||
$userAdmin->setEnabled(true);
|
||||
$userAdmin->addRole('ROLE_SUPER_ADMIN');
|
||||
|
||||
$manager->persist($userAdmin);
|
||||
|
||||
|
@ -29,7 +30,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
|
|||
$bobUser->setName('Bobby');
|
||||
$bobUser->setEmail('bobby@wallabag.org');
|
||||
$bobUser->setUsername('bob');
|
||||
$bobUser->setPassword('mypassword');
|
||||
$bobUser->setPlainPassword('mypassword');
|
||||
$bobUser->setEnabled(true);
|
||||
|
||||
$manager->persist($bobUser);
|
||||
|
|
|
@ -6,7 +6,6 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
|
||||
use JMS\Serializer\Annotation\ExclusionPolicy;
|
||||
use JMS\Serializer\Annotation\Expose;
|
||||
use FOS\UserBundle\Model\User as BaseUser;
|
||||
|
@ -22,7 +21,7 @@ use FOS\UserBundle\Model\User as BaseUser;
|
|||
* @UniqueEntity("email")
|
||||
* @UniqueEntity("username")
|
||||
*/
|
||||
class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
||||
class User extends BaseUser
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
|
@ -75,6 +74,7 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
parent::__construct();
|
||||
$this->entries = new ArrayCollection();
|
||||
$this->tags = new ArrayCollection();
|
||||
$this->roles = array('ROLE_USER');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,24 +90,6 @@ class User extends BaseUser implements AdvancedUserInterface, \Serializable
|
|||
$this->updatedAt = new \DateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set password.
|
||||
*
|
||||
* @param string $password
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
if (!$password && 0 === strlen($password)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->password = sha1($password.$this->getUsername().$this->getSalt());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set name.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\EventListener;
|
||||
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use FOS\UserBundle\Event\FilterUserResponseEvent;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
|
||||
class AuthenticationListener implements EventSubscriberInterface
|
||||
{
|
||||
private $em;
|
||||
private $container;
|
||||
|
||||
public function __construct(Container $container, $em)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
FOSUserEvents::REGISTRATION_CONFIRMED => 'authenticate',
|
||||
);
|
||||
}
|
||||
|
||||
public function authenticate(FilterUserResponseEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null)
|
||||
{
|
||||
if (!$event->getUser()->isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$config = new Config($event->getUser());
|
||||
$config->setTheme($this->container->getParameter('theme'));
|
||||
$config->setItemsPerPage($this->container->getParameter('items_on_page'));
|
||||
$config->setRssLimit($this->container->getParameter('rss_limit'));
|
||||
$config->setLanguage($this->container->getParameter('language'));
|
||||
$this->em->persist($config);
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
|
@ -13,7 +13,8 @@ class NewUserType extends AbstractType
|
|||
{
|
||||
$builder
|
||||
->add('username', 'text', array('required' => true))
|
||||
->add('password', 'password', array(
|
||||
->add('plainPassword', 'repeated', array(
|
||||
'type' => 'password',
|
||||
'constraints' => array(
|
||||
new Constraints\Length(array(
|
||||
'min' => 8,
|
||||
|
|
24
src/Wallabag/CoreBundle/Form/Type/RegistrationType.php
Normal file
24
src/Wallabag/CoreBundle/Form/Type/RegistrationType.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class RegistrationType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add('name');
|
||||
}
|
||||
|
||||
public function getParent()
|
||||
{
|
||||
return 'fos_user_registration';
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'wallabag_user_registration';
|
||||
}
|
||||
}
|
|
@ -13,6 +13,11 @@ services:
|
|||
tags:
|
||||
- { name: form.type, alias: config }
|
||||
|
||||
wallabag_core.form.registration:
|
||||
class: Wallabag\CoreBundle\Form\Type\RegistrationType
|
||||
tags:
|
||||
- { name: form.type, alias: wallabag_user_registration }
|
||||
|
||||
wallabag_core.form.type.forgot_password:
|
||||
class: Wallabag\CoreBundle\Form\Type\ForgotPasswordType
|
||||
arguments:
|
||||
|
@ -40,3 +45,9 @@ services:
|
|||
class: Wallabag\CoreBundle\Helper\ContentProxy
|
||||
arguments:
|
||||
- @wallabag_core.graby
|
||||
|
||||
wallabag_core.registration_confirmed:
|
||||
class: Wallabag\CoreBundle\EventListener\AuthenticationListener
|
||||
arguments: [@service_container, @doctrine.orm.entity_manager]
|
||||
tags:
|
||||
- { name: kernel.event_subscriber }
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
{{ form_rest(form.pwd) }}
|
||||
</form>
|
||||
|
||||
{% if is_granted('ROLE_SUPER_ADMIN') %}
|
||||
<h2>{% trans %}Add a user{% endtrans %}</h2>
|
||||
|
||||
<form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}>
|
||||
|
@ -150,9 +151,17 @@
|
|||
|
||||
<fieldset class="w500p inline">
|
||||
<div class="row">
|
||||
{{ form_label(form.new_user.password) }}
|
||||
{{ form_errors(form.new_user.password) }}
|
||||
{{ form_widget(form.new_user.password) }}
|
||||
{{ form_label(form.new_user.plainPassword.first) }}
|
||||
{{ form_errors(form.new_user.plainPassword.first) }}
|
||||
{{ form_widget(form.new_user.plainPassword.first) }}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="w500p inline">
|
||||
<div class="row">
|
||||
{{ form_label(form.new_user.plainPassword.second) }}
|
||||
{{ form_errors(form.new_user.plainPassword.second) }}
|
||||
{{ form_widget(form.new_user.plainPassword.second) }}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
@ -165,5 +174,6 @@
|
|||
</fieldset>
|
||||
|
||||
{{ form_rest(form.new_user) }}
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -15,7 +15,9 @@
|
|||
<li class="tab col s3"><a href="#set2">{% trans %}RSS{% endtrans %}</a></li>
|
||||
<li class="tab col s3"><a href="#set3">{% trans %}User information{% endtrans %}</a></li>
|
||||
<li class="tab col s3"><a href="#set4">{% trans %}Password{% endtrans %}</a></li>
|
||||
{% if is_granted('ROLE_SUPER_ADMIN') %}
|
||||
<li class="tab col s3"><a href="#set5">{% trans %}Add a user{% endtrans %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
@ -175,7 +177,7 @@
|
|||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
{% if is_granted('ROLE_SUPER_ADMIN') %}
|
||||
<div id="set5" class="col s12">
|
||||
<form action="{{ path('config') }}#set5" method="post" {{ form_enctype(form.new_user) }}>
|
||||
{{ form_errors(form.new_user) }}
|
||||
|
@ -190,9 +192,17 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.new_user.password) }}
|
||||
{{ form_errors(form.new_user.password) }}
|
||||
{{ form_widget(form.new_user.password) }}
|
||||
{{ form_label(form.new_user.plainPassword.first) }}
|
||||
{{ form_errors(form.new_user.plainPassword.first) }}
|
||||
{{ form_widget(form.new_user.plainPassword.first) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.new_user.plainPassword.second) }}
|
||||
{{ form_errors(form.new_user.plainPassword.second) }}
|
||||
{{ form_widget(form.new_user.plainPassword.second) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -211,6 +221,7 @@
|
|||
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
{% trans %}Login{% endtrans %}
|
||||
<i class="mdi-content-send right"></i>
|
||||
</button>
|
||||
<a href="{{ path('fos_user_registration_register') }}">{% trans %}Register{% endtrans %}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -258,7 +258,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => '',
|
||||
'new_user[password]' => '',
|
||||
'new_user[plainPassword][first]' => '',
|
||||
'new_user[plainPassword][second]' => '',
|
||||
'new_user[email]' => '',
|
||||
),
|
||||
'Please enter a username',
|
||||
|
@ -266,7 +267,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => 'a',
|
||||
'new_user[password]' => 'mypassword',
|
||||
'new_user[plainPassword][first]' => 'mypassword',
|
||||
'new_user[plainPassword][second]' => 'mypassword',
|
||||
'new_user[email]' => '',
|
||||
),
|
||||
'The username is too short',
|
||||
|
@ -274,7 +276,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => 'wallace',
|
||||
'new_user[password]' => 'mypassword',
|
||||
'new_user[plainPassword][first]' => 'mypassword',
|
||||
'new_user[plainPassword][second]' => 'mypassword',
|
||||
'new_user[email]' => 'test',
|
||||
),
|
||||
'The email is not valid',
|
||||
|
@ -282,11 +285,21 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
array(
|
||||
array(
|
||||
'new_user[username]' => 'admin',
|
||||
'new_user[password]' => 'wallacewallace',
|
||||
'new_user[plainPassword][first]' => 'wallacewallace',
|
||||
'new_user[plainPassword][second]' => 'wallacewallace',
|
||||
'new_user[email]' => 'wallace@wallace.me',
|
||||
),
|
||||
'The username is already used',
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'new_user[username]' => 'wallace',
|
||||
'new_user[plainPassword][first]' => 'mypassword1',
|
||||
'new_user[plainPassword][second]' => 'mypassword2',
|
||||
'new_user[email]' => 'wallace@wallace.me',
|
||||
),
|
||||
'This value is not valid',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -325,7 +338,8 @@ class ConfigControllerTest extends WallabagCoreTestCase
|
|||
|
||||
$data = array(
|
||||
'new_user[username]' => 'wallace',
|
||||
'new_user[password]' => 'wallace1',
|
||||
'new_user[plainPassword][first]' => 'wallace1',
|
||||
'new_user[plainPassword][second]' => 'wallace1',
|
||||
'new_user[email]' => 'wallace@wallace.me',
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue