diff options
author | Nicolas Lœuillet <nicolas@loeuillet.org> | 2015-01-31 15:14:10 +0100 |
---|---|---|
committer | Nicolas Lœuillet <nicolas@loeuillet.org> | 2015-01-31 15:14:10 +0100 |
commit | c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf (patch) | |
tree | 271305a039d31059c7af8be220da08b9331baeec /src | |
parent | 71691fe44a7b2a80f3b9d96d54720cce7994ad08 (diff) | |
download | wallabag-c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf.tar.gz wallabag-c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf.tar.zst wallabag-c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf.zip |
first implementation of security
Diffstat (limited to 'src')
16 files changed, 417 insertions, 31 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/SecurityController.php b/src/Wallabag/CoreBundle/Controller/SecurityController.php new file mode 100644 index 00000000..51f9cc26 --- /dev/null +++ b/src/Wallabag/CoreBundle/Controller/SecurityController.php | |||
@@ -0,0 +1,27 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Controller; | ||
4 | |||
5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||
6 | use Symfony\Component\HttpFoundation\Request; | ||
7 | use Symfony\Component\Security\Core\SecurityContext; | ||
8 | |||
9 | class SecurityController extends Controller | ||
10 | { | ||
11 | public function loginAction(Request $request) | ||
12 | { | ||
13 | $session = $request->getSession(); | ||
14 | // get the login error if there is one | ||
15 | if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) { | ||
16 | $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR); | ||
17 | } else { | ||
18 | $error = $session->get(SecurityContext::AUTHENTICATION_ERROR); | ||
19 | $session->remove(SecurityContext::AUTHENTICATION_ERROR); | ||
20 | } | ||
21 | return $this->render('WallabagCoreBundle:Security:login.html.twig', array( | ||
22 | // last username entered by the user | ||
23 | 'last_username' => $session->get(SecurityContext::LAST_USERNAME), | ||
24 | 'error' => $error, | ||
25 | )); | ||
26 | } | ||
27 | } \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/Controller/WallabagRestController.php b/src/Wallabag/CoreBundle/Controller/WallabagRestController.php index a6c0db37..8e018e88 100644 --- a/src/Wallabag/CoreBundle/Controller/WallabagRestController.php +++ b/src/Wallabag/CoreBundle/Controller/WallabagRestController.php | |||
@@ -82,17 +82,18 @@ class WallabagRestController extends Controller | |||
82 | */ | 82 | */ |
83 | public function postEntriesAction(Request $request) | 83 | public function postEntriesAction(Request $request) |
84 | { | 84 | { |
85 | //TODO la récup ne marche | 85 | //TODO la récup ne marche pas |
86 | //TODO gérer si on passe le titre | 86 | //TODO gérer si on passe le titre |
87 | //TODO gérer si on passe les tags | 87 | //TODO gérer si on passe les tags |
88 | //TODO ne pas avoir du code comme ça qui doit se trouver dans le Repository | 88 | //TODO ne pas avoir du code comme ça qui doit se trouver dans le Repository |
89 | $url = $request->request->get('url'); | ||
90 | |||
91 | $content = Extractor::extract($url); | ||
89 | $entry = new Entries(); | 92 | $entry = new Entries(); |
90 | $entry->setUserId(1); | 93 | $entry->setUserId(1); |
91 | $content = Extractor::extract($request->request->get('url')); | 94 | $entry->setUrl($url); |
92 | |||
93 | $entry->setTitle($content->getTitle()); | 95 | $entry->setTitle($content->getTitle()); |
94 | $entry->setContent($content->getBody()); | 96 | $entry->setContent($content->getBody()); |
95 | |||
96 | $em = $this->getDoctrine()->getManager(); | 97 | $em = $this->getDoctrine()->getManager(); |
97 | $em->persist($entry); | 98 | $em->persist($entry); |
98 | $em->flush(); | 99 | $em->flush(); |
diff --git a/src/Wallabag/CoreBundle/DependencyInjection/Security/Factory/WsseFactory.php b/src/Wallabag/CoreBundle/DependencyInjection/Security/Factory/WsseFactory.php new file mode 100644 index 00000000..9807fe9a --- /dev/null +++ b/src/Wallabag/CoreBundle/DependencyInjection/Security/Factory/WsseFactory.php | |||
@@ -0,0 +1,40 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\DependencyInjection\Security\Factory; | ||
4 | |||
5 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
6 | use Symfony\Component\DependencyInjection\Reference; | ||
7 | use Symfony\Component\DependencyInjection\DefinitionDecorator; | ||
8 | use Symfony\Component\Config\Definition\Builder\NodeDefinition; | ||
9 | use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; | ||
10 | |||
11 | class WsseFactory implements SecurityFactoryInterface | ||
12 | { | ||
13 | public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) | ||
14 | { | ||
15 | $providerId = 'security.authentication.provider.wsse.'.$id; | ||
16 | $container | ||
17 | ->setDefinition($providerId, new DefinitionDecorator('wsse.security.authentication.provider')) | ||
18 | ->replaceArgument(0, new Reference($userProvider)) | ||
19 | ; | ||
20 | |||
21 | $listenerId = 'security.authentication.listener.wsse.'.$id; | ||
22 | $listener = $container->setDefinition($listenerId, new DefinitionDecorator('wsse.security.authentication.listener')); | ||
23 | |||
24 | return array($providerId, $listenerId, $defaultEntryPoint); | ||
25 | } | ||
26 | |||
27 | public function getPosition() | ||
28 | { | ||
29 | return 'pre_auth'; | ||
30 | } | ||
31 | |||
32 | public function getKey() | ||
33 | { | ||
34 | return 'wsse'; | ||
35 | } | ||
36 | |||
37 | public function addConfiguration(NodeDefinition $node) | ||
38 | { | ||
39 | } | ||
40 | } \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/Entity/Entries.php b/src/Wallabag/CoreBundle/Entity/Entries.php index 712ff126..3c061a37 100644 --- a/src/Wallabag/CoreBundle/Entity/Entries.php +++ b/src/Wallabag/CoreBundle/Entity/Entries.php | |||
@@ -10,6 +10,7 @@ use Symfony\Component\Validator\Constraints as Assert; | |||
10 | * | 10 | * |
11 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\EntriesRepository") | 11 | * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\EntriesRepository") |
12 | * @ORM\Table(name="entries") | 12 | * @ORM\Table(name="entries") |
13 | * | ||
13 | */ | 14 | */ |
14 | class Entries | 15 | class Entries |
15 | { | 16 | { |
diff --git a/src/Wallabag/CoreBundle/Entity/Users.php b/src/Wallabag/CoreBundle/Entity/Users.php index 3db4a3fd..96867bd6 100644 --- a/src/Wallabag/CoreBundle/Entity/Users.php +++ b/src/Wallabag/CoreBundle/Entity/Users.php | |||
@@ -3,6 +3,9 @@ | |||
3 | namespace Wallabag\CoreBundle\Entity; | 3 | namespace Wallabag\CoreBundle\Entity; |
4 | 4 | ||
5 | use Doctrine\ORM\Mapping as ORM; | 5 | use Doctrine\ORM\Mapping as ORM; |
6 | use Symfony\Component\Security\Core\User\UserInterface; | ||
7 | use Symfony\Component\Security\Core\User\EquatableInterface; | ||
8 | use Symfony\Component\Security\Core\User\AdvancedUserInterface; | ||
6 | 9 | ||
7 | /** | 10 | /** |
8 | * Users | 11 | * Users |
@@ -10,7 +13,7 @@ use Doctrine\ORM\Mapping as ORM; | |||
10 | * @ORM\Table(name="users") | 13 | * @ORM\Table(name="users") |
11 | * @ORM\Entity | 14 | * @ORM\Entity |
12 | */ | 15 | */ |
13 | class Users | 16 | class Users implements AdvancedUserInterface, \Serializable |
14 | { | 17 | { |
15 | /** | 18 | /** |
16 | * @var integer | 19 | * @var integer |
@@ -29,6 +32,11 @@ class Users | |||
29 | private $username; | 32 | private $username; |
30 | 33 | ||
31 | /** | 34 | /** |
35 | * @ORM\Column(type="string", length=32) | ||
36 | */ | ||
37 | private $salt; | ||
38 | |||
39 | /** | ||
32 | * @var string | 40 | * @var string |
33 | * | 41 | * |
34 | * @ORM\Column(name="password", type="text", nullable=true) | 42 | * @ORM\Column(name="password", type="text", nullable=true) |
@@ -49,7 +57,16 @@ class Users | |||
49 | */ | 57 | */ |
50 | private $email; | 58 | private $email; |
51 | 59 | ||
60 | /** | ||
61 | * @ORM\Column(name="is_active", type="boolean") | ||
62 | */ | ||
63 | private $isActive; | ||
52 | 64 | ||
65 | public function __construct() | ||
66 | { | ||
67 | $this->isActive = true; | ||
68 | $this->salt = md5(uniqid(null, true)); | ||
69 | } | ||
53 | 70 | ||
54 | /** | 71 | /** |
55 | * Get id | 72 | * Get id |
@@ -85,6 +102,22 @@ class Users | |||
85 | } | 102 | } |
86 | 103 | ||
87 | /** | 104 | /** |
105 | * @inheritDoc | ||
106 | */ | ||
107 | public function getSalt() | ||
108 | { | ||
109 | return $this->salt; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * @inheritDoc | ||
114 | */ | ||
115 | public function getRoles() | ||
116 | { | ||
117 | return array('ROLE_USER'); | ||
118 | } | ||
119 | |||
120 | /** | ||
88 | * Set password | 121 | * Set password |
89 | * | 122 | * |
90 | * @param string $password | 123 | * @param string $password |
@@ -152,4 +185,56 @@ class Users | |||
152 | { | 185 | { |
153 | return $this->email; | 186 | return $this->email; |
154 | } | 187 | } |
188 | |||
189 | /** | ||
190 | * @inheritDoc | ||
191 | */ | ||
192 | public function eraseCredentials() | ||
193 | { | ||
194 | } | ||
195 | |||
196 | /** | ||
197 | * @see \Serializable::serialize() | ||
198 | */ | ||
199 | public function serialize() | ||
200 | { | ||
201 | return serialize(array( | ||
202 | $this->id, | ||
203 | )); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * @see \Serializable::unserialize() | ||
208 | */ | ||
209 | public function unserialize($serialized) | ||
210 | { | ||
211 | list ( | ||
212 | $this->id, | ||
213 | ) = unserialize($serialized); | ||
214 | } | ||
215 | |||
216 | public function isEqualTo(UserInterface $user) | ||
217 | { | ||
218 | return $this->username === $user->getUsername(); | ||
219 | } | ||
220 | |||
221 | public function isAccountNonExpired() | ||
222 | { | ||
223 | return true; | ||
224 | } | ||
225 | |||
226 | public function isAccountNonLocked() | ||
227 | { | ||
228 | return true; | ||
229 | } | ||
230 | |||
231 | public function isCredentialsNonExpired() | ||
232 | { | ||
233 | return true; | ||
234 | } | ||
235 | |||
236 | public function isEnabled() | ||
237 | { | ||
238 | return $this->isActive; | ||
239 | } | ||
155 | } | 240 | } |
diff --git a/src/Wallabag/CoreBundle/Helper/Entries.php b/src/Wallabag/CoreBundle/Helper/Entries.php new file mode 100644 index 00000000..a54c3a74 --- /dev/null +++ b/src/Wallabag/CoreBundle/Helper/Entries.php | |||
@@ -0,0 +1,10 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Helper; | ||
4 | |||
5 | |||
6 | class Entries { | ||
7 | |||
8 | |||
9 | |||
10 | } \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/Repository/EntriesRepository.php b/src/Wallabag/CoreBundle/Repository/EntriesRepository.php index edbb96b4..e63c67e2 100644 --- a/src/Wallabag/CoreBundle/Repository/EntriesRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntriesRepository.php | |||
@@ -5,6 +5,8 @@ namespace Wallabag\CoreBundle\Repository; | |||
5 | use Doctrine\ORM\Query; | 5 | use Doctrine\ORM\Query; |
6 | use Doctrine\ORM\EntityRepository; | 6 | use Doctrine\ORM\EntityRepository; |
7 | use Doctrine\ORM\Tools\Pagination\Paginator; | 7 | use Doctrine\ORM\Tools\Pagination\Paginator; |
8 | use Wallabag\CoreBundle\Entity\Entries; | ||
9 | use Wallabag\CoreBundle\Service\Extractor; | ||
8 | 10 | ||
9 | class EntriesRepository extends EntityRepository | 11 | class EntriesRepository extends EntityRepository |
10 | { | 12 | { |
@@ -79,6 +81,7 @@ class EntriesRepository extends EntityRepository | |||
79 | 81 | ||
80 | public function findEntries($userId, $isArchived, $isStarred, $isDeleted, $sort, $order) | 82 | public function findEntries($userId, $isArchived, $isStarred, $isDeleted, $sort, $order) |
81 | { | 83 | { |
84 | //TODO tous les paramètres ne sont pas utilisés, à corriger | ||
82 | $qb = $this->createQueryBuilder('e') | 85 | $qb = $this->createQueryBuilder('e') |
83 | ->select('e') | 86 | ->select('e') |
84 | ->where('e.isFav =:isStarred')->setParameter('isStarred', $isStarred) | 87 | ->where('e.isFav =:isStarred')->setParameter('isStarred', $isStarred) |
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.xml b/src/Wallabag/CoreBundle/Resources/config/services.xml index 02308e6a..d5bc5cca 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.xml +++ b/src/Wallabag/CoreBundle/Resources/config/services.xml | |||
@@ -5,12 +5,24 @@ | |||
5 | xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> | 5 | xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> |
6 | 6 | ||
7 | <services> | 7 | <services> |
8 | <!-- Twig --> | ||
8 | <service id="wallabag_core.twig.wallabag" class="Wallabag\CoreBundle\Twig\Extension\WallabagExtension"> | 9 | <service id="wallabag_core.twig.wallabag" class="Wallabag\CoreBundle\Twig\Extension\WallabagExtension"> |
9 | <tag name="twig.extension" /> | 10 | <tag name="twig.extension" /> |
10 | </service> | 11 | </service> |
11 | </services> | ||
12 | 12 | ||
13 | <!-- Security --> | ||
14 | <service id="wsse.security.authentication.provider" | ||
15 | class="Wallabag\CoreBundle\Security\Authentication\Provider\WsseProvider" public="false"> | ||
16 | <argument /> <!-- User Provider --> | ||
17 | <argument>%kernel.cache_dir%/security/nonces</argument> | ||
18 | </service> | ||
13 | 19 | ||
20 | <service id="wsse.security.authentication.listener" | ||
21 | class="Wallabag\CoreBundle\Security\Firewall\WsseListener" public="false"> | ||
22 | <argument type="service" id="security.context"/> | ||
23 | <argument type="service" id="security.authentication.manager" /> | ||
24 | </service> | ||
25 | </services> | ||
14 | 26 | ||
15 | </container> | 27 | </container> |
16 | 28 | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/Security/login.html.twig b/src/Wallabag/CoreBundle/Resources/views/Security/login.html.twig new file mode 100644 index 00000000..2437e3b0 --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/Security/login.html.twig | |||
@@ -0,0 +1,32 @@ | |||
1 | {% extends "WallabagCoreBundle::layout-login.html.twig" %} | ||
2 | |||
3 | {% block title %}{% trans %}login to your wallabag{% endtrans %}{% endblock %} | ||
4 | {% block content %} | ||
5 | {% if error %} | ||
6 | <div>{{ error.message }}</div> | ||
7 | {% endif %} | ||
8 | |||
9 | <form action="{{ path('login_check') }}" method="post" name="loginform"> | ||
10 | <fieldset class="w500p center"> | ||
11 | <h2 class="mbs txtcenter">{% trans %}Login to wallabag{% endtrans %}</h2> | ||
12 | |||
13 | <div class="row"> | ||
14 | <label class="col w150p" for="username">{% trans %}Username{% endtrans %}</label> | ||
15 | <input type="text" id="username" name="_username" value="{{ last_username }}" /> | ||
16 | </div> | ||
17 | |||
18 | <div class="row"> | ||
19 | <label class="col w150p" for="password">{% trans %}Password{% endtrans %}</label> | ||
20 | <input type="password" id="password" name="_password" /> | ||
21 | </div> | ||
22 | {# | ||
23 | Si vous voulez contrôler l'URL vers laquelle l'utilisateur est redirigé en cas de succès | ||
24 | (plus de détails ci-dessous) | ||
25 | <input type="hidden" name="_target_path" value="/account" /> | ||
26 | #} | ||
27 | <div class="row mts txtcenter"> | ||
28 | <button type="submit">login</button> | ||
29 | </div> | ||
30 | </fieldset> | ||
31 | </form> | ||
32 | {% endblock %} | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig b/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig index d4560e84..3065ce44 100644 --- a/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig | |||
@@ -10,6 +10,6 @@ | |||
10 | </li> | 10 | </li> |
11 | <li><a href="?view=config">{% trans %}config{% endtrans %}</a></li> | 11 | <li><a href="?view=config">{% trans %}config{% endtrans %}</a></li> |
12 | <li><a href={{ path('about') }}>{% trans %}about{% endtrans %}</a></li> | 12 | <li><a href={{ path('about') }}>{% trans %}about{% endtrans %}</a></li> |
13 | <li><a class="icon icon-power" href="?logout" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li> | 13 | <li><a class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li> |
14 | </ul> | 14 | </ul> |
15 | 15 | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/layout-login.html.twig b/src/Wallabag/CoreBundle/Resources/views/layout-login.html.twig new file mode 100644 index 00000000..9c39ea9f --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/layout-login.html.twig | |||
@@ -0,0 +1,26 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!--[if lte IE 6]><html class="no-js ie6 ie67 ie678" lang="en"><![endif]--> | ||
3 | <!--[if lte IE 7]><html class="no-js ie7 ie67 ie678" lang="en"><![endif]--> | ||
4 | <!--[if IE 8]><html class="no-js ie8 ie678" lang="en"><![endif]--> | ||
5 | <!--[if gt IE 8]><html class="no-js" lang="en"><![endif]--> | ||
6 | <html lang="en"> | ||
7 | <head> | ||
8 | <meta name="viewport" content="initial-scale=1.0"> | ||
9 | <meta charset="utf-8"> | ||
10 | <!--[if IE]> | ||
11 | <meta http-equiv="X-UA-Compatible" content="IE=10"> | ||
12 | <![endif]--> | ||
13 | <title>{% block title %}{% endblock %} - wallabag</title> | ||
14 | {% include "WallabagCoreBundle::_head.html.twig" %} | ||
15 | </head> | ||
16 | <body class="login"> | ||
17 | {% include "WallabagCoreBundle::_top.html.twig" %} | ||
18 | <div id="main"> | ||
19 | {% block menu %}{% endblock %} | ||
20 | <div id="content" class="w600p center"> | ||
21 | {% block content %}{% endblock %} | ||
22 | </div> | ||
23 | </div> | ||
24 | {% include "WallabagCoreBundle::_footer.html.twig" %} | ||
25 | </body> | ||
26 | </html> \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/Resources/views/layout.html.twig b/src/Wallabag/CoreBundle/Resources/views/layout.html.twig index 83830a4a..1f1753a4 100644 --- a/src/Wallabag/CoreBundle/Resources/views/layout.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/layout.html.twig | |||
@@ -4,30 +4,30 @@ | |||
4 | <!--[if IE 8]><html class="no-js ie8 ie678" lang="en"><![endif]--> | 4 | <!--[if IE 8]><html class="no-js ie8 ie678" lang="en"><![endif]--> |
5 | <!--[if gt IE 8]><html class="no-js" lang="en"><![endif]--> | 5 | <!--[if gt IE 8]><html class="no-js" lang="en"><![endif]--> |
6 | <html lang="en"> | 6 | <html lang="en"> |
7 | <head> | 7 | <head> |
8 | <meta name="viewport" content="initial-scale=1.0"> | 8 | <meta name="viewport" content="initial-scale=1.0"> |
9 | <meta charset="utf-8"> | 9 | <meta charset="utf-8"> |
10 | <!--[if IE]> | 10 | <!--[if IE]> |
11 | <meta http-equiv="X-UA-Compatible" content="IE=10"> | 11 | <meta http-equiv="X-UA-Compatible" content="IE=10"> |
12 | <![endif]--> | 12 | <![endif]--> |
13 | <title>{% block title %}{% endblock %} - wallabag</title> | 13 | <title>{% block title %}{% endblock %} - wallabag</title> |
14 | {% include "WallabagCoreBundle::_head.html.twig" %} | 14 | {% include "WallabagCoreBundle::_head.html.twig" %} |
15 | {% include "WallabagCoreBundle::_bookmarklet.html.twig" %} | 15 | {% include "WallabagCoreBundle::_bookmarklet.html.twig" %} |
16 | </head> | 16 | </head> |
17 | <body> | 17 | <body> |
18 | {% include "WallabagCoreBundle::_top.html.twig" %} | 18 | {% include "WallabagCoreBundle::_top.html.twig" %} |
19 | <div id="main"> | 19 | <div id="main"> |
20 | {% block menu %}{% endblock %} | 20 | {% block menu %}{% endblock %} |
21 | {% block precontent %}{% endblock %} | 21 | {% block precontent %}{% endblock %} |
22 | {% for flashMessage in app.session.flashbag.get('notice') %} | 22 | {% for flashMessage in app.session.flashbag.get('notice') %} |
23 | <div class="flash-notice"> | 23 | <div class="flash-notice"> |
24 | {{ flashMessage }} | 24 | {{ flashMessage }} |
25 | </div> | ||
26 | {% endfor %} | ||
27 | <div id="content" class="w600p center"> | ||
28 | {% block content %}{% endblock %} | ||
25 | </div> | 29 | </div> |
26 | {% endfor %} | ||
27 | <div id="content" class="w600p center"> | ||
28 | {% block content %}{% endblock %} | ||
29 | </div> | 30 | </div> |
30 | </div> | 31 | {% include "WallabagCoreBundle::_footer.html.twig" %} |
31 | {% include "WallabagCoreBundle::_footer.html.twig" %} | 32 | </body> |
32 | </body> | ||
33 | </html> \ No newline at end of file | 33 | </html> \ No newline at end of file |
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Provider/WsseProvider.php b/src/Wallabag/CoreBundle/Security/Authentication/Provider/WsseProvider.php new file mode 100644 index 00000000..ac57e27d --- /dev/null +++ b/src/Wallabag/CoreBundle/Security/Authentication/Provider/WsseProvider.php | |||
@@ -0,0 +1,59 @@ | |||
1 | <?php | ||
2 | namespace Wallabag\CoreBundle\Security\Authentication\Provider; | ||
3 | |||
4 | use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; | ||
5 | use Symfony\Component\Security\Core\User\UserProviderInterface; | ||
6 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
7 | use Symfony\Component\Security\Core\Exception\NonceExpiredException; | ||
8 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||
9 | use Wallabag\CoreBundle\Security\Authentication\Token\WsseUserToken; | ||
10 | |||
11 | class WsseProvider implements AuthenticationProviderInterface | ||
12 | { | ||
13 | private $userProvider; | ||
14 | private $cacheDir; | ||
15 | |||
16 | public function __construct(UserProviderInterface $userProvider, $cacheDir) | ||
17 | { | ||
18 | $this->userProvider = $userProvider; | ||
19 | $this->cacheDir = $cacheDir; | ||
20 | } | ||
21 | |||
22 | public function authenticate(TokenInterface $token) | ||
23 | { | ||
24 | $user = $this->userProvider->loadUserByUsername($token->getUsername()); | ||
25 | |||
26 | if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) { | ||
27 | $authenticatedToken = new WsseUserToken($user->getRoles()); | ||
28 | $authenticatedToken->setUser($user); | ||
29 | |||
30 | return $authenticatedToken; | ||
31 | } | ||
32 | |||
33 | throw new AuthenticationException('The WSSE authentication failed.'); | ||
34 | } | ||
35 | |||
36 | protected function validateDigest($digest, $nonce, $created, $secret) | ||
37 | { | ||
38 | // Expire le timestamp après 5 minutes | ||
39 | if (time() - strtotime($created) > 300) { | ||
40 | return false; | ||
41 | } | ||
42 | |||
43 | // Valide que le nonce est unique dans les 5 minutes | ||
44 | if (file_exists($this->cacheDir.'/'.$nonce) && file_get_contents($this->cacheDir.'/'.$nonce) + 300 > time()) { | ||
45 | throw new NonceExpiredException('Previously used nonce detected'); | ||
46 | } | ||
47 | file_put_contents($this->cacheDir.'/'.$nonce, time()); | ||
48 | |||
49 | // Valide le Secret | ||
50 | $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true)); | ||
51 | |||
52 | return $digest === $expected; | ||
53 | } | ||
54 | |||
55 | public function supports(TokenInterface $token) | ||
56 | { | ||
57 | return $token instanceof WsseUserToken; | ||
58 | } | ||
59 | } \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Token/WsseUserToken.php b/src/Wallabag/CoreBundle/Security/Authentication/Token/WsseUserToken.php new file mode 100644 index 00000000..b189e22a --- /dev/null +++ b/src/Wallabag/CoreBundle/Security/Authentication/Token/WsseUserToken.php | |||
@@ -0,0 +1,23 @@ | |||
1 | <?php | ||
2 | namespace Wallabag\CoreBundle\Security\Authentication\Token; | ||
3 | |||
4 | use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; | ||
5 | |||
6 | class WsseUserToken extends AbstractToken | ||
7 | { | ||
8 | public $created; | ||
9 | public $digest; | ||
10 | public $nonce; | ||
11 | |||
12 | public function __construct(array $roles = array()) | ||
13 | { | ||
14 | parent::__construct($roles); | ||
15 | |||
16 | $this->setAuthenticated(count($roles) > 0); | ||
17 | } | ||
18 | |||
19 | public function getCredentials() | ||
20 | { | ||
21 | return ''; | ||
22 | } | ||
23 | } \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/Security/Firewall/WsseListener.php b/src/Wallabag/CoreBundle/Security/Firewall/WsseListener.php new file mode 100644 index 00000000..b2474785 --- /dev/null +++ b/src/Wallabag/CoreBundle/Security/Firewall/WsseListener.php | |||
@@ -0,0 +1,58 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Security\Firewall; | ||
4 | |||
5 | use Symfony\Component\HttpFoundation\Response; | ||
6 | use Symfony\Component\HttpKernel\Event\GetResponseEvent; | ||
7 | use Symfony\Component\Security\Http\Firewall\ListenerInterface; | ||
8 | use Symfony\Component\Security\Core\Exception\AuthenticationException; | ||
9 | use Symfony\Component\Security\Core\SecurityContextInterface; | ||
10 | use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; | ||
11 | use Wallabag\CoreBundle\Security\Authentication\Token\WsseUserToken; | ||
12 | |||
13 | class WsseListener implements ListenerInterface | ||
14 | { | ||
15 | protected $securityContext; | ||
16 | protected $authenticationManager; | ||
17 | |||
18 | public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager) | ||
19 | { | ||
20 | $this->securityContext = $securityContext; | ||
21 | $this->authenticationManager = $authenticationManager; | ||
22 | } | ||
23 | |||
24 | public function handle(GetResponseEvent $event) | ||
25 | { | ||
26 | $request = $event->getRequest(); | ||
27 | |||
28 | $wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/'; | ||
29 | if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches)) { | ||
30 | return; | ||
31 | } | ||
32 | |||
33 | $token = new WsseUserToken(); | ||
34 | $token->setUser($matches[1]); | ||
35 | |||
36 | $token->digest = $matches[2]; | ||
37 | $token->nonce = $matches[3]; | ||
38 | $token->created = $matches[4]; | ||
39 | |||
40 | try { | ||
41 | $authToken = $this->authenticationManager->authenticate($token); | ||
42 | |||
43 | $this->securityContext->setToken($authToken); | ||
44 | } catch (AuthenticationException $failed) { | ||
45 | // ... you might log something here | ||
46 | |||
47 | // To deny the authentication clear the token. This will redirect to the login page. | ||
48 | // $this->securityContext->setToken(null); | ||
49 | // return; | ||
50 | |||
51 | // Deny authentication with a '403 Forbidden' HTTP response | ||
52 | $response = new Response(); | ||
53 | $response->setStatusCode(403); | ||
54 | $event->setResponse($response); | ||
55 | |||
56 | } | ||
57 | } | ||
58 | } \ No newline at end of file | ||
diff --git a/src/Wallabag/CoreBundle/WallabagCoreBundle.php b/src/Wallabag/CoreBundle/WallabagCoreBundle.php index f5899e39..1deab03a 100644 --- a/src/Wallabag/CoreBundle/WallabagCoreBundle.php +++ b/src/Wallabag/CoreBundle/WallabagCoreBundle.php | |||
@@ -3,7 +3,16 @@ | |||
3 | namespace Wallabag\CoreBundle; | 3 | namespace Wallabag\CoreBundle; |
4 | 4 | ||
5 | use Symfony\Component\HttpKernel\Bundle\Bundle; | 5 | use Symfony\Component\HttpKernel\Bundle\Bundle; |
6 | use Wallabag\CoreBundle\DependencyInjection\Security\Factory\WsseFactory; | ||
7 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
6 | 8 | ||
7 | class WallabagCoreBundle extends Bundle | 9 | class WallabagCoreBundle extends Bundle |
8 | { | 10 | { |
11 | public function build(ContainerBuilder $container) | ||
12 | { | ||
13 | parent::build($container); | ||
14 | |||
15 | $extension = $container->getExtension('security'); | ||
16 | $extension->addSecurityListenerFactory(new WsseFactory()); | ||
17 | } | ||
9 | } | 18 | } |