ElggPAM.php 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. <?php
  2. /**
  3. * \ElggPAM Pluggable Authentication Module
  4. *
  5. * @package Elgg.Core
  6. * @subpackage Authentication
  7. */
  8. class ElggPAM {
  9. /**
  10. * @var string PAM policy type: user, api or plugin-defined policies
  11. */
  12. protected $policy;
  13. /**
  14. * @var array Failure mesages
  15. */
  16. protected $messages;
  17. /**
  18. * \ElggPAM constructor
  19. *
  20. * @param string $policy PAM policy type: user, api, or plugin-defined policies
  21. */
  22. public function __construct($policy) {
  23. $this->policy = $policy;
  24. $this->messages = array('sufficient' => array(), 'required' => array());
  25. }
  26. /**
  27. * Authenticate a set of credentials against a policy
  28. * This function will process all registered PAM handlers or stop when the first
  29. * handler fails. A handler fails by either returning false or throwing an
  30. * exception. The advantage of throwing an exception is that it returns a message
  31. * that can be passed to the user. The processing order of the handlers is
  32. * determined by the order that they were registered.
  33. *
  34. * If $credentials are provided, the PAM handler should authenticate using the
  35. * provided credentials. If not, then credentials should be prompted for or
  36. * otherwise retrieved (eg from the HTTP header or $_SESSION).
  37. *
  38. * @param array $credentials Credentials array dependant on policy type
  39. * @return bool
  40. */
  41. public function authenticate($credentials = array()) {
  42. global $_PAM_HANDLERS;
  43. if (!isset($_PAM_HANDLERS[$this->policy]) ||
  44. !is_array($_PAM_HANDLERS[$this->policy])) {
  45. return false;
  46. }
  47. $authenticated = false;
  48. foreach ($_PAM_HANDLERS[$this->policy] as $v) {
  49. $handler = $v->handler;
  50. if (!is_callable($handler)) {
  51. continue;
  52. }
  53. /* @var callable $handler */
  54. $importance = $v->importance;
  55. try {
  56. // Execute the handler
  57. // @todo don't assume $handler is a global function
  58. $result = call_user_func($handler, $credentials);
  59. if ($result) {
  60. $authenticated = true;
  61. } elseif ($result === false) {
  62. if ($importance == 'required') {
  63. $this->messages['required'][] = "$handler:failed";
  64. return false;
  65. } else {
  66. $this->messages['sufficient'][] = "$handler:failed";
  67. }
  68. }
  69. } catch (Exception $e) {
  70. if ($importance == 'required') {
  71. $this->messages['required'][] = $e->getMessage();
  72. return false;
  73. } else {
  74. $this->messages['sufficient'][] = $e->getMessage();
  75. }
  76. }
  77. }
  78. return $authenticated;
  79. }
  80. /**
  81. * Get a failure message to display to user
  82. *
  83. * @return string
  84. */
  85. public function getFailureMessage() {
  86. $message = _elgg_services()->translator->translate('auth:nopams');
  87. if (!empty($this->messages['required'])) {
  88. $message = $this->messages['required'][0];
  89. } elseif (!empty($this->messages['sufficient'])) {
  90. $message = $this->messages['sufficient'][0];
  91. }
  92. return _elgg_services()->hooks->trigger('fail', 'auth', $this->messages, $message);
  93. }
  94. }