Skip to content
Snippets Groups Projects
Commit c3258608 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 1440 additions and 0 deletions
.idea/
vendor/
LICENSE 0 → 100644
Copyright (c) 2013, ZF-Commons Contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the ZF-Commons nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<?php
namespace ZfcUser;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\Feature\ControllerPluginProviderInterface;
use Zend\ModuleManager\Feature\ControllerProviderInterface;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
class Module implements
ControllerProviderInterface,
ControllerPluginProviderInterface,
ConfigProviderInterface,
ServiceProviderInterface
{
public function getConfig($env = null)
{
return include __DIR__ . '/config/module.config.php';
}
public function getControllerPluginConfig()
{
return array(
'factories' => array(
'zfcUserAuthentication' => \ZfcUser\Factory\Controller\Plugin\ZfcUserAuthentication::class,
),
);
}
public function getControllerConfig()
{
return array(
'factories' => array(
'zfcuser' => \ZfcUser\Factory\Controller\UserControllerFactory::class,
),
);
}
public function getViewHelperConfig()
{
return array(
'factories' => array(
'zfcUserDisplayName' => \ZfcUser\Factory\View\Helper\ZfcUserDisplayName::class,
'zfcUserIdentity' => \ZfcUser\Factory\View\Helper\ZfcUserIdentity::class,
'zfcUserLoginWidget' => \ZfcUser\Factory\View\Helper\ZfcUserLoginWidget::class,
),
);
}
public function getServiceConfig()
{
return array(
'aliases' => array(
'zfcuser_zend_db_adapter' => \Zend\Db\Adapter\Adapter::class,
),
'invokables' => array(
'zfcuser_register_form_hydrator' => \Zend\Hydrator\ClassMethods::class,
),
'factories' => array(
'zfcuser_redirect_callback' => \ZfcUser\Factory\Controller\RedirectCallbackFactory::class,
'zfcuser_module_options' => \ZfcUser\Factory\Options\ModuleOptions::class,
'ZfcUser\Authentication\Adapter\AdapterChain' => \ZfcUser\Authentication\Adapter\AdapterChainServiceFactory::class,
// We alias this one because it's ZfcUser's instance of
// Zend\Authentication\AuthenticationService. We don't want to
// hog the FQCN service alias for a Zend\* class.
'zfcuser_auth_service' => \ZfcUser\Factory\AuthenticationService::class,
'zfcuser_user_hydrator' => \ZfcUser\Factory\UserHydrator::class,
'zfcuser_user_mapper' => \ZfcUser\Factory\Mapper\User::class,
'zfcuser_login_form' => \ZfcUser\Factory\Form\Login::class,
'zfcuser_register_form' => \ZfcUser\Factory\Form\Register::class,
'zfcuser_change_password_form' => \ZfcUser\Factory\Form\ChangePassword::class,
'zfcuser_change_email_form' => \ZfcUser\Factory\Form\ChangeEmail::class,
'ZfcUser\Authentication\Adapter\Db' => \ZfcUser\Factory\Authentication\Adapter\DbFactory::class,
'ZfcUser\Authentication\Storage\Db' => \ZfcUser\Factory\Authentication\Storage\DbFactory::class,
'zfcuser_user_service' => \ZfcUser\Factory\Service\UserFactory::class,
),
);
}
}
README.md 0 → 100644
ZfcUser
=======
[![Build Status](https://travis-ci.org/ZF-Commons/ZfcUser.png)](https://travis-ci.org/ZF-Commons/ZfcUser)
[![Code Coverage](https://scrutinizer-ci.com/g/ZF-Commons/ZfcUser/badges/coverage.png?s=7d5932c77bea64a417ac8e3da51dca6da1fcb22e)](https://scrutinizer-ci.com/g/ZF-Commons/ZfcUser/)
[![Latest Stable Version](https://poser.pugx.org/zf-commons/zfc-user/v/stable.png)](https://packagist.org/packages/zf-commons/zfc-user)
[![Latest Unstable Version](https://poser.pugx.org/zf-commons/zfc-user/v/unstable.png)](https://packagist.org/packages/zf-commons/zfc-user)
Created by Evan Coury and the ZF-Commons team
Introduction
------------
ZfcUser is a user registration and authentication module for Zend Framework 2.
Out of the box, ZfcUser works with Zend\Db, however alternative storage adapter
modules are available (see below). ZfcUser provides the foundations for adding
user authentication and registration to your ZF2 site. It is designed to be very
simple and easy to extend.
More information and examples are available on the [ZfcUser Wiki](https://github.com/ZF-Commons/ZfcUser/wiki)
Versions
--------
Please use below table to figure out what version of ZfcUser you should use.
| ZfcUser version | Supported Zend Framework version |
|-----------------|----------------------------------|
| 1.x | <= 2.5 |
| 2.x | >= 2.6 or 3.x |
Storage Adapter Modules
-----------------------
By default, ZfcUser ships with support for using Zend\Db for persisting users.
However, by installing an optional alternative storage adapter module, you can
take advantage of other methods of persisting users:
- [ZfcUserDoctrineORM](https://github.com/ZF-Commons/ZfcUserDoctrineORM) - Doctrine2 ORM
- [ZfcUserDoctrineMongoODM](https://github.com/ZF-Commons/ZfcUserDoctrineMongoODM) - Doctrine2 MongoDB ODM
Requirements
------------
* [Zend Framework 2](https://github.com/zendframework/zf2) (latest master)
* [ZfcBase](https://github.com/ZF-Commons/ZfcBase) (latest master).
Features / Goals
----------------
* Authenticate via username, email, or both (can opt out of the concept of
username and use strictly email) [COMPLETE]
* User registration [COMPLETE]
* Forms protected against CSRF [COMPLETE]
* Out-of-the-box support for Doctrine2 _and_ Zend\Db [COMPLETE]
* Robust event system to allow for extending [COMPLETE]
* Provide ActionController plugin and view helper [COMPLETE]
Installation
------------
### Main Setup
#### By cloning project
1. Install the [ZfcBase](https://github.com/ZF-Commons/ZfcBase) ZF2 module
by cloning it into `./vendor/`.
2. Clone this project into your `./vendor/` directory.
#### With composer
1. Add this project and [ZfcBase](https://github.com/ZF-Commons/ZfcBase) in your composer.json:
```json
"require": {
"zf-commons/zfc-user": "dev-master"
}
```
2. Now tell composer to download ZfcUser by running the command:
```bash
$ php composer.phar update
```
#### Post installation
1. Enabling it in your `application.config.php`file.
```php
<?php
return array(
'modules' => array(
// ...
'ZfcUser',
),
// ...
);
```
2. Then Import the SQL schema located in `./vendor/zf-commons/zfc-user/data/schema.sql` (if you installed using the Composer) or in `./vendor/ZfcUser/data/schema.sql`.
### Post-Install: Doctrine2 ORM
Coming soon...
### Post-Install: Doctrine2 MongoDB ODM
Coming soon...
### Post-Install: Zend\Db
1. If you do not already have a valid Zend\Db\Adapter\Adapter in your service
manager configuration, put the following in `./config/autoload/database.local.php`:
```php
<?php
return array(
'db' => array(
'driver' => 'PdoMysql',
'hostname' => 'changeme',
'database' => 'changeme',
'username' => 'changeme',
'password' => 'changeme',
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
```
Navigate to http://yourproject/user and you should land on a login page.
Password Security
-----------------
**DO NOT CHANGE THE PASSWORD HASH SETTINGS FROM THEIR DEFAULTS** unless A) you
have done sufficient research and fully understand exactly what you are
changing, **AND** B) you have a **very** specific reason to deviate from the
default settings.
If you are planning on changing the default password hash settings, please read
the following:
- [PHP Manual: crypt() function](http://php.net/manual/en/function.crypt.php)
- [Securely Storing Passwords in PHP by Adrian Schneider](http://www.syndicatetheory.com/labs/securely-storing-passwords-in-php)
The password hash settings may be changed at any time without invalidating existing
user accounts. Existing user passwords will be re-hashed automatically on their next
successful login.
**WARNING:** Changing the default password hash settings can cause serious
problems such as making your hashed passwords more vulnerable to brute force
attacks or making hashing so expensive that login and registration is
unacceptably slow for users and produces a large burden on your server(s). The
default settings provided are a very reasonable balance between the two,
suitable for computing power in 2013.
Options
-------
The ZfcUser module has some options to allow you to quickly customize the basic
functionality. After installing ZfcUser, copy
`./vendor/zf-commons/zfc-user/config/zfcuser.global.php.dist` to
`./config/autoload/zfcuser.global.php` and change the values as desired.
The following options are available:
- **user_entity_class** - Name of Entity class to use. Useful for using your own
entity class instead of the default one provided. Default is
`ZfcUser\Entity\User`.
- **enable_username** - Boolean value, enables username field on the
registration form. Default is `false`.
- **auth_identity_fields** - Array value, specifies which fields a user can
use as the 'identity' field when logging in. Acceptable values: username, email.
- **enable_display_name** - Boolean value, enables a display name field on the
registration form. Default value is `false`.
- **enable_registration** - Boolean value, Determines if a user should be
allowed to register. Default value is `true`.
- **login_after_registration** - Boolean value, automatically logs the user in
after they successfully register. Default value is `false`.
- **use_registration_form_captcha** - Boolean value, determines if a captcha should
be utilized on the user registration form. Default value is `true`. (Note,
right now this only utilizes a weak Zend\Text\Figlet CAPTCHA, but I have plans
to make all Zend\Captcha adapters work.)
- **login_form_timeout** - Integer value, specify the timeout for the CSRF security
field of the login form in seconds. Default value is 300 seconds.
- **user_form_timeout** - Integer value, specify the timeout for the CSRF security
field of the registration form in seconds. Default value is 300 seconds.
- **use_redirect_parameter_if_present** - Boolean value, if a redirect GET
parameter is specified, the user will be redirected to the specified URL if
authentication is successful (if present, a GET parameter will override the
login_redirect_route specified below).
- **login_redirect_route** String value, name of a route in the application
which the user will be redirected to after a successful login.
- **logout_redirect_route** String value, name of a route in the application which
the user will be redirected to after logging out.
- **password_cost** - This should be an integer between 4 and 31. The number
represents the base-2 logarithm of the iteration count used for hashing.
Default is `10` (about 10 hashes per second on an i5).
- **enable_user_state** - Boolean value, enable user state usage. Should user's
state be used in the registration/login process?
- **default_user_state** - Integer value, default user state upon registration.
What state user should have upon registration?
- **allowed_login_states** - Array value, states which are allowing user to login.
When user tries to login, is his/her state one of the following? Include null if
you want user's with no state to login as well.
Changing Registration Captcha Element
-------------------------------------
**NOTICE** These instructions are currently out of date.
By default, the user registration uses the Figlet captcha engine. This is
because it's the only one that doesn't require API keys. It's possible to change
out the captcha engine with DI. For example, to change to Recaptcha, you would
add this to one of your configuration files (global.config.php,
module.config.php, or a dedicated recaptcha.config.php):
<?php
// ./config/autoload/recaptcha.config.php
return array(
'di'=> array(
'instance'=>array(
'alias'=>array(
// OTHER ELEMENTS....
'recaptcha_element' => 'Zend\Form\Element\Captcha',
),
'recaptcha_element' => array(
'parameters' => array(
'spec' => 'captcha',
'options'=>array(
'label' => '',
'required' => true,
'order' => 500,
'captcha' => array(
'captcha' => 'ReCaptcha',
'privkey' => RECAPTCHA_PRIVATE_KEY,
'pubkey' => RECAPTCHA_PUBLIC_KEY,
),
),
),
),
'ZfcUser\Form\Register' => array(
'parameters' => array(
'captcha_element'=>'recaptcha_element',
),
),
),
),
);
*
!logs
!.gitignore
!coverage-checker.php
\ No newline at end of file
*
!.gitignore
\ No newline at end of file
{
"name": "unicaen/zfc-user",
"description": "A generic user registration and authentication module for ZF2. Supports Zend\\Db and Doctrine2.",
"type": "library",
"require": {
"php": "^5.5|^7.0",
"zendframework/zend-authentication": "^2.5",
"zendframework/zend-crypt": "^3.0",
"zendframework/zend-form": "^2.9",
"zendframework/zend-inputfilter": "^2.7",
"zendframework/zend-loader": "^2.5",
"zendframework/zend-modulemanager": "^2.7",
"zendframework/zend-mvc": "^3.0",
"zendframework/zend-servicemanager": "^3.0",
"zendframework/zend-stdlib": "^3.0",
"zendframework/zend-validator": "^2.8",
"zendframework/zend-db": "^2.8",
"zendframework/zend-view": "^2.8",
"zendframework/zend-session" : "^2.7",
"zendframework/zend-http" : "^2.5",
"zendframework/zend-mvc-plugin-flashmessenger": "^1.0",
"zendframework/zend-i18n": "^2.7",
"zendframework/zend-mvc-plugin-prg": "^1.0",
"zendframework/zend-hydrator": "^2.0"
},
"require-dev" : {
"phpunit/phpunit" : ">=3.7,<4",
"phpmd/phpmd" : "1.4.*",
"squizlabs/php_codesniffer" : "1.4.*",
"zendframework/zend-captcha" : "^2.6"
},
"suggest": {
"zendframework/zend-captcha" : "Zend\\Captcha if you want to use the captcha component"
},
"autoload": {
"psr-0": {
"ZfcUser": "src/"
},
"classmap": [
"./Module.php"
]
}
}
DO NOT EDIT THE CONFIG FILES DIRECTLY IN THIS DIRECTORY!
--------------------------------------------------------
Copy the dist file into your `./config/autoload` directory. (Remove the .dist
part)
<?php
return array(
'view_manager' => array(
'template_path_stack' => array(
'zfcuser' => __DIR__ . '/../view',
),
),
'router' => array(
'routes' => array(
'zfcuser' => array(
'type' => 'Literal',
'priority' => 1000,
'options' => array(
'route' => '/user',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'login' => array(
'type' => 'Literal',
'options' => array(
'route' => '/login',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'login',
),
),
),
'authenticate' => array(
'type' => 'Literal',
'options' => array(
'route' => '/authenticate',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'authenticate',
),
),
),
'logout' => array(
'type' => 'Literal',
'options' => array(
'route' => '/logout',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'logout',
),
),
),
'register' => array(
'type' => 'Literal',
'options' => array(
'route' => '/register',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'register',
),
),
),
'changepassword' => array(
'type' => 'Literal',
'options' => array(
'route' => '/change-password',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'changepassword',
),
),
),
'changeemail' => array(
'type' => 'Literal',
'options' => array(
'route' => '/change-email',
'defaults' => array(
'controller' => 'zfcuser',
'action' => 'changeemail',
),
),
),
),
),
),
),
);
<?php
/**
* ZfcUser Configuration
*
* 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(
/**
* Zend\Db\Adapter\Adapter DI Alias
*
* Please specify the DI alias for the configured Zend\Db\Adapter\Adapter
* instance that ZfcUser should use.
*/
//'zend_db_adapter' => 'Zend\Db\Adapter\Adapter',
/**
* User Model Entity Class
*
* Name of Entity class to use. Useful for using your own entity class
* instead of the default one provided. Default is ZfcUser\Entity\User.
* The entity class should implement ZfcUser\Entity\UserInterface
*/
//'user_entity_class' => 'ZfcUser\Entity\User',
/**
* Enable registration
*
* Allows users to register through the website.
*
* Accepted values: boolean true or false
*/
//'enable_registration' => true,
/**
* Enable Username
*
* Enables username field on the registration form, and allows users to log
* in using their username OR email address. Default is false.
*
* Accepted values: boolean true or false
*/
//'enable_username' => false,
/**
* Authentication Adapters
*
* Specify the adapters that will be used to try and authenticate the user
*
* 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' ),
/**
* Enable Display Name
*
* Enables a display name field on the registration form, which is persisted
* in the database. Default value is false.
*
* Accepted values: boolean true or false
*/
//'enable_display_name' => true,
/**
* Modes for authentication identity match
*
* Specify the allowable identity modes, in the order they should be
* checked by the Authentication plugin.
*
* Default value: array containing 'email'
* Accepted values: array containing one or more of: email, username
*/
//'auth_identity_fields' => array( 'email' ),
/**
* Login form timeout
*
* Specify the timeout for the CSRF security field of the login form
* in seconds. Default value is 300 seconds.
*
* Accepted values: positive int value
*/
//'login_form_timeout' => 300,
/**
* Registration form timeout
*
* Specify the timeout for the CSRF security field of the registration form
* in seconds. Default value is 300 seconds.
*
* Accepted values: positive int value
*/
//'user_form_timeout' => 300,
/**
* Login After Registration
*
* Automatically logs the user in after they successfully register. Default
* value is false.
*
* Accepted values: boolean true or false
*/
//'login_after_registration' => true,
/**
* Registration Form Captcha
*
* Determines if a captcha should be utilized on the user registration form.
* Default value is false.
*/
//'use_registration_form_captcha' => false,
/**
* Form Captcha Options
*
* Currently used for the registration form, but re-usable anywhere. Use
* this to configure which Zend\Captcha adapter to use, and the options to
* pass to it. The default uses the Figlet captcha.
*/
/*'form_captcha_options' => array(
'class' => 'figlet',
'options' => array(
'wordLen' => 5,
'expiration' => 300,
'timeout' => 300,
),
),*/
/**
* Use Redirect Parameter If Present
*
* Upon successful authentication, check for a 'redirect' POST or GET parameter
*
* Accepted values: boolean true or false
*/
//'use_redirect_parameter_if_present' => true,
/**
* Sets the view template for the user login widget
*
* Default value: 'zfc-user/user/login.phtml'
* Accepted values: string path to a view script
*/
//'user_login_widget_view_template' => 'zfc-user/user/login.phtml',
/**
* Login Redirect Route
*
* Upon successful login the user will be redirected to the entered route
*
* Default value: 'zfcuser'
* Accepted values: A valid route name within your application
*
*/
//'login_redirect_route' => 'zfcuser',
/**
* Logout Redirect Route
*
* Upon logging out the user will be redirected to the entered route
*
* Default value: 'zfcuser/login'
* Accepted values: A valid route name within your application
*/
//'logout_redirect_route' => 'zfcuser/login',
/**
* Password Security
*
* DO NOT CHANGE THE PASSWORD HASH SETTINGS FROM THEIR DEFAULTS
* Unless A) you have done sufficient research and fully understand exactly
* what you are changing, AND B) you have a very specific reason to deviate
* from the default settings and know what you're doing.
*
* The password hash settings may be changed at any time without
* invalidating existing user accounts. Existing user passwords will be
* re-hashed automatically on their next successful login.
*/
/**
* Password Cost
*
* The number represents the base-2 logarithm of the iteration count used for
* hashing. Default is 14 (about 10 hashes per second on an i5).
*
* Accepted values: integer between 4 and 31
*/
//'password_cost' => 14,
/**
* Enable user state usage
*
* Should user's state be used in the registration/login process?
*/
//'enable_user_state' => true,
/**
* Default user state upon registration
*
* What state user should have upon registration?
* Allowed value type: integer
*/
//'default_user_state' => 1,
/**
* States which are allowing user to login
*
* When user tries to login, is his/her state one of the following?
* 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 ),
/**
* User table name
*/
//'table_name' => 'user',
/**
* End of ZfcUser configuration
*/
);
/**
* You do not need to edit below this line
*/
return array(
'zfcuser' => $settings,
'service_manager' => array(
'aliases' => array(
'zfcuser_zend_db_adapter' => (isset($settings['zend_db_adapter'])) ? $settings['zend_db_adapter']: 'Zend\Db\Adapter\Adapter',
),
),
);
CREATE TABLE `user`
(
`user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(255) DEFAULT NULL UNIQUE,
`email` VARCHAR(255) DEFAULT NULL UNIQUE,
`display_name` VARCHAR(50) DEFAULT NULL,
`password` VARCHAR(128) NOT NULL,
`state` SMALLINT UNSIGNED
) ENGINE=InnoDB CHARSET="utf8";
CREATE TABLE public.user
(
user_id serial NOT NULL,
username character varying(255) DEFAULT NULL UNIQUE,
email character varying(255) DEFAULT NULL UNIQUE,
display_name character varying(50) DEFAULT NULL,
password character varying(128) NOT NULL,
state smallint,
CONSTRAINT user_pkey PRIMARY KEY (user_id),
CONSTRAINT user_username_key UNIQUE (username),
CONSTRAINT user_email_key UNIQUE (email)
);
CREATE TABLE user
(
user_id INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,
username VARCHAR(255) DEFAULT NULL UNIQUE,
email VARCHAR(255) DEFAULT NULL UNIQUE,
display_name VARCHAR(50) DEFAULT NULL,
password VARCHAR(128) NOT NULL,
state SMALLINT
) ENGINE=InnoDB;
CREATE TABLE user
(
user_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
username VARCHAR(255) DEFAULT NULL UNIQUE,
email VARCHAR(255) DEFAULT NULL UNIQUE,
display_name VARCHAR(50) DEFAULT NULL,
password VARCHAR(128) NOT NULL,
state SMALLINT
);
<?php
namespace ZfcUser\Authentication\Adapter;
use Zend\Authentication\Storage;
abstract class AbstractAdapter implements ChainableAdapter
{
/**
* @var Storage\StorageInterface
*/
protected $storage;
/**
* Returns the persistent storage handler
*
* Session storage is used by default unless a different storage adapter has been set.
*
* @return Storage\StorageInterface
*/
public function getStorage()
{
if (null === $this->storage) {
$this->setStorage(new Storage\Session(get_class($this)));
}
return $this->storage;
}
/**
* Sets the persistent storage handler
*
* @param Storage\StorageInterface $storage
* @return AbstractAdapter Provides a fluent interface
*/
public function setStorage(Storage\StorageInterface $storage)
{
$this->storage = $storage;
return $this;
}
/**
* Check if this adapter is satisfied or not
*
* @return bool
*/
public function isSatisfied()
{
$storage = $this->getStorage()->read();
return (isset($storage['is_satisfied']) && true === $storage['is_satisfied']);
}
/**
* Set if this adapter is satisfied or not
*
* @param bool $bool
* @return AbstractAdapter
*/
public function setSatisfied($bool = true)
{
$storage = $this->getStorage()->read() ?: array();
$storage['is_satisfied'] = $bool;
$this->getStorage()->write($storage);
return $this;
}
}
<?php
namespace ZfcUser\Authentication\Adapter;
use Zend\Authentication\Adapter\AdapterInterface;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\EventManager\Event;
use Zend\EventManager\EventManagerAwareTrait;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Stdlib\ResponseInterface as Response;
use ZfcUser\Exception;
class AdapterChain implements AdapterInterface
{
use EventManagerAwareTrait;
/**
* @var AdapterChainEvent
*/
protected $event;
/**
* Returns the authentication result
*
* @return AuthenticationResult
*/
public function authenticate()
{
$e = $this->getEvent();
$result = new AuthenticationResult(
$e->getCode(),
$e->getIdentity(),
$e->getMessages()
);
$this->resetAdapters();
return $result;
}
/**
* prepareForAuthentication
*
* @param Request $request
* @return Response|bool
* @throws Exception\AuthenticationEventException
*/
public function prepareForAuthentication(Request $request)
{
$e = $this->getEvent();
$e->setRequest($request);
$this->getEventManager()->trigger('authenticate.pre', $e);
$result = $this->getEventManager()->trigger('authenticate', $e, function ($test) {
return ($test instanceof Response);
});
if ($result->stopped()) {
if ($result->last() instanceof Response) {
return $result->last();
}
throw new Exception\AuthenticationEventException(
sprintf(
'Auth event was stopped without a response. Got "%s" instead',
is_object($result->last()) ? get_class($result->last()) : gettype($result->last())
)
);
}
if ($e->getIdentity()) {
$this->getEventManager()->trigger('authenticate.success', $e);
return true;
}
$this->getEventManager()->trigger('authenticate.fail', $e);
return false;
}
/**
* resetAdapters
*
* @return AdapterChain
*/
public function resetAdapters()
{
$sharedManager = $this->getEventManager()->getSharedManager();
if ($sharedManager) {
$listeners = $sharedManager->getListeners(['authenticate'], 'authenticate');
foreach ($listeners as $listener) {
if (is_array($listener) && $listener[0] instanceof ChainableAdapter) {
$listener[0]->getStorage()->clear();
}
}
}
return $this;
}
/**
* logoutAdapters
*
* @return AdapterChain
*/
public function logoutAdapters()
{
//Adapters might need to perform additional cleanup after logout
$this->getEventManager()->trigger('logout', $this->getEvent());
}
/**
* Get the auth event
*
* @return AdapterChainEvent
*/
public function getEvent()
{
if (null === $this->event) {
$this->setEvent(new AdapterChainEvent);
$this->event->setTarget($this);
}
return $this->event;
}
/**
* Set an event to use during dispatch
*
* By default, will re-cast to AdapterChainEvent if another event type is provided.
*
* @param Event $e
* @return AdapterChain
*/
public function setEvent(Event $e)
{
if (!$e instanceof AdapterChainEvent) {
$eventParams = $e->getParams();
$e = new AdapterChainEvent();
$e->setParams($eventParams);
}
$this->event = $e;
return $this;
}
}
<?php
namespace ZfcUser\Authentication\Adapter;
use Zend\EventManager\Event;
use Zend\Stdlib\RequestInterface as Request;
class AdapterChainEvent extends Event
{
/**
* getIdentity
*
* @return mixed
*/
public function getIdentity()
{
return $this->getParam('identity');
}
/**
* setIdentity
*
* @param mixed $identity
* @return AdapterChainEvent
*/
public function setIdentity($identity = null)
{
if (null === $identity) {
// Setting the identity to null resets the code and messages.
$this->setCode();
$this->setMessages();
}
$this->setParam('identity', $identity);
return $this;
}
/**
* getCode
*
* @return int
*/
public function getCode()
{
return $this->getParam('code');
}
/**
* setCode
*
* @param int $code
* @return AdapterChainEvent
*/
public function setCode($code = null)
{
$this->setParam('code', $code);
return $this;
}
/**
* getMessages
*
* @return array
*/
public function getMessages()
{
return $this->getParam('messages') ?: array();
}
/**
* setMessages
*
* @param array $messages
* @return AdapterChainEvent
*/
public function setMessages($messages = array())
{
$this->setParam('messages', $messages);
return $this;
}
/**
* getRequest
*
* @return Request
*/
public function getRequest()
{
return $this->getParam('request');
}
/**
* setRequest
*
* @param Request $request
* @return AdapterChainEvent
*/
public function setRequest(Request $request)
{
$this->setParam('request', $request);
$this->request = $request;
return $this;
}
}
<?php
namespace ZfcUser\Authentication\Adapter;
use Interop\Container\ContainerInterface;
use Interop\Container\Exception\ContainerException;
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
use Zend\ServiceManager\Exception\ServiceNotFoundException;
use Zend\ServiceManager\Factory\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use ZfcUser\Authentication\Adapter\AdapterChain;
use ZfcUser\Options\ModuleOptions;
use ZfcUser\Authentication\Adapter\Exception\OptionsNotFoundException;
class AdapterChainServiceFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $serviceLocator, $requestedName, array $options = null)
{
$chain = new AdapterChain();
$options = $this->getOptions($serviceLocator);
//iterate and attach multiple adapters and events if offered
foreach ($options->getAuthAdapters() as $priority => $adapterName) {
$adapter = $serviceLocator->get($adapterName);
if (is_callable(array($adapter, 'authenticate'))) {
$chain->getEventManager()->attach('authenticate', array($adapter, 'authenticate'), $priority);
}
if (is_callable(array($adapter, 'logout'))) {
$chain->getEventManager()->attach('logout', array($adapter, 'logout'), $priority);
}
}
return $chain;
}
/**
* @var ModuleOptions
*/
protected $options;
public function createService(ServiceLocatorInterface $serviceLocator)
{
$this->__invoke($serviceLocator, null);
}
/**
* set options
*
* @param ModuleOptions $options
* @return AdapterChainServiceFactory
*/
public function setOptions(ModuleOptions $options)
{
$this->options = $options;
return $this;
}
/**
* get options
*
* @param ServiceLocatorInterface $serviceLocator (optional) Service Locator
* @return ModuleOptions $options
* @throws OptionsNotFoundException If options tried to retrieve without being set but no SL was provided
*/
public function getOptions(ServiceLocatorInterface $serviceLocator = null)
{
if (!$this->options) {
if (!$serviceLocator) {
throw new OptionsNotFoundException(
'Options were tried to retrieve but not set ' .
'and no service locator was provided'
);
}
$this->setOptions($serviceLocator->get('zfcuser_module_options'));
}
return $this->options;
}
}
<?php
namespace ZfcUser\Authentication\Adapter;
use Zend\Authentication\Storage\StorageInterface;
use Zend\EventManager\EventInterface;
interface ChainableAdapter
{
/**
* @param EventInterface $e
* @return bool
*/
public function authenticate(EventInterface $e);
/**
* @return StorageInterface
*/
public function getStorage();
}
<?php
namespace ZfcUser\Authentication\Adapter;
use Interop\Container\ContainerInterface;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\EventManager\EventInterface;
use Zend\ServiceManager\ServiceManager;
use Zend\Crypt\Password\Bcrypt;
use Zend\Session\Container as SessionContainer;
use ZfcUser\Entity\UserInterface;
use ZfcUser\Mapper\UserInterface as UserMapperInterface;
use ZfcUser\Options\ModuleOptions;
class Db extends AbstractAdapter
{
/**
* @var UserMapperInterface
*/
protected $mapper;
/**
* @var callable
*/
protected $credentialPreprocessor;
/**
* @var ServiceManager
*/
protected $serviceManager;
/**
* @var ModuleOptions
*/
protected $options;
/**
* Called when user id logged out
* @param EventInterface $e
*/
public function logout(EventInterface $e)
{
$this->getStorage()->clear();
}
/**
* @param EventInterface $e
* @return bool
*/
public function authenticate(EventInterface $e)
{
$e = $e->getTarget();
if ($this->isSatisfied()) {
$storage = $this->getStorage()->read();
$e->setIdentity($storage['identity'])
->setCode(AuthenticationResult::SUCCESS)
->setMessages(array('Authentication successful.'));
return;
}
$identity = $e->getRequest()->getPost()->get('identity');
$credential = $e->getRequest()->getPost()->get('credential');
$credential = $this->preProcessCredential($credential);
/** @var UserInterface|null $userObject */
$userObject = null;
// Cycle through the configured identity sources and test each
$fields = $this->getOptions()->getAuthIdentityFields();
while (!is_object($userObject) && count($fields) > 0) {
$mode = array_shift($fields);
switch ($mode) {
case 'username':
$userObject = $this->getMapper()->findByUsername($identity);
break;
case 'email':
$userObject = $this->getMapper()->findByEmail($identity);
break;
}
}
if (!$userObject) {
$e->setCode(AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND)
->setMessages(array('A record with the supplied identity could not be found.'));
$this->setSatisfied(false);
return false;
}
if ($this->getOptions()->getEnableUserState()) {
// Don't allow user to login if state is not in allowed list
if (!in_array($userObject->getState(), $this->getOptions()->getAllowedLoginStates())) {
$e->setCode(AuthenticationResult::FAILURE_UNCATEGORIZED)
->setMessages(array('A record with the supplied identity is not active.'));
$this->setSatisfied(false);
return false;
}
}
$bcrypt = new Bcrypt();
$bcrypt->setCost($this->getOptions()->getPasswordCost());
if (!$bcrypt->verify($credential, $userObject->getPassword())) {
// Password does not match
$e->setCode(AuthenticationResult::FAILURE_CREDENTIAL_INVALID)
->setMessages(array('Supplied credential is invalid.'));
$this->setSatisfied(false);
return false;
}
// regen the id
$session = new SessionContainer($this->getStorage()->getNameSpace());
$session->getManager()->regenerateId();
// Success!
$e->setIdentity($userObject->getId());
// Update user's password hash if the cost parameter has changed
$this->updateUserPasswordHash($userObject, $credential, $bcrypt);
$this->setSatisfied(true);
$storage = $this->getStorage()->read();
$storage['identity'] = $e->getIdentity();
$this->getStorage()->write($storage);
$e->setCode(AuthenticationResult::SUCCESS)
->setMessages(array('Authentication successful.'));
}
protected function updateUserPasswordHash(UserInterface $userObject, $password, Bcrypt $bcrypt)
{
$hash = explode('$', $userObject->getPassword());
if ($hash[2] === $bcrypt->getCost()) {
return;
}
$userObject->setPassword($bcrypt->create($password));
$this->getMapper()->update($userObject);
return $this;
}
public function preProcessCredential($credential)
{
$processor = $this->getCredentialPreprocessor();
if (is_callable($processor)) {
return $processor($credential);
}
return $credential;
}
/**
* getMapper
*
* @return UserMapperInterface
*/
public function getMapper()
{
if (null === $this->mapper) {
$this->mapper = $this->getServiceManager()->get('zfcuser_user_mapper');
}
return $this->mapper;
}
/**
* setMapper
*
* @param UserMapperInterface $mapper
* @return Db
*/
public function setMapper(UserMapperInterface $mapper)
{
$this->mapper = $mapper;
return $this;
}
/**
* Get credentialPreprocessor.
*
* @return callable
*/
public function getCredentialPreprocessor()
{
return $this->credentialPreprocessor;
}
/**
* Set credentialPreprocessor.
*
* @param callable $credentialPreprocessor
* @return $this
*/
public function setCredentialPreprocessor($credentialPreprocessor)
{
$this->credentialPreprocessor = $credentialPreprocessor;
return $this;
}
/**
* Retrieve service manager instance
*
* @return ServiceManager
*/
public function getServiceManager()
{
return $this->serviceManager;
}
/**
* Set service manager instance
*
* @param ContainerInterface $serviceManager
*/
public function setServiceManager(ContainerInterface $serviceManager)
{
$this->serviceManager = $serviceManager;
}
/**
* @param ModuleOptions $options
*/
public function setOptions(ModuleOptions $options)
{
$this->options = $options;
}
/**
* @return ModuleOptions
*/
public function getOptions()
{
if ($this->options === null) {
$this->setOptions($this->getServiceManager()->get('zfcuser_module_options'));
}
return $this->options;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment