mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2025-01-31 09:06:17 +00:00
Adding SecurityComponent::requireLogin() - Supports basic and digest HTTP authentication, for Ticket #571
git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@3120 3807eeeb-6ff5-0310-8944-8be069107fe0
This commit is contained in:
parent
96ce786fe7
commit
06c626c113
1 changed files with 214 additions and 59 deletions
|
@ -36,8 +36,7 @@
|
|||
* @package cake
|
||||
* @subpackage cake.cake.libs.controller.components
|
||||
*/
|
||||
class SecurityComponent extends Object
|
||||
{
|
||||
class SecurityComponent extends Object {
|
||||
|
||||
var $Security = null;
|
||||
|
||||
|
@ -47,6 +46,12 @@ class SecurityComponent extends Object
|
|||
|
||||
var $requireAuth = array();
|
||||
|
||||
var $requireLogin = array();
|
||||
|
||||
var $loginOptions = array();
|
||||
|
||||
var $loginUsers = array();
|
||||
|
||||
var $allowedControllers = array();
|
||||
|
||||
var $allowedActions = array();
|
||||
|
@ -57,65 +62,83 @@ class SecurityComponent extends Object
|
|||
* Security class constructor
|
||||
*
|
||||
*/
|
||||
function __construct ()
|
||||
{
|
||||
function __construct () {
|
||||
$this->Security = Security::getInstance();
|
||||
}
|
||||
|
||||
function startup(&$controller) {
|
||||
|
||||
function startup(&$controller)
|
||||
{
|
||||
if (is_array($this->requirePost) && !empty($this->requirePost))
|
||||
{
|
||||
if (in_array($controller->action, $this->requirePost))
|
||||
{
|
||||
if (!$this->RequestHandler->isPost())
|
||||
{
|
||||
if (!$this->blackHole($controller))
|
||||
{
|
||||
// Check requirePost
|
||||
if (is_array($this->requirePost) && !empty($this->requirePost)) {
|
||||
if (in_array($controller->action, $this->requirePost) || $this->requirePost == array('*')) {
|
||||
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
if (!$this->blackHole($controller, 'post')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($controller->params['form']))
|
||||
{
|
||||
if (in_array($controller->action, $this->requireAuth))
|
||||
{
|
||||
if (!isset($controller->params['data']['_Token']))
|
||||
{
|
||||
if (!$this->blackHole($controller))
|
||||
{
|
||||
// Check requireAuth
|
||||
if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($controller->params['form'])) {
|
||||
if (in_array($controller->action, $this->requireAuth) || $this->requireAuth == array('*')) {
|
||||
|
||||
if (!isset($controller->params['data']['_Token'])) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$token = $controller->params['data']['_Token']['key'];
|
||||
|
||||
if ($this->Session->check('_Token'))
|
||||
{
|
||||
if ($this->Session->check('_Token')) {
|
||||
$tData = $this->Session->read('_Token');
|
||||
if (!(intval($tData['expires']) > strtotime('now')) || $tData['key'] !== $token)
|
||||
{
|
||||
if (!$this->blackHole($controller))
|
||||
{
|
||||
if (!(intval($tData['expires']) > strtotime('now')) || $tData['key'] !== $token) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!empty($tData['allowedControllers']) && !in_array($controller->params['controller'], $tData['allowedControllers']) ||!empty($tData['allowedActions']) && !in_array($controller->params['action'], $tData['allowedActions']))
|
||||
{
|
||||
if (!$this->blackHole($controller))
|
||||
{
|
||||
if (!empty($tData['allowedControllers']) && !in_array($controller->params['controller'], $tData['allowedControllers']) ||!empty($tData['allowedActions']) && !in_array($controller->params['action'], $tData['allowedActions'])) {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$this->blackHole($controller, 'auth')) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$this->blackHole($controller))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check requireLogin
|
||||
if (is_array($this->requireLogin) && !empty($this->requireLogin)) {
|
||||
if (in_array($controller->action, $this->requireLogin) || $this->requireLogin = array('*')) {
|
||||
|
||||
if (!isset($this->loginOptions['type'])) {
|
||||
$this->loginOptions['type'] = '';
|
||||
}
|
||||
$login = $this->loginCredentials($this->loginOptions['type']);
|
||||
if ($login == null) {
|
||||
// User hasn't been authenticated yet
|
||||
header($this->loginRequest());
|
||||
if (isset($this->loginOptions['prompt'])) {
|
||||
$this->__callback($controller, $this->loginOptions['prompt']);
|
||||
} else {
|
||||
$this->blackHole($controller, 'login');
|
||||
}
|
||||
} else {
|
||||
if (isset($this->loginOptions['login'])) {
|
||||
$this->__callback($controller, $this->loginOptions['login'], array($login));
|
||||
} else {
|
||||
if (low($this->loginOptions['type']) == 'digest') {
|
||||
// Do digest authentication
|
||||
} else {
|
||||
if (!(in_array($login[0], array_keys($this->loginUsers)) && $this->loginUsers[$login[0]] == $login[1])) {
|
||||
$this->blackHole($controller, 'login');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,44 +147,176 @@ class SecurityComponent extends Object
|
|||
// Add auth key for new form posts
|
||||
$authKey = Security::generateAuthKey();
|
||||
$expires = strtotime('+'.Security::inactiveMins().' minutes');
|
||||
$token = array('key' => $authKey,
|
||||
'expires' => $expires,
|
||||
'allowedControllers' => $this->allowedControllers,
|
||||
'allowedActions' => $this->allowedActions);
|
||||
$token = array(
|
||||
'key' => $authKey,
|
||||
'expires' => $expires,
|
||||
'allowedControllers' => $this->allowedControllers,
|
||||
'allowedActions' => $this->allowedActions
|
||||
);
|
||||
|
||||
if (!isset($controller->params['data']))
|
||||
{
|
||||
if (!isset($controller->params['data'])) {
|
||||
$controller->params['data'] = array();
|
||||
}
|
||||
$controller->params['_Token'] = $token;
|
||||
$this->Session->write('_Token', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Black-hole an invalid request with a 404 error or custom callback
|
||||
*
|
||||
*/
|
||||
function blackHole(&$controller)
|
||||
{
|
||||
if ($this->blackHoleCallback == null)
|
||||
{
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
function blackHole(&$controller, $error = '') {
|
||||
if ($this->blackHoleCallback == null) {
|
||||
if ($error == 'login') {
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
} else {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
}
|
||||
exit();
|
||||
}
|
||||
elseif (method_exists($controller, $this->blackHoleCallback))
|
||||
{
|
||||
return $controller->{$this->blackHoleCallback}();
|
||||
} elseif (method_exists($controller, $this->blackHoleCallback)) {
|
||||
return $controller->{$this->blackHoleCallback}($error);
|
||||
}
|
||||
}
|
||||
|
||||
function requirePost()
|
||||
{
|
||||
/**
|
||||
* Sets the actions that require a POST request, or empty for all actions
|
||||
*
|
||||
*/
|
||||
function requirePost() {
|
||||
$this->requirePost = func_get_args();
|
||||
if (empty($this->requirePost)) {
|
||||
$this->requirePost = array('*');
|
||||
}
|
||||
}
|
||||
|
||||
function requireAuth()
|
||||
{
|
||||
/**
|
||||
* Sets the actions that require an authenticated request, or empty for all actions
|
||||
*
|
||||
*/
|
||||
function requireAuth() {
|
||||
$this->requireAuth = func_get_args();
|
||||
if (empty($this->requireAuth)) {
|
||||
$this->requireAuth = array('*');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the actions that require an HTTP-authenticated request, or empty for all actions
|
||||
*
|
||||
*/
|
||||
function requireLogin() {
|
||||
$args = func_get_args();
|
||||
foreach ($args as $arg) {
|
||||
if (is_array($arg)) {
|
||||
$this->loginOptions = $arg;
|
||||
} else {
|
||||
$this->requireLogin[] = $arg;
|
||||
}
|
||||
}
|
||||
if (empty($this->requireLogin)) {
|
||||
$this->requireLogin = array('*');
|
||||
}
|
||||
if (isset($this->loginOptions['users'])) {
|
||||
$this->loginUsers =& $this->loginOptions['users'];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the login credentials for an HTTP-authenticated request
|
||||
*
|
||||
* @param string $type Either 'basic', 'digest', or empty. If empty, will try both.
|
||||
* @return mixed If successful, returns an array with login name and password, otherwise null.
|
||||
*/
|
||||
function loginCredentials($type = '') {
|
||||
|
||||
if ($type == '' || low($type) == 'basic') {
|
||||
$login = array(env('PHP_AUTH_USER'), env('PHP_AUTH_PW'));
|
||||
if ($login[0] != null) {
|
||||
return $login;
|
||||
}
|
||||
}
|
||||
|
||||
if ($type == '' || low($type) == 'digest') {
|
||||
|
||||
$digest = null;
|
||||
if (version_compare(phpversion(), '5.1') != -1) {
|
||||
$digest = env('PHP_AUTH_DIGEST');
|
||||
|
||||
} elseif (function_exists('apache_request_headers')) {
|
||||
$headers = apache_request_headers();
|
||||
if (isset($headers['Authorization']) && !empty($headers['Authorization'])) {
|
||||
if (substr($headers['Authorization'], 0, 7) == 'Digest ') {
|
||||
$digest = substr($headers['Authorization'], 7);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Server doesn't support digest-auth headers
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($digest == null) {
|
||||
return null;
|
||||
}
|
||||
$data = $this->parseDigestAuthData($digest);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Sets the default login options for an HTTP-authenticated request
|
||||
*
|
||||
*/
|
||||
function __setLoginDefaults(&$options) {
|
||||
if (!isset($options['type']) || empty($options['type'])) {
|
||||
$options['type'] = 'basic';
|
||||
}
|
||||
if (!isset($options['realm']) || empty($options['realm'])) {
|
||||
$options['realm'] = env('SERVER_NAME');
|
||||
}
|
||||
if (!isset($options['qop']) || empty($options['qop'])) {
|
||||
$options['qop'] = 'auth';
|
||||
}
|
||||
if (!isset($options['nonce']) || empty($options['nonce'])) {
|
||||
$options['nonce'] = uniqid();
|
||||
}
|
||||
if (!isset($options['opaque']) || empty($options['opaque'])) {
|
||||
$options['opaque'] = md5($options['realm']);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Generates the text of an HTTP-authentication request header from an array of options
|
||||
*
|
||||
*/
|
||||
function loginRequest($options = array()) {
|
||||
if (empty($options)) {
|
||||
$options = $this->loginOptions;
|
||||
}
|
||||
$this->__setLoginDefaults($options);
|
||||
$data = 'WWW-Authenticate: ' . ucfirst($options['type']);
|
||||
$data .= ' realm="' . $options['realm'] . '"';
|
||||
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* Parses an HTTP digest authentication response, and returns an array of the data,
|
||||
* or null on failure.
|
||||
*
|
||||
*/
|
||||
function parseDigestAuthData($digest) {
|
||||
if (substr($digest, 0, 7) == 'Digest ') {
|
||||
$digest = substr($digest, 7);
|
||||
}
|
||||
|
||||
$keys = array();
|
||||
$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;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
Loading…
Add table
Reference in a new issue