Added authentication for restricted access articles

Fix #438. Thank you so much @bdunogier
This commit is contained in:
Bertrand Dunogier 2016-09-29 10:14:43 +02:00 committed by Nicolas Lœuillet
parent bb28368f69
commit 7aab0ecf2f
7 changed files with 235 additions and 1 deletions

View 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(),

View file

@ -56,3 +56,6 @@ parameters:
redis_port: 6379
redis_path: null
redis_password: null
# sites credentials
sites_credentials: {}

View 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",

View file

@ -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);
}
}

View file

@ -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;
}
}

View 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:

View file

@ -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
);
}
}