MasterPasswordBehavior.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. App::uses('ModelBehavior', 'Model');
  3. /**
  4. * MasterPassword Behavior for admin views
  5. *
  6. * Uses
  7. * - Tools.Hash Shell to hash password
  8. * - master_password element of Tools plugin for Form input
  9. *
  10. * Usage:
  11. * In the controller:
  12. * $this->ModelName->Behaviors->load('Tools.MasterPassword');
  13. * In the view:
  14. * echo $this->element('master_password', array(), array('plugin'=>'tools'));
  15. * Put this into your private configs:
  16. * Configure::write('MasterPassword.password', 'your_hashed_pwd_string');
  17. * You can also use an array to store multiple passwords
  18. *
  19. * Note:
  20. * sha1 is the default hashing algorithm
  21. *
  22. * Use Configure::write('MasterPassword.password', false) to deactivate
  23. *
  24. * Copyright 2011, dereuromark (http://www.dereuromark.de)
  25. *
  26. * @author Mark Scherer
  27. * @link http://github.com/dereuromark/
  28. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  29. */
  30. /**
  31. * 2011-12-22 ms
  32. */
  33. class MasterPasswordBehavior extends ModelBehavior {
  34. protected $_defaults = array(
  35. 'message' => 'Incorrect Master Password',
  36. 'field' => 'master_pwd',
  37. 'model' => null,
  38. 'before' => 'validate',
  39. 'hash' => 'sha1',
  40. 'salt' => false, //TODO: maybe allow to use core salt for additional security?
  41. 'log' => false //TODO: log the usage of pwds to a log file `master_password`
  42. );
  43. public function setup(Model $Model, $settings = array()) {
  44. if (!isset($this->settings[$Model->alias])) {
  45. $this->settings[$Model->alias] = $this->_defaults;
  46. }
  47. $this->settings[$Model->alias] = array_merge($this->settings[$Model->alias], is_array($settings) ? $settings : array());
  48. # deactivate dynamically
  49. if (Configure::read('MasterPassword.password') === false) {
  50. $this->settings[$Model->alias]['before'] = '';
  51. }
  52. }
  53. public function beforeValidate(Model $Model) {
  54. $return = parent::beforeValidate($Model);
  55. if ($this->settings[$Model->alias]['before'] == 'validate') {
  56. # we dont want to return the value, because other fields might then not be validated
  57. # (save will not continue with errors, anyway)
  58. $this->confirm($Model, $return);
  59. }
  60. return $return;
  61. }
  62. public function beforeSave(Model $Model) {
  63. $return = parent::beforeSave($Model);
  64. if ($this->settings[$Model->alias]['before'] == 'save') {
  65. return $this->confirm($Model, $return);
  66. }
  67. return $return;
  68. }
  69. /**
  70. * Run before a model is saved, used...
  71. *
  72. * @param object $Model Model about to be saved.
  73. * @return boolean true if save should proceed, false otherwise
  74. * @access public
  75. */
  76. public function confirm(Model $Model, $return = true) {
  77. $field = $this->settings[$Model->alias]['field'];
  78. $message = $this->settings[$Model->alias]['message'];
  79. if (!$this->isAuthorized($Model, $field)) {
  80. $Model->invalidate($field, $message);
  81. return false;
  82. }
  83. return $return;
  84. }
  85. /**
  86. * checks a string against the stored hash values of master passwords
  87. * @param string $pwd: plain password string (not hashed etc)
  88. * @return bool $success
  89. * 2011-12-22 ms
  90. */
  91. public function isAuthorized(Model $Model, $field) {
  92. if (empty($Model->data[$Model->alias][$field])) {
  93. return false;
  94. }
  95. $masterPwds = (array)Configure::read('MasterPassword.password');
  96. $pwd = $this->_hash($Model->data[$Model->alias][$field], $this->settings[$Model->alias]['hash'], $this->settings[$Model->alias]['salt']);
  97. foreach ($masterPwds as $masterPwd) {
  98. if ($masterPwd === $pwd) {
  99. return true;
  100. }
  101. }
  102. return false;
  103. }
  104. /**
  105. * @retur string $hash or FALSE on failure
  106. */
  107. protected function _hash($string, $algorithm, $salt) {
  108. if ($salt) {
  109. if (is_string($salt)) {
  110. $string = $salt . $string;
  111. } else {
  112. $string = Configure::read('Security.salt') . $string;
  113. }
  114. }
  115. if ($algorithm == 'sha1') {
  116. return sha1($string);
  117. }
  118. if ($algorithm == 'md5') {
  119. return md5($string);
  120. }
  121. # mcrypt installed?
  122. if (function_exists('hash') && in_array($algorithm, hash_algos())) {
  123. return hash($algorithm, $string);
  124. }
  125. trigger_error('Hash method not available');
  126. return false;
  127. }
  128. }