diff --git a/config/zfcuser.global.php.dist b/config/zfcuser.global.php.dist index 9e230fe4..ceea3097 100644 --- a/config/zfcuser.global.php.dist +++ b/config/zfcuser.global.php.dist @@ -5,7 +5,7 @@ * If you have a ./config/autoload/ directory set up for your project, you can * drop this config file in it and change the values as you wish. */ -$settings = array( +$settings = [ /** * Laminas\Db\Adapter\Adapter DI Alias * @@ -50,7 +50,7 @@ $settings = array( * Default value: array containing 'ZfcUser\Authentication\Adapter\Db' with priority 100 * Accepted values: array containing services that implement 'ZfcUser\Authentication\Adapter\ChainableAdapter' */ - 'auth_adapters' => array( 100 => 'ZfcUser\Authentication\Adapter\Db' ), + 'auth_adapters' => [100 => 'ZfcUser\Authentication\Adapter\Db'], /** * Enable Display Name @@ -71,7 +71,7 @@ $settings = array( * Default value: array containing 'email' * Accepted values: array containing one or more of: email, username */ - //'auth_identity_fields' => array( 'email' ), + //'auth_identity_fields' => ['email'], /** * Login form timeout @@ -111,6 +111,15 @@ $settings = array( */ //'use_registration_form_captcha' => false, + + /** + * Login Form Captcha + * + * Determines if a captcha should be utilized on the user login form. + * Default value is false. + */ + //'use_login_form_captcha' => false, + /** * Form Captcha Options * @@ -118,14 +127,14 @@ $settings = array( * this to configure which Laminas\Captcha adapter to use, and the options to * pass to it. The default uses the Figlet captcha. */ - /*'form_captcha_options' => array( + /*'form_captcha_options' => [ 'class' => 'figlet', - 'options' => array( + 'options' => [ 'wordLen' => 5, 'expiration' => 300, 'timeout' => 300, - ), - ),*/ + ], + ],*/ /** * Use Redirect Parameter If Present @@ -210,7 +219,7 @@ $settings = array( * Include null if you want user's with no state to login as well. * Allowed value types: null and integer */ - //'allowed_login_states' => array( null, 1 ), + //'allowed_login_states' => [null, 1], /** * User table name @@ -220,16 +229,16 @@ $settings = array( /** * End of ZfcUser configuration */ -); +]; /** * You do not need to edit below this line */ -return array( +return [ 'zfcuser' => $settings, - 'service_manager' => array( - 'aliases' => array( + 'service_manager' => [ + 'aliases' => [ 'zfcuser_zend_db_adapter' => (isset($settings['zend_db_adapter'])) ? $settings['zend_db_adapter']: 'Laminas\Db\Adapter\Adapter', - ), - ), -); + ], + ], +]; diff --git a/src/ZfcUser/Form/Login.php b/src/ZfcUser/Form/Login.php index e84a935e..e438b931 100644 --- a/src/ZfcUser/Form/Login.php +++ b/src/ZfcUser/Form/Login.php @@ -7,6 +7,7 @@ use Laminas\Form\Element\Text; use ZfcUser\Options\AuthenticationOptionsInterface; use Laminas\Form\Element\Csrf; +use Laminas\Form\Element\Captcha; class Login extends ProvidesEventsForm { @@ -61,11 +62,16 @@ public function __construct($name, AuthenticationOptionsInterface $options) ], ]); - // @todo: Fix this - // 1) getValidator() is a protected method - // 2) i don't believe the login form is actually being validated by the login action - // (but keep in mind we don't want to show invalid username vs invalid password or - // anything like that, it should just say "login failed" without any additional info) + if ($this->getAuthenticationOptions()->getUseLoginFormCaptcha()) { + $this->add([ + 'name' => 'captcha', + 'type' => Captcha::class, + 'options' => [ + 'label' => 'Please type the following text', + 'captcha' => $this->getAuthenticationOptions()->getFormCaptchaOptions(), + ], + ]); + } $submitElement = new Button('submit'); $submitElement diff --git a/src/ZfcUser/Form/LoginFilter.php b/src/ZfcUser/Form/LoginFilter.php index e9c1c421..b7b395ff 100644 --- a/src/ZfcUser/Form/LoginFilter.php +++ b/src/ZfcUser/Form/LoginFilter.php @@ -16,6 +16,9 @@ public function __construct(AuthenticationOptionsInterface $options) 'name' => 'identity', 'required' => true, 'validators' => [], + 'filters' => [ + ['name' => StringTrim::class], + ], ]; $identityFields = $options->getAuthIdentityFields(); diff --git a/src/ZfcUser/Options/AuthenticationOptionsInterface.php b/src/ZfcUser/Options/AuthenticationOptionsInterface.php index 9a35d875..15c4cd6e 100644 --- a/src/ZfcUser/Options/AuthenticationOptionsInterface.php +++ b/src/ZfcUser/Options/AuthenticationOptionsInterface.php @@ -33,4 +33,34 @@ public function setAuthIdentityFields($authIdentityFields); * @return array */ public function getAuthIdentityFields(); + + /** + * set use a captcha in registration form + * + * @param bool $useRegistrationFormCaptcha + * @return ModuleOptions + */ + public function setUseLoginFormCaptcha(bool $useRegistrationFormCaptcha): ModuleOptions; + + /** + * get use a captcha in registration form + * + * @return bool + */ + public function getUseLoginFormCaptcha(): bool; + + /** + * set form CAPTCHA options + * + * @param array $formCaptchaOptions + * @return ModuleOptions + */ + public function setFormCaptchaOptions($formCaptchaOptions); + + /** + * get form CAPTCHA options + * + * @return array + */ + public function getFormCaptchaOptions(); } diff --git a/src/ZfcUser/Options/ModuleOptions.php b/src/ZfcUser/Options/ModuleOptions.php index 2ab81e09..154760b6 100644 --- a/src/ZfcUser/Options/ModuleOptions.php +++ b/src/ZfcUser/Options/ModuleOptions.php @@ -98,6 +98,11 @@ class ModuleOptions extends AbstractOptions implements */ protected $useRegistrationFormCaptcha = false; + /** + * @var bool + */ + protected $useLoginFormCaptcha = false; + /** * @var int */ @@ -473,6 +478,28 @@ public function getUseRegistrationFormCaptcha() return $this->useRegistrationFormCaptcha; } + /** + * set use a captcha in login form + * + * @param bool $useRegistrationFormCaptcha + * @return ModuleOptions + */ + public function setUseLoginFormCaptcha(bool $useLoginFormCaptcha): ModuleOptions + { + $this->useLoginFormCaptcha = $useLoginFormCaptcha; + return $this; + } + + /** + * get use a captcha in login form + * + * @return bool + */ + public function getUseLoginFormCaptcha(): bool + { + return $this->useLoginFormCaptcha; + } + /** * set user entity class name * diff --git a/tests/ZfcUserTest/Form/LoginTest.php b/tests/ZfcUserTest/Form/LoginTest.php index 39010898..179bcc04 100644 --- a/tests/ZfcUserTest/Form/LoginTest.php +++ b/tests/ZfcUserTest/Form/LoginTest.php @@ -2,6 +2,7 @@ namespace ZfcUserTest\Form; +use Laminas\Captcha\AbstractAdapter; use PHPUnit\Framework\TestCase; use ZfcUser\Form\Login as Form; use ZfcUser\Options\AuthenticationOptionsInterface; @@ -12,13 +13,23 @@ class LoginTest extends TestCase * @covers ZfcUser\Form\Login::__construct * @dataProvider providerTestConstruct */ - public function testConstruct($authIdentityFields = []): void + public function testConstruct(array $authIdentityFields = [], bool $useCaptcha): void { $options = $this->getMockBuilder(AuthenticationOptionsInterface::class) ->getMock(); $options->expects($this->once()) ->method('getAuthIdentityFields') ->will($this->returnValue($authIdentityFields)); + $options->expects($this->any()) + ->method('getUseLoginFormCaptcha') + ->will($this->returnValue($useCaptcha)); + if ($useCaptcha && class_exists(AbstractAdapter::class)) { + $captcha = $this->getMockForAbstractClass(AbstractAdapter::class); + + $options->expects($this->once()) + ->method('getFormCaptchaOptions') + ->will($this->returnValue($captcha)); + } $form = new Form(null, $options); @@ -28,6 +39,12 @@ public function testConstruct($authIdentityFields = []): void $this->assertArrayHasKey('credential', $elements); $this->assertArrayHasKey('csrf', $elements); + if ($useCaptcha) { + $this->assertArrayHasKey('captcha', $elements); + } else { + $this->assertArrayNotHasKey('captcha', $elements); + } + $expectedLabel = ''; if (count($authIdentityFields) > 0) { foreach ($authIdentityFields as $field) { @@ -59,9 +76,10 @@ public function testSetGetAuthenticationOptions(): void public function providerTestConstruct(): array { return [ - [[]], - [['email']], - [['username','email']], + [[], false], + [['email'], false], + [['username','email'], false], + [[], true], ]; } } diff --git a/tests/ZfcUserTest/Form/RegisterTest.php b/tests/ZfcUserTest/Form/RegisterTest.php index f61656d3..531bf27b 100644 --- a/tests/ZfcUserTest/Form/RegisterTest.php +++ b/tests/ZfcUserTest/Form/RegisterTest.php @@ -45,6 +45,12 @@ public function testConstruct($useCaptcha = false): void $this->assertArrayHasKey('password', $elements); $this->assertArrayHasKey('passwordVerify', $elements); $this->assertArrayHasKey('csrf', $elements); + + if ($useCaptcha) { + $this->assertArrayHasKey('captcha', $elements); + } else { + $this->assertArrayNotHasKey('captcha', $elements); + } } public function providerTestConstruct(): array diff --git a/tests/ZfcUserTest/Options/ModuleOptionsTest.php b/tests/ZfcUserTest/Options/ModuleOptionsTest.php index ebde3d25..f8724cc5 100644 --- a/tests/ZfcUserTest/Options/ModuleOptionsTest.php +++ b/tests/ZfcUserTest/Options/ModuleOptionsTest.php @@ -318,6 +318,24 @@ public function testGetUseRegistrationFormCaptcha() $this->assertFalse($this->options->getUseRegistrationFormCaptcha()); } + /** + * @covers ZfcUser\Options\ModuleOptions::getUseLoginFormCaptcha + * @covers ZfcUser\Options\ModuleOptions::setUseLoginFormCaptcha + */ + public function testSetGetUseLoginFormCaptcha() + { + $this->options->setUseLoginFormCaptcha(true); + $this->assertTrue($this->options->getUseLoginFormCaptcha()); + } + + /** + * @covers ZfcUser\Options\ModuleOptions::getUseLoginFormCaptcha + */ + public function testGetUseLoginFormCaptcha() + { + $this->assertFalse($this->options->getUseLoginFormCaptcha()); + } + /** * @covers ZfcUser\Options\ModuleOptions::getUserEntityClass * @covers ZfcUser\Options\ModuleOptions::setUserEntityClass