]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Added authentication for restricted access articles
authorBertrand Dunogier <bertrand.dunogier@gmail.com>
Thu, 29 Sep 2016 08:14:43 +0000 (10:14 +0200)
committerNicolas LÅ“uillet <nicolas@loeuillet.org>
Tue, 22 Nov 2016 13:01:46 +0000 (14:01 +0100)
Fix #438. Thank you so much @bdunogier

app/AppKernel.php
app/config/parameters.yml.dist
composer.json
src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Helper/HttpClientFactory.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/config/services.yml
tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php [new file with mode: 0644]

index 81b83ef9d40472322dec346edaa4c67cc50b2bb3..c8382d5f6c27991f2034dfcb93e1c030b30e35cc 100644 (file)
@@ -31,6 +31,7 @@ class AppKernel extends Kernel
             new Craue\ConfigBundle\CraueConfigBundle(),
             new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(),
             new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
+            new BD\GuzzleSiteAuthenticatorBundle\BDGuzzleSiteAuthenticatorBundle(),
 
             // wallabag bundles
             new Wallabag\CoreBundle\WallabagCoreBundle(),
index f821f2a85c8e6513e5256a947737e0d219327c07..a4dc0bdea5df1f654275f713436a7cf209af4613 100644 (file)
@@ -56,3 +56,6 @@ parameters:
     redis_port: 6379
     redis_path: null
     redis_password: null
+
+    # sites credentials
+    sites_credentials: {}
index 1548d6ec60db32bfcd912380e426f4e51d844326..e2aeb424cf59aa2d71322a443f9499abe9adc618 100644 (file)
@@ -83,7 +83,8 @@
         "predis/predis": "^1.0",
         "javibravo/simpleue": "^1.0",
         "symfony/dom-crawler": "^3.1",
-        "friendsofsymfony/jsrouting-bundle": "^1.6"
+        "friendsofsymfony/jsrouting-bundle": "^1.6",
+        "bdunogier/guzzle-site-authenticator": "^1.0@beta"
     },
     "require-dev": {
         "doctrine/doctrine-fixtures-bundle": "~2.2",
diff --git a/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php b/src/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilder.php
new file mode 100644 (file)
index 0000000..6d4129e
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+namespace Wallabag\CoreBundle\GuzzleSiteAuthenticator;
+
+use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig;
+use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfigBuilder;
+use Graby\SiteConfig\ConfigBuilder;
+use OutOfRangeException;
+
+class GrabySiteConfigBuilder implements SiteConfigBuilder
+{
+    /**
+     * @var \Graby\SiteConfig\ConfigBuilder
+     */
+    private $grabyConfigBuilder;
+    /**
+     * @var array
+     */
+    private $credentials;
+
+    /**
+     * GrabySiteConfigBuilder constructor.
+     *
+     * @param \Graby\SiteConfig\ConfigBuilder $grabyConfigBuilder
+     * @param array                           $credentials
+     */
+    public function __construct(ConfigBuilder $grabyConfigBuilder, array $credentials = [])
+    {
+        $this->grabyConfigBuilder = $grabyConfigBuilder;
+        $this->credentials = $credentials;
+    }
+
+    /**
+     * Builds the SiteConfig for a host.
+     *
+     * @param string $host The "www." prefix is ignored
+     *
+     * @return SiteConfig
+     *
+     * @throws OutOfRangeException If there is no config for $host
+     */
+    public function buildForHost($host)
+    {
+        // required by credentials below
+        $host = strtolower($host);
+        if (substr($host, 0, 4) == 'www.') {
+            $host = substr($host, 4);
+        }
+
+        $config = $this->grabyConfigBuilder->buildForHost($host);
+        $parameters = [
+            'host' => $host,
+            'requiresLogin' => $config->requires_login ?: false,
+            'loginUri' => $config->login_uri ?: null,
+            'usernameField' => $config->login_username_field ?: null,
+            'passwordField' => $config->login_password_field ?: null,
+            'extraFields' => is_array($config->login_extra_fields) ? $config->login_extra_fields : [],
+            'notLoggedInXpath' => $config->not_logged_in_xpath ?: null,
+        ];
+
+        if (isset($this->credentials[$host])) {
+            $parameters['username'] = $this->credentials[$host]['username'];
+            $parameters['password'] = $this->credentials[$host]['password'];
+        }
+
+        return new SiteConfig($parameters);
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php b/src/Wallabag/CoreBundle/Helper/HttpClientFactory.php
new file mode 100644 (file)
index 0000000..3e1d1ed
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+namespace Wallabag\CoreBundle\Helper;
+
+use Graby\Ring\Client\SafeCurlHandler;
+use GuzzleHttp\Client;
+use GuzzleHttp\Cookie\CookieJar;
+use GuzzleHttp\Event\SubscriberInterface;
+
+/**
+ * Builds and configures the Guzzle HTTP client.
+ */
+class HttpClientFactory
+{
+    /** @var \GuzzleHttp\Event\SubscriberInterface */
+    private $authenticatorSubscriber;
+
+    /** @var \GuzzleHttp\Cookie\CookieJar */
+    private $cookieJar;
+
+    /**
+     * HttpClientFactory constructor.
+     *
+     * @param \GuzzleHttp\Event\SubscriberInterface $authenticatorSubscriber
+     * @param \GuzzleHttp\Cookie\CookieJar          $cookieJar
+     */
+    public function __construct(SubscriberInterface $authenticatorSubscriber, CookieJar $cookieJar)
+    {
+        $this->authenticatorSubscriber = $authenticatorSubscriber;
+        $this->cookieJar = $cookieJar;
+    }
+
+    /**
+     * @return \GuzzleHttp\Client
+     */
+    public function buildHttpClient()
+    {
+        // need to set the (shared) cookie jar
+        $client = new Client(['handler' => new SafeCurlHandler(), 'defaults' => ['cookies' => $this->cookieJar]]);
+        $client->getEmitter()->attach($this->authenticatorSubscriber);
+
+        return $client;
+    }
+}
index 0280bc182a754e58835f04ccdea6a4e5bf4a83df..1b7f39fc225b417d74a24073bcad12a73eb396c0 100644 (file)
@@ -41,11 +41,43 @@ services:
         arguments:
             -
                 error_message: '%wallabag_core.fetching_error_message%'
+            - "@wallabag_core.guzzle.http_client"
+            - "@wallabag_core.graby.config_builder"
         calls:
             - [ setLogger, [ "@logger" ] ]
         tags:
             - { name: monolog.logger, channel: graby }
 
+    wallabag_core.graby.config_builder:
+        class: Graby\SiteConfig\ConfigBuilder
+        arguments:
+            - {}
+            - "@logger"
+
+    wallabag_core.guzzle.http_client:
+        class: GuzzleHttp\ClientInterface
+        factory: ["@wallabag_core.guzzle.http_client_factory", buildHttpClient]
+
+    wallabag_core.guzzle_authenticator.config_builder:
+        class: Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder
+        arguments:
+            - "@wallabag_core.graby.config_builder"
+            - "%sites_credentials%"
+
+    # service alias override
+    bd_guzzle_site_authenticator.site_config_builder:
+        alias: wallabag_core.guzzle_authenticator.config_builder
+
+    wallabag_core.guzzle.http_client_factory:
+        class: Wallabag\CoreBundle\Helper\HttpClientFactory
+        arguments:
+            - "@bd_guzzle_site_authenticator.authenticator_subscriber"
+            - "@wallabag_core.guzzle.cookie_jar"
+
+    wallabag_core.guzzle.cookie_jar:
+        class: GuzzleHttp\Cookie\FileCookieJar
+        arguments: ["%kernel.cache_dir%/cookiejar.json"]
+
     wallabag_core.content_proxy:
         class: Wallabag\CoreBundle\Helper\ContentProxy
         arguments:
diff --git a/tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php b/tests/Wallabag/CoreBundle/GuzzleSiteAuthenticator/GrabySiteConfigBuilderTest.php
new file mode 100644 (file)
index 0000000..aee6725
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+
+namespace Tests\Wallabag\CoreBundle\GuzzleSiteAuthenticator;
+
+use BD\GuzzleSiteAuthenticator\SiteConfig\SiteConfig;
+use Graby\SiteConfig\SiteConfig as GrabySiteConfig;
+use PHPUnit_Framework_TestCase;
+use Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder;
+
+class GrabySiteConfigBuilderTest extends PHPUnit_Framework_TestCase
+{
+    /** @var \Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder */
+    protected $builder;
+
+    public function testBuildConfigExists()
+    {
+        /* @var \Graby\SiteConfig\ConfigBuilder|\PHPUnit_Framework_MockObject_MockObject */
+        $grabyConfigBuilderMock = $this->getMockBuilder('\Graby\SiteConfig\ConfigBuilder')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $grabySiteConfig = new GrabySiteConfig();
+        $grabySiteConfig->requires_login = true;
+        $grabySiteConfig->login_uri = 'http://example.com/login';
+        $grabySiteConfig->login_username_field = 'login';
+        $grabySiteConfig->login_password_field = 'password';
+        $grabySiteConfig->login_extra_fields = ['field' => 'value'];
+        $grabySiteConfig->not_logged_in_xpath = '//div[@class="need-login"]';
+
+        $grabyConfigBuilderMock
+            ->method('buildForHost')
+            ->with('example.com')
+            ->will($this->returnValue($grabySiteConfig));
+
+        $this->builder = new GrabySiteConfigBuilder(
+            $grabyConfigBuilderMock,
+            ['example.com' => ['username' => 'foo', 'password' => 'bar']]
+        );
+
+        $config = $this->builder->buildForHost('example.com');
+
+        self::assertEquals(
+            new SiteConfig([
+                'host' => 'example.com',
+                'requiresLogin' => true,
+                'loginUri' => 'http://example.com/login',
+                'usernameField' => 'login',
+                'passwordField' => 'password',
+                'extraFields' => ['field' => 'value'],
+                'notLoggedInXpath' => '//div[@class="need-login"]',
+                'username' => 'foo',
+                'password' => 'bar',
+            ]),
+            $config
+        );
+    }
+
+    public function testBuildConfigDoesntExist()
+    {
+        /* @var \Graby\SiteConfig\ConfigBuilder|\PHPUnit_Framework_MockObject_MockObject */
+        $grabyConfigBuilderMock = $this->getMockBuilder('\Graby\SiteConfig\ConfigBuilder')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $grabyConfigBuilderMock
+            ->method('buildForHost')
+            ->with('unknown.com')
+            ->will($this->returnValue(new GrabySiteConfig()));
+
+        $this->builder = new GrabySiteConfigBuilder($grabyConfigBuilderMock, []);
+
+        $config = $this->builder->buildForHost('unknown.com');
+
+        self::assertEquals(
+            new SiteConfig([
+                'host' => 'unknown.com',
+                'requiresLogin' => false,
+                'username' => null,
+                'password' => null,
+                'extraFields' => [],
+            ]),
+            $config
+        );
+    }
+}