Skip to content

Commit

Permalink
PHRAS-1718 add google recaptcha (#4224)
Browse files Browse the repository at this point in the history
* PHRAS-1718 Add google recaptcha lib - Dont merge some quick fixes remaining

* PHRAS-1718 Add error on registration form if captcha is not filled

* Update dependencies

* PHRAS-1718 Add trials-before-display var on admin setup form. Add integer constraint on this field

* fix

* test

* test

* fix

* test

* test

* fix

* test

* fix

* test

* add captcha on forgotten password

* fix

* add patch

* add locale on captcha

* bump version

Co-authored-by: Xavier Rousset <[email protected]>
  • Loading branch information
aynsix and xrousset78800 authored Jan 25, 2023
1 parent 851e97d commit 9902457
Show file tree
Hide file tree
Showing 26 changed files with 239 additions and 206 deletions.
19 changes: 9 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
"repositories": [
{
"type": "package",
"package": {
"name": "facebook/php-sdk",
"version": "3.2.3",
"source": {
"url": "https://github.com/facebookarchive/facebook-php-sdk.git",
"type": "git",
"reference": "3.2.3"
}
}
"package": {
"name": "facebook/php-sdk",
"version": "3.2.3",
"source": {
"url": "https://github.com/facebookarchive/facebook-php-sdk.git",
"type": "git",
"reference": "3.2.3"
}
}
},
{
"type": "package",
Expand Down Expand Up @@ -100,7 +100,6 @@
"monolog/monolog": "~1.3",
"mrclay/minify": "~2.1.6",
"neutron/process-manager": "2.0.x-dev@dev",
"neutron/recaptcha": "~0.1.0",
"neutron/silex-filesystem-provider": "~1.0",
"neutron/silex-imagine-provider": "~0.1.0",
"neutron/temporary-filesystem": "~2.1",
Expand Down
46 changes: 1 addition & 45 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions config/configuration.sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,6 @@ border-manager:
authentication:
auto-create:
templates: { }
captcha:
enabled: true
trials-before-display: 9
providers:
facebook:
enabled: false
Expand Down
12 changes: 4 additions & 8 deletions lib/Alchemy/Phrasea/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Neutron\ReCaptcha\ReCaptchaServiceProvider;
use Psr\Log\LoggerInterface;
use Silex\Application as SilexApplication;
use Silex\Application\TranslationTrait;
Expand Down Expand Up @@ -203,25 +202,21 @@ public function __construct($environment = null)
$this->setupGeonames();
$this->register(new NotificationDelivererServiceProvider());
$this->register(new RepositoriesServiceProvider());
$this->register(new ManipulatorServiceProvider());
$this->register(new TechnicalDataServiceProvider());
$this->register(new MediaSubdefServiceProvider());
$this->register(new CaptionServiceProvider());
$this->register(new InstallerServiceProvider());
$this->register(new PhraseaVersionServiceProvider());

$this->register(new RandomGeneratorServiceProvider());
$this->register(new ReCaptchaServiceProvider());
$this->register(new SubdefServiceProvider());
$this->register(new ZippyServiceProvider());
$this->setupRecaptacha();

if ($this['configuration.store']->isSetup()) {
$this->register(new SearchEngineServiceProvider());
$this->register(new BorderManagerServiceProvider());
}


$this->register(new SerializerServiceProvider());
$this->register(new ServiceControllerServiceProvider());
$this->register(new SwiftmailerServiceProvider());
Expand Down Expand Up @@ -261,6 +256,7 @@ public function __construct($environment = null)
$this->register(new LocaleServiceProvider());

$this->setupEventDispatcher();
$this->setupRecaptacha();

$this->register(new DataboxServiceProvider());
$this->register(new QueueServiceProvider());
Expand Down Expand Up @@ -464,7 +460,7 @@ public function getUnlockAccountData()
*/
public function requireCaptcha()
{
if ($this['conf']->get(['registry', 'webservices', 'captcha-enabled'])) {
if ($this['conf']->get(['registry', 'webservices', 'captchas-enabled'])) {
$this['session']->set('require_captcha', true);
}

Expand Down Expand Up @@ -658,12 +654,12 @@ private function setupForm()
private function setupRecaptacha()
{
$this['recaptcha.public-key'] = $this->share(function (Application $app) {
if ($app['conf']->get(['registry', 'webservices', 'captcha-enabled'])) {
if ($app['conf']->get(['registry', 'webservices', 'captchas-enabled'])) {
return $app['conf']->get(['registry', 'webservices', 'recaptcha-public-key']);
}
});
$this['recaptcha.private-key'] = $this->share(function (Application $app) {
if ($app['conf']->get(['registry', 'webservices', 'captcha-enabled'])) {
if ($app['conf']->get(['registry', 'webservices', 'captchas-enabled'])) {
return $app['conf']->get(['registry', 'webservices', 'recaptcha-private-key']);
}
});
Expand Down
14 changes: 9 additions & 5 deletions lib/Alchemy/Phrasea/Authentication/Phrasea/FailureManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Alchemy\Phrasea\Model\Repositories\AuthFailureRepository;
use Doctrine\ORM\EntityManager;
use Alchemy\Phrasea\Model\Entities\AuthFailure;
use Neutron\ReCaptcha\ReCaptcha;
use ReCaptcha\ReCaptcha;
use Symfony\Component\HttpFoundation\Request;

class FailureManager
Expand Down Expand Up @@ -111,18 +111,22 @@ public function resetLockedFailureByUsername($username)
public function checkFailures($username, Request $request)
{
$failures = $this->repository->findLockedFailuresMatching($username, $request->getClientIp());
$captchaResp = $request->get('g-recaptcha-response');

if (0 === count($failures)) {
return $this;
}

if ($this->trials < count($failures) && $this->captcha->isSetup()) {
$response = $this->captcha->bind($request);

if (!$response->isValid()) {
if ($this->trials <= count($failures)) {
if ($captchaResp === null) {
throw new RequireCaptchaException('Too many failures, require captcha');
}

$response = $this->captcha->verify($captchaResp, $request->getClientIp());
if (!$response->isSuccess()) {
throw new RequireCaptchaException('Please fill captcha');
}

foreach ($failures as $failure) {
$failure->setLocked(false);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Alchemy/Phrasea/Controller/Api/V1Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ private function getGlobalValuesInformation()
'googleAnalyticsId' => $conf->get(['registry', 'general', 'analytics']),
'i18nWebService' => $conf->get(['registry', 'webservices', 'geonames-server']),
'recaptacha' => [
'active' => $conf->get(['registry', 'webservices', 'captcha-enabled']),
'active' => $conf->get(['registry', 'webservices', 'captchas-enabled']),
'publicKey' => $conf->get(['registry', 'webservices', 'recaptcha-public-key']),
'privateKey' => $conf->get(['registry', 'webservices', 'recaptcha-private-key']),
],
Expand Down
31 changes: 21 additions & 10 deletions lib/Alchemy/Phrasea/Controller/Root/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@
use Alchemy\Phrasea\Notification\Receiver;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Neutron\ReCaptcha\ReCaptcha;
use RandomLib\Generator;
use ReCaptcha\ReCaptcha;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RedirectResponse;
Expand Down Expand Up @@ -94,7 +95,7 @@ public function getDefaultTemplateVariables(Request $request)

$conf = $this->getConf();
$browser = $this->getBrowser();

return [
'last_publication_items' => $items,
'instance_title' => $conf->get(['registry', 'general', 'title']),
Expand All @@ -108,6 +109,7 @@ public function getDefaultTemplateVariables(Request $request)
'current_url' => $request->getUri(),
'flash_types' => $this->app->getAvailableFlashTypes(),
'recaptcha_display' => $this->app->isCaptchaRequired(),
'recaptcha_enabled' => $conf->get(['registry', 'webservices', 'captchas-enabled']),
'unlock_usr_id' => $this->app->getUnlockAccountData(),
'guest_allowed' => $this->app->isGuestAllowed(),
'register_enable' => $this->getRegistrationManager()->isRegistrationEnabled(),
Expand Down Expand Up @@ -187,6 +189,14 @@ public function doRegistration(Request $request)
$data = $form->getData();

$provider = null;

if(isset($requestData['g-recaptcha-response']) && $requestData['g-recaptcha-response'] == "") {
$this->app->addFlash('error', $this->app->trans('Please fill captcha'));

$dateError = new FormError("");
$form->get('captcha')->addError($dateError);
}

if ($data['provider-id']) {
try {
$provider = $this->findProvider($data['provider-id']);
Expand Down Expand Up @@ -222,13 +232,6 @@ public function doRegistration(Request $request)

try {
if ($form->isValid()) {
$captcha = $this->getRecaptcha()->bind($request);

$conf = $this->getConf();
if ($conf->get(['registry', 'webservices', 'captcha-enabled']) && !$captcha->isValid()) {
throw new FormProcessingException($this->app->trans('Invalid captcha answer.'));
}

$registrationService = $this->getRegistrationService();
$providerId = isset($data['provider-id']) ? $data['provider-id'] : null;
$selectedCollections = isset($data['collections']) ? $data['collections'] : null;
Expand Down Expand Up @@ -428,6 +431,14 @@ public function forgotPassword(Request $request)
try {
if ('POST' === $request->getMethod()) {
$form->handleRequest($request);
$requestData = $request->request->all();

if(isset($requestData['g-recaptcha-response']) && $requestData['g-recaptcha-response'] == "") {
$this->app->addFlash('error', $this->app->trans('Please fill captcha'));

$dataError = new FormError("");
$form->get('captcha')->addError($dataError);
}

if ($form->isValid()) {
$data = $form->getData();
Expand Down Expand Up @@ -832,7 +843,7 @@ private function doAuthentication(Request $request, FormInterface $form, $redire
);
} catch (RequireCaptchaException $e) {
$this->app->requireCaptcha();
$this->app->addFlash('warning', $this->app->trans('Please fill the captcha'));
$this->app->addFlash('warning', $e->getMessage());

throw new AuthenticationException(call_user_func($redirector, $params));
} catch (AccountLockedException $e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ private function getDefaultData(array $config)
'captchas-enabled' => false,
'recaptcha-public-key' => '',
'recaptcha-private-key' => '',
'trials-before-display' => 5,
],
'executables' => [
'h264-streaming-enabled' => false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?php

/*
* This file is part of Phraseanet
*
Expand All @@ -8,9 +7,7 @@
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Alchemy\Phrasea\Core\Provider;

use Alchemy\Phrasea\Authentication\AccountCreator;
use Alchemy\Phrasea\Authentication\Authenticator;
use Alchemy\Phrasea\Authentication\Manager;
Expand All @@ -27,16 +24,23 @@
use Alchemy\Phrasea\Authentication\SuggestionFinder;
use Alchemy\Phrasea\Core\Event\Subscriber\PersistentCookieSubscriber;
use Silex\Application;
use ReCaptcha\ReCaptcha;
use Silex\ServiceProviderInterface;

class AuthenticationManagerServiceProvider implements ServiceProviderInterface

{
public function register(Application $app)
{
$app['authentication'] = $app->share(function (Application $app) {
return new Authenticator($app, $app['browser'], $app['session'], $app['orm.em']);
});

if ($app['configuration.store']->isSetup() && $app['conf']->get(['registry', 'webservices', 'recaptcha-private-key']) !== "") {
$app['recaptcha'] = $app->share(function (Application $app) {
return new ReCaptcha($app['conf']->get(['registry', 'webservices', 'recaptcha-private-key']));
});
}

$app['authentication.persistent-manager'] = $app->share(function (Application $app) {
return new CookieManager($app['auth.password-encoder'], $app['repo.sessions'], $app['browser']);
});
Expand Down Expand Up @@ -162,8 +166,7 @@ public function register(Application $app)
});

$app['auth.native.failure-manager'] = $app->share(function (Application $app) {
$authConf = $app['conf']->get(['authentication', 'captcha']);

$authConf = $app['conf']->get(['registry', 'webservices']);
return new FailureManager($app['repo.auth-failures'], $app['orm.em'], $app['recaptcha'], isset($authConf['trials-before-display']) ? $authConf['trials-before-display'] : 9);
});

Expand All @@ -172,9 +175,9 @@ public function register(Application $app)
});

$app['auth.native'] = $app->share(function (Application $app) {
$authConf = $app['conf']->get('authentication');
$authConf = $app['conf']->get(['registry', 'webservices']);

if ($authConf['captcha']['enabled']) {
if ($authConf['captchas-enabled']) {
return new FailureHandledNativeAuthentication(
$app['auth.password-checker'],
$app['auth.native.failure-manager']
Expand Down
2 changes: 1 addition & 1 deletion lib/Alchemy/Phrasea/Core/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Version
* @var string
*/

private $number = '4.1.7-rc3';
private $number = '4.1.7-rc4';

/**
* @var string
Expand Down
Loading

0 comments on commit 9902457

Please sign in to comment.