aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas@loeuillet.org>2015-01-31 15:14:10 +0100
committerNicolas Lœuillet <nicolas@loeuillet.org>2015-01-31 15:14:10 +0100
commitc3235553ddc2bb5965f6fe00e750cfe4aac9ccdf (patch)
tree271305a039d31059c7af8be220da08b9331baeec /src
parent71691fe44a7b2a80f3b9d96d54720cce7994ad08 (diff)
downloadwallabag-c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf.tar.gz
wallabag-c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf.tar.zst
wallabag-c3235553ddc2bb5965f6fe00e750cfe4aac9ccdf.zip
first implementation of security
Diffstat (limited to 'src')
-rw-r--r--src/Wallabag/CoreBundle/Controller/SecurityController.php27
-rw-r--r--src/Wallabag/CoreBundle/Controller/WallabagRestController.php9
-rw-r--r--src/Wallabag/CoreBundle/DependencyInjection/Security/Factory/WsseFactory.php40
-rw-r--r--src/Wallabag/CoreBundle/Entity/Entries.php1
-rw-r--r--src/Wallabag/CoreBundle/Entity/Users.php87
-rw-r--r--src/Wallabag/CoreBundle/Helper/Entries.php10
-rw-r--r--src/Wallabag/CoreBundle/Repository/EntriesRepository.php3
-rw-r--r--src/Wallabag/CoreBundle/Resources/config/services.xml14
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/Security/login.html.twig32
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/_menu.html.twig2
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/layout-login.html.twig26
-rw-r--r--src/Wallabag/CoreBundle/Resources/views/layout.html.twig48
-rw-r--r--src/Wallabag/CoreBundle/Security/Authentication/Provider/WsseProvider.php59
-rw-r--r--src/Wallabag/CoreBundle/Security/Authentication/Token/WsseUserToken.php23
-rw-r--r--src/Wallabag/CoreBundle/Security/Firewall/WsseListener.php58
-rw-r--r--src/Wallabag/CoreBundle/WallabagCoreBundle.php9
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
3namespace Wallabag\CoreBundle\Controller;
4
5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Security\Core\SecurityContext;
8
9class 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
3namespace Wallabag\CoreBundle\DependencyInjection\Security\Factory;
4
5use Symfony\Component\DependencyInjection\ContainerBuilder;
6use Symfony\Component\DependencyInjection\Reference;
7use Symfony\Component\DependencyInjection\DefinitionDecorator;
8use Symfony\Component\Config\Definition\Builder\NodeDefinition;
9use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
10
11class 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 */
14class Entries 15class 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 @@
3namespace Wallabag\CoreBundle\Entity; 3namespace Wallabag\CoreBundle\Entity;
4 4
5use Doctrine\ORM\Mapping as ORM; 5use Doctrine\ORM\Mapping as ORM;
6use Symfony\Component\Security\Core\User\UserInterface;
7use Symfony\Component\Security\Core\User\EquatableInterface;
8use 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 */
13class Users 16class 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
3namespace Wallabag\CoreBundle\Helper;
4
5
6class 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;
5use Doctrine\ORM\Query; 5use Doctrine\ORM\Query;
6use Doctrine\ORM\EntityRepository; 6use Doctrine\ORM\EntityRepository;
7use Doctrine\ORM\Tools\Pagination\Paginator; 7use Doctrine\ORM\Tools\Pagination\Paginator;
8use Wallabag\CoreBundle\Entity\Entries;
9use Wallabag\CoreBundle\Service\Extractor;
8 10
9class EntriesRepository extends EntityRepository 11class 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
2namespace Wallabag\CoreBundle\Security\Authentication\Provider;
3
4use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
5use Symfony\Component\Security\Core\User\UserProviderInterface;
6use Symfony\Component\Security\Core\Exception\AuthenticationException;
7use Symfony\Component\Security\Core\Exception\NonceExpiredException;
8use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
9use Wallabag\CoreBundle\Security\Authentication\Token\WsseUserToken;
10
11class 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
2namespace Wallabag\CoreBundle\Security\Authentication\Token;
3
4use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
5
6class 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
3namespace Wallabag\CoreBundle\Security\Firewall;
4
5use Symfony\Component\HttpFoundation\Response;
6use Symfony\Component\HttpKernel\Event\GetResponseEvent;
7use Symfony\Component\Security\Http\Firewall\ListenerInterface;
8use Symfony\Component\Security\Core\Exception\AuthenticationException;
9use Symfony\Component\Security\Core\SecurityContextInterface;
10use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
11use Wallabag\CoreBundle\Security\Authentication\Token\WsseUserToken;
12
13class 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 @@
3namespace Wallabag\CoreBundle; 3namespace Wallabag\CoreBundle;
4 4
5use Symfony\Component\HttpKernel\Bundle\Bundle; 5use Symfony\Component\HttpKernel\Bundle\Bundle;
6use Wallabag\CoreBundle\DependencyInjection\Security\Factory\WsseFactory;
7use Symfony\Component\DependencyInjection\ContainerBuilder;
6 8
7class WallabagCoreBundle extends Bundle 9class 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}