MasterPasswordBehavior.php 3.9 KB

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