mirror of
https://github.com/brmlab/brmbiolab_sklad.git
synced 2025-06-12 07:03:59 +02:00
Initial commit
This commit is contained in:
commit
3b93da31de
1004 changed files with 265840 additions and 0 deletions
73
lib/Cake/Controller/Component/Acl/AclInterface.php
Normal file
73
lib/Cake/Controller/Component/Acl/AclInterface.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Access Control List interface.
|
||||
* Implementing classes are used by AclComponent to perform ACL checks in Cake.
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
interface AclInterface {
|
||||
|
||||
/**
|
||||
* Empty method to be overridden in subclasses
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Allow methods are used to grant an ARO access to an ACO.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Deny methods are used to remove permission from an ARO to access an ACO.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Inherit methods modify the permission for an ARO to be that of its parent object.
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*");
|
||||
|
||||
/**
|
||||
* Initialization method for the Acl implementation
|
||||
*
|
||||
* @param Component $component The AclComponent instance.
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $component);
|
||||
|
||||
}
|
163
lib/Cake/Controller/Component/Acl/DbAcl.php
Normal file
163
lib/Cake/Controller/Component/Acl/DbAcl.php
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AclInterface', 'Controller/Component/Acl');
|
||||
App::uses('Hash', 'Utility');
|
||||
App::uses('ClassRegistry', 'Utility');
|
||||
|
||||
/**
|
||||
* DbAcl implements an ACL control system in the database. ARO's and ACO's are
|
||||
* structured into trees and a linking table is used to define permissions. You
|
||||
* can install the schema for DbAcl with the Schema Shell.
|
||||
*
|
||||
* `$aco` and `$aro` parameters can be slash delimited paths to tree nodes.
|
||||
*
|
||||
* eg. `controllers/Users/edit`
|
||||
*
|
||||
* Would point to a tree structure like
|
||||
*
|
||||
* {{{
|
||||
* controllers
|
||||
* Users
|
||||
* edit
|
||||
* }}}
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
class DbAcl extends Object implements AclInterface {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->Permission = ClassRegistry::init(array('class' => 'Permission', 'alias' => 'Permission'));
|
||||
$this->Aro = $this->Permission->Aro;
|
||||
$this->Aco = $this->Permission->Aco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the containing component and sets the Aro/Aco objects to it.
|
||||
*
|
||||
* @param AclComponent $component The AclComponent instance.
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $component) {
|
||||
$component->Aro = $this->Aro;
|
||||
$component->Aco = $this->Aco;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given $aro has access to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success (true if ARO has access to action in ACO, false otherwise)
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#checking-permissions-the-acl-component
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*") {
|
||||
return $this->Permission->check($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow $aro to have access to action $actions in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $actions Action (defaults to *)
|
||||
* @param int $value Value to indicate access type (1 to give access, -1 to deny, 0 to inherit)
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
|
||||
*/
|
||||
public function allow($aro, $aco, $actions = "*", $value = 1) {
|
||||
return $this->Permission->allow($aro, $aco, $actions, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for $aro to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html#assigning-permissions
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Let access for $aro to action $action in $aco be inherited
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow $aro to have access to action $actions in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @see allow()
|
||||
*/
|
||||
public function grant($aro, $aco, $action = "*") {
|
||||
return $this->allow($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny access for $aro to action $action in $aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @see deny()
|
||||
*/
|
||||
public function revoke($aro, $aco, $action = "*") {
|
||||
return $this->deny($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of access-control links between the given Aro and Aco
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @return array Indexed array with: 'aro', 'aco' and 'link'
|
||||
*/
|
||||
public function getAclLink($aro, $aco) {
|
||||
return $this->Permission->getAclLink($aro, $aco);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the keys used in an ACO
|
||||
*
|
||||
* @param array $keys Permission model info
|
||||
* @return array ACO keys
|
||||
*/
|
||||
protected function _getAcoKeys($keys) {
|
||||
return $this->Permission->getAcoKeys($keys);
|
||||
}
|
||||
|
||||
}
|
174
lib/Cake/Controller/Component/Acl/IniAcl.php
Normal file
174
lib/Cake/Controller/Component/Acl/IniAcl.php
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AclInterface', 'Controller/Component/Acl');
|
||||
|
||||
/**
|
||||
* IniAcl implements an access control system using an INI file. An example
|
||||
* of the ini file used can be found in /config/acl.ini.php.
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
class IniAcl extends Object implements AclInterface {
|
||||
|
||||
/**
|
||||
* Array with configuration, parsed from ini file
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $config = null;
|
||||
|
||||
/**
|
||||
* The Hash::extract() path to the user/aro identifier in the
|
||||
* acl.ini file. This path will be used to extract the string
|
||||
* representation of a user used in the ini file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $userPath = 'User.username';
|
||||
|
||||
/**
|
||||
* Initialize method
|
||||
*
|
||||
* @param Component $component The AclComponent instance.
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $component) {
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, allow cannot be done with IniAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, deny cannot be done with IniAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, inherit cannot be done with IniAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main ACL check function. Checks to see if the ARO (access request object) has access to the
|
||||
* ACO (access control object).Looks at the acl.ini.php file for permissions
|
||||
* (see instructions in /config/acl.ini.php).
|
||||
*
|
||||
* @param string $aro ARO
|
||||
* @param string $aco ACO
|
||||
* @param string $action Action
|
||||
* @return bool Success
|
||||
*/
|
||||
public function check($aro, $aco, $action = null) {
|
||||
if (!$this->config) {
|
||||
$this->config = $this->readConfigFile(APP . 'Config' . DS . 'acl.ini.php');
|
||||
}
|
||||
$aclConfig = $this->config;
|
||||
|
||||
if (is_array($aro)) {
|
||||
$aro = Hash::get($aro, $this->userPath);
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['deny'])) {
|
||||
$userDenies = $this->arrayTrim(explode(",", $aclConfig[$aro]['deny']));
|
||||
|
||||
if (array_search($aco, $userDenies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['allow'])) {
|
||||
$userAllows = $this->arrayTrim(explode(",", $aclConfig[$aro]['allow']));
|
||||
|
||||
if (array_search($aco, $userAllows)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$aro]['groups'])) {
|
||||
$userGroups = $this->arrayTrim(explode(",", $aclConfig[$aro]['groups']));
|
||||
|
||||
foreach ($userGroups as $group) {
|
||||
if (array_key_exists($group, $aclConfig)) {
|
||||
if (isset($aclConfig[$group]['deny'])) {
|
||||
$groupDenies = $this->arrayTrim(explode(",", $aclConfig[$group]['deny']));
|
||||
|
||||
if (array_search($aco, $groupDenies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aclConfig[$group]['allow'])) {
|
||||
$groupAllows = $this->arrayTrim(explode(",", $aclConfig[$group]['allow']));
|
||||
|
||||
if (array_search($aco, $groupAllows)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an INI file and returns an array that reflects the
|
||||
* INI file's section structure. Double-quote friendly.
|
||||
*
|
||||
* @param string $filename File
|
||||
* @return array INI section structure
|
||||
*/
|
||||
public function readConfigFile($filename) {
|
||||
App::uses('IniReader', 'Configure');
|
||||
$iniFile = new IniReader(dirname($filename) . DS);
|
||||
return $iniFile->read(basename($filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes trailing spaces on all array elements (to prepare for searching)
|
||||
*
|
||||
* @param array $array Array to trim
|
||||
* @return array Trimmed array
|
||||
*/
|
||||
public function arrayTrim($array) {
|
||||
foreach ($array as $key => $value) {
|
||||
$array[$key] = trim($value);
|
||||
}
|
||||
array_unshift($array, "");
|
||||
return $array;
|
||||
}
|
||||
|
||||
}
|
563
lib/Cake/Controller/Component/Acl/PhpAcl.php
Normal file
563
lib/Cake/Controller/Component/Acl/PhpAcl.php
Normal file
|
@ -0,0 +1,563 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP configuration based AclInterface implementation
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component.Acl
|
||||
* @since CakePHP(tm) v 2.1
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* PhpAcl implements an access control system using a plain PHP configuration file.
|
||||
* An example file can be found in app/Config/acl.php
|
||||
*
|
||||
* @package Cake.Controller.Component.Acl
|
||||
*/
|
||||
class PhpAcl extends Object implements AclInterface {
|
||||
|
||||
/**
|
||||
* Constant for deny
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
const DENY = false;
|
||||
|
||||
/**
|
||||
* Constant for allow
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
const ALLOW = true;
|
||||
|
||||
/**
|
||||
* Options:
|
||||
* - policy: determines behavior of the check method. Deny policy needs explicit allow rules, allow policy needs explicit deny rules
|
||||
* - config: absolute path to config file that contains the acl rules (@see app/Config/acl.php)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $options = array();
|
||||
|
||||
/**
|
||||
* Aro Object
|
||||
*
|
||||
* @var PhpAro
|
||||
*/
|
||||
public $Aro = null;
|
||||
|
||||
/**
|
||||
* Aco Object
|
||||
*
|
||||
* @var PhpAco
|
||||
*/
|
||||
public $Aco = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Sets a few default settings up.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->options = array(
|
||||
'policy' => self::DENY,
|
||||
'config' => APP . 'Config' . DS . 'acl.php',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize method
|
||||
*
|
||||
* @param AclComponent $Component Component instance
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Component $Component) {
|
||||
if (!empty($Component->settings['adapter'])) {
|
||||
$this->options = $Component->settings['adapter'] + $this->options;
|
||||
}
|
||||
|
||||
App::uses('PhpReader', 'Configure');
|
||||
$Reader = new PhpReader(dirname($this->options['config']) . DS);
|
||||
$config = $Reader->read(basename($this->options['config']));
|
||||
$this->build($config);
|
||||
$Component->Aco = $this->Aco;
|
||||
$Component->Aro = $this->Aro;
|
||||
}
|
||||
|
||||
/**
|
||||
* build and setup internal ACL representation
|
||||
*
|
||||
* @param array $config configuration array, see docs
|
||||
* @return void
|
||||
* @throws AclException When required keys are missing.
|
||||
*/
|
||||
public function build(array $config) {
|
||||
if (empty($config['roles'])) {
|
||||
throw new AclException(__d('cake_dev', '"roles" section not found in configuration.'));
|
||||
}
|
||||
|
||||
if (empty($config['rules']['allow']) && empty($config['rules']['deny'])) {
|
||||
throw new AclException(__d('cake_dev', 'Neither "allow" nor "deny" rules were provided in configuration.'));
|
||||
}
|
||||
|
||||
$rules['allow'] = !empty($config['rules']['allow']) ? $config['rules']['allow'] : array();
|
||||
$rules['deny'] = !empty($config['rules']['deny']) ? $config['rules']['deny'] : array();
|
||||
$roles = !empty($config['roles']) ? $config['roles'] : array();
|
||||
$map = !empty($config['map']) ? $config['map'] : array();
|
||||
$alias = !empty($config['alias']) ? $config['alias'] : array();
|
||||
|
||||
$this->Aro = new PhpAro($roles, $map, $alias);
|
||||
$this->Aco = new PhpAco($rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method, allow cannot be done with PhpAcl
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*") {
|
||||
return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'allow');
|
||||
}
|
||||
|
||||
/**
|
||||
* deny ARO access to ACO
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
return $this->Aco->access($this->Aro->resolve($aro), $aco, $action, 'deny');
|
||||
}
|
||||
|
||||
/**
|
||||
* No op method
|
||||
*
|
||||
* @param string $aro ARO The requesting object identifier.
|
||||
* @param string $aco ACO The controlled object identifier.
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main ACL check function. Checks to see if the ARO (access request object) has access to the
|
||||
* ACO (access control object).
|
||||
*
|
||||
* @param string $aro ARO
|
||||
* @param string $aco ACO
|
||||
* @param string $action Action
|
||||
* @return bool true if access is granted, false otherwise
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*") {
|
||||
$allow = $this->options['policy'];
|
||||
$prioritizedAros = $this->Aro->roles($aro);
|
||||
|
||||
if ($action && $action !== "*") {
|
||||
$aco .= '/' . $action;
|
||||
}
|
||||
|
||||
$path = $this->Aco->path($aco);
|
||||
|
||||
if (empty($path)) {
|
||||
return $allow;
|
||||
}
|
||||
|
||||
foreach ($path as $node) {
|
||||
foreach ($prioritizedAros as $aros) {
|
||||
if (!empty($node['allow'])) {
|
||||
$allow = $allow || count(array_intersect($node['allow'], $aros));
|
||||
}
|
||||
|
||||
if (!empty($node['deny'])) {
|
||||
$allow = $allow && !count(array_intersect($node['deny'], $aros));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $allow;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Control Object
|
||||
*
|
||||
*/
|
||||
class PhpAco {
|
||||
|
||||
/**
|
||||
* holds internal ACO representation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_tree = array();
|
||||
|
||||
/**
|
||||
* map modifiers for ACO paths to their respective PCRE pattern
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modifiers = array(
|
||||
'*' => '.*',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $rules Rules array
|
||||
*/
|
||||
public function __construct(array $rules = array()) {
|
||||
foreach (array('allow', 'deny') as $type) {
|
||||
if (empty($rules[$type])) {
|
||||
$rules[$type] = array();
|
||||
}
|
||||
}
|
||||
|
||||
$this->build($rules['allow'], $rules['deny']);
|
||||
}
|
||||
|
||||
/**
|
||||
* return path to the requested ACO with allow and deny rules attached on each level
|
||||
*
|
||||
* @param string $aco ACO string
|
||||
* @return array
|
||||
*/
|
||||
public function path($aco) {
|
||||
$aco = $this->resolve($aco);
|
||||
$path = array();
|
||||
$level = 0;
|
||||
$root = $this->_tree;
|
||||
$stack = array(array($root, 0));
|
||||
|
||||
while (!empty($stack)) {
|
||||
list($root, $level) = array_pop($stack);
|
||||
|
||||
if (empty($path[$level])) {
|
||||
$path[$level] = array();
|
||||
}
|
||||
|
||||
foreach ($root as $node => $elements) {
|
||||
$pattern = '/^' . str_replace(array_keys(self::$modifiers), array_values(self::$modifiers), $node) . '$/';
|
||||
|
||||
if ($node == $aco[$level] || preg_match($pattern, $aco[$level])) {
|
||||
// merge allow/denies with $path of current level
|
||||
foreach (array('allow', 'deny') as $policy) {
|
||||
if (!empty($elements[$policy])) {
|
||||
if (empty($path[$level][$policy])) {
|
||||
$path[$level][$policy] = array();
|
||||
}
|
||||
$path[$level][$policy] = array_merge($path[$level][$policy], $elements[$policy]);
|
||||
}
|
||||
}
|
||||
|
||||
// traverse
|
||||
if (!empty($elements['children']) && isset($aco[$level + 1])) {
|
||||
array_push($stack, array($elements['children'], $level + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* allow/deny ARO access to ARO
|
||||
*
|
||||
* @param string $aro ARO string
|
||||
* @param string $aco ACO string
|
||||
* @param string $action Action string
|
||||
* @param string $type access type
|
||||
* @return void
|
||||
*/
|
||||
public function access($aro, $aco, $action, $type = 'deny') {
|
||||
$aco = $this->resolve($aco);
|
||||
$depth = count($aco);
|
||||
$root = $this->_tree;
|
||||
$tree = &$root;
|
||||
|
||||
foreach ($aco as $i => $node) {
|
||||
if (!isset($tree[$node])) {
|
||||
$tree[$node] = array(
|
||||
'children' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
if ($i < $depth - 1) {
|
||||
$tree = &$tree[$node]['children'];
|
||||
} else {
|
||||
if (empty($tree[$node][$type])) {
|
||||
$tree[$node][$type] = array();
|
||||
}
|
||||
|
||||
$tree[$node][$type] = array_merge(is_array($aro) ? $aro : array($aro), $tree[$node][$type]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->_tree = &$root;
|
||||
}
|
||||
|
||||
/**
|
||||
* resolve given ACO string to a path
|
||||
*
|
||||
* @param string $aco ACO string
|
||||
* @return array path
|
||||
*/
|
||||
public function resolve($aco) {
|
||||
if (is_array($aco)) {
|
||||
return array_map('strtolower', $aco);
|
||||
}
|
||||
|
||||
// strip multiple occurrences of '/'
|
||||
$aco = preg_replace('#/+#', '/', $aco);
|
||||
// make case insensitive
|
||||
$aco = ltrim(strtolower($aco), '/');
|
||||
return array_filter(array_map('trim', explode('/', $aco)));
|
||||
}
|
||||
|
||||
/**
|
||||
* build a tree representation from the given allow/deny informations for ACO paths
|
||||
*
|
||||
* @param array $allow ACO allow rules
|
||||
* @param array $deny ACO deny rules
|
||||
* @return void
|
||||
*/
|
||||
public function build(array $allow, array $deny = array()) {
|
||||
$this->_tree = array();
|
||||
|
||||
foreach ($allow as $dotPath => $aros) {
|
||||
if (is_string($aros)) {
|
||||
$aros = array_map('trim', explode(',', $aros));
|
||||
}
|
||||
|
||||
$this->access($aros, $dotPath, null, 'allow');
|
||||
}
|
||||
|
||||
foreach ($deny as $dotPath => $aros) {
|
||||
if (is_string($aros)) {
|
||||
$aros = array_map('trim', explode(',', $aros));
|
||||
}
|
||||
|
||||
$this->access($aros, $dotPath, null, 'deny');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Access Request Object
|
||||
*
|
||||
*/
|
||||
class PhpAro {
|
||||
|
||||
/**
|
||||
* role to resolve to when a provided ARO is not listed in
|
||||
* the internal tree
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_ROLE = 'Role/default';
|
||||
|
||||
/**
|
||||
* map external identifiers. E.g. if
|
||||
*
|
||||
* array('User' => array('username' => 'jeff', 'role' => 'editor'))
|
||||
*
|
||||
* is passed as an ARO to one of the methods of AclComponent, PhpAcl
|
||||
* will check if it can be resolved to an User or a Role defined in the
|
||||
* configuration file.
|
||||
*
|
||||
* @var array
|
||||
* @see app/Config/acl.php
|
||||
*/
|
||||
public $map = array(
|
||||
'User' => 'User/username',
|
||||
'Role' => 'User/role',
|
||||
);
|
||||
|
||||
/**
|
||||
* aliases to map
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $aliases = array();
|
||||
|
||||
/**
|
||||
* internal ARO representation
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_tree = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $aro The aro data
|
||||
* @param array $map The identifier mappings
|
||||
* @param array $aliases The aliases to map.
|
||||
*/
|
||||
public function __construct(array $aro = array(), array $map = array(), array $aliases = array()) {
|
||||
if (!empty($map)) {
|
||||
$this->map = $map;
|
||||
}
|
||||
|
||||
$this->aliases = $aliases;
|
||||
$this->build($aro);
|
||||
}
|
||||
|
||||
/**
|
||||
* From the perspective of the given ARO, walk down the tree and
|
||||
* collect all inherited AROs levelwise such that AROs from different
|
||||
* branches with equal distance to the requested ARO will be collected at the same
|
||||
* index. The resulting array will contain a prioritized list of (list of) roles ordered from
|
||||
* the most distant AROs to the requested one itself.
|
||||
*
|
||||
* @param string|array $aro An ARO identifier
|
||||
* @return array prioritized AROs
|
||||
*/
|
||||
public function roles($aro) {
|
||||
$aros = array();
|
||||
$aro = $this->resolve($aro);
|
||||
$stack = array(array($aro, 0));
|
||||
|
||||
while (!empty($stack)) {
|
||||
list($element, $depth) = array_pop($stack);
|
||||
$aros[$depth][] = $element;
|
||||
|
||||
foreach ($this->_tree as $node => $children) {
|
||||
if (in_array($element, $children)) {
|
||||
array_push($stack, array($node, $depth + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($aros);
|
||||
}
|
||||
|
||||
/**
|
||||
* resolve an ARO identifier to an internal ARO string using
|
||||
* the internal mapping information.
|
||||
*
|
||||
* @param string|array $aro ARO identifier (User.jeff, array('User' => ...), etc)
|
||||
* @return string internal aro string (e.g. User/jeff, Role/default)
|
||||
*/
|
||||
public function resolve($aro) {
|
||||
foreach ($this->map as $aroGroup => $map) {
|
||||
list ($model, $field) = explode('/', $map, 2);
|
||||
$mapped = '';
|
||||
|
||||
if (is_array($aro)) {
|
||||
if (isset($aro['model']) && isset($aro['foreign_key']) && $aro['model'] === $aroGroup) {
|
||||
$mapped = $aroGroup . '/' . $aro['foreign_key'];
|
||||
} elseif (isset($aro[$model][$field])) {
|
||||
$mapped = $aroGroup . '/' . $aro[$model][$field];
|
||||
} elseif (isset($aro[$field])) {
|
||||
$mapped = $aroGroup . '/' . $aro[$field];
|
||||
}
|
||||
} elseif (is_string($aro)) {
|
||||
$aro = ltrim($aro, '/');
|
||||
|
||||
if (strpos($aro, '/') === false) {
|
||||
$mapped = $aroGroup . '/' . $aro;
|
||||
} else {
|
||||
list($aroModel, $aroValue) = explode('/', $aro, 2);
|
||||
|
||||
$aroModel = Inflector::camelize($aroModel);
|
||||
|
||||
if ($aroModel === $model || $aroModel === $aroGroup) {
|
||||
$mapped = $aroGroup . '/' . $aroValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->_tree[$mapped])) {
|
||||
return $mapped;
|
||||
}
|
||||
|
||||
// is there a matching alias defined (e.g. Role/1 => Role/admin)?
|
||||
if (!empty($this->aliases[$mapped])) {
|
||||
return $this->aliases[$mapped];
|
||||
}
|
||||
}
|
||||
return self::DEFAULT_ROLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a new ARO to the tree
|
||||
*
|
||||
* @param array $aro one or more ARO records
|
||||
* @return void
|
||||
*/
|
||||
public function addRole(array $aro) {
|
||||
foreach ($aro as $role => $inheritedRoles) {
|
||||
if (!isset($this->_tree[$role])) {
|
||||
$this->_tree[$role] = array();
|
||||
}
|
||||
|
||||
if (!empty($inheritedRoles)) {
|
||||
if (is_string($inheritedRoles)) {
|
||||
$inheritedRoles = array_map('trim', explode(',', $inheritedRoles));
|
||||
}
|
||||
|
||||
foreach ($inheritedRoles as $dependency) {
|
||||
// detect cycles
|
||||
$roles = $this->roles($dependency);
|
||||
|
||||
if (in_array($role, Hash::flatten($roles))) {
|
||||
$path = '';
|
||||
|
||||
foreach ($roles as $roleDependencies) {
|
||||
$path .= implode('|', (array)$roleDependencies) . ' -> ';
|
||||
}
|
||||
|
||||
trigger_error(__d('cake_dev', 'cycle detected when inheriting %s from %s. Path: %s', $role, $dependency, $path . $role));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($this->_tree[$dependency])) {
|
||||
$this->_tree[$dependency] = array();
|
||||
}
|
||||
|
||||
$this->_tree[$dependency][] = $role;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds one or more aliases to the internal map. Overwrites existing entries.
|
||||
*
|
||||
* @param array $alias alias from => to (e.g. Role/13 -> Role/editor)
|
||||
* @return void
|
||||
*/
|
||||
public function addAlias(array $alias) {
|
||||
$this->aliases = $alias + $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* build an ARO tree structure for internal processing
|
||||
*
|
||||
* @param array $aros array of AROs as key and their inherited AROs as values
|
||||
* @return void
|
||||
*/
|
||||
public function build(array $aros) {
|
||||
$this->_tree = array();
|
||||
$this->addRole($aros);
|
||||
}
|
||||
|
||||
}
|
180
lib/Cake/Controller/Component/AclComponent.php
Normal file
180
lib/Cake/Controller/Component/AclComponent.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('AclInterface', 'Controller/Component/Acl');
|
||||
|
||||
/**
|
||||
* Access Control List factory class.
|
||||
*
|
||||
* Uses a strategy pattern to allow custom ACL implementations to be used with the same component interface.
|
||||
* You can define by changing `Configure::write('Acl.classname', 'DbAcl');` in your core.php. The adapter
|
||||
* you specify must implement `AclInterface`
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/access-control-lists.html
|
||||
*/
|
||||
class AclComponent extends Component {
|
||||
|
||||
/**
|
||||
* Instance of an ACL class
|
||||
*
|
||||
* @var AclInterface
|
||||
*/
|
||||
protected $_Instance = null;
|
||||
|
||||
/**
|
||||
* Aro object.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Aro;
|
||||
|
||||
/**
|
||||
* Aco object
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $Aco;
|
||||
|
||||
/**
|
||||
* Constructor. Will return an instance of the correct ACL class as defined in `Configure::read('Acl.classname')`
|
||||
*
|
||||
* @param ComponentCollection $collection Collection instance.
|
||||
* @param array $settings Settings list.
|
||||
* @throws CakeException when Acl.classname could not be loaded.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
parent::__construct($collection, $settings);
|
||||
$name = Configure::read('Acl.classname');
|
||||
if (!class_exists($name)) {
|
||||
list($plugin, $name) = pluginSplit($name, true);
|
||||
App::uses($name, $plugin . 'Controller/Component/Acl');
|
||||
if (!class_exists($name)) {
|
||||
throw new CakeException(__d('cake_dev', 'Could not find %s.', $name));
|
||||
}
|
||||
}
|
||||
$this->adapter($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets or gets the Adapter object currently in the AclComponent.
|
||||
*
|
||||
* `$this->Acl->adapter();` will get the current adapter class while
|
||||
* `$this->Acl->adapter($obj);` will set the adapter class
|
||||
*
|
||||
* Will call the initialize method on the adapter if setting a new one.
|
||||
*
|
||||
* @param AclInterface|string $adapter Instance of AclInterface or a string name of the class to use. (optional)
|
||||
* @return AclInterface|void either null, or the adapter implementation.
|
||||
* @throws CakeException when the given class is not an instance of AclInterface
|
||||
*/
|
||||
public function adapter($adapter = null) {
|
||||
if ($adapter) {
|
||||
if (is_string($adapter)) {
|
||||
$adapter = new $adapter();
|
||||
}
|
||||
if (!$adapter instanceof AclInterface) {
|
||||
throw new CakeException(__d('cake_dev', 'AclComponent adapters must implement AclInterface'));
|
||||
}
|
||||
$this->_Instance = $adapter;
|
||||
$this->_Instance->initialize($this);
|
||||
return;
|
||||
}
|
||||
return $this->_Instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL check instance. Check methods
|
||||
* are used to check whether or not an ARO can access an ACO
|
||||
*
|
||||
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
|
||||
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function check($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->check($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL allow instance. Allow methods
|
||||
* are used to grant an ARO access to an ACO.
|
||||
*
|
||||
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
|
||||
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function allow($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->allow($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL deny instance. Deny methods
|
||||
* are used to remove permission from an ARO to access an ACO.
|
||||
*
|
||||
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
|
||||
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function deny($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->deny($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL inherit instance. Inherit methods
|
||||
* modify the permission for an ARO to be that of its parent object.
|
||||
*
|
||||
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
|
||||
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
*/
|
||||
public function inherit($aro, $aco, $action = "*") {
|
||||
return $this->_Instance->inherit($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL grant instance. An alias for AclComponent::allow()
|
||||
*
|
||||
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
|
||||
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @deprecated Will be removed in 3.0.
|
||||
*/
|
||||
public function grant($aro, $aco, $action = "*") {
|
||||
trigger_error(__d('cake_dev', '%s is deprecated, use %s instead', 'AclComponent::grant()', 'allow()'), E_USER_WARNING);
|
||||
return $this->_Instance->allow($aro, $aco, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass-thru function for ACL grant instance. An alias for AclComponent::deny()
|
||||
*
|
||||
* @param array|string|Model $aro ARO The requesting object identifier. See `AclNode::node()` for possible formats
|
||||
* @param array|string|Model $aco ACO The controlled object identifier. See `AclNode::node()` for possible formats
|
||||
* @param string $action Action (defaults to *)
|
||||
* @return bool Success
|
||||
* @deprecated Will be removed in 3.0.
|
||||
*/
|
||||
public function revoke($aro, $aco, $action = "*") {
|
||||
trigger_error(__d('cake_dev', '%s is deprecated, use %s instead', 'AclComponent::revoke()', 'deny()'), E_USER_WARNING);
|
||||
return $this->_Instance->deny($aro, $aco, $action);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.4.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abstract password hashing class
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
*/
|
||||
abstract class AbstractPasswordHasher {
|
||||
|
||||
/**
|
||||
* Configurations for this object. Settings passed from authenticator class to
|
||||
* the constructor are merged with this property.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_config = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $config Array of config.
|
||||
*/
|
||||
public function __construct($config = array()) {
|
||||
$this->config($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/Set the config
|
||||
*
|
||||
* @param array $config Sets config, if null returns existing config
|
||||
* @return array Returns configs
|
||||
*/
|
||||
public function config($config = null) {
|
||||
if (is_array($config)) {
|
||||
$this->_config = array_merge($this->_config, $config);
|
||||
}
|
||||
return $this->_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates password hash.
|
||||
*
|
||||
* @param string|array $password Plain text password to hash or array of data
|
||||
* required to generate password hash.
|
||||
* @return string Password hash
|
||||
*/
|
||||
abstract public function hash($password);
|
||||
|
||||
/**
|
||||
* Check hash. Generate hash from user provided password string or data array
|
||||
* and check against existing hash.
|
||||
*
|
||||
* @param string|array $password Plain text password to hash or data array.
|
||||
* @param string $hashedPassword Existing hashed password.
|
||||
* @return bool True if hashes match else false.
|
||||
*/
|
||||
abstract public function check($password, $hashedPassword);
|
||||
|
||||
}
|
41
lib/Cake/Controller/Component/Auth/ActionsAuthorize.php
Normal file
41
lib/Cake/Controller/Component/Auth/ActionsAuthorize.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('BaseAuthorize', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* An authorization adapter for AuthComponent. Provides the ability to authorize using the AclComponent,
|
||||
* If AclComponent is not already loaded it will be loaded using the Controller's ComponentCollection.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
* @see AuthComponent::$authenticate
|
||||
* @see AclComponent::check()
|
||||
*/
|
||||
class ActionsAuthorize extends BaseAuthorize {
|
||||
|
||||
/**
|
||||
* Authorize a user using the AclComponent.
|
||||
*
|
||||
* @param array $user The user to authorize
|
||||
* @param CakeRequest $request The request needing authorization.
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize($user, CakeRequest $request) {
|
||||
$Acl = $this->_Collection->load('Acl');
|
||||
$user = array($this->settings['userModel'] => $user);
|
||||
return $Acl->check($user, $this->action($request));
|
||||
}
|
||||
|
||||
}
|
219
lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
Normal file
219
lib/Cake/Controller/Component/Auth/BaseAuthenticate.php
Normal file
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Security', 'Utility');
|
||||
App::uses('Hash', 'Utility');
|
||||
|
||||
/**
|
||||
* Base Authentication class with common methods and properties.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
*/
|
||||
abstract class BaseAuthenticate {
|
||||
|
||||
/**
|
||||
* Settings for this object.
|
||||
*
|
||||
* - `fields` The fields to use to identify a user by.
|
||||
* - `userModel` The model name of the User, defaults to User.
|
||||
* - `scope` Additional conditions to use when looking up and authenticating users,
|
||||
* i.e. `array('User.is_active' => 1).`
|
||||
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
|
||||
* - `contain` Extra models to contain and store in session.
|
||||
* - `passwordHasher` Password hasher class. Can be a string specifying class name
|
||||
* or an array containing `className` key, any other keys will be passed as
|
||||
* settings to the class. Defaults to 'Simple'.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings = array(
|
||||
'fields' => array(
|
||||
'username' => 'username',
|
||||
'password' => 'password'
|
||||
),
|
||||
'userModel' => 'User',
|
||||
'scope' => array(),
|
||||
'recursive' => 0,
|
||||
'contain' => null,
|
||||
'passwordHasher' => 'Simple'
|
||||
);
|
||||
|
||||
/**
|
||||
* A Component collection, used to get more components.
|
||||
*
|
||||
* @var ComponentCollection
|
||||
*/
|
||||
protected $_Collection;
|
||||
|
||||
/**
|
||||
* Password hasher instance.
|
||||
*
|
||||
* @var AbstractPasswordHasher
|
||||
*/
|
||||
protected $_passwordHasher;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ComponentCollection $collection The Component collection used on this request.
|
||||
* @param array $settings Array of settings to use.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings) {
|
||||
$this->_Collection = $collection;
|
||||
$this->settings = Hash::merge($this->settings, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a user record using the standard options.
|
||||
*
|
||||
* The $username parameter can be a (string)username or an array containing
|
||||
* conditions for Model::find('first'). If the $password param is not provided
|
||||
* the password field will be present in returned array.
|
||||
*
|
||||
* Input passwords will be hashed even when a user doesn't exist. This
|
||||
* helps mitigate timing attacks that are attempting to find valid usernames.
|
||||
*
|
||||
* @param string|array $username The username/identifier, or an array of find conditions.
|
||||
* @param string $password The password, only used if $username param is string.
|
||||
* @return bool|array Either false on failure, or an array of user data.
|
||||
*/
|
||||
protected function _findUser($username, $password = null) {
|
||||
$userModel = $this->settings['userModel'];
|
||||
list(, $model) = pluginSplit($userModel);
|
||||
$fields = $this->settings['fields'];
|
||||
|
||||
if (is_array($username)) {
|
||||
$conditions = $username;
|
||||
} else {
|
||||
$conditions = array(
|
||||
$model . '.' . $fields['username'] => $username
|
||||
);
|
||||
}
|
||||
|
||||
if (!empty($this->settings['scope'])) {
|
||||
$conditions = array_merge($conditions, $this->settings['scope']);
|
||||
}
|
||||
|
||||
$result = ClassRegistry::init($userModel)->find('first', array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => $this->settings['recursive'],
|
||||
'contain' => $this->settings['contain'],
|
||||
));
|
||||
if (empty($result[$model])) {
|
||||
$this->passwordHasher()->hash($password);
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = $result[$model];
|
||||
if ($password !== null) {
|
||||
if (!$this->passwordHasher()->check($password, $user[$fields['password']])) {
|
||||
return false;
|
||||
}
|
||||
unset($user[$fields['password']]);
|
||||
}
|
||||
|
||||
unset($result[$model]);
|
||||
return array_merge($user, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return password hasher object
|
||||
*
|
||||
* @return AbstractPasswordHasher Password hasher instance
|
||||
* @throws CakeException If password hasher class not found or
|
||||
* it does not extend AbstractPasswordHasher
|
||||
*/
|
||||
public function passwordHasher() {
|
||||
if ($this->_passwordHasher) {
|
||||
return $this->_passwordHasher;
|
||||
}
|
||||
|
||||
$config = array();
|
||||
if (is_string($this->settings['passwordHasher'])) {
|
||||
$class = $this->settings['passwordHasher'];
|
||||
} else {
|
||||
$class = $this->settings['passwordHasher']['className'];
|
||||
$config = $this->settings['passwordHasher'];
|
||||
unset($config['className']);
|
||||
}
|
||||
list($plugin, $class) = pluginSplit($class, true);
|
||||
$className = $class . 'PasswordHasher';
|
||||
App::uses($className, $plugin . 'Controller/Component/Auth');
|
||||
if (!class_exists($className)) {
|
||||
throw new CakeException(__d('cake_dev', 'Password hasher class "%s" was not found.', $class));
|
||||
}
|
||||
if (!is_subclass_of($className, 'AbstractPasswordHasher')) {
|
||||
throw new CakeException(__d('cake_dev', 'Password hasher must extend AbstractPasswordHasher class.'));
|
||||
}
|
||||
$this->_passwordHasher = new $className($config);
|
||||
return $this->_passwordHasher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash the plain text password so that it matches the hashed/encrypted password
|
||||
* in the datasource.
|
||||
*
|
||||
* @param string $password The plain text password.
|
||||
* @return string The hashed form of the password.
|
||||
* @deprecated Since 2.4. Use a PasswordHasher class instead.
|
||||
*/
|
||||
protected function _password($password) {
|
||||
return Security::hash($password, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user based on the request information.
|
||||
*
|
||||
* @param CakeRequest $request Request to get authentication information from.
|
||||
* @param CakeResponse $response A response object that can have headers added.
|
||||
* @return mixed Either false on failure, or an array of user data on success.
|
||||
*/
|
||||
abstract public function authenticate(CakeRequest $request, CakeResponse $response);
|
||||
|
||||
/**
|
||||
* Allows you to hook into AuthComponent::logout(),
|
||||
* and implement specialized logout behavior.
|
||||
*
|
||||
* All attached authentication objects will have this method
|
||||
* called when a user logs out.
|
||||
*
|
||||
* @param array $user The user about to be logged out.
|
||||
* @return void
|
||||
*/
|
||||
public function logout($user) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user based on information in the request. Primarily used by stateless authentication
|
||||
* systems like basic and digest auth.
|
||||
*
|
||||
* @param CakeRequest $request Request object.
|
||||
* @return mixed Either false or an array of user information
|
||||
*/
|
||||
public function getUser(CakeRequest $request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unauthenticated access attempt.
|
||||
*
|
||||
* @param CakeRequest $request A request object.
|
||||
* @param CakeResponse $response A response object.
|
||||
* @return mixed Either true to indicate the unauthenticated request has been
|
||||
* dealt with and no more action is required by AuthComponent or void (default).
|
||||
*/
|
||||
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
|
||||
}
|
||||
|
||||
}
|
168
lib/Cake/Controller/Component/Auth/BaseAuthorize.php
Normal file
168
lib/Cake/Controller/Component/Auth/BaseAuthorize.php
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Hash', 'Utility');
|
||||
|
||||
/**
|
||||
* Abstract base authorization adapter for AuthComponent.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
* @see AuthComponent::$authenticate
|
||||
*/
|
||||
abstract class BaseAuthorize {
|
||||
|
||||
/**
|
||||
* Controller for the request.
|
||||
*
|
||||
* @var Controller
|
||||
*/
|
||||
protected $_Controller = null;
|
||||
|
||||
/**
|
||||
* Component collection instance for getting more components.
|
||||
*
|
||||
* @var ComponentCollection
|
||||
*/
|
||||
protected $_Collection;
|
||||
|
||||
/**
|
||||
* Settings for authorize objects.
|
||||
*
|
||||
* - `actionPath` - The path to ACO nodes that contains the nodes for controllers. Used as a prefix
|
||||
* when calling $this->action();
|
||||
* - `actionMap` - Action -> crud mappings. Used by authorization objects that want to map actions to CRUD roles.
|
||||
* - `userModel` - Model name that ARO records can be found under. Defaults to 'User'.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings = array(
|
||||
'actionPath' => null,
|
||||
'actionMap' => array(
|
||||
'index' => 'read',
|
||||
'add' => 'create',
|
||||
'edit' => 'update',
|
||||
'view' => 'read',
|
||||
'delete' => 'delete',
|
||||
'remove' => 'delete'
|
||||
),
|
||||
'userModel' => 'User'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ComponentCollection $collection The controller for this request.
|
||||
* @param string $settings An array of settings. This class does not use any settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
$this->_Collection = $collection;
|
||||
$controller = $collection->getController();
|
||||
$this->controller($controller);
|
||||
$this->settings = Hash::merge($this->settings, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks user authorization.
|
||||
*
|
||||
* @param array $user Active user data
|
||||
* @param CakeRequest $request Request instance.
|
||||
* @return bool
|
||||
*/
|
||||
abstract public function authorize($user, CakeRequest $request);
|
||||
|
||||
/**
|
||||
* Accessor to the controller object.
|
||||
*
|
||||
* @param Controller $controller null to get, a controller to set.
|
||||
* @return mixed
|
||||
* @throws CakeException
|
||||
*/
|
||||
public function controller(Controller $controller = null) {
|
||||
if ($controller) {
|
||||
if (!$controller instanceof Controller) {
|
||||
throw new CakeException(__d('cake_dev', '$controller needs to be an instance of Controller'));
|
||||
}
|
||||
$this->_Controller = $controller;
|
||||
return true;
|
||||
}
|
||||
return $this->_Controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the action path for a given request. Primarily used by authorize objects
|
||||
* that need to get information about the plugin, controller, and action being invoked.
|
||||
*
|
||||
* @param CakeRequest $request The request a path is needed for.
|
||||
* @param string $path Path format.
|
||||
* @return string the action path for the given request.
|
||||
*/
|
||||
public function action(CakeRequest $request, $path = '/:plugin/:controller/:action') {
|
||||
$plugin = empty($request['plugin']) ? null : Inflector::camelize($request['plugin']) . '/';
|
||||
$path = str_replace(
|
||||
array(':controller', ':action', ':plugin/'),
|
||||
array(Inflector::camelize($request['controller']), $request['action'], $plugin),
|
||||
$this->settings['actionPath'] . $path
|
||||
);
|
||||
$path = str_replace('//', '/', $path);
|
||||
return trim($path, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps crud actions to actual action names. Used to modify or get the current mapped actions.
|
||||
*
|
||||
* Create additional mappings for a standard CRUD operation:
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->mapActions(array('create' => array('add', 'register'));
|
||||
* }}}
|
||||
*
|
||||
* Or equivalently:
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->mapActions(array('register' => 'create', 'add' => 'create'));
|
||||
* }}}
|
||||
*
|
||||
* Create mappings for custom CRUD operations:
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->mapActions(array('range' => 'search'));
|
||||
* }}}
|
||||
*
|
||||
* You can use the custom CRUD operations to create additional generic permissions
|
||||
* that behave like CRUD operations. Doing this will require additional columns on the
|
||||
* permissions lookup. For example if one wanted an additional search CRUD operation
|
||||
* one would create and additional column '_search' in the aros_acos table. One could
|
||||
* create a custom admin CRUD operation for administration functions similarly if needed.
|
||||
*
|
||||
* @param array $map Either an array of mappings, or undefined to get current values.
|
||||
* @return mixed Either the current mappings or null when setting.
|
||||
* @see AuthComponent::mapActions()
|
||||
*/
|
||||
public function mapActions($map = array()) {
|
||||
if (empty($map)) {
|
||||
return $this->settings['actionMap'];
|
||||
}
|
||||
foreach ($map as $action => $type) {
|
||||
if (is_array($type)) {
|
||||
foreach ($type as $typedAction) {
|
||||
$this->settings['actionMap'][$typedAction] = $action;
|
||||
}
|
||||
} else {
|
||||
$this->settings['actionMap'][$action] = $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
117
lib/Cake/Controller/Component/Auth/BasicAuthenticate.php
Normal file
117
lib/Cake/Controller/Component/Auth/BasicAuthenticate.php
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* Basic Authentication adapter for AuthComponent.
|
||||
*
|
||||
* Provides Basic HTTP authentication support for AuthComponent. Basic Auth will
|
||||
* authenticate users against the configured userModel and verify the username
|
||||
* and passwords match.
|
||||
*
|
||||
* ### Using Basic auth
|
||||
*
|
||||
* In your controller's components array, add auth + the required settings.
|
||||
* {{{
|
||||
* public $components = array(
|
||||
* 'Auth' => array(
|
||||
* 'authenticate' => array('Basic')
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* You should also set `AuthComponent::$sessionKey = false;` in your AppController's
|
||||
* beforeFilter() to prevent CakePHP from sending a session cookie to the client.
|
||||
*
|
||||
* Since HTTP Basic Authentication is stateless you don't need a login() action
|
||||
* in your controller. The user credentials will be checked on each request. If
|
||||
* valid credentials are not provided, required authentication headers will be sent
|
||||
* by this authentication provider which triggers the login dialog in the browser/client.
|
||||
*
|
||||
* You may also want to use `$this->Auth->unauthorizedRedirect = false;`.
|
||||
* By default, unauthorized users are redirected to the referrer URL,
|
||||
* `AuthComponent::$loginAction`, or '/'. If unauthorizedRedirect is set to
|
||||
* false, a ForbiddenException exception is thrown instead of redirecting.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
*/
|
||||
class BasicAuthenticate extends BaseAuthenticate {
|
||||
|
||||
/**
|
||||
* Constructor, completes configuration for basic authentication.
|
||||
*
|
||||
* @param ComponentCollection $collection The Component collection used on this request.
|
||||
* @param array $settings An array of settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings) {
|
||||
parent::__construct($collection, $settings);
|
||||
if (empty($this->settings['realm'])) {
|
||||
$this->settings['realm'] = env('SERVER_NAME');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate a user using HTTP auth. Will use the configured User model and attempt a
|
||||
* login using HTTP auth.
|
||||
*
|
||||
* @param CakeRequest $request The request to authenticate with.
|
||||
* @param CakeResponse $response The response to add headers to.
|
||||
* @return mixed Either false on failure, or an array of user data on success.
|
||||
*/
|
||||
public function authenticate(CakeRequest $request, CakeResponse $response) {
|
||||
return $this->getUser($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
|
||||
*
|
||||
* @param CakeRequest $request Request object.
|
||||
* @return mixed Either false or an array of user information
|
||||
*/
|
||||
public function getUser(CakeRequest $request) {
|
||||
$username = env('PHP_AUTH_USER');
|
||||
$pass = env('PHP_AUTH_PW');
|
||||
|
||||
if (!is_string($username) || $username === '' || !is_string($pass) || $pass === '') {
|
||||
return false;
|
||||
}
|
||||
return $this->_findUser($username, $pass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an unauthenticated access attempt by sending appropriate login headers
|
||||
*
|
||||
* @param CakeRequest $request A request object.
|
||||
* @param CakeResponse $response A response object.
|
||||
* @return void
|
||||
* @throws UnauthorizedException
|
||||
*/
|
||||
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
|
||||
$Exception = new UnauthorizedException();
|
||||
$Exception->responseHeader(array($this->loginHeaders()));
|
||||
throw $Exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the login headers
|
||||
*
|
||||
* @return string Headers for logging in.
|
||||
*/
|
||||
public function loginHeaders() {
|
||||
return sprintf('WWW-Authenticate: Basic realm="%s"', $this->settings['realm']);
|
||||
}
|
||||
|
||||
}
|
53
lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php
Normal file
53
lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of the files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('FormAuthenticate', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* An authentication adapter for AuthComponent. Provides the ability to authenticate using POST data using Blowfish
|
||||
* hashing. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->authenticate = array(
|
||||
* 'Blowfish' => array(
|
||||
* 'scope' => array('User.active' => 1)
|
||||
* )
|
||||
* )
|
||||
* }}}
|
||||
*
|
||||
* When configuring BlowfishAuthenticate you can pass in settings to which fields, model and additional conditions
|
||||
* are used. See FormAuthenticate::$settings for more information.
|
||||
*
|
||||
* For initial password hashing/creation see Security::hash(). Other than how the password is initially hashed,
|
||||
* BlowfishAuthenticate works exactly the same way as FormAuthenticate.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since CakePHP(tm) v 2.3
|
||||
* @see AuthComponent::$authenticate
|
||||
* @deprecated Since 2.4. Just use FormAuthenticate with 'passwordHasher' setting set to 'Blowfish'
|
||||
*/
|
||||
class BlowfishAuthenticate extends FormAuthenticate {
|
||||
|
||||
/**
|
||||
* Constructor. Sets default passwordHasher to Blowfish
|
||||
*
|
||||
* @param ComponentCollection $collection The Component collection used on this request.
|
||||
* @param array $settings Array of settings to use.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings) {
|
||||
$this->settings['passwordHasher'] = 'Blowfish';
|
||||
parent::__construct($collection, $settings);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.4.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
|
||||
App::uses('Security', 'Utility');
|
||||
|
||||
/**
|
||||
* Blowfish password hashing class.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
*/
|
||||
class BlowfishPasswordHasher extends AbstractPasswordHasher {
|
||||
|
||||
/**
|
||||
* Generates password hash.
|
||||
*
|
||||
* @param string $password Plain text password to hash.
|
||||
* @return string Password hash
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#using-bcrypt-for-passwords
|
||||
*/
|
||||
public function hash($password) {
|
||||
return Security::hash($password, 'blowfish', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check hash. Generate hash for user provided password and check against existing hash.
|
||||
*
|
||||
* @param string $password Plain text password to hash.
|
||||
* @param string $hashedPassword Existing hashed password.
|
||||
* @return bool True if hashes match else false.
|
||||
*/
|
||||
public function check($password, $hashedPassword) {
|
||||
return $hashedPassword === Security::hash($password, 'blowfish', $hashedPassword);
|
||||
}
|
||||
|
||||
}
|
66
lib/Cake/Controller/Component/Auth/ControllerAuthorize.php
Normal file
66
lib/Cake/Controller/Component/Auth/ControllerAuthorize.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('BaseAuthorize', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* An authorization adapter for AuthComponent. Provides the ability to authorize using a controller callback.
|
||||
* Your controller's isAuthorized() method should return a boolean to indicate whether or not the user is authorized.
|
||||
*
|
||||
* {{{
|
||||
* public function isAuthorized($user) {
|
||||
* if (!empty($this->request->params['admin'])) {
|
||||
* return $user['role'] === 'admin';
|
||||
* }
|
||||
* return !empty($user);
|
||||
* }
|
||||
* }}}
|
||||
*
|
||||
* the above is simple implementation that would only authorize users of the 'admin' role to access
|
||||
* admin routing.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
* @see AuthComponent::$authenticate
|
||||
*/
|
||||
class ControllerAuthorize extends BaseAuthorize {
|
||||
|
||||
/**
|
||||
* Get/set the controller this authorize object will be working with. Also checks that isAuthorized is implemented.
|
||||
*
|
||||
* @param Controller $controller null to get, a controller to set.
|
||||
* @return mixed
|
||||
* @throws CakeException
|
||||
*/
|
||||
public function controller(Controller $controller = null) {
|
||||
if ($controller) {
|
||||
if (!method_exists($controller, 'isAuthorized')) {
|
||||
throw new CakeException(__d('cake_dev', '$controller does not implement an %s method.', 'isAuthorized()'));
|
||||
}
|
||||
}
|
||||
return parent::controller($controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks user authorization using a controller callback.
|
||||
*
|
||||
* @param array $user Active user data
|
||||
* @param CakeRequest $request Request instance.
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize($user, CakeRequest $request) {
|
||||
return (bool)$this->_Controller->isAuthorized($user);
|
||||
}
|
||||
|
||||
}
|
101
lib/Cake/Controller/Component/Auth/CrudAuthorize.php
Normal file
101
lib/Cake/Controller/Component/Auth/CrudAuthorize.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('BaseAuthorize', 'Controller/Component/Auth');
|
||||
App::uses('Router', 'Routing');
|
||||
|
||||
/**
|
||||
* An authorization adapter for AuthComponent. Provides the ability to authorize using CRUD mappings.
|
||||
* CRUD mappings allow you to translate controller actions into *C*reate *R*ead *U*pdate *D*elete actions.
|
||||
* This is then checked in the AclComponent as specific permissions.
|
||||
*
|
||||
* For example, taking `/posts/index` as the current request. The default mapping for `index`, is a `read` permission
|
||||
* check. The Acl check would then be for the `posts` controller with the `read` permission. This allows you
|
||||
* to create permission systems that focus more on what is being done to resources, rather than the specific actions
|
||||
* being visited.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
* @see AuthComponent::$authenticate
|
||||
* @see AclComponent::check()
|
||||
*/
|
||||
class CrudAuthorize extends BaseAuthorize {
|
||||
|
||||
/**
|
||||
* Sets up additional actionMap values that match the configured `Routing.prefixes`.
|
||||
*
|
||||
* @param ComponentCollection $collection The component collection from the controller.
|
||||
* @param string $settings An array of settings. This class does not use any settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
parent::__construct($collection, $settings);
|
||||
$this->_setPrefixMappings();
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the crud mappings for prefix routes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _setPrefixMappings() {
|
||||
$crud = array('create', 'read', 'update', 'delete');
|
||||
$map = array_combine($crud, $crud);
|
||||
|
||||
$prefixes = Router::prefixes();
|
||||
if (!empty($prefixes)) {
|
||||
foreach ($prefixes as $prefix) {
|
||||
$map = array_merge($map, array(
|
||||
$prefix . '_index' => 'read',
|
||||
$prefix . '_add' => 'create',
|
||||
$prefix . '_edit' => 'update',
|
||||
$prefix . '_view' => 'read',
|
||||
$prefix . '_remove' => 'delete',
|
||||
$prefix . '_create' => 'create',
|
||||
$prefix . '_read' => 'read',
|
||||
$prefix . '_update' => 'update',
|
||||
$prefix . '_delete' => 'delete'
|
||||
));
|
||||
}
|
||||
}
|
||||
$this->mapActions($map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authorize a user using the mapped actions and the AclComponent.
|
||||
*
|
||||
* @param array $user The user to authorize
|
||||
* @param CakeRequest $request The request needing authorization.
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize($user, CakeRequest $request) {
|
||||
if (!isset($this->settings['actionMap'][$request->params['action']])) {
|
||||
trigger_error(__d('cake_dev',
|
||||
'CrudAuthorize::authorize() - Attempted access of un-mapped action "%1$s" in controller "%2$s"',
|
||||
$request->action,
|
||||
$request->controller
|
||||
),
|
||||
E_USER_WARNING
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$user = array($this->settings['userModel'] => $user);
|
||||
$Acl = $this->_Collection->load('Acl');
|
||||
return $Acl->check(
|
||||
$user,
|
||||
$this->action($request, ':controller'),
|
||||
$this->settings['actionMap'][$request->params['action']]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
224
lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
Normal file
224
lib/Cake/Controller/Component/Auth/DigestAuthenticate.php
Normal file
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('BasicAuthenticate', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* Digest Authentication adapter for AuthComponent.
|
||||
*
|
||||
* Provides Digest HTTP authentication support for AuthComponent. Unlike most AuthComponent adapters,
|
||||
* DigestAuthenticate requires a special password hash that conforms to RFC2617. You can create this
|
||||
* password using `DigestAuthenticate::password()`. If you wish to use digest authentication alongside other
|
||||
* authentication methods, its recommended that you store the digest authentication separately.
|
||||
*
|
||||
* Clients using Digest Authentication must support cookies. Since AuthComponent identifies users based
|
||||
* on Session contents, clients without support for cookies will not function properly.
|
||||
*
|
||||
* ### Using Digest auth
|
||||
*
|
||||
* In your controller's components array, add auth + the required settings.
|
||||
* {{{
|
||||
* public $components = array(
|
||||
* 'Auth' => array(
|
||||
* 'authenticate' => array('Digest')
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* In your login function just call `$this->Auth->login()` without any checks for POST data. This
|
||||
* will send the authentication headers, and trigger the login dialog in the browser/client.
|
||||
*
|
||||
* ### Generating passwords compatible with Digest authentication.
|
||||
*
|
||||
* Due to the Digest authentication specification, digest auth requires a special password value. You
|
||||
* can generate this password using `DigestAuthenticate::password()`
|
||||
*
|
||||
* `$digestPass = DigestAuthenticate::password($username, env('SERVER_NAME'), $password);`
|
||||
*
|
||||
* Its recommended that you store this digest auth only password separate from password hashes used for other
|
||||
* login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would
|
||||
* store the password hash for use with other methods like Basic or Form.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
*/
|
||||
class DigestAuthenticate extends BasicAuthenticate {
|
||||
|
||||
/**
|
||||
* Settings for this object.
|
||||
*
|
||||
* - `fields` The fields to use to identify a user by.
|
||||
* - `userModel` The model name of the User, defaults to User.
|
||||
* - `scope` Additional conditions to use when looking up and authenticating users,
|
||||
* i.e. `array('User.is_active' => 1).`
|
||||
* - `recursive` The value of the recursive key passed to find(). Defaults to 0.
|
||||
* - `contain` Extra models to contain and store in session.
|
||||
* - `realm` The realm authentication is for, Defaults to the servername.
|
||||
* - `nonce` A nonce used for authentication. Defaults to `uniqid()`.
|
||||
* - `qop` Defaults to auth, no other values are supported at this time.
|
||||
* - `opaque` A string that must be returned unchanged by clients.
|
||||
* Defaults to `md5($settings['realm'])`
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings = array(
|
||||
'fields' => array(
|
||||
'username' => 'username',
|
||||
'password' => 'password'
|
||||
),
|
||||
'userModel' => 'User',
|
||||
'scope' => array(),
|
||||
'recursive' => 0,
|
||||
'contain' => null,
|
||||
'realm' => '',
|
||||
'qop' => 'auth',
|
||||
'nonce' => '',
|
||||
'opaque' => '',
|
||||
'passwordHasher' => 'Simple',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor, completes configuration for digest authentication.
|
||||
*
|
||||
* @param ComponentCollection $collection The Component collection used on this request.
|
||||
* @param array $settings An array of settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings) {
|
||||
parent::__construct($collection, $settings);
|
||||
if (empty($this->settings['nonce'])) {
|
||||
$this->settings['nonce'] = uniqid('');
|
||||
}
|
||||
if (empty($this->settings['opaque'])) {
|
||||
$this->settings['opaque'] = md5($this->settings['realm']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user based on information in the request. Used by cookie-less auth for stateless clients.
|
||||
*
|
||||
* @param CakeRequest $request Request object.
|
||||
* @return mixed Either false or an array of user information
|
||||
*/
|
||||
public function getUser(CakeRequest $request) {
|
||||
$digest = $this->_getDigest();
|
||||
if (empty($digest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list(, $model) = pluginSplit($this->settings['userModel']);
|
||||
$user = $this->_findUser(array(
|
||||
$model . '.' . $this->settings['fields']['username'] => $digest['username']
|
||||
));
|
||||
if (empty($user)) {
|
||||
return false;
|
||||
}
|
||||
$password = $user[$this->settings['fields']['password']];
|
||||
unset($user[$this->settings['fields']['password']]);
|
||||
if ($digest['response'] === $this->generateResponseHash($digest, $password)) {
|
||||
return $user;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the digest headers from the request/environment.
|
||||
*
|
||||
* @return array Array of digest information.
|
||||
*/
|
||||
protected function _getDigest() {
|
||||
$digest = env('PHP_AUTH_DIGEST');
|
||||
if (empty($digest) && function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
if (!empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) === 'Digest ') {
|
||||
$digest = substr($headers['Authorization'], 7);
|
||||
}
|
||||
}
|
||||
if (empty($digest)) {
|
||||
return false;
|
||||
}
|
||||
return $this->parseAuthData($digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the digest authentication headers and split them up.
|
||||
*
|
||||
* @param string $digest The raw digest authentication headers.
|
||||
* @return array An array of digest authentication headers
|
||||
*/
|
||||
public function parseAuthData($digest) {
|
||||
if (substr($digest, 0, 7) === 'Digest ') {
|
||||
$digest = substr($digest, 7);
|
||||
}
|
||||
$keys = $match = array();
|
||||
$req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1);
|
||||
preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9\:\#\%@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER);
|
||||
|
||||
foreach ($match as $i) {
|
||||
$keys[$i[1]] = $i[3];
|
||||
unset($req[$i[1]]);
|
||||
}
|
||||
|
||||
if (empty($req)) {
|
||||
return $keys;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the response hash for a given digest array.
|
||||
*
|
||||
* @param array $digest Digest information containing data from DigestAuthenticate::parseAuthData().
|
||||
* @param string $password The digest hash password generated with DigestAuthenticate::password()
|
||||
* @return string Response hash
|
||||
*/
|
||||
public function generateResponseHash($digest, $password) {
|
||||
return md5(
|
||||
$password .
|
||||
':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' .
|
||||
md5(env('REQUEST_METHOD') . ':' . $digest['uri'])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an auth digest password hash to store
|
||||
*
|
||||
* @param string $username The username to use in the digest hash.
|
||||
* @param string $password The unhashed password to make a digest hash for.
|
||||
* @param string $realm The realm the password is for.
|
||||
* @return string the hashed password that can later be used with Digest authentication.
|
||||
*/
|
||||
public static function password($username, $password, $realm) {
|
||||
return md5($username . ':' . $realm . ':' . $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the login headers
|
||||
*
|
||||
* @return string Headers for logging in.
|
||||
*/
|
||||
public function loginHeaders() {
|
||||
$options = array(
|
||||
'realm' => $this->settings['realm'],
|
||||
'qop' => $this->settings['qop'],
|
||||
'nonce' => $this->settings['nonce'],
|
||||
'opaque' => $this->settings['opaque']
|
||||
);
|
||||
$opts = array();
|
||||
foreach ($options as $k => $v) {
|
||||
$opts[] = sprintf('%s="%s"', $k, $v);
|
||||
}
|
||||
return 'WWW-Authenticate: Digest ' . implode(',', $opts);
|
||||
}
|
||||
|
||||
}
|
82
lib/Cake/Controller/Component/Auth/FormAuthenticate.php
Normal file
82
lib/Cake/Controller/Component/Auth/FormAuthenticate.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* An authentication adapter for AuthComponent. Provides the ability to authenticate using POST
|
||||
* data. Can be used by configuring AuthComponent to use it via the AuthComponent::$authenticate setting.
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->authenticate = array(
|
||||
* 'Form' => array(
|
||||
* 'scope' => array('User.active' => 1)
|
||||
* )
|
||||
* )
|
||||
* }}}
|
||||
*
|
||||
* When configuring FormAuthenticate you can pass in settings to which fields, model and additional conditions
|
||||
* are used. See FormAuthenticate::$settings for more information.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
* @since 2.0
|
||||
* @see AuthComponent::$authenticate
|
||||
*/
|
||||
class FormAuthenticate extends BaseAuthenticate {
|
||||
|
||||
/**
|
||||
* Checks the fields to ensure they are supplied.
|
||||
*
|
||||
* @param CakeRequest $request The request that contains login information.
|
||||
* @param string $model The model used for login verification.
|
||||
* @param array $fields The fields to be checked.
|
||||
* @return bool False if the fields have not been supplied. True if they exist.
|
||||
*/
|
||||
protected function _checkFields(CakeRequest $request, $model, $fields) {
|
||||
if (empty($request->data[$model])) {
|
||||
return false;
|
||||
}
|
||||
foreach (array($fields['username'], $fields['password']) as $field) {
|
||||
$value = $request->data($model . '.' . $field);
|
||||
if (empty($value) && $value !== '0' || !is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields`
|
||||
* to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if
|
||||
* there is no post data, either username or password is missing, or if the scope conditions have not been met.
|
||||
*
|
||||
* @param CakeRequest $request The request that contains login information.
|
||||
* @param CakeResponse $response Unused response object.
|
||||
* @return mixed False on login failure. An array of User data on success.
|
||||
*/
|
||||
public function authenticate(CakeRequest $request, CakeResponse $response) {
|
||||
$userModel = $this->settings['userModel'];
|
||||
list(, $model) = pluginSplit($userModel);
|
||||
|
||||
$fields = $this->settings['fields'];
|
||||
if (!$this->_checkFields($request, $model, $fields)) {
|
||||
return false;
|
||||
}
|
||||
return $this->_findUser(
|
||||
$request->data[$model][$fields['username']],
|
||||
$request->data[$model][$fields['password']]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
55
lib/Cake/Controller/Component/Auth/SimplePasswordHasher.php
Normal file
55
lib/Cake/Controller/Component/Auth/SimplePasswordHasher.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/**
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @since CakePHP(tm) v 2.4.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
|
||||
App::uses('Security', 'Utility');
|
||||
|
||||
/**
|
||||
* Simple password hashing class.
|
||||
*
|
||||
* @package Cake.Controller.Component.Auth
|
||||
*/
|
||||
class SimplePasswordHasher extends AbstractPasswordHasher {
|
||||
|
||||
/**
|
||||
* Config for this object.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_config = array('hashType' => null);
|
||||
|
||||
/**
|
||||
* Generates password hash.
|
||||
*
|
||||
* @param string $password Plain text password to hash.
|
||||
* @return string Password hash
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#hashing-passwords
|
||||
*/
|
||||
public function hash($password) {
|
||||
return Security::hash($password, $this->_config['hashType'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check hash. Generate hash for user provided password and check against existing hash.
|
||||
*
|
||||
* @param string $password Plain text password to hash.
|
||||
* @param string $hashedPassword Existing hashed password.
|
||||
* @return bool True if hashes match else false.
|
||||
*/
|
||||
public function check($password, $hashedPassword) {
|
||||
return $hashedPassword === $this->hash($password);
|
||||
}
|
||||
|
||||
}
|
835
lib/Cake/Controller/Component/AuthComponent.php
Normal file
835
lib/Cake/Controller/Component/AuthComponent.php
Normal file
|
@ -0,0 +1,835 @@
|
|||
<?php
|
||||
/**
|
||||
* Authentication component
|
||||
*
|
||||
* Manages user logins and permissions.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 0.10.0.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('Router', 'Routing');
|
||||
App::uses('Security', 'Utility');
|
||||
App::uses('Debugger', 'Utility');
|
||||
App::uses('Hash', 'Utility');
|
||||
App::uses('CakeSession', 'Model/Datasource');
|
||||
App::uses('BaseAuthorize', 'Controller/Component/Auth');
|
||||
App::uses('BaseAuthenticate', 'Controller/Component/Auth');
|
||||
|
||||
/**
|
||||
* Authentication control component class
|
||||
*
|
||||
* Binds access control with user authentication and session management.
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
|
||||
*/
|
||||
class AuthComponent extends Component {
|
||||
|
||||
/**
|
||||
* Constant for 'all'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const ALL = 'all';
|
||||
|
||||
/**
|
||||
* Other components utilized by AuthComponent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
/**
|
||||
* An array of authentication objects to use for authenticating users. You can configure
|
||||
* multiple adapters and they will be checked sequentially when users are identified.
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->authenticate = array(
|
||||
* 'Form' => array(
|
||||
* 'userModel' => 'Users.User'
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* Using the class name without 'Authenticate' as the key, you can pass in an array of settings for each
|
||||
* authentication object. Additionally you can define settings that should be set to all authentications objects
|
||||
* using the 'all' key:
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->authenticate = array(
|
||||
* 'all' => array(
|
||||
* 'userModel' => 'Users.User',
|
||||
* 'scope' => array('User.active' => 1)
|
||||
* ),
|
||||
* 'Form',
|
||||
* 'Basic'
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* You can also use AuthComponent::ALL instead of the string 'all'.
|
||||
*
|
||||
* @var array
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
|
||||
*/
|
||||
public $authenticate = array('Form');
|
||||
|
||||
/**
|
||||
* Objects that will be used for authentication checks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_authenticateObjects = array();
|
||||
|
||||
/**
|
||||
* An array of authorization objects to use for authorizing users. You can configure
|
||||
* multiple adapters and they will be checked sequentially when authorization checks are done.
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->authorize = array(
|
||||
* 'Crud' => array(
|
||||
* 'actionPath' => 'controllers/'
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* Using the class name without 'Authorize' as the key, you can pass in an array of settings for each
|
||||
* authorization object. Additionally you can define settings that should be set to all authorization objects
|
||||
* using the 'all' key:
|
||||
*
|
||||
* {{{
|
||||
* $this->Auth->authorize = array(
|
||||
* 'all' => array(
|
||||
* 'actionPath' => 'controllers/'
|
||||
* ),
|
||||
* 'Crud',
|
||||
* 'CustomAuth'
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* You can also use AuthComponent::ALL instead of the string 'all'
|
||||
*
|
||||
* @var mixed
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#authorization
|
||||
*/
|
||||
public $authorize = false;
|
||||
|
||||
/**
|
||||
* Objects that will be used for authorization checks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_authorizeObjects = array();
|
||||
|
||||
/**
|
||||
* The name of an optional view element to render when an Ajax request is made
|
||||
* with an invalid or expired session
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $ajaxLogin = null;
|
||||
|
||||
/**
|
||||
* Settings to use when Auth needs to do a flash message with SessionComponent::setFlash().
|
||||
* Available keys are:
|
||||
*
|
||||
* - `element` - The element to use, defaults to 'default'.
|
||||
* - `key` - The key to use, defaults to 'auth'
|
||||
* - `params` - The array of additional params to use, defaults to array()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $flash = array(
|
||||
'element' => 'default',
|
||||
'key' => 'auth',
|
||||
'params' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* The session key name where the record of the current user is stored. Default
|
||||
* key is "Auth.User". If you are using only stateless authenticators set this
|
||||
* to false to ensure session is not started.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $sessionKey = 'Auth.User';
|
||||
|
||||
/**
|
||||
* The current user, used for stateless authentication when
|
||||
* sessions are not available.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_user = array();
|
||||
|
||||
/**
|
||||
* A URL (defined as a string or array) to the controller action that handles
|
||||
* logins. Defaults to `/users/login`.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $loginAction = array(
|
||||
'controller' => 'users',
|
||||
'action' => 'login',
|
||||
'plugin' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* Normally, if a user is redirected to the $loginAction page, the location they
|
||||
* were redirected from will be stored in the session so that they can be
|
||||
* redirected back after a successful login. If this session value is not
|
||||
* set, redirectUrl() method will return the URL specified in $loginRedirect.
|
||||
*
|
||||
* @var mixed
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$loginRedirect
|
||||
*/
|
||||
public $loginRedirect = null;
|
||||
|
||||
/**
|
||||
* The default action to redirect to after the user is logged out. While AuthComponent does
|
||||
* not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout().
|
||||
* Defaults to AuthComponent::$loginAction.
|
||||
*
|
||||
* @var mixed
|
||||
* @see AuthComponent::$loginAction
|
||||
* @see AuthComponent::logout()
|
||||
*/
|
||||
public $logoutRedirect = null;
|
||||
|
||||
/**
|
||||
* Error to display when user attempts to access an object or action to which they do not have
|
||||
* access.
|
||||
*
|
||||
* @var string|bool
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$authError
|
||||
*/
|
||||
public $authError = null;
|
||||
|
||||
/**
|
||||
* Controls handling of unauthorized access.
|
||||
* - For default value `true` unauthorized user is redirected to the referrer URL
|
||||
* or AuthComponent::$loginRedirect or '/'.
|
||||
* - If set to a string or array the value is used as a URL to redirect to.
|
||||
* - If set to false a ForbiddenException exception is thrown instead of redirecting.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $unauthorizedRedirect = true;
|
||||
|
||||
/**
|
||||
* Controller actions for which user validation is not required.
|
||||
*
|
||||
* @var array
|
||||
* @see AuthComponent::allow()
|
||||
*/
|
||||
public $allowedActions = array();
|
||||
|
||||
/**
|
||||
* Request object
|
||||
*
|
||||
* @var CakeRequest
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/**
|
||||
* Response object
|
||||
*
|
||||
* @var CakeResponse
|
||||
*/
|
||||
public $response;
|
||||
|
||||
/**
|
||||
* Method list for bound controller.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_methods = array();
|
||||
|
||||
/**
|
||||
* Initializes AuthComponent for use in the controller.
|
||||
*
|
||||
* @param Controller $controller A reference to the instantiating controller object
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Controller $controller) {
|
||||
$this->request = $controller->request;
|
||||
$this->response = $controller->response;
|
||||
$this->_methods = $controller->methods;
|
||||
|
||||
if (Configure::read('debug') > 0) {
|
||||
Debugger::checkSecurityKeys();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution method. Handles redirecting of invalid users, and processing
|
||||
* of login form data.
|
||||
*
|
||||
* @param Controller $controller A reference to the instantiating controller object
|
||||
* @return bool
|
||||
*/
|
||||
public function startup(Controller $controller) {
|
||||
$methods = array_flip(array_map('strtolower', $controller->methods));
|
||||
$action = strtolower($controller->request->params['action']);
|
||||
|
||||
$isMissingAction = (
|
||||
$controller->scaffold === false &&
|
||||
!isset($methods[$action])
|
||||
);
|
||||
|
||||
if ($isMissingAction) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->_setDefaults()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->_isAllowed($controller)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->_getUser()) {
|
||||
return $this->_unauthenticated($controller);
|
||||
}
|
||||
|
||||
if ($this->_isLoginAction($controller) ||
|
||||
empty($this->authorize) ||
|
||||
$this->isAuthorized($this->user())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->_unauthorized($controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current action is accessible without authentication.
|
||||
*
|
||||
* @param Controller $controller A reference to the instantiating controller object
|
||||
* @return bool True if action is accessible without authentication else false
|
||||
*/
|
||||
protected function _isAllowed(Controller $controller) {
|
||||
$action = strtolower($controller->request->params['action']);
|
||||
if (in_array($action, array_map('strtolower', $this->allowedActions))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unauthenticated access attempt. First the `unathenticated()` method
|
||||
* of the last authenticator in the chain will be called. The authenticator can
|
||||
* handle sending response or redirection as appropriate and return `true` to
|
||||
* indicate no furthur action is necessary. If authenticator returns null this
|
||||
* method redirects user to login action. If it's an ajax request and
|
||||
* $ajaxLogin is specified that element is rendered else a 403 http status code
|
||||
* is returned.
|
||||
*
|
||||
* @param Controller $controller A reference to the controller object.
|
||||
* @return bool True if current action is login action else false.
|
||||
*/
|
||||
protected function _unauthenticated(Controller $controller) {
|
||||
if (empty($this->_authenticateObjects)) {
|
||||
$this->constructAuthenticate();
|
||||
}
|
||||
$auth = $this->_authenticateObjects[count($this->_authenticateObjects) - 1];
|
||||
if ($auth->unauthenticated($this->request, $this->response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->_isLoginAction($controller)) {
|
||||
if (empty($controller->request->data)) {
|
||||
if (!$this->Session->check('Auth.redirect') && env('HTTP_REFERER')) {
|
||||
$this->Session->write('Auth.redirect', $controller->referer(null, true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$controller->request->is('ajax')) {
|
||||
$this->flash($this->authError);
|
||||
$this->Session->write('Auth.redirect', $controller->request->here(false));
|
||||
$controller->redirect($this->loginAction);
|
||||
return false;
|
||||
}
|
||||
if (!empty($this->ajaxLogin)) {
|
||||
$controller->response->statusCode(403);
|
||||
$controller->viewPath = 'Elements';
|
||||
echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout);
|
||||
$this->_stop();
|
||||
return false;
|
||||
}
|
||||
$controller->redirect(null, 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes $loginAction and checks if current request URL is same as login action.
|
||||
*
|
||||
* @param Controller $controller A reference to the controller object.
|
||||
* @return bool True if current action is login action else false.
|
||||
*/
|
||||
protected function _isLoginAction(Controller $controller) {
|
||||
$url = '';
|
||||
if (isset($controller->request->url)) {
|
||||
$url = $controller->request->url;
|
||||
}
|
||||
$url = Router::normalize($url);
|
||||
$loginAction = Router::normalize($this->loginAction);
|
||||
|
||||
return $loginAction === $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unauthorized access attempt
|
||||
*
|
||||
* @param Controller $controller A reference to the controller object
|
||||
* @return bool Returns false
|
||||
* @throws ForbiddenException
|
||||
* @see AuthComponent::$unauthorizedRedirect
|
||||
*/
|
||||
protected function _unauthorized(Controller $controller) {
|
||||
if ($this->unauthorizedRedirect === false) {
|
||||
throw new ForbiddenException($this->authError);
|
||||
}
|
||||
|
||||
$this->flash($this->authError);
|
||||
if ($this->unauthorizedRedirect === true) {
|
||||
$default = '/';
|
||||
if (!empty($this->loginRedirect)) {
|
||||
$default = $this->loginRedirect;
|
||||
}
|
||||
$url = $controller->referer($default, true);
|
||||
} else {
|
||||
$url = $this->unauthorizedRedirect;
|
||||
}
|
||||
$controller->redirect($url, null, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to introspect the correct values for object properties.
|
||||
*
|
||||
* @return bool True
|
||||
*/
|
||||
protected function _setDefaults() {
|
||||
$defaults = array(
|
||||
'logoutRedirect' => $this->loginAction,
|
||||
'authError' => __d('cake', 'You are not authorized to access that location.')
|
||||
);
|
||||
foreach ($defaults as $key => $value) {
|
||||
if (!isset($this->{$key}) || $this->{$key} === true) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the provided user is authorized for the request.
|
||||
*
|
||||
* Uses the configured Authorization adapters to check whether or not a user is authorized.
|
||||
* Each adapter will be checked in sequence, if any of them return true, then the user will
|
||||
* be authorized for the request.
|
||||
*
|
||||
* @param array $user The user to check the authorization of. If empty the user in the session will be used.
|
||||
* @param CakeRequest $request The request to authenticate for. If empty, the current request will be used.
|
||||
* @return bool True if $user is authorized, otherwise false
|
||||
*/
|
||||
public function isAuthorized($user = null, CakeRequest $request = null) {
|
||||
if (empty($user) && !$this->user()) {
|
||||
return false;
|
||||
}
|
||||
if (empty($user)) {
|
||||
$user = $this->user();
|
||||
}
|
||||
if (empty($request)) {
|
||||
$request = $this->request;
|
||||
}
|
||||
if (empty($this->_authorizeObjects)) {
|
||||
$this->constructAuthorize();
|
||||
}
|
||||
foreach ($this->_authorizeObjects as $authorizer) {
|
||||
if ($authorizer->authorize($user, $request) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the authorization objects configured.
|
||||
*
|
||||
* @return mixed Either null when authorize is empty, or the loaded authorization objects.
|
||||
* @throws CakeException
|
||||
*/
|
||||
public function constructAuthorize() {
|
||||
if (empty($this->authorize)) {
|
||||
return;
|
||||
}
|
||||
$this->_authorizeObjects = array();
|
||||
$config = Hash::normalize((array)$this->authorize);
|
||||
$global = array();
|
||||
if (isset($config[AuthComponent::ALL])) {
|
||||
$global = $config[AuthComponent::ALL];
|
||||
unset($config[AuthComponent::ALL]);
|
||||
}
|
||||
foreach ($config as $class => $settings) {
|
||||
list($plugin, $class) = pluginSplit($class, true);
|
||||
$className = $class . 'Authorize';
|
||||
App::uses($className, $plugin . 'Controller/Component/Auth');
|
||||
if (!class_exists($className)) {
|
||||
throw new CakeException(__d('cake_dev', 'Authorization adapter "%s" was not found.', $class));
|
||||
}
|
||||
if (!method_exists($className, 'authorize')) {
|
||||
throw new CakeException(__d('cake_dev', 'Authorization objects must implement an %s method.', 'authorize()'));
|
||||
}
|
||||
$settings = array_merge($global, (array)$settings);
|
||||
$this->_authorizeObjects[] = new $className($this->_Collection, $settings);
|
||||
}
|
||||
return $this->_authorizeObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a list of actions in the current controller for which authentication is not required, or
|
||||
* no parameters to allow all actions.
|
||||
*
|
||||
* You can use allow with either an array, or var args.
|
||||
*
|
||||
* `$this->Auth->allow(array('edit', 'add'));` or
|
||||
* `$this->Auth->allow('edit', 'add');` or
|
||||
* `$this->Auth->allow();` to allow all actions
|
||||
*
|
||||
* @param string|array $action Controller action name or array of actions
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#making-actions-public
|
||||
*/
|
||||
public function allow($action = null) {
|
||||
$args = func_get_args();
|
||||
if (empty($args) || $action === null) {
|
||||
$this->allowedActions = $this->_methods;
|
||||
return;
|
||||
}
|
||||
if (isset($args[0]) && is_array($args[0])) {
|
||||
$args = $args[0];
|
||||
}
|
||||
$this->allowedActions = array_merge($this->allowedActions, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes items from the list of allowed/no authentication required actions.
|
||||
*
|
||||
* You can use deny with either an array, or var args.
|
||||
*
|
||||
* `$this->Auth->deny(array('edit', 'add'));` or
|
||||
* `$this->Auth->deny('edit', 'add');` or
|
||||
* `$this->Auth->deny();` to remove all items from the allowed list
|
||||
*
|
||||
* @param string|array $action Controller action name or array of actions
|
||||
* @return void
|
||||
* @see AuthComponent::allow()
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#making-actions-require-authorization
|
||||
*/
|
||||
public function deny($action = null) {
|
||||
$args = func_get_args();
|
||||
if (empty($args) || $action === null) {
|
||||
$this->allowedActions = array();
|
||||
return;
|
||||
}
|
||||
if (isset($args[0]) && is_array($args[0])) {
|
||||
$args = $args[0];
|
||||
}
|
||||
foreach ($args as $arg) {
|
||||
$i = array_search($arg, $this->allowedActions);
|
||||
if (is_int($i)) {
|
||||
unset($this->allowedActions[$i]);
|
||||
}
|
||||
}
|
||||
$this->allowedActions = array_values($this->allowedActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps action names to CRUD operations.
|
||||
*
|
||||
* Used for controller-based authentication. Make sure
|
||||
* to configure the authorize property before calling this method. As it delegates $map to all the
|
||||
* attached authorize objects.
|
||||
*
|
||||
* @param array $map Actions to map
|
||||
* @return void
|
||||
* @see BaseAuthorize::mapActions()
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#mapping-actions-when-using-crudauthorize
|
||||
*/
|
||||
public function mapActions($map = array()) {
|
||||
if (empty($this->_authorizeObjects)) {
|
||||
$this->constructAuthorize();
|
||||
}
|
||||
foreach ($this->_authorizeObjects as $auth) {
|
||||
$auth->mapActions($map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a user in.
|
||||
*
|
||||
* If a $user is provided that data will be stored as the logged in user. If `$user` is empty or not
|
||||
* specified, the request will be used to identify a user. If the identification was successful,
|
||||
* the user record is written to the session key specified in AuthComponent::$sessionKey. Logging in
|
||||
* will also change the session id in order to help mitigate session replays.
|
||||
*
|
||||
* @param array $user Either an array of user data, or null to identify a user using the current request.
|
||||
* @return bool True on login success, false on failure
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#identifying-users-and-logging-them-in
|
||||
*/
|
||||
public function login($user = null) {
|
||||
$this->_setDefaults();
|
||||
|
||||
if (empty($user)) {
|
||||
$user = $this->identify($this->request, $this->response);
|
||||
}
|
||||
if ($user) {
|
||||
$this->Session->renew();
|
||||
$this->Session->write(self::$sessionKey, $user);
|
||||
}
|
||||
return $this->loggedIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a user out.
|
||||
*
|
||||
* Returns the logout action to redirect to. Triggers the logout() method of
|
||||
* all the authenticate objects, so they can perform custom logout logic.
|
||||
* AuthComponent will remove the session data, so there is no need to do that
|
||||
* in an authentication object. Logging out will also renew the session id.
|
||||
* This helps mitigate issues with session replays.
|
||||
*
|
||||
* @return string AuthComponent::$logoutRedirect
|
||||
* @see AuthComponent::$logoutRedirect
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#logging-users-out
|
||||
*/
|
||||
public function logout() {
|
||||
$this->_setDefaults();
|
||||
if (empty($this->_authenticateObjects)) {
|
||||
$this->constructAuthenticate();
|
||||
}
|
||||
$user = $this->user();
|
||||
foreach ($this->_authenticateObjects as $auth) {
|
||||
$auth->logout($user);
|
||||
}
|
||||
$this->Session->delete(self::$sessionKey);
|
||||
$this->Session->delete('Auth.redirect');
|
||||
$this->Session->renew();
|
||||
return Router::normalize($this->logoutRedirect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user.
|
||||
*
|
||||
* Will prefer the static user cache over sessions. The static user
|
||||
* cache is primarily used for stateless authentication. For stateful authentication,
|
||||
* cookies + sessions will be used.
|
||||
*
|
||||
* @param string $key field to retrieve. Leave null to get entire User record
|
||||
* @return mixed User record. or null if no user is logged in.
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user
|
||||
*/
|
||||
public static function user($key = null) {
|
||||
if (!empty(self::$_user)) {
|
||||
$user = self::$_user;
|
||||
} elseif (self::$sessionKey && CakeSession::check(self::$sessionKey)) {
|
||||
$user = CakeSession::read(self::$sessionKey);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if ($key === null) {
|
||||
return $user;
|
||||
}
|
||||
return Hash::get($user, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to AuthComponent::user() except if the session user cannot be found, connected authentication
|
||||
* objects will have their getUser() methods called. This lets stateless authentication methods function correctly.
|
||||
*
|
||||
* @return bool true if a user can be found, false if one cannot.
|
||||
*/
|
||||
protected function _getUser() {
|
||||
$user = $this->user();
|
||||
if ($user) {
|
||||
$this->Session->delete('Auth.redirect');
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty($this->_authenticateObjects)) {
|
||||
$this->constructAuthenticate();
|
||||
}
|
||||
foreach ($this->_authenticateObjects as $auth) {
|
||||
$result = $auth->getUser($this->request);
|
||||
if (!empty($result) && is_array($result)) {
|
||||
self::$_user = $result;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compatible alias for AuthComponent::redirectUrl().
|
||||
*
|
||||
* @param string|array $url Optional URL to write as the login redirect URL.
|
||||
* @return string Redirect URL
|
||||
* @deprecated 2.3 Use AuthComponent::redirectUrl() instead
|
||||
*/
|
||||
public function redirect($url = null) {
|
||||
return $this->redirectUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL a user should be redirected to upon login.
|
||||
*
|
||||
* Pass a URL in to set the destination a user should be redirected to upon
|
||||
* logging in.
|
||||
*
|
||||
* If no parameter is passed, gets the authentication redirect URL. The URL
|
||||
* returned is as per following rules:
|
||||
*
|
||||
* - Returns the normalized URL from session Auth.redirect value if it is
|
||||
* present and for the same domain the current app is running on.
|
||||
* - If there is no session value and there is a $loginRedirect, the $loginRedirect
|
||||
* value is returned.
|
||||
* - If there is no session and no $loginRedirect, / is returned.
|
||||
*
|
||||
* @param string|array $url Optional URL to write as the login redirect URL.
|
||||
* @return string Redirect URL
|
||||
*/
|
||||
public function redirectUrl($url = null) {
|
||||
if ($url !== null) {
|
||||
$redir = $url;
|
||||
$this->Session->write('Auth.redirect', $redir);
|
||||
} elseif ($this->Session->check('Auth.redirect')) {
|
||||
$redir = $this->Session->read('Auth.redirect');
|
||||
$this->Session->delete('Auth.redirect');
|
||||
|
||||
if (Router::normalize($redir) === Router::normalize($this->loginAction)) {
|
||||
$redir = $this->loginRedirect;
|
||||
}
|
||||
} elseif ($this->loginRedirect) {
|
||||
$redir = $this->loginRedirect;
|
||||
} else {
|
||||
$redir = '/';
|
||||
}
|
||||
if (is_array($redir)) {
|
||||
return Router::url($redir + array('base' => false));
|
||||
}
|
||||
return $redir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the configured authentication adapters, and attempt to identify the user
|
||||
* by credentials contained in $request.
|
||||
*
|
||||
* @param CakeRequest $request The request that contains authentication data.
|
||||
* @param CakeResponse $response The response
|
||||
* @return array User record data, or false, if the user could not be identified.
|
||||
*/
|
||||
public function identify(CakeRequest $request, CakeResponse $response) {
|
||||
if (empty($this->_authenticateObjects)) {
|
||||
$this->constructAuthenticate();
|
||||
}
|
||||
foreach ($this->_authenticateObjects as $auth) {
|
||||
$result = $auth->authenticate($request, $response);
|
||||
if (!empty($result) && is_array($result)) {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configured authentication objects.
|
||||
*
|
||||
* @return mixed either null on empty authenticate value, or an array of loaded objects.
|
||||
* @throws CakeException
|
||||
*/
|
||||
public function constructAuthenticate() {
|
||||
if (empty($this->authenticate)) {
|
||||
return;
|
||||
}
|
||||
$this->_authenticateObjects = array();
|
||||
$config = Hash::normalize((array)$this->authenticate);
|
||||
$global = array();
|
||||
if (isset($config[AuthComponent::ALL])) {
|
||||
$global = $config[AuthComponent::ALL];
|
||||
unset($config[AuthComponent::ALL]);
|
||||
}
|
||||
foreach ($config as $class => $settings) {
|
||||
if (!empty($settings['className'])) {
|
||||
$class = $settings['className'];
|
||||
unset($settings['className']);
|
||||
}
|
||||
list($plugin, $class) = pluginSplit($class, true);
|
||||
$className = $class . 'Authenticate';
|
||||
App::uses($className, $plugin . 'Controller/Component/Auth');
|
||||
if (!class_exists($className)) {
|
||||
throw new CakeException(__d('cake_dev', 'Authentication adapter "%s" was not found.', $class));
|
||||
}
|
||||
if (!method_exists($className, 'authenticate')) {
|
||||
throw new CakeException(__d('cake_dev', 'Authentication objects must implement an %s method.', 'authenticate()'));
|
||||
}
|
||||
$settings = array_merge($global, (array)$settings);
|
||||
$this->_authenticateObjects[] = new $className($this->_Collection, $settings);
|
||||
}
|
||||
return $this->_authenticateObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a password with the application's salt value (as defined with Configure::write('Security.salt');
|
||||
*
|
||||
* This method is intended as a convenience wrapper for Security::hash(). If you want to use
|
||||
* a hashing/encryption system not supported by that method, do not use this method.
|
||||
*
|
||||
* @param string $password Password to hash
|
||||
* @return string Hashed password
|
||||
* @deprecated Since 2.4. Use Security::hash() directly or a password hasher object.
|
||||
*/
|
||||
public static function password($password) {
|
||||
return Security::hash($password, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not the current user has data in the session, and is considered logged in.
|
||||
*
|
||||
* @return bool true if the user is logged in, false otherwise
|
||||
* @deprecated Since 2.5. Use AuthComponent::user() directly.
|
||||
*/
|
||||
public function loggedIn() {
|
||||
return (bool)$this->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a flash message. Uses the Session component, and values from AuthComponent::$flash.
|
||||
*
|
||||
* @param string $message The message to set.
|
||||
* @return void
|
||||
*/
|
||||
public function flash($message) {
|
||||
if ($message === false) {
|
||||
return;
|
||||
}
|
||||
$this->Session->setFlash($message, $this->flash['element'], $this->flash['params'], $this->flash['key']);
|
||||
}
|
||||
|
||||
}
|
571
lib/Cake/Controller/Component/CookieComponent.php
Normal file
571
lib/Cake/Controller/Component/CookieComponent.php
Normal file
|
@ -0,0 +1,571 @@
|
|||
<?php
|
||||
/**
|
||||
* Cookie Component
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 1.2.0.4213
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('Security', 'Utility');
|
||||
App::uses('Hash', 'Utility');
|
||||
|
||||
/**
|
||||
* Cookie Component.
|
||||
*
|
||||
* Cookie handling for the controller.
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html
|
||||
*
|
||||
*/
|
||||
class CookieComponent extends Component {
|
||||
|
||||
/**
|
||||
* The name of the cookie.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->name = 'CookieName';
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'CakeCookie';
|
||||
|
||||
/**
|
||||
* The time a cookie will remain valid.
|
||||
*
|
||||
* Can be either integer Unix timestamp or a date string.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->time = '5 Days';
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $time = null;
|
||||
|
||||
/**
|
||||
* Cookie path.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->path = '/';
|
||||
*
|
||||
* The path on the server in which the cookie will be available on.
|
||||
* If public $cookiePath is set to '/foo/', the cookie will only be available
|
||||
* within the /foo/ directory and all sub-directories such as /foo/bar/ of domain.
|
||||
* The default value is the entire domain.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $path = '/';
|
||||
|
||||
/**
|
||||
* Domain path.
|
||||
*
|
||||
* The domain that the cookie is available.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->domain = '.example.com';
|
||||
*
|
||||
* To make the cookie available on all subdomains of example.com.
|
||||
* Set $this->Cookie->domain = '.example.com'; in your controller beforeFilter
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $domain = '';
|
||||
|
||||
/**
|
||||
* Secure HTTPS only cookie.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->secure = true;
|
||||
*
|
||||
* Indicates that the cookie should only be transmitted over a secure HTTPS connection.
|
||||
* When set to true, the cookie will only be set if a secure connection exists.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $secure = false;
|
||||
|
||||
/**
|
||||
* Encryption key.
|
||||
*
|
||||
* Overridden with the controller beforeFilter();
|
||||
* $this->Cookie->key = 'SomeRandomString';
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $key = null;
|
||||
|
||||
/**
|
||||
* HTTP only cookie
|
||||
*
|
||||
* Set to true to make HTTP only cookies. Cookies that are HTTP only
|
||||
* are not accessible in JavaScript.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $httpOnly = false;
|
||||
|
||||
/**
|
||||
* Values stored in the cookie.
|
||||
*
|
||||
* Accessed in the controller using $this->Cookie->read('Name.key');
|
||||
*
|
||||
* @see CookieComponent::read();
|
||||
* @var string
|
||||
*/
|
||||
protected $_values = array();
|
||||
|
||||
/**
|
||||
* Type of encryption to use.
|
||||
*
|
||||
* Currently two methods are available: cipher and rijndael
|
||||
* Defaults to Security::cipher(). Cipher is horribly insecure and only
|
||||
* the default because of backwards compatibility. In new applications you should
|
||||
* always change this to 'aes' or 'rijndael'.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_type = 'cipher';
|
||||
|
||||
/**
|
||||
* Used to reset cookie time if $expire is passed to CookieComponent::write()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_reset = null;
|
||||
|
||||
/**
|
||||
* Expire time of the cookie
|
||||
*
|
||||
* This is controlled by CookieComponent::time;
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_expires = 0;
|
||||
|
||||
/**
|
||||
* A reference to the Controller's CakeResponse object
|
||||
*
|
||||
* @var CakeResponse
|
||||
*/
|
||||
protected $_response = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ComponentCollection $collection A ComponentCollection for this component
|
||||
* @param array $settings Array of settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
$this->key = Configure::read('Security.salt');
|
||||
parent::__construct($collection, $settings);
|
||||
if (isset($this->time)) {
|
||||
$this->_expire($this->time);
|
||||
}
|
||||
|
||||
$controller = $collection->getController();
|
||||
if ($controller && isset($controller->response)) {
|
||||
$this->_response = $controller->response;
|
||||
} else {
|
||||
$this->_response = new CakeResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start CookieComponent for use in the controller
|
||||
*
|
||||
* @param Controller $controller Controller instance.
|
||||
* @return void
|
||||
*/
|
||||
public function startup(Controller $controller) {
|
||||
$this->_expire($this->time);
|
||||
|
||||
$this->_values[$this->name] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the $_COOKIE[$key];
|
||||
*
|
||||
* Optional [Name.], required key, optional $value, optional $encrypt, optional $expires
|
||||
* $this->Cookie->write('[Name.]key, $value);
|
||||
*
|
||||
* By default all values are encrypted.
|
||||
* You must pass $encrypt false to store values in clear test
|
||||
*
|
||||
* You must use this method before any output is sent to the browser.
|
||||
* Failure to do so will result in header already sent errors.
|
||||
*
|
||||
* @param string|array $key Key for the value
|
||||
* @param mixed $value Value
|
||||
* @param bool $encrypt Set to true to encrypt value, false otherwise
|
||||
* @param int|string $expires Can be either the number of seconds until a cookie
|
||||
* expires, or a strtotime compatible time offset.
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::write
|
||||
*/
|
||||
public function write($key, $value = null, $encrypt = true, $expires = null) {
|
||||
if (empty($this->_values[$this->name])) {
|
||||
$this->read();
|
||||
}
|
||||
|
||||
if ($encrypt === null) {
|
||||
$encrypt = true;
|
||||
}
|
||||
$this->_encrypted = $encrypt;
|
||||
$this->_expire($expires);
|
||||
|
||||
if (!is_array($key)) {
|
||||
$key = array($key => $value);
|
||||
}
|
||||
|
||||
foreach ($key as $name => $value) {
|
||||
$names = array($name);
|
||||
if (strpos($name, '.') !== false) {
|
||||
$names = explode('.', $name, 2);
|
||||
}
|
||||
$firstName = $names[0];
|
||||
$isMultiValue = (is_array($value) || count($names) > 1);
|
||||
|
||||
if (!isset($this->_values[$this->name][$firstName]) && $isMultiValue) {
|
||||
$this->_values[$this->name][$firstName] = array();
|
||||
}
|
||||
|
||||
if (count($names) > 1) {
|
||||
$this->_values[$this->name][$firstName] = Hash::insert(
|
||||
$this->_values[$this->name][$firstName],
|
||||
$names[1],
|
||||
$value
|
||||
);
|
||||
} else {
|
||||
$this->_values[$this->name][$firstName] = $value;
|
||||
}
|
||||
$this->_write('[' . $firstName . ']', $this->_values[$this->name][$firstName]);
|
||||
}
|
||||
$this->_encrypted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the value of the $_COOKIE[$key];
|
||||
*
|
||||
* Optional [Name.], required key
|
||||
* $this->Cookie->read(Name.key);
|
||||
*
|
||||
* @param string $key Key of the value to be obtained. If none specified, obtain map key => values
|
||||
* @return string or null, value for specified key
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::read
|
||||
*/
|
||||
public function read($key = null) {
|
||||
if (empty($this->_values[$this->name]) && isset($_COOKIE[$this->name])) {
|
||||
$this->_values[$this->name] = $this->_decrypt($_COOKIE[$this->name]);
|
||||
}
|
||||
if (empty($this->_values[$this->name])) {
|
||||
$this->_values[$this->name] = array();
|
||||
}
|
||||
if ($key === null) {
|
||||
return $this->_values[$this->name];
|
||||
}
|
||||
|
||||
if (strpos($key, '.') !== false) {
|
||||
$names = explode('.', $key, 2);
|
||||
$key = $names[0];
|
||||
}
|
||||
if (!isset($this->_values[$this->name][$key])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!empty($names[1])) {
|
||||
return Hash::get($this->_values[$this->name][$key], $names[1]);
|
||||
}
|
||||
return $this->_values[$this->name][$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if given variable is set in cookie.
|
||||
*
|
||||
* @param string $key Variable name to check for
|
||||
* @return bool True if variable is there
|
||||
*/
|
||||
public function check($key = null) {
|
||||
if (empty($key)) {
|
||||
return false;
|
||||
}
|
||||
return $this->read($key) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a cookie value
|
||||
*
|
||||
* Optional [Name.], required key
|
||||
* $this->Cookie->delete('Name.key);
|
||||
*
|
||||
* You must use this method before any output is sent to the browser.
|
||||
* Failure to do so will result in header already sent errors.
|
||||
*
|
||||
* This method will delete both the top level and 2nd level cookies set.
|
||||
* For example assuming that $name = App, deleting `User` will delete
|
||||
* both `App[User]` and any other cookie values like `App[User][email]`
|
||||
* This is done to clean up cookie storage from before 2.4.3, where cookies
|
||||
* were stored inconsistently.
|
||||
*
|
||||
* @param string $key Key of the value to be deleted
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::delete
|
||||
*/
|
||||
public function delete($key) {
|
||||
if (empty($this->_values[$this->name])) {
|
||||
$this->read();
|
||||
}
|
||||
if (strpos($key, '.') === false) {
|
||||
if (isset($this->_values[$this->name][$key]) && is_array($this->_values[$this->name][$key])) {
|
||||
foreach ($this->_values[$this->name][$key] as $idx => $val) {
|
||||
$this->_delete("[$key][$idx]");
|
||||
}
|
||||
}
|
||||
$this->_delete("[$key]");
|
||||
unset($this->_values[$this->name][$key]);
|
||||
return;
|
||||
}
|
||||
$names = explode('.', $key, 2);
|
||||
if (isset($this->_values[$this->name][$names[0]])) {
|
||||
$this->_values[$this->name][$names[0]] = Hash::remove($this->_values[$this->name][$names[0]], $names[1]);
|
||||
}
|
||||
$this->_delete('[' . implode('][', $names) . ']');
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy current cookie
|
||||
*
|
||||
* You must use this method before any output is sent to the browser.
|
||||
* Failure to do so will result in header already sent errors.
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/cookie.html#CookieComponent::destroy
|
||||
*/
|
||||
public function destroy() {
|
||||
if (isset($_COOKIE[$this->name])) {
|
||||
$this->_values[$this->name] = $this->_decrypt($_COOKIE[$this->name]);
|
||||
}
|
||||
|
||||
foreach ($this->_values[$this->name] as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $val) {
|
||||
unset($this->_values[$this->name][$name][$key]);
|
||||
$this->_delete("[$name][$key]");
|
||||
}
|
||||
}
|
||||
unset($this->_values[$this->name][$name]);
|
||||
$this->_delete("[$name]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will allow overriding default encryption method. Use this method
|
||||
* in ex: AppController::beforeFilter() before you have read or
|
||||
* written any cookies.
|
||||
*
|
||||
* @param string $type Encryption method
|
||||
* @return void
|
||||
*/
|
||||
public function type($type = 'cipher') {
|
||||
$availableTypes = array(
|
||||
'cipher',
|
||||
'rijndael',
|
||||
'aes'
|
||||
);
|
||||
if (!in_array($type, $availableTypes)) {
|
||||
trigger_error(__d('cake_dev', 'You must use cipher, rijndael or aes for cookie encryption type'), E_USER_WARNING);
|
||||
$type = 'cipher';
|
||||
}
|
||||
$this->_type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expire time for a session variable.
|
||||
*
|
||||
* Creates a new expire time for a session variable.
|
||||
* $expire can be either integer Unix timestamp or a date string.
|
||||
*
|
||||
* Used by write()
|
||||
* CookieComponent::write(string, string, boolean, 8400);
|
||||
* CookieComponent::write(string, string, boolean, '5 Days');
|
||||
*
|
||||
* @param int|string $expires Can be either Unix timestamp, or date string
|
||||
* @return int Unix timestamp
|
||||
*/
|
||||
protected function _expire($expires = null) {
|
||||
if ($expires === null) {
|
||||
return $this->_expires;
|
||||
}
|
||||
$this->_reset = $this->_expires;
|
||||
if (!$expires) {
|
||||
return $this->_expires = 0;
|
||||
}
|
||||
$now = new DateTime();
|
||||
|
||||
if (is_int($expires) || is_numeric($expires)) {
|
||||
return $this->_expires = $now->format('U') + intval($expires);
|
||||
}
|
||||
$now->modify($expires);
|
||||
return $this->_expires = $now->format('U');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cookie
|
||||
*
|
||||
* @param string $name Name for cookie
|
||||
* @param string $value Value for cookie
|
||||
* @return void
|
||||
*/
|
||||
protected function _write($name, $value) {
|
||||
$this->_response->cookie(array(
|
||||
'name' => $this->name . $name,
|
||||
'value' => $this->_encrypt($value),
|
||||
'expire' => $this->_expires,
|
||||
'path' => $this->path,
|
||||
'domain' => $this->domain,
|
||||
'secure' => $this->secure,
|
||||
'httpOnly' => $this->httpOnly
|
||||
));
|
||||
|
||||
if (!empty($this->_reset)) {
|
||||
$this->_expires = $this->_reset;
|
||||
$this->_reset = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a cookie expire time to remove cookie value
|
||||
*
|
||||
* @param string $name Name of cookie
|
||||
* @return void
|
||||
*/
|
||||
protected function _delete($name) {
|
||||
$this->_response->cookie(array(
|
||||
'name' => $this->name . $name,
|
||||
'value' => '',
|
||||
'expire' => time() - 42000,
|
||||
'path' => $this->path,
|
||||
'domain' => $this->domain,
|
||||
'secure' => $this->secure,
|
||||
'httpOnly' => $this->httpOnly
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts $value using public $type method in Security class
|
||||
*
|
||||
* @param string $value Value to encrypt
|
||||
* @return string Encoded values
|
||||
*/
|
||||
protected function _encrypt($value) {
|
||||
if (is_array($value)) {
|
||||
$value = $this->_implode($value);
|
||||
}
|
||||
if (!$this->_encrypted) {
|
||||
return $value;
|
||||
}
|
||||
$prefix = "Q2FrZQ==.";
|
||||
if ($this->_type === 'rijndael') {
|
||||
$cipher = Security::rijndael($value, $this->key, 'encrypt');
|
||||
}
|
||||
if ($this->_type === 'cipher') {
|
||||
$cipher = Security::cipher($value, $this->key);
|
||||
}
|
||||
if ($this->_type === 'aes') {
|
||||
$cipher = Security::encrypt($value, $this->key);
|
||||
}
|
||||
return $prefix . base64_encode($cipher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts $value using public $type method in Security class
|
||||
*
|
||||
* @param array $values Values to decrypt
|
||||
* @return string decrypted string
|
||||
*/
|
||||
protected function _decrypt($values) {
|
||||
$decrypted = array();
|
||||
$type = $this->_type;
|
||||
|
||||
foreach ((array)$values as $name => $value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $val) {
|
||||
$decrypted[$name][$key] = $this->_decode($val);
|
||||
}
|
||||
} else {
|
||||
$decrypted[$name] = $this->_decode($value);
|
||||
}
|
||||
}
|
||||
return $decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes and decrypts a single value.
|
||||
*
|
||||
* @param string $value The value to decode & decrypt.
|
||||
* @return string Decoded value.
|
||||
*/
|
||||
protected function _decode($value) {
|
||||
$prefix = 'Q2FrZQ==.';
|
||||
$pos = strpos($value, $prefix);
|
||||
if ($pos === false) {
|
||||
return $this->_explode($value);
|
||||
}
|
||||
$value = base64_decode(substr($value, strlen($prefix)));
|
||||
if ($this->_type === 'rijndael') {
|
||||
$plain = Security::rijndael($value, $this->key, 'decrypt');
|
||||
}
|
||||
if ($this->_type === 'cipher') {
|
||||
$plain = Security::cipher($value, $this->key);
|
||||
}
|
||||
if ($this->_type === 'aes') {
|
||||
$plain = Security::decrypt($value, $this->key);
|
||||
}
|
||||
return $this->_explode($plain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implode method to keep keys are multidimensional arrays
|
||||
*
|
||||
* @param array $array Map of key and values
|
||||
* @return string A json encoded string.
|
||||
*/
|
||||
protected function _implode(array $array) {
|
||||
return json_encode($array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Explode method to return array from string set in CookieComponent::_implode()
|
||||
* Maintains reading backwards compatibility with 1.x CookieComponent::_implode().
|
||||
*
|
||||
* @param string $string A string containing JSON encoded data, or a bare string.
|
||||
* @return array Map of key and values
|
||||
*/
|
||||
protected function _explode($string) {
|
||||
$first = substr($string, 0, 1);
|
||||
if ($first === '{' || $first === '[') {
|
||||
$ret = json_decode($string, true);
|
||||
return ($ret !== null) ? $ret : $string;
|
||||
}
|
||||
$array = array();
|
||||
foreach (explode(',', $string) as $pair) {
|
||||
$key = explode('|', $pair);
|
||||
if (!isset($key[1])) {
|
||||
return $key[0];
|
||||
}
|
||||
$array[$key[0]] = $key[1];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
464
lib/Cake/Controller/Component/EmailComponent.php
Normal file
464
lib/Cake/Controller/Component/EmailComponent.php
Normal file
|
@ -0,0 +1,464 @@
|
|||
<?php
|
||||
/**
|
||||
* Email Component
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 1.2.0.3467
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('Multibyte', 'I18n');
|
||||
App::uses('CakeEmail', 'Network/Email');
|
||||
|
||||
/**
|
||||
* EmailComponent
|
||||
*
|
||||
* This component is used for handling Internet Message Format based
|
||||
* based on the standard outlined in http://www.rfc-editor.org/rfc/rfc2822.txt
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/email.html
|
||||
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/email.html
|
||||
* @deprecated Will be removed in 3.0. Use Network/CakeEmail instead
|
||||
*/
|
||||
class EmailComponent extends Component {
|
||||
|
||||
/**
|
||||
* Recipient of the email
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $to = null;
|
||||
|
||||
/**
|
||||
* The mail which the email is sent from
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $from = null;
|
||||
|
||||
/**
|
||||
* The email the recipient will reply to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $replyTo = null;
|
||||
|
||||
/**
|
||||
* The read receipt email
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $readReceipt = null;
|
||||
|
||||
/**
|
||||
* The mail that will be used in case of any errors like
|
||||
* - Remote mailserver down
|
||||
* - Remote user has exceeded his quota
|
||||
* - Unknown user
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $return = null;
|
||||
|
||||
/**
|
||||
* Carbon Copy
|
||||
*
|
||||
* List of email's that should receive a copy of the email.
|
||||
* The Recipient WILL be able to see this list
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cc = array();
|
||||
|
||||
/**
|
||||
* Blind Carbon Copy
|
||||
*
|
||||
* List of email's that should receive a copy of the email.
|
||||
* The Recipient WILL NOT be able to see this list
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $bcc = array();
|
||||
|
||||
/**
|
||||
* The date to put in the Date: header. This should be a date
|
||||
* conforming with the RFC2822 standard. Leave null, to have
|
||||
* today's date generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $date = null;
|
||||
|
||||
/**
|
||||
* The subject of the email
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $subject = null;
|
||||
|
||||
/**
|
||||
* Associative array of a user defined headers
|
||||
* Keys will be prefixed 'X-' as per RFC2822 Section 4.7.5
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $headers = array();
|
||||
|
||||
/**
|
||||
* List of additional headers
|
||||
*
|
||||
* These will NOT be used if you are using safemode and mail()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $additionalParams = null;
|
||||
|
||||
/**
|
||||
* Layout for the View
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $layout = 'default';
|
||||
|
||||
/**
|
||||
* Template for the view
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $template = null;
|
||||
|
||||
/**
|
||||
* Line feed character(s) to be used when sending using mail() function
|
||||
* By default PHP_EOL is used.
|
||||
* RFC2822 requires it to be CRLF but some Unix
|
||||
* mail transfer agents replace LF by CRLF automatically
|
||||
* (which leads to doubling CR if CRLF is used).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $lineFeed = PHP_EOL;
|
||||
|
||||
/**
|
||||
* What format should the email be sent in
|
||||
*
|
||||
* Supported formats:
|
||||
* - text
|
||||
* - html
|
||||
* - both
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $sendAs = 'text';
|
||||
|
||||
/**
|
||||
* What method should the email be sent by
|
||||
*
|
||||
* Supported methods:
|
||||
* - mail
|
||||
* - smtp
|
||||
* - debug
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $delivery = 'mail';
|
||||
|
||||
/**
|
||||
* charset the email is sent in
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $charset = 'utf-8';
|
||||
|
||||
/**
|
||||
* List of files that should be attached to the email.
|
||||
*
|
||||
* Can be both absolute and relative paths
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $attachments = array();
|
||||
|
||||
/**
|
||||
* What mailer should EmailComponent identify itself as
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $xMailer = 'CakePHP Email Component';
|
||||
|
||||
/**
|
||||
* The list of paths to search if an attachment isn't absolute
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $filePaths = array();
|
||||
|
||||
/**
|
||||
* List of options to use for smtp mail method
|
||||
*
|
||||
* Options is:
|
||||
* - port
|
||||
* - host
|
||||
* - timeout
|
||||
* - username
|
||||
* - password
|
||||
* - client
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $smtpOptions = array();
|
||||
|
||||
/**
|
||||
* Contains the rendered plain text message if one was sent.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $textMessage = null;
|
||||
|
||||
/**
|
||||
* Contains the rendered HTML message if one was sent.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $htmlMessage = null;
|
||||
|
||||
/**
|
||||
* Whether to generate a Message-ID header for the
|
||||
* e-mail. True to generate a Message-ID, False to let
|
||||
* it be handled by sendmail (or similar) or a string
|
||||
* to completely override the Message-ID.
|
||||
*
|
||||
* If you are sending Email from a shell, be sure to set this value. As you
|
||||
* could encounter delivery issues if you do not.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $messageId = true;
|
||||
|
||||
/**
|
||||
* Controller reference
|
||||
*
|
||||
* @var Controller
|
||||
*/
|
||||
protected $_controller = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ComponentCollection $collection A ComponentCollection this component can use to lazy load its components
|
||||
* @param array $settings Array of configuration settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
$this->_controller = $collection->getController();
|
||||
parent::__construct($collection, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize component
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @return void
|
||||
*/
|
||||
public function initialize(Controller $controller) {
|
||||
if (Configure::read('App.encoding') !== null) {
|
||||
$this->charset = Configure::read('App.encoding');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email using the specified content, template and layout
|
||||
*
|
||||
* @param string|array $content Either an array of text lines, or a string with contents
|
||||
* If you are rendering a template this variable will be sent to the templates as `$content`
|
||||
* @param string $template Template to use when sending email
|
||||
* @param string $layout Layout to use to enclose email body
|
||||
* @return bool Success
|
||||
*/
|
||||
public function send($content = null, $template = null, $layout = null) {
|
||||
$lib = new CakeEmail();
|
||||
$lib->charset = $this->charset;
|
||||
$lib->headerCharset = $this->charset;
|
||||
|
||||
$lib->from($this->_formatAddresses((array)$this->from));
|
||||
if (!empty($this->to)) {
|
||||
$lib->to($this->_formatAddresses((array)$this->to));
|
||||
}
|
||||
if (!empty($this->cc)) {
|
||||
$lib->cc($this->_formatAddresses((array)$this->cc));
|
||||
}
|
||||
if (!empty($this->bcc)) {
|
||||
$lib->bcc($this->_formatAddresses((array)$this->bcc));
|
||||
}
|
||||
if (!empty($this->replyTo)) {
|
||||
$lib->replyTo($this->_formatAddresses((array)$this->replyTo));
|
||||
}
|
||||
if (!empty($this->return)) {
|
||||
$lib->returnPath($this->_formatAddresses((array)$this->return));
|
||||
}
|
||||
if (!empty($this->readReceipt)) {
|
||||
$lib->readReceipt($this->_formatAddresses((array)$this->readReceipt));
|
||||
}
|
||||
|
||||
$lib->subject($this->subject)->messageID($this->messageId);
|
||||
$lib->helpers($this->_controller->helpers);
|
||||
|
||||
$headers = array('X-Mailer' => $this->xMailer);
|
||||
foreach ($this->headers as $key => $value) {
|
||||
$headers['X-' . $key] = $value;
|
||||
}
|
||||
if ($this->date) {
|
||||
$headers['Date'] = $this->date;
|
||||
}
|
||||
$lib->setHeaders($headers);
|
||||
|
||||
if ($template) {
|
||||
$this->template = $template;
|
||||
}
|
||||
if ($layout) {
|
||||
$this->layout = $layout;
|
||||
}
|
||||
$lib->template($this->template, $this->layout)->viewVars($this->_controller->viewVars)->emailFormat($this->sendAs);
|
||||
|
||||
if (!empty($this->attachments)) {
|
||||
$lib->attachments($this->_formatAttachFiles());
|
||||
}
|
||||
|
||||
$lib->transport(ucfirst($this->delivery));
|
||||
if ($this->delivery === 'mail') {
|
||||
$lib->config(array('eol' => $this->lineFeed, 'additionalParameters' => $this->additionalParams));
|
||||
} elseif ($this->delivery === 'smtp') {
|
||||
$lib->config($this->smtpOptions);
|
||||
} else {
|
||||
$lib->config(array());
|
||||
}
|
||||
|
||||
$sent = $lib->send($content);
|
||||
|
||||
$this->htmlMessage = $lib->message(CakeEmail::MESSAGE_HTML);
|
||||
if (empty($this->htmlMessage)) {
|
||||
$this->htmlMessage = null;
|
||||
}
|
||||
$this->textMessage = $lib->message(CakeEmail::MESSAGE_TEXT);
|
||||
if (empty($this->textMessage)) {
|
||||
$this->textMessage = null;
|
||||
}
|
||||
|
||||
$this->_header = array();
|
||||
$this->_message = array();
|
||||
|
||||
return $sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all EmailComponent internal variables to be able to send out a new email.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset() {
|
||||
$this->template = null;
|
||||
$this->to = array();
|
||||
$this->from = null;
|
||||
$this->replyTo = null;
|
||||
$this->return = null;
|
||||
$this->cc = array();
|
||||
$this->bcc = array();
|
||||
$this->subject = null;
|
||||
$this->additionalParams = null;
|
||||
$this->date = null;
|
||||
$this->attachments = array();
|
||||
$this->htmlMessage = null;
|
||||
$this->textMessage = null;
|
||||
$this->messageId = true;
|
||||
$this->delivery = 'mail';
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the attach array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _formatAttachFiles() {
|
||||
$files = array();
|
||||
foreach ($this->attachments as $filename => $attachment) {
|
||||
$file = $this->_findFiles($attachment);
|
||||
if (!empty($file)) {
|
||||
if (is_int($filename)) {
|
||||
$filename = basename($file);
|
||||
}
|
||||
$files[$filename] = $file;
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the specified attachment in the list of file paths
|
||||
*
|
||||
* @param string $attachment Attachment file name to find
|
||||
* @return string Path to located file
|
||||
*/
|
||||
protected function _findFiles($attachment) {
|
||||
if (file_exists($attachment)) {
|
||||
return $attachment;
|
||||
}
|
||||
foreach ($this->filePaths as $path) {
|
||||
if (file_exists($path . DS . $attachment)) {
|
||||
$file = $path . DS . $attachment;
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format addresses to be an array with email as key and alias as value
|
||||
*
|
||||
* @param array $addresses Address to format.
|
||||
* @return array
|
||||
*/
|
||||
protected function _formatAddresses($addresses) {
|
||||
$formatted = array();
|
||||
foreach ($addresses as $address) {
|
||||
if (preg_match('/((.*))?\s?<(.+)>/', $address, $matches) && !empty($matches[2])) {
|
||||
$formatted[$this->_strip($matches[3])] = $matches[2];
|
||||
} else {
|
||||
$address = $this->_strip($address);
|
||||
$formatted[$address] = $address;
|
||||
}
|
||||
}
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove certain elements (such as bcc:, to:, %0a) from given value.
|
||||
* Helps prevent header injection / manipulation on user content.
|
||||
*
|
||||
* @param string $value Value to strip
|
||||
* @param bool $message Set to true to indicate main message content
|
||||
* @return string Stripped value
|
||||
*/
|
||||
protected function _strip($value, $message = false) {
|
||||
$search = '%0a|%0d|Content-(?:Type|Transfer-Encoding)\:';
|
||||
$search .= '|charset\=|mime-version\:|multipart/mixed|(?:[^a-z]to|b?cc)\:.*';
|
||||
|
||||
if ($message !== true) {
|
||||
$search .= '|\r|\n';
|
||||
}
|
||||
$search = '#(?:' . $search . ')#i';
|
||||
while (preg_match($search, $value)) {
|
||||
$value = preg_replace($search, '', $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
428
lib/Cake/Controller/Component/PaginatorComponent.php
Normal file
428
lib/Cake/Controller/Component/PaginatorComponent.php
Normal file
|
@ -0,0 +1,428 @@
|
|||
<?php
|
||||
/**
|
||||
* Paginator Component
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 2.0
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('Hash', 'Utility');
|
||||
|
||||
/**
|
||||
* This component is used to handle automatic model data pagination. The primary way to use this
|
||||
* component is to call the paginate() method. There is a convenience wrapper on Controller as well.
|
||||
*
|
||||
* ### Configuring pagination
|
||||
*
|
||||
* You configure pagination using the PaginatorComponent::$settings. This allows you to configure
|
||||
* the default pagination behavior in general or for a specific model. General settings are used when there
|
||||
* are no specific model configuration, or the model you are paginating does not have specific settings.
|
||||
*
|
||||
* {{{
|
||||
* $this->Paginator->settings = array(
|
||||
* 'limit' => 20,
|
||||
* 'maxLimit' => 100
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* The above settings will be used to paginate any model. You can configure model specific settings by
|
||||
* keying the settings with the model name.
|
||||
*
|
||||
* {{{
|
||||
* $this->Paginator->settings = array(
|
||||
* 'Post' => array(
|
||||
* 'limit' => 20,
|
||||
* 'maxLimit' => 100
|
||||
* ),
|
||||
* 'Comment' => array( ... )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* This would allow you to have different pagination settings for `Comment` and `Post` models.
|
||||
*
|
||||
* #### Paginating with custom finders
|
||||
*
|
||||
* You can paginate with any find type defined on your model using the `findType` option.
|
||||
*
|
||||
* {{{
|
||||
* $this->Paginator->settings = array(
|
||||
* 'Post' => array(
|
||||
* 'findType' => 'popular'
|
||||
* )
|
||||
* );
|
||||
* }}}
|
||||
*
|
||||
* Would paginate using the `find('popular')` method.
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html
|
||||
*/
|
||||
class PaginatorComponent extends Component {
|
||||
|
||||
/**
|
||||
* Pagination settings. These settings control pagination at a general level.
|
||||
* You can also define sub arrays for pagination settings for specific models.
|
||||
*
|
||||
* - `maxLimit` The maximum limit users can choose to view. Defaults to 100
|
||||
* - `limit` The initial number of items per page. Defaults to 20.
|
||||
* - `page` The starting page, defaults to 1.
|
||||
* - `paramType` What type of parameters you want pagination to use?
|
||||
* - `named` Use named parameters / routed parameters.
|
||||
* - `querystring` Use query string parameters.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $settings = array(
|
||||
'page' => 1,
|
||||
'limit' => 20,
|
||||
'maxLimit' => 100,
|
||||
'paramType' => 'named'
|
||||
);
|
||||
|
||||
/**
|
||||
* A list of parameters users are allowed to set using request parameters. Modifying
|
||||
* this list will allow users to have more influence over pagination,
|
||||
* be careful with what you permit.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $whitelist = array(
|
||||
'limit', 'sort', 'page', 'direction'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ComponentCollection $collection A ComponentCollection this component can use to lazy load its components
|
||||
* @param array $settings Array of configuration settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
$settings = array_merge($this->settings, (array)$settings);
|
||||
$this->Controller = $collection->getController();
|
||||
parent::__construct($collection, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles automatic pagination of model records.
|
||||
*
|
||||
* @param Model|string $object Model to paginate (e.g: model instance, or 'Model', or 'Model.InnerModel')
|
||||
* @param string|array $scope Additional find conditions to use while paginating
|
||||
* @param array $whitelist List of allowed fields for ordering. This allows you to prevent ordering
|
||||
* on non-indexed, or undesirable columns. See PaginatorComponent::validateSort() for additional details
|
||||
* on how the whitelisting and sort field validation works.
|
||||
* @return array Model query results
|
||||
* @throws MissingModelException
|
||||
* @throws NotFoundException
|
||||
*/
|
||||
public function paginate($object = null, $scope = array(), $whitelist = array()) {
|
||||
if (is_array($object)) {
|
||||
$whitelist = $scope;
|
||||
$scope = $object;
|
||||
$object = null;
|
||||
}
|
||||
|
||||
$object = $this->_getObject($object);
|
||||
|
||||
if (!is_object($object)) {
|
||||
throw new MissingModelException($object);
|
||||
}
|
||||
|
||||
$options = $this->mergeOptions($object->alias);
|
||||
$options = $this->validateSort($object, $options, $whitelist);
|
||||
$options = $this->checkLimit($options);
|
||||
|
||||
$conditions = $fields = $order = $limit = $page = $recursive = null;
|
||||
|
||||
if (!isset($options['conditions'])) {
|
||||
$options['conditions'] = array();
|
||||
}
|
||||
|
||||
$type = 'all';
|
||||
|
||||
if (isset($options[0])) {
|
||||
$type = $options[0];
|
||||
unset($options[0]);
|
||||
}
|
||||
|
||||
extract($options);
|
||||
|
||||
if (is_array($scope) && !empty($scope)) {
|
||||
$conditions = array_merge($conditions, $scope);
|
||||
} elseif (is_string($scope)) {
|
||||
$conditions = array($conditions, $scope);
|
||||
}
|
||||
if ($recursive === null) {
|
||||
$recursive = $object->recursive;
|
||||
}
|
||||
|
||||
$extra = array_diff_key($options, compact(
|
||||
'conditions', 'fields', 'order', 'limit', 'page', 'recursive'
|
||||
));
|
||||
|
||||
if (!empty($extra['findType'])) {
|
||||
$type = $extra['findType'];
|
||||
unset($extra['findType']);
|
||||
}
|
||||
|
||||
if ($type !== 'all') {
|
||||
$extra['type'] = $type;
|
||||
}
|
||||
|
||||
if (intval($page) < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
$page = $options['page'] = (int)$page;
|
||||
|
||||
if ($object->hasMethod('paginate')) {
|
||||
$results = $object->paginate(
|
||||
$conditions, $fields, $order, $limit, $page, $recursive, $extra
|
||||
);
|
||||
} else {
|
||||
$parameters = compact('conditions', 'fields', 'order', 'limit', 'page');
|
||||
if ($recursive != $object->recursive) {
|
||||
$parameters['recursive'] = $recursive;
|
||||
}
|
||||
$results = $object->find($type, array_merge($parameters, $extra));
|
||||
}
|
||||
$defaults = $this->getDefaults($object->alias);
|
||||
unset($defaults[0]);
|
||||
|
||||
if (!$results) {
|
||||
$count = 0;
|
||||
} elseif ($object->hasMethod('paginateCount')) {
|
||||
$count = $object->paginateCount($conditions, $recursive, $extra);
|
||||
} elseif ($page === 1 && count($results) < $limit) {
|
||||
$count = count($results);
|
||||
} else {
|
||||
$parameters = compact('conditions');
|
||||
if ($recursive != $object->recursive) {
|
||||
$parameters['recursive'] = $recursive;
|
||||
}
|
||||
$count = $object->find('count', array_merge($parameters, $extra));
|
||||
}
|
||||
$pageCount = intval(ceil($count / $limit));
|
||||
$requestedPage = $page;
|
||||
$page = max(min($page, $pageCount), 1);
|
||||
|
||||
$paging = array(
|
||||
'page' => $page,
|
||||
'current' => count($results),
|
||||
'count' => $count,
|
||||
'prevPage' => ($page > 1),
|
||||
'nextPage' => ($count > ($page * $limit)),
|
||||
'pageCount' => $pageCount,
|
||||
'order' => $order,
|
||||
'limit' => $limit,
|
||||
'options' => Hash::diff($options, $defaults),
|
||||
'paramType' => $options['paramType']
|
||||
);
|
||||
|
||||
if (!isset($this->Controller->request['paging'])) {
|
||||
$this->Controller->request['paging'] = array();
|
||||
}
|
||||
$this->Controller->request['paging'] = array_merge(
|
||||
(array)$this->Controller->request['paging'],
|
||||
array($object->alias => $paging)
|
||||
);
|
||||
|
||||
if ($requestedPage > $page) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (
|
||||
!in_array('Paginator', $this->Controller->helpers) &&
|
||||
!array_key_exists('Paginator', $this->Controller->helpers)
|
||||
) {
|
||||
$this->Controller->helpers[] = 'Paginator';
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object pagination will occur on.
|
||||
*
|
||||
* @param string|Model $object The object you are looking for.
|
||||
* @return mixed The model object to paginate on.
|
||||
*/
|
||||
protected function _getObject($object) {
|
||||
if (is_string($object)) {
|
||||
$assoc = null;
|
||||
if (strpos($object, '.') !== false) {
|
||||
list($object, $assoc) = pluginSplit($object);
|
||||
}
|
||||
if ($assoc && isset($this->Controller->{$object}->{$assoc})) {
|
||||
return $this->Controller->{$object}->{$assoc};
|
||||
}
|
||||
if ($assoc && isset($this->Controller->{$this->Controller->modelClass}->{$assoc})) {
|
||||
return $this->Controller->{$this->Controller->modelClass}->{$assoc};
|
||||
}
|
||||
if (isset($this->Controller->{$object})) {
|
||||
return $this->Controller->{$object};
|
||||
}
|
||||
if (isset($this->Controller->{$this->Controller->modelClass}->{$object})) {
|
||||
return $this->Controller->{$this->Controller->modelClass}->{$object};
|
||||
}
|
||||
}
|
||||
if (empty($object) || $object === null) {
|
||||
if (isset($this->Controller->{$this->Controller->modelClass})) {
|
||||
return $this->Controller->{$this->Controller->modelClass};
|
||||
}
|
||||
|
||||
$className = null;
|
||||
$name = $this->Controller->uses[0];
|
||||
if (strpos($this->Controller->uses[0], '.') !== false) {
|
||||
list($name, $className) = explode('.', $this->Controller->uses[0]);
|
||||
}
|
||||
if ($className) {
|
||||
return $this->Controller->{$className};
|
||||
}
|
||||
|
||||
return $this->Controller->{$name};
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the various options that Pagination uses.
|
||||
* Pulls settings together from the following places:
|
||||
*
|
||||
* - General pagination settings
|
||||
* - Model specific settings.
|
||||
* - Request parameters
|
||||
*
|
||||
* The result of this method is the aggregate of all the option sets combined together. You can change
|
||||
* PaginatorComponent::$whitelist to modify which options/values can be set using request parameters.
|
||||
*
|
||||
* @param string $alias Model alias being paginated, if the general settings has a key with this value
|
||||
* that key's settings will be used for pagination instead of the general ones.
|
||||
* @return array Array of merged options.
|
||||
*/
|
||||
public function mergeOptions($alias) {
|
||||
$defaults = $this->getDefaults($alias);
|
||||
switch ($defaults['paramType']) {
|
||||
case 'named':
|
||||
$request = $this->Controller->request->params['named'];
|
||||
break;
|
||||
case 'querystring':
|
||||
$request = $this->Controller->request->query;
|
||||
break;
|
||||
}
|
||||
$request = array_intersect_key($request, array_flip($this->whitelist));
|
||||
return array_merge($defaults, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default settings for a $model. If there are no settings for a specific model, the general settings
|
||||
* will be used.
|
||||
*
|
||||
* @param string $alias Model name to get default settings for.
|
||||
* @return array An array of pagination defaults for a model, or the general settings.
|
||||
*/
|
||||
public function getDefaults($alias) {
|
||||
$defaults = $this->settings;
|
||||
if (isset($this->settings[$alias])) {
|
||||
$defaults = $this->settings[$alias];
|
||||
}
|
||||
if (isset($defaults['limit']) &&
|
||||
(empty($defaults['maxLimit']) || $defaults['limit'] > $defaults['maxLimit'])
|
||||
) {
|
||||
$defaults['maxLimit'] = $defaults['limit'];
|
||||
}
|
||||
return array_merge(
|
||||
array('page' => 1, 'limit' => 20, 'maxLimit' => 100, 'paramType' => 'named'),
|
||||
$defaults
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the desired sorting can be performed on the $object. Only fields or
|
||||
* virtualFields can be sorted on. The direction param will also be sanitized. Lastly
|
||||
* sort + direction keys will be converted into the model friendly order key.
|
||||
*
|
||||
* You can use the whitelist parameter to control which columns/fields are available for sorting.
|
||||
* This helps prevent users from ordering large result sets on un-indexed values.
|
||||
*
|
||||
* Any columns listed in the sort whitelist will be implicitly trusted. You can use this to sort
|
||||
* on synthetic columns, or columns added in custom find operations that may not exist in the schema.
|
||||
*
|
||||
* @param Model $object The model being paginated.
|
||||
* @param array $options The pagination options being used for this request.
|
||||
* @param array $whitelist The list of columns that can be used for sorting. If empty all keys are allowed.
|
||||
* @return array An array of options with sort + direction removed and replaced with order if possible.
|
||||
*/
|
||||
public function validateSort(Model $object, array $options, array $whitelist = array()) {
|
||||
if (empty($options['order']) && is_array($object->order)) {
|
||||
$options['order'] = $object->order;
|
||||
}
|
||||
|
||||
if (isset($options['sort'])) {
|
||||
$direction = null;
|
||||
if (isset($options['direction'])) {
|
||||
$direction = strtolower($options['direction']);
|
||||
}
|
||||
if (!in_array($direction, array('asc', 'desc'))) {
|
||||
$direction = 'asc';
|
||||
}
|
||||
$options['order'] = array($options['sort'] => $direction);
|
||||
}
|
||||
|
||||
if (!empty($whitelist) && isset($options['order']) && is_array($options['order'])) {
|
||||
$field = key($options['order']);
|
||||
$inWhitelist = in_array($field, $whitelist, true);
|
||||
if (!$inWhitelist) {
|
||||
$options['order'] = null;
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
if (!empty($options['order']) && is_array($options['order'])) {
|
||||
$order = array();
|
||||
foreach ($options['order'] as $key => $value) {
|
||||
$field = $key;
|
||||
$alias = $object->alias;
|
||||
if (strpos($key, '.') !== false) {
|
||||
list($alias, $field) = explode('.', $key);
|
||||
}
|
||||
$correctAlias = ($object->alias === $alias);
|
||||
|
||||
if ($correctAlias && $object->hasField($field)) {
|
||||
$order[$object->alias . '.' . $field] = $value;
|
||||
} elseif ($correctAlias && $object->hasField($key, true)) {
|
||||
$order[$field] = $value;
|
||||
} elseif (isset($object->{$alias}) && $object->{$alias}->hasField($field, true)) {
|
||||
$order[$alias . '.' . $field] = $value;
|
||||
}
|
||||
}
|
||||
$options['order'] = $order;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the limit parameter and ensure its within the maxLimit bounds.
|
||||
*
|
||||
* @param array $options An array of options with a limit key to be checked.
|
||||
* @return array An array of options for pagination
|
||||
*/
|
||||
public function checkLimit(array $options) {
|
||||
$options['limit'] = (int)$options['limit'];
|
||||
if (empty($options['limit']) || $options['limit'] < 1) {
|
||||
$options['limit'] = 1;
|
||||
}
|
||||
$options['limit'] = min($options['limit'], $options['maxLimit']);
|
||||
return $options;
|
||||
}
|
||||
|
||||
}
|
783
lib/Cake/Controller/Component/RequestHandlerComponent.php
Normal file
783
lib/Cake/Controller/Component/RequestHandlerComponent.php
Normal file
|
@ -0,0 +1,783 @@
|
|||
<?php
|
||||
/**
|
||||
* Request object for handling alternative HTTP requests
|
||||
*
|
||||
* Alternative HTTP requests can come from wireless units like mobile phones, palmtop computers,
|
||||
* and the like. These units have no use for Ajax requests, and this Component can tell how Cake
|
||||
* should respond to the different needs of a handheld computer and a desktop machine.
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 0.10.4.1076
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('Xml', 'Utility');
|
||||
|
||||
/**
|
||||
* Request object for handling alternative HTTP requests
|
||||
*
|
||||
* Alternative HTTP requests can come from wireless units like mobile phones, palmtop computers,
|
||||
* and the like. These units have no use for Ajax requests, and this Component can tell how Cake
|
||||
* should respond to the different needs of a handheld computer and a desktop machine.
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/request-handling.html
|
||||
*
|
||||
*/
|
||||
class RequestHandlerComponent extends Component {
|
||||
|
||||
/**
|
||||
* The layout that will be switched to for Ajax requests
|
||||
*
|
||||
* @var string
|
||||
* @see RequestHandler::setAjax()
|
||||
*/
|
||||
public $ajaxLayout = 'ajax';
|
||||
|
||||
/**
|
||||
* Determines whether or not callbacks will be fired on this component
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $enabled = true;
|
||||
|
||||
/**
|
||||
* Holds the reference to Controller::$request
|
||||
*
|
||||
* @var CakeRequest
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/**
|
||||
* Holds the reference to Controller::$response
|
||||
*
|
||||
* @var CakeResponse
|
||||
*/
|
||||
public $response;
|
||||
|
||||
/**
|
||||
* Contains the file extension parsed out by the Router
|
||||
*
|
||||
* @var string
|
||||
* @see Router::parseExtensions()
|
||||
*/
|
||||
public $ext = null;
|
||||
|
||||
/**
|
||||
* The template to use when rendering the given content type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_renderType = null;
|
||||
|
||||
/**
|
||||
* A mapping between extensions and deserializers for request bodies of that type.
|
||||
* By default only JSON and XML are mapped, use RequestHandlerComponent::addInputType()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_inputTypeMap = array(
|
||||
'json' => array('json_decode', true)
|
||||
);
|
||||
|
||||
/**
|
||||
* A mapping between type and viewClass
|
||||
* By default only JSON and XML are mapped, use RequestHandlerComponent::viewClassMap()
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_viewClassMap = array(
|
||||
'json' => 'Json',
|
||||
'xml' => 'Xml'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT
|
||||
*
|
||||
* @param ComponentCollection $collection ComponentCollection object.
|
||||
* @param array $settings Array of settings.
|
||||
*/
|
||||
public function __construct(ComponentCollection $collection, $settings = array()) {
|
||||
parent::__construct($collection, $settings + array('checkHttpCache' => true));
|
||||
$this->addInputType('xml', array(array($this, 'convertXml')));
|
||||
|
||||
$Controller = $collection->getController();
|
||||
$this->request = $Controller->request;
|
||||
$this->response = $Controller->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a file extension has been parsed by the Router, or if the
|
||||
* HTTP_ACCEPT_TYPE has matches only one content type with the supported extensions.
|
||||
* If there is only one matching type between the supported content types & extensions,
|
||||
* and the requested mime-types, RequestHandler::$ext is set to that value.
|
||||
*
|
||||
* @param Controller $controller A reference to the controller
|
||||
* @return void
|
||||
* @see Router::parseExtensions()
|
||||
*/
|
||||
public function initialize(Controller $controller) {
|
||||
if (isset($this->request->params['ext'])) {
|
||||
$this->ext = $this->request->params['ext'];
|
||||
}
|
||||
if (empty($this->ext) || $this->ext === 'html') {
|
||||
$this->_setExtension();
|
||||
}
|
||||
$this->params = $controller->params;
|
||||
if (!empty($this->settings['viewClassMap'])) {
|
||||
$this->viewClassMap($this->settings['viewClassMap']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extension based on the accept headers.
|
||||
* Compares the accepted types and configured extensions.
|
||||
* If there is one common type, that is assigned as the ext/content type
|
||||
* for the response.
|
||||
* Type with the highest weight will be set. If the highest weight has more
|
||||
* then one type matching the extensions, the order in which extensions are specified
|
||||
* determines which type will be set.
|
||||
*
|
||||
* If html is one of the preferred types, no content type will be set, this
|
||||
* is to avoid issues with browsers that prefer html and several other content types.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _setExtension() {
|
||||
$accept = $this->request->parseAccept();
|
||||
if (empty($accept)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$accepts = $this->response->mapType($accept);
|
||||
$preferedTypes = current($accepts);
|
||||
if (array_intersect($preferedTypes, array('html', 'xhtml'))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$extensions = Router::extensions();
|
||||
foreach ($accepts as $types) {
|
||||
$ext = array_intersect($extensions, $types);
|
||||
if ($ext) {
|
||||
$this->ext = current($ext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The startup method of the RequestHandler enables several automatic behaviors
|
||||
* related to the detection of certain properties of the HTTP request, including:
|
||||
*
|
||||
* - Disabling layout rendering for Ajax requests (based on the HTTP_X_REQUESTED_WITH header)
|
||||
* - If Router::parseExtensions() is enabled, the layout and template type are
|
||||
* switched based on the parsed extension or Accept-Type header. For example, if `controller/action.xml`
|
||||
* is requested, the view path becomes `app/View/Controller/xml/action.ctp`. Also if
|
||||
* `controller/action` is requested with `Accept-Type: application/xml` in the headers
|
||||
* the view path will become `app/View/Controller/xml/action.ctp`. Layout and template
|
||||
* types will only switch to mime-types recognized by CakeResponse. If you need to declare
|
||||
* additional mime-types, you can do so using CakeResponse::type() in your controllers beforeFilter()
|
||||
* method.
|
||||
* - If a helper with the same name as the extension exists, it is added to the controller.
|
||||
* - If the extension is of a type that RequestHandler understands, it will set that
|
||||
* Content-type in the response header.
|
||||
* - If the XML data is POSTed, the data is parsed into an XML object, which is assigned
|
||||
* to the $data property of the controller, which can then be saved to a model object.
|
||||
*
|
||||
* @param Controller $controller A reference to the controller
|
||||
* @return void
|
||||
*/
|
||||
public function startup(Controller $controller) {
|
||||
$controller->request->params['isAjax'] = $this->request->is('ajax');
|
||||
$isRecognized = (
|
||||
!in_array($this->ext, array('html', 'htm')) &&
|
||||
$this->response->getMimeType($this->ext)
|
||||
);
|
||||
|
||||
if (!empty($this->ext) && $isRecognized) {
|
||||
$this->renderAs($controller, $this->ext);
|
||||
} elseif ($this->request->is('ajax')) {
|
||||
$this->renderAs($controller, 'ajax');
|
||||
} elseif (empty($this->ext) || in_array($this->ext, array('html', 'htm'))) {
|
||||
$this->respondAs('html', array('charset' => Configure::read('App.encoding')));
|
||||
}
|
||||
|
||||
foreach ($this->_inputTypeMap as $type => $handler) {
|
||||
if ($this->requestedWith($type)) {
|
||||
$input = call_user_func_array(array($controller->request, 'input'), $handler);
|
||||
$controller->request->data = $input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to parse xml input data, due to lack of anonymous functions
|
||||
* this lives here.
|
||||
*
|
||||
* @param string $xml XML string.
|
||||
* @return array Xml array data
|
||||
*/
|
||||
public function convertXml($xml) {
|
||||
try {
|
||||
$xml = Xml::build($xml);
|
||||
if (isset($xml->data)) {
|
||||
return Xml::toArray($xml->data);
|
||||
}
|
||||
return Xml::toArray($xml);
|
||||
} catch (XmlException $e) {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles (fakes) redirects for Ajax requests using requestAction()
|
||||
* Modifies the $_POST and $_SERVER['REQUEST_METHOD'] to simulate a new GET request.
|
||||
*
|
||||
* @param Controller $controller A reference to the controller
|
||||
* @param string|array $url A string or array containing the redirect location
|
||||
* @param int|array $status HTTP Status for redirect
|
||||
* @param bool $exit Whether to exit script, defaults to `true`.
|
||||
* @return void
|
||||
*/
|
||||
public function beforeRedirect(Controller $controller, $url, $status = null, $exit = true) {
|
||||
if (!$this->request->is('ajax')) {
|
||||
return;
|
||||
}
|
||||
if (empty($url)) {
|
||||
return;
|
||||
}
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
foreach ($_POST as $key => $val) {
|
||||
unset($_POST[$key]);
|
||||
}
|
||||
if (is_array($url)) {
|
||||
$url = Router::url($url + array('base' => false));
|
||||
}
|
||||
if (!empty($status)) {
|
||||
$statusCode = $this->response->httpCodes($status);
|
||||
$code = key($statusCode);
|
||||
$this->response->statusCode($code);
|
||||
}
|
||||
$this->response->body($this->requestAction($url, array('return', 'bare' => false)));
|
||||
$this->response->send();
|
||||
$this->_stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the response can be considered different according to the request
|
||||
* headers, and the caching response headers. If it was not modified, then the
|
||||
* render process is skipped. And the client will get a blank response with a
|
||||
* "304 Not Modified" header.
|
||||
*
|
||||
* @param Controller $controller Controller instance.
|
||||
* @return bool false if the render process should be aborted
|
||||
*/
|
||||
public function beforeRender(Controller $controller) {
|
||||
if ($this->settings['checkHttpCache'] && $this->response->checkNotModified($this->request)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current HTTP request is Ajax, false otherwise
|
||||
*
|
||||
* @return bool True if call is Ajax
|
||||
* @deprecated use `$this->request->is('ajax')` instead.
|
||||
*/
|
||||
public function isAjax() {
|
||||
return $this->request->is('ajax');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current HTTP request is coming from a Flash-based client
|
||||
*
|
||||
* @return bool True if call is from Flash
|
||||
* @deprecated use `$this->request->is('flash')` instead.
|
||||
*/
|
||||
public function isFlash() {
|
||||
return $this->request->is('flash');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current request is over HTTPS, false otherwise.
|
||||
*
|
||||
* @return bool True if call is over HTTPS
|
||||
* @deprecated use `$this->request->is('ssl')` instead.
|
||||
*/
|
||||
public function isSSL() {
|
||||
return $this->request->is('ssl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call accepts an XML response, false otherwise
|
||||
*
|
||||
* @return bool True if client accepts an XML response
|
||||
*/
|
||||
public function isXml() {
|
||||
return $this->prefers('xml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call accepts an RSS response, false otherwise
|
||||
*
|
||||
* @return bool True if client accepts an RSS response
|
||||
*/
|
||||
public function isRss() {
|
||||
return $this->prefers('rss');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call accepts an Atom response, false otherwise
|
||||
*
|
||||
* @return bool True if client accepts an RSS response
|
||||
*/
|
||||
public function isAtom() {
|
||||
return $this->prefers('atom');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if user agent string matches a mobile web browser, or if the
|
||||
* client accepts WAP content.
|
||||
*
|
||||
* @return bool True if user agent is a mobile web browser
|
||||
*/
|
||||
public function isMobile() {
|
||||
return $this->request->is('mobile') || $this->accepts('wap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the client accepts WAP content
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isWap() {
|
||||
return $this->prefers('wap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a POST request
|
||||
*
|
||||
* @return bool True if call is a POST
|
||||
* @deprecated Use $this->request->is('post'); from your controller.
|
||||
*/
|
||||
public function isPost() {
|
||||
return $this->request->is('post');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a PUT request
|
||||
*
|
||||
* @return bool True if call is a PUT
|
||||
* @deprecated Use $this->request->is('put'); from your controller.
|
||||
*/
|
||||
public function isPut() {
|
||||
return $this->request->is('put');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a GET request
|
||||
*
|
||||
* @return bool True if call is a GET
|
||||
* @deprecated Use $this->request->is('get'); from your controller.
|
||||
*/
|
||||
public function isGet() {
|
||||
return $this->request->is('get');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current call a DELETE request
|
||||
*
|
||||
* @return bool True if call is a DELETE
|
||||
* @deprecated Use $this->request->is('delete'); from your controller.
|
||||
*/
|
||||
public function isDelete() {
|
||||
return $this->request->is('delete');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Prototype version if call is Ajax, otherwise empty string.
|
||||
* The Prototype library sets a special "Prototype version" HTTP header.
|
||||
*
|
||||
* @return string|bool When Ajax the prototype version of component making the call otherwise false
|
||||
*/
|
||||
public function getAjaxVersion() {
|
||||
$httpX = env('HTTP_X_PROTOTYPE_VERSION');
|
||||
return ($httpX === null) ? false : $httpX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds/sets the Content-type(s) for the given name. This method allows
|
||||
* content-types to be mapped to friendly aliases (or extensions), which allows
|
||||
* RequestHandler to automatically respond to requests of that type in the
|
||||
* startup method.
|
||||
*
|
||||
* @param string $name The name of the Content-type, i.e. "html", "xml", "css"
|
||||
* @param string|array $type The Content-type or array of Content-types assigned to the name,
|
||||
* i.e. "text/html", or "application/xml"
|
||||
* @return void
|
||||
* @deprecated use `$this->response->type()` instead.
|
||||
*/
|
||||
public function setContent($name, $type = null) {
|
||||
$this->response->type(array($name => $type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server name from which this request was referred
|
||||
*
|
||||
* @return string Server address
|
||||
* @deprecated use $this->request->referer() from your controller instead
|
||||
*/
|
||||
public function getReferer() {
|
||||
return $this->request->referer(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets remote client IP
|
||||
*
|
||||
* @param bool $safe Use safe = false when you think the user might manipulate
|
||||
* their HTTP_CLIENT_IP header. Setting $safe = false will also look at HTTP_X_FORWARDED_FOR
|
||||
* @return string Client IP address
|
||||
* @deprecated use $this->request->clientIp() from your, controller instead.
|
||||
*/
|
||||
public function getClientIP($safe = true) {
|
||||
return $this->request->clientIp($safe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which content types the client accepts. Acceptance is based on
|
||||
* the file extension parsed by the Router (if present), and by the HTTP_ACCEPT
|
||||
* header. Unlike CakeRequest::accepts() this method deals entirely with mapped content types.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* `$this->RequestHandler->accepts(array('xml', 'html', 'json'));`
|
||||
*
|
||||
* Returns true if the client accepts any of the supplied types.
|
||||
*
|
||||
* `$this->RequestHandler->accepts('xml');`
|
||||
*
|
||||
* Returns true if the client accepts xml.
|
||||
*
|
||||
* @param string|array $type Can be null (or no parameter), a string type name, or an
|
||||
* array of types
|
||||
* @return mixed If null or no parameter is passed, returns an array of content
|
||||
* types the client accepts. If a string is passed, returns true
|
||||
* if the client accepts it. If an array is passed, returns true
|
||||
* if the client accepts one or more elements in the array.
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
*/
|
||||
public function accepts($type = null) {
|
||||
$accepted = $this->request->accepts();
|
||||
|
||||
if (!$type) {
|
||||
return $this->mapType($accepted);
|
||||
}
|
||||
if (is_array($type)) {
|
||||
foreach ($type as $t) {
|
||||
$t = $this->mapAlias($t);
|
||||
if (in_array($t, $accepted)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (is_string($type)) {
|
||||
return in_array($this->mapAlias($type), $accepted);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the content type of the data the client has sent (i.e. in a POST request)
|
||||
*
|
||||
* @param string|array $type Can be null (or no parameter), a string type name, or an array of types
|
||||
* @return mixed If a single type is supplied a boolean will be returned. If no type is provided
|
||||
* The mapped value of CONTENT_TYPE will be returned. If an array is supplied the first type
|
||||
* in the request content type will be returned.
|
||||
*/
|
||||
public function requestedWith($type = null) {
|
||||
if (!$this->request->is('post') && !$this->request->is('put')) {
|
||||
return null;
|
||||
}
|
||||
if (is_array($type)) {
|
||||
foreach ($type as $t) {
|
||||
if ($this->requestedWith($t)) {
|
||||
return $t;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
list($contentType) = explode(';', env('CONTENT_TYPE'));
|
||||
if ($contentType === '') {
|
||||
list($contentType) = explode(';', CakeRequest::header('CONTENT_TYPE'));
|
||||
}
|
||||
if (!$type) {
|
||||
return $this->mapType($contentType);
|
||||
}
|
||||
if (is_string($type)) {
|
||||
return ($type === $this->mapType($contentType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which content-types the client prefers. If no parameters are given,
|
||||
* the single content-type that the client most likely prefers is returned. If $type is
|
||||
* an array, the first item in the array that the client accepts is returned.
|
||||
* Preference is determined primarily by the file extension parsed by the Router
|
||||
* if provided, and secondarily by the list of content-types provided in
|
||||
* HTTP_ACCEPT.
|
||||
*
|
||||
* @param string|array $type An optional array of 'friendly' content-type names, i.e.
|
||||
* 'html', 'xml', 'js', etc.
|
||||
* @return mixed If $type is null or not provided, the first content-type in the
|
||||
* list, based on preference, is returned. If a single type is provided
|
||||
* a boolean will be returned if that type is preferred.
|
||||
* If an array of types are provided then the first preferred type is returned.
|
||||
* If no type is provided the first preferred type is returned.
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
*/
|
||||
public function prefers($type = null) {
|
||||
$acceptRaw = $this->request->parseAccept();
|
||||
|
||||
if (empty($acceptRaw)) {
|
||||
return $this->ext;
|
||||
}
|
||||
$accepts = $this->mapType(array_shift($acceptRaw));
|
||||
|
||||
if (!$type) {
|
||||
if (empty($this->ext) && !empty($accepts)) {
|
||||
return $accepts[0];
|
||||
}
|
||||
return $this->ext;
|
||||
}
|
||||
|
||||
$types = (array)$type;
|
||||
|
||||
if (count($types) === 1) {
|
||||
if (!empty($this->ext)) {
|
||||
return in_array($this->ext, $types);
|
||||
}
|
||||
return in_array($types[0], $accepts);
|
||||
}
|
||||
|
||||
$intersect = array_values(array_intersect($accepts, $types));
|
||||
if (empty($intersect)) {
|
||||
return false;
|
||||
}
|
||||
return $intersect[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the layout and template paths for the content type defined by $type.
|
||||
*
|
||||
* ### Usage:
|
||||
*
|
||||
* Render the response as an 'ajax' response.
|
||||
*
|
||||
* `$this->RequestHandler->renderAs($this, 'ajax');`
|
||||
*
|
||||
* Render the response as an xml file and force the result as a file download.
|
||||
*
|
||||
* `$this->RequestHandler->renderAs($this, 'xml', array('attachment' => 'myfile.xml');`
|
||||
*
|
||||
* @param Controller $controller A reference to a controller object
|
||||
* @param string $type Type of response to send (e.g: 'ajax')
|
||||
* @param array $options Array of options to use
|
||||
* @return void
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
* @see RequestHandlerComponent::respondAs()
|
||||
*/
|
||||
public function renderAs(Controller $controller, $type, $options = array()) {
|
||||
$defaults = array('charset' => 'UTF-8');
|
||||
|
||||
if (Configure::read('App.encoding') !== null) {
|
||||
$defaults['charset'] = Configure::read('App.encoding');
|
||||
}
|
||||
$options += $defaults;
|
||||
|
||||
if ($type === 'ajax') {
|
||||
$controller->layout = $this->ajaxLayout;
|
||||
return $this->respondAs('html', $options);
|
||||
}
|
||||
|
||||
$pluginDot = null;
|
||||
$viewClassMap = $this->viewClassMap();
|
||||
if (array_key_exists($type, $viewClassMap)) {
|
||||
list($pluginDot, $viewClass) = pluginSplit($viewClassMap[$type], true);
|
||||
} else {
|
||||
$viewClass = Inflector::classify($type);
|
||||
}
|
||||
$viewName = $viewClass . 'View';
|
||||
if (!class_exists($viewName)) {
|
||||
App::uses($viewName, $pluginDot . 'View');
|
||||
}
|
||||
if (class_exists($viewName)) {
|
||||
$controller->viewClass = $viewClass;
|
||||
} elseif (empty($this->_renderType)) {
|
||||
$controller->viewPath .= DS . $type;
|
||||
} else {
|
||||
$controller->viewPath = preg_replace(
|
||||
"/([\/\\\\]{$this->_renderType})$/",
|
||||
DS . $type,
|
||||
$controller->viewPath
|
||||
);
|
||||
}
|
||||
$this->_renderType = $type;
|
||||
$controller->layoutPath = $type;
|
||||
|
||||
if ($this->response->getMimeType($type)) {
|
||||
$this->respondAs($type, $options);
|
||||
}
|
||||
|
||||
$helper = ucfirst($type);
|
||||
|
||||
if (!in_array($helper, $controller->helpers) && empty($controller->helpers[$helper])) {
|
||||
App::uses('AppHelper', 'View/Helper');
|
||||
App::uses($helper . 'Helper', 'View/Helper');
|
||||
if (class_exists($helper . 'Helper')) {
|
||||
$controller->helpers[] = $helper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the response header based on type map index name. This wraps several methods
|
||||
* available on CakeResponse. It also allows you to use Content-Type aliases.
|
||||
*
|
||||
* @param string|array $type Friendly type name, i.e. 'html' or 'xml', or a full content-type,
|
||||
* like 'application/x-shockwave'.
|
||||
* @param array $options If $type is a friendly type name that is associated with
|
||||
* more than one type of content, $index is used to select which content-type to use.
|
||||
* @return bool Returns false if the friendly type name given in $type does
|
||||
* not exist in the type map, or if the Content-type header has
|
||||
* already been set by this method.
|
||||
* @see RequestHandlerComponent::setContent()
|
||||
*/
|
||||
public function respondAs($type, $options = array()) {
|
||||
$defaults = array('index' => null, 'charset' => null, 'attachment' => false);
|
||||
$options = $options + $defaults;
|
||||
|
||||
$cType = $type;
|
||||
if (strpos($type, '/') === false) {
|
||||
$cType = $this->response->getMimeType($type);
|
||||
}
|
||||
if (is_array($cType)) {
|
||||
if (isset($cType[$options['index']])) {
|
||||
$cType = $cType[$options['index']];
|
||||
}
|
||||
|
||||
if ($this->prefers($cType)) {
|
||||
$cType = $this->prefers($cType);
|
||||
} else {
|
||||
$cType = $cType[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$type) {
|
||||
return false;
|
||||
}
|
||||
if (empty($this->request->params['requested'])) {
|
||||
$this->response->type($cType);
|
||||
}
|
||||
if (!empty($options['charset'])) {
|
||||
$this->response->charset($options['charset']);
|
||||
}
|
||||
if (!empty($options['attachment'])) {
|
||||
$this->response->download($options['attachment']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current response type (Content-type header), or null if not alias exists
|
||||
*
|
||||
* @return mixed A string content type alias, or raw content type if no alias map exists,
|
||||
* otherwise null
|
||||
*/
|
||||
public function responseType() {
|
||||
return $this->mapType($this->response->type());
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a content-type back to an alias
|
||||
*
|
||||
* @param string|array $cType Either a string content type to map, or an array of types.
|
||||
* @return string|array Aliases for the types provided.
|
||||
* @deprecated Use $this->response->mapType() in your controller instead.
|
||||
*/
|
||||
public function mapType($cType) {
|
||||
return $this->response->mapType($cType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a content type alias back to its mime-type(s)
|
||||
*
|
||||
* @param string|array $alias String alias to convert back into a content type. Or an array of aliases to map.
|
||||
* @return string Null on an undefined alias. String value of the mapped alias type. If an
|
||||
* alias maps to more than one content type, the first one will be returned.
|
||||
*/
|
||||
public function mapAlias($alias) {
|
||||
if (is_array($alias)) {
|
||||
return array_map(array($this, 'mapAlias'), $alias);
|
||||
}
|
||||
$type = $this->response->getMimeType($alias);
|
||||
if ($type) {
|
||||
if (is_array($type)) {
|
||||
return $type[0];
|
||||
}
|
||||
return $type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new mapped input type. Mapped input types are automatically
|
||||
* converted by RequestHandlerComponent during the startup() callback.
|
||||
*
|
||||
* @param string $type The type alias being converted, ie. json
|
||||
* @param array $handler The handler array for the type. The first index should
|
||||
* be the handling callback, all other arguments should be additional parameters
|
||||
* for the handler.
|
||||
* @return void
|
||||
* @throws CakeException
|
||||
*/
|
||||
public function addInputType($type, $handler) {
|
||||
if (!is_array($handler) || !isset($handler[0]) || !is_callable($handler[0])) {
|
||||
throw new CakeException(__d('cake_dev', 'You must give a handler callback.'));
|
||||
}
|
||||
$this->_inputTypeMap[$type] = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter/setter for viewClassMap
|
||||
*
|
||||
* @param array|string $type The type string or array with format `array('type' => 'viewClass')` to map one or more
|
||||
* @param array $viewClass The viewClass to be used for the type without `View` appended
|
||||
* @return array|string Returns viewClass when only string $type is set, else array with viewClassMap
|
||||
*/
|
||||
public function viewClassMap($type = null, $viewClass = null) {
|
||||
if (!$viewClass && is_string($type) && isset($this->_viewClassMap[$type])) {
|
||||
return $this->_viewClassMap[$type];
|
||||
}
|
||||
if (is_string($type)) {
|
||||
$this->_viewClassMap[$type] = $viewClass;
|
||||
} elseif (is_array($type)) {
|
||||
foreach ($type as $key => $value) {
|
||||
$this->viewClassMap($key, $value);
|
||||
}
|
||||
}
|
||||
return $this->_viewClassMap;
|
||||
}
|
||||
|
||||
}
|
626
lib/Cake/Controller/Component/SecurityComponent.php
Normal file
626
lib/Cake/Controller/Component/SecurityComponent.php
Normal file
|
@ -0,0 +1,626 @@
|
|||
<?php
|
||||
/**
|
||||
* Security Component
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 0.10.8.2156
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('String', 'Utility');
|
||||
App::uses('Hash', 'Utility');
|
||||
App::uses('Security', 'Utility');
|
||||
|
||||
/**
|
||||
* The Security Component creates an easy way to integrate tighter security in
|
||||
* your application. It provides methods for various tasks like:
|
||||
*
|
||||
* - Restricting which HTTP methods your application accepts.
|
||||
* - CSRF protection.
|
||||
* - Form tampering protection
|
||||
* - Requiring that SSL be used.
|
||||
* - Limiting cross controller communication.
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html
|
||||
*/
|
||||
class SecurityComponent extends Component {
|
||||
|
||||
/**
|
||||
* The controller method that will be called if this request is black-hole'd
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $blackHoleCallback = null;
|
||||
|
||||
/**
|
||||
* List of controller actions for which a POST request is required
|
||||
*
|
||||
* @var array
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @see SecurityComponent::requirePost()
|
||||
*/
|
||||
public $requirePost = array();
|
||||
|
||||
/**
|
||||
* List of controller actions for which a GET request is required
|
||||
*
|
||||
* @var array
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @see SecurityComponent::requireGet()
|
||||
*/
|
||||
public $requireGet = array();
|
||||
|
||||
/**
|
||||
* List of controller actions for which a PUT request is required
|
||||
*
|
||||
* @var array
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @see SecurityComponent::requirePut()
|
||||
*/
|
||||
public $requirePut = array();
|
||||
|
||||
/**
|
||||
* List of controller actions for which a DELETE request is required
|
||||
*
|
||||
* @var array
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @see SecurityComponent::requireDelete()
|
||||
*/
|
||||
public $requireDelete = array();
|
||||
|
||||
/**
|
||||
* List of actions that require an SSL-secured connection
|
||||
*
|
||||
* @var array
|
||||
* @see SecurityComponent::requireSecure()
|
||||
*/
|
||||
public $requireSecure = array();
|
||||
|
||||
/**
|
||||
* List of actions that require a valid authentication key
|
||||
*
|
||||
* @var array
|
||||
* @see SecurityComponent::requireAuth()
|
||||
*/
|
||||
public $requireAuth = array();
|
||||
|
||||
/**
|
||||
* Controllers from which actions of the current controller are allowed to receive
|
||||
* requests.
|
||||
*
|
||||
* @var array
|
||||
* @see SecurityComponent::requireAuth()
|
||||
*/
|
||||
public $allowedControllers = array();
|
||||
|
||||
/**
|
||||
* Actions from which actions of the current controller are allowed to receive
|
||||
* requests.
|
||||
*
|
||||
* @var array
|
||||
* @see SecurityComponent::requireAuth()
|
||||
*/
|
||||
public $allowedActions = array();
|
||||
|
||||
/**
|
||||
* Deprecated property, superseded by unlockedFields.
|
||||
*
|
||||
* @var array
|
||||
* @deprecated
|
||||
* @see SecurityComponent::$unlockedFields
|
||||
*/
|
||||
public $disabledFields = array();
|
||||
|
||||
/**
|
||||
* Form fields to exclude from POST validation. Fields can be unlocked
|
||||
* either in the Component, or with FormHelper::unlockField().
|
||||
* Fields that have been unlocked are not required to be part of the POST
|
||||
* and hidden unlocked fields do not have their values checked.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $unlockedFields = array();
|
||||
|
||||
/**
|
||||
* Actions to exclude from CSRF and POST validation checks.
|
||||
* Other checks like requireAuth(), requireSecure(),
|
||||
* requirePost(), requireGet() etc. will still be applied.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $unlockedActions = array();
|
||||
|
||||
/**
|
||||
* Whether to validate POST data. Set to false to disable for data coming from 3rd party
|
||||
* services, etc.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $validatePost = true;
|
||||
|
||||
/**
|
||||
* Whether to use CSRF protected forms. Set to false to disable CSRF protection on forms.
|
||||
*
|
||||
* @var bool
|
||||
* @see http://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
|
||||
* @see SecurityComponent::$csrfExpires
|
||||
*/
|
||||
public $csrfCheck = true;
|
||||
|
||||
/**
|
||||
* The duration from when a CSRF token is created that it will expire on.
|
||||
* Each form/page request will generate a new token that can only be submitted once unless
|
||||
* it expires. Can be any value compatible with strtotime()
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $csrfExpires = '+30 minutes';
|
||||
|
||||
/**
|
||||
* Controls whether or not CSRF tokens are use and burn. Set to false to not generate
|
||||
* new tokens on each request. One token will be reused until it expires. This reduces
|
||||
* the chances of users getting invalid requests because of token consumption.
|
||||
* It has the side effect of making CSRF less secure, as tokens are reusable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $csrfUseOnce = true;
|
||||
|
||||
/**
|
||||
* Control the number of tokens a user can keep open.
|
||||
* This is most useful with one-time use tokens. Since new tokens
|
||||
* are created on each request, having a hard limit on the number of open tokens
|
||||
* can be useful in controlling the size of the session file.
|
||||
*
|
||||
* When tokens are evicted, the oldest ones will be removed, as they are the most likely
|
||||
* to be dead/expired.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $csrfLimit = 100;
|
||||
|
||||
/**
|
||||
* Other components used by the Security component
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $components = array('Session');
|
||||
|
||||
/**
|
||||
* Holds the current action of the controller
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_action = null;
|
||||
|
||||
/**
|
||||
* Request object
|
||||
*
|
||||
* @var CakeRequest
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/**
|
||||
* Component startup. All security checking happens here.
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @return void
|
||||
*/
|
||||
public function startup(Controller $controller) {
|
||||
$this->request = $controller->request;
|
||||
$this->_action = $this->request->params['action'];
|
||||
$this->_methodsRequired($controller);
|
||||
$this->_secureRequired($controller);
|
||||
$this->_authRequired($controller);
|
||||
|
||||
$isPost = $this->request->is(array('post', 'put'));
|
||||
$isNotRequestAction = (
|
||||
!isset($controller->request->params['requested']) ||
|
||||
$controller->request->params['requested'] != 1
|
||||
);
|
||||
|
||||
if ($this->_action === $this->blackHoleCallback) {
|
||||
return $this->blackHole($controller, 'auth');
|
||||
}
|
||||
|
||||
if (!in_array($this->_action, (array)$this->unlockedActions) && $isPost && $isNotRequestAction) {
|
||||
if ($this->validatePost && $this->_validatePost($controller) === false) {
|
||||
return $this->blackHole($controller, 'auth');
|
||||
}
|
||||
if ($this->csrfCheck && $this->_validateCsrf($controller) === false) {
|
||||
return $this->blackHole($controller, 'csrf');
|
||||
}
|
||||
}
|
||||
$this->generateToken($controller->request);
|
||||
if ($isPost && is_array($controller->request->data)) {
|
||||
unset($controller->request->data['_Token']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a POST request, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requirePost
|
||||
*/
|
||||
public function requirePost() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Post', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a GET request, or empty for all actions
|
||||
*
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @return void
|
||||
*/
|
||||
public function requireGet() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Get', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a PUT request, or empty for all actions
|
||||
*
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @return void
|
||||
*/
|
||||
public function requirePut() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Put', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a DELETE request, or empty for all actions
|
||||
*
|
||||
* @deprecated Use CakeRequest::onlyAllow() instead.
|
||||
* @return void
|
||||
*/
|
||||
public function requireDelete() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Delete', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a request that is SSL-secured, or empty for all actions
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requireSecure
|
||||
*/
|
||||
public function requireSecure() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Secure', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require whitelisted form submissions.
|
||||
*
|
||||
* Adding actions with this method will enforce the restrictions
|
||||
* set in SecurityComponent::$allowedControllers and
|
||||
* SecurityComponent::$allowedActions.
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#SecurityComponent::requireAuth
|
||||
*/
|
||||
public function requireAuth() {
|
||||
$args = func_get_args();
|
||||
$this->_requireMethod('Auth', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Black-hole an invalid request with a 400 error or custom callback. If SecurityComponent::$blackHoleCallback
|
||||
* is specified, it will use this callback by executing the method indicated in $error
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @param string $error Error method
|
||||
* @return mixed If specified, controller blackHoleCallback's response, or no return otherwise
|
||||
* @see SecurityComponent::$blackHoleCallback
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#handling-blackhole-callbacks
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function blackHole(Controller $controller, $error = '') {
|
||||
if (!$this->blackHoleCallback) {
|
||||
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
|
||||
}
|
||||
return $this->_callback($controller, $this->blackHoleCallback, array($error));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the actions that require a $method HTTP request, or empty for all actions
|
||||
*
|
||||
* @param string $method The HTTP method to assign controller actions to
|
||||
* @param array $actions Controller actions to set the required HTTP method to.
|
||||
* @return void
|
||||
*/
|
||||
protected function _requireMethod($method, $actions = array()) {
|
||||
if (isset($actions[0]) && is_array($actions[0])) {
|
||||
$actions = $actions[0];
|
||||
}
|
||||
$this->{'require' . $method} = (empty($actions)) ? array('*') : $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if HTTP methods are required
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @return bool true if $method is required
|
||||
*/
|
||||
protected function _methodsRequired(Controller $controller) {
|
||||
foreach (array('Post', 'Get', 'Put', 'Delete') as $method) {
|
||||
$property = 'require' . $method;
|
||||
if (is_array($this->$property) && !empty($this->$property)) {
|
||||
$require = $this->$property;
|
||||
if (in_array($this->_action, $require) || $this->$property === array('*')) {
|
||||
if (!$this->request->is($method)) {
|
||||
if (!$this->blackHole($controller, $method)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if access requires secure connection
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @return bool true if secure connection required
|
||||
*/
|
||||
protected function _secureRequired(Controller $controller) {
|
||||
if (is_array($this->requireSecure) && !empty($this->requireSecure)) {
|
||||
$requireSecure = $this->requireSecure;
|
||||
|
||||
if (in_array($this->_action, $requireSecure) || $this->requireSecure === array('*')) {
|
||||
if (!$this->request->is('ssl')) {
|
||||
if (!$this->blackHole($controller, 'secure')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if authentication is required
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @return bool true if authentication required
|
||||
*/
|
||||
protected function _authRequired(Controller $controller) {
|
||||
if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($this->request->data)) {
|
||||
$requireAuth = $this->requireAuth;
|
||||
|
||||
if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth === array('*')) {
|
||||
if (!isset($controller->request->data['_Token'])) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tData = $this->Session->read('_Token');
|
||||
|
||||
if (
|
||||
!empty($tData['allowedControllers']) &&
|
||||
!in_array($this->request->params['controller'], $tData['allowedControllers']) ||
|
||||
!empty($tData['allowedActions']) &&
|
||||
!in_array($this->request->params['action'], $tData['allowedActions'])
|
||||
) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate submitted form
|
||||
*
|
||||
* @param Controller $controller Instantiating controller
|
||||
* @return bool true if submitted form is valid
|
||||
*/
|
||||
protected function _validatePost(Controller $controller) {
|
||||
if (empty($controller->request->data)) {
|
||||
return true;
|
||||
}
|
||||
$data = $controller->request->data;
|
||||
|
||||
if (!isset($data['_Token']) || !isset($data['_Token']['fields']) || !isset($data['_Token']['unlocked'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$locked = '';
|
||||
$check = $controller->request->data;
|
||||
$token = urldecode($check['_Token']['fields']);
|
||||
$unlocked = urldecode($check['_Token']['unlocked']);
|
||||
|
||||
if (strpos($token, ':')) {
|
||||
list($token, $locked) = explode(':', $token, 2);
|
||||
}
|
||||
unset($check['_Token']);
|
||||
|
||||
$locked = explode('|', $locked);
|
||||
$unlocked = explode('|', $unlocked);
|
||||
|
||||
$lockedFields = array();
|
||||
$fields = Hash::flatten($check);
|
||||
$fieldList = array_keys($fields);
|
||||
$multi = array();
|
||||
|
||||
foreach ($fieldList as $i => $key) {
|
||||
if (preg_match('/(\.\d+){1,10}$/', $key)) {
|
||||
$multi[$i] = preg_replace('/(\.\d+){1,10}$/', '', $key);
|
||||
unset($fieldList[$i]);
|
||||
}
|
||||
}
|
||||
if (!empty($multi)) {
|
||||
$fieldList += array_unique($multi);
|
||||
}
|
||||
|
||||
$unlockedFields = array_unique(
|
||||
array_merge((array)$this->disabledFields, (array)$this->unlockedFields, $unlocked)
|
||||
);
|
||||
|
||||
foreach ($fieldList as $i => $key) {
|
||||
$isLocked = (is_array($locked) && in_array($key, $locked));
|
||||
|
||||
if (!empty($unlockedFields)) {
|
||||
foreach ($unlockedFields as $off) {
|
||||
$off = explode('.', $off);
|
||||
$field = array_values(array_intersect(explode('.', $key), $off));
|
||||
$isUnlocked = ($field === $off);
|
||||
if ($isUnlocked) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isUnlocked || $isLocked) {
|
||||
unset($fieldList[$i]);
|
||||
if ($isLocked) {
|
||||
$lockedFields[$key] = $fields[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
sort($unlocked, SORT_STRING);
|
||||
sort($fieldList, SORT_STRING);
|
||||
ksort($lockedFields, SORT_STRING);
|
||||
|
||||
$fieldList += $lockedFields;
|
||||
$unlocked = implode('|', $unlocked);
|
||||
$hashParts = array(
|
||||
$this->request->here(),
|
||||
serialize($fieldList),
|
||||
$unlocked,
|
||||
Configure::read('Security.salt')
|
||||
);
|
||||
$check = Security::hash(implode('', $hashParts), 'sha1');
|
||||
return ($token === $check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually add CSRF token information into the provided request object.
|
||||
*
|
||||
* @param CakeRequest $request The request object to add into.
|
||||
* @return bool
|
||||
*/
|
||||
public function generateToken(CakeRequest $request) {
|
||||
if (isset($request->params['requested']) && $request->params['requested'] === 1) {
|
||||
if ($this->Session->check('_Token')) {
|
||||
$request->params['_Token'] = $this->Session->read('_Token');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$authKey = Security::generateAuthKey();
|
||||
$token = array(
|
||||
'key' => $authKey,
|
||||
'allowedControllers' => $this->allowedControllers,
|
||||
'allowedActions' => $this->allowedActions,
|
||||
'unlockedFields' => array_merge($this->disabledFields, $this->unlockedFields),
|
||||
'csrfTokens' => array()
|
||||
);
|
||||
|
||||
$tokenData = array();
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tokenData = $this->Session->read('_Token');
|
||||
if (!empty($tokenData['csrfTokens']) && is_array($tokenData['csrfTokens'])) {
|
||||
$token['csrfTokens'] = $this->_expireTokens($tokenData['csrfTokens']);
|
||||
}
|
||||
}
|
||||
if ($this->csrfUseOnce || empty($token['csrfTokens'])) {
|
||||
$token['csrfTokens'][$authKey] = strtotime($this->csrfExpires);
|
||||
}
|
||||
if (!$this->csrfUseOnce) {
|
||||
$csrfTokens = array_keys($token['csrfTokens']);
|
||||
$authKey = $csrfTokens[0];
|
||||
$token['key'] = $authKey;
|
||||
$token['csrfTokens'][$authKey] = strtotime($this->csrfExpires);
|
||||
}
|
||||
$this->Session->write('_Token', $token);
|
||||
$request->params['_Token'] = array(
|
||||
'key' => $token['key'],
|
||||
'unlockedFields' => $token['unlockedFields']
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the controller has a CSRF token in the POST data
|
||||
* and that the token is legit/not expired. If the token is valid
|
||||
* it will be removed from the list of valid tokens.
|
||||
*
|
||||
* @param Controller $controller A controller to check
|
||||
* @return bool Valid csrf token.
|
||||
*/
|
||||
protected function _validateCsrf(Controller $controller) {
|
||||
$token = $this->Session->read('_Token');
|
||||
$requestToken = $controller->request->data('_Token.key');
|
||||
if (isset($token['csrfTokens'][$requestToken]) && $token['csrfTokens'][$requestToken] >= time()) {
|
||||
if ($this->csrfUseOnce) {
|
||||
$this->Session->delete('_Token.csrfTokens.' . $requestToken);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire CSRF nonces and remove them from the valid tokens.
|
||||
* Uses a simple timeout to expire the tokens.
|
||||
*
|
||||
* @param array $tokens An array of nonce => expires.
|
||||
* @return array An array of nonce => expires.
|
||||
*/
|
||||
protected function _expireTokens($tokens) {
|
||||
$now = time();
|
||||
foreach ($tokens as $nonce => $expires) {
|
||||
if ($expires < $now) {
|
||||
unset($tokens[$nonce]);
|
||||
}
|
||||
}
|
||||
$overflow = count($tokens) - $this->csrfLimit;
|
||||
if ($overflow > 0) {
|
||||
$tokens = array_slice($tokens, $overflow + 1, null, true);
|
||||
}
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a controller callback method
|
||||
*
|
||||
* @param Controller $controller Controller to run callback on
|
||||
* @param string $method Method to execute
|
||||
* @param array $params Parameters to send to method
|
||||
* @return mixed Controller callback method's response
|
||||
* @throws BadRequestException When a the blackholeCallback is not callable.
|
||||
*/
|
||||
protected function _callback(Controller $controller, $method, $params = array()) {
|
||||
if (!is_callable(array($controller, $method))) {
|
||||
throw new BadRequestException(__d('cake_dev', 'The request has been black-holed'));
|
||||
}
|
||||
return call_user_func_array(array(&$controller, $method), empty($params) ? null : $params);
|
||||
}
|
||||
|
||||
}
|
189
lib/Cake/Controller/Component/SessionComponent.php
Normal file
189
lib/Cake/Controller/Component/SessionComponent.php
Normal file
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
/**
|
||||
* SessionComponent. Provides access to Sessions from the Controller layer
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
||||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* For full copyright and license information, please see the LICENSE.txt
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
|
||||
* @link http://cakephp.org CakePHP(tm) Project
|
||||
* @package Cake.Controller.Component
|
||||
* @since CakePHP(tm) v 0.10.0.1232
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
App::uses('Component', 'Controller');
|
||||
App::uses('CakeSession', 'Model/Datasource');
|
||||
|
||||
/**
|
||||
* The CakePHP SessionComponent provides a way to persist client data between
|
||||
* page requests. It acts as a wrapper for the `$_SESSION` as well as providing
|
||||
* convenience methods for several `$_SESSION` related functions.
|
||||
*
|
||||
* @package Cake.Controller.Component
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html
|
||||
* @link http://book.cakephp.org/2.0/en/development/sessions.html
|
||||
*/
|
||||
class SessionComponent extends Component {
|
||||
|
||||
/**
|
||||
* Get / Set the userAgent
|
||||
*
|
||||
* @param string $userAgent Set the userAgent
|
||||
* @return void
|
||||
*/
|
||||
public function userAgent($userAgent = null) {
|
||||
return CakeSession::userAgent($userAgent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to write a value to a session key.
|
||||
*
|
||||
* In your controller: $this->Session->write('Controller.sessKey', 'session value');
|
||||
*
|
||||
* @param string $name The name of the key your are setting in the session.
|
||||
* This should be in a Controller.key format for better organizing
|
||||
* @param string $value The value you want to store in a session.
|
||||
* @return bool Success
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::write
|
||||
*/
|
||||
public function write($name, $value = null) {
|
||||
return CakeSession::write($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to read a session values for a key or return values for all keys.
|
||||
*
|
||||
* In your controller: $this->Session->read('Controller.sessKey');
|
||||
* Calling the method without a param will return all session vars
|
||||
*
|
||||
* @param string $name the name of the session key you want to read
|
||||
* @return mixed value from the session vars
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::read
|
||||
*/
|
||||
public function read($name = null) {
|
||||
return CakeSession::read($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for SessionComponent::del();
|
||||
*
|
||||
* In your controller: $this->Session->delete('Controller.sessKey');
|
||||
*
|
||||
* @param string $name the name of the session key you want to delete
|
||||
* @return bool true is session variable is set and can be deleted, false is variable was not set.
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::delete
|
||||
*/
|
||||
public function delete($name) {
|
||||
return CakeSession::delete($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check if a session variable is set
|
||||
*
|
||||
* In your controller: $this->Session->check('Controller.sessKey');
|
||||
*
|
||||
* @param string $name the name of the session key you want to check
|
||||
* @return bool true is session variable is set, false if not
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::check
|
||||
*/
|
||||
public function check($name) {
|
||||
return CakeSession::check($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the last error in a session.
|
||||
*
|
||||
* In your controller: $this->Session->error();
|
||||
*
|
||||
* @return string Last session error
|
||||
*/
|
||||
public function error() {
|
||||
return CakeSession::error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to set a session variable that can be used to output messages in the view.
|
||||
*
|
||||
* In your controller: $this->Session->setFlash('This has been saved');
|
||||
*
|
||||
* Additional params below can be passed to customize the output, or the Message.[key].
|
||||
* You can also set additional parameters when rendering flash messages. See SessionHelper::flash()
|
||||
* for more information on how to do that.
|
||||
*
|
||||
* @param string $message Message to be flashed
|
||||
* @param string $element Element to wrap flash message in.
|
||||
* @param array $params Parameters to be sent to layout as view variables
|
||||
* @param string $key Message key, default is 'flash'
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#creating-notification-messages
|
||||
*/
|
||||
public function setFlash($message, $element = 'default', $params = array(), $key = 'flash') {
|
||||
CakeSession::write('Message.' . $key, compact('message', 'element', 'params'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to renew a session id
|
||||
*
|
||||
* In your controller: $this->Session->renew();
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function renew() {
|
||||
return CakeSession::renew();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to check for a valid session.
|
||||
*
|
||||
* In your controller: $this->Session->valid();
|
||||
*
|
||||
* @return bool true is session is valid, false is session is invalid
|
||||
*/
|
||||
public function valid() {
|
||||
return CakeSession::valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to destroy sessions
|
||||
*
|
||||
* In your controller: $this->Session->destroy();
|
||||
*
|
||||
* @return void
|
||||
* @link http://book.cakephp.org/2.0/en/core-libraries/components/sessions.html#SessionComponent::destroy
|
||||
*/
|
||||
public function destroy() {
|
||||
return CakeSession::destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get/Set the session id.
|
||||
*
|
||||
* When fetching the session id, the session will be started
|
||||
* if it has not already been started. When setting the session id,
|
||||
* the session will not be started.
|
||||
*
|
||||
* @param string $id Id to use (optional)
|
||||
* @return string The current session id.
|
||||
*/
|
||||
public function id($id = null) {
|
||||
if (empty($id)) {
|
||||
CakeSession::start();
|
||||
}
|
||||
return CakeSession::id($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bool, whether or not the session has been started.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function started() {
|
||||
return CakeSession::started();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue