Http.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\security\auth\adapter;
  9. /**
  10. * The `Http` adapter provides basic and digest authentication based on the HTTP protocol.
  11. * By default, the adapter uses Http Digest based authentication.
  12. * {{{
  13. * Auth::config(array('name' => array('adapter' => 'Http', 'users' => array('gwoo' => 'li3'))))
  14. * }}}
  15. *
  16. * To use Basic authentication, set the `method` to basic.
  17. * {{{
  18. * Auth::config(array('name' => array(
  19. * 'adapter' => 'Http', 'users' => array('gwoo' => 'li3'),
  20. * 'method' => 'basic'
  21. * )))
  22. * }}}
  23. *
  24. * @link http://tools.ietf.org/html/rfc2068#section-14.8
  25. * @see lithium\action\Request
  26. */
  27. class Http extends \lithium\core\Object {
  28. /**
  29. * Dynamic class dependencies.
  30. *
  31. * @var array Associative array of class names & their namespaces.
  32. */
  33. protected $_classes = array(
  34. 'auth' => 'lithium\net\http\Auth'
  35. );
  36. /**
  37. * Setup default configuration options.
  38. *
  39. * @param array $config
  40. * - `method`: default: `digest` options: `basic|digest`
  41. * - `realm`: default: `Protected by Lithium`
  42. * - `users`: the users to permit. key => value pair of username => password
  43. */
  44. public function __construct(array $config = array()) {
  45. $defaults = array(
  46. 'method' => 'digest', 'realm' => basename(LITHIUM_APP_PATH), 'users' => array()
  47. );
  48. parent::__construct($config + $defaults);
  49. }
  50. /**
  51. * Called by the `Auth` class to run an authentication check against the HTTP data using the
  52. * credentials in a data container (a `Request` object), and returns an array of user
  53. * information on success, or `false` on failure.
  54. *
  55. * @param object $request A env container which wraps the authentication credentials used
  56. * by HTTP (usually a `Request` object). See the documentation for this
  57. * class for further details.
  58. * @param array $options Additional configuration options. Not currently implemented in this
  59. * adapter.
  60. * @return array Returns an array containing user information on success, or `false` on failure.
  61. */
  62. public function check($request, array $options = array()) {
  63. $method = "_{$this->_config['method']}";
  64. return $this->{$method}($request);
  65. }
  66. /**
  67. * A pass-through method called by `Auth`. Returns the value of `$data`, which is written to
  68. * a user's session. When implementing a custom adapter, this method may be used to modify or
  69. * reject data before it is written to the session.
  70. *
  71. * @param array $data User data to be written to the session.
  72. * @param array $options Adapter-specific options. Not implemented in the `Form` adapter.
  73. * @return array Returns the value of `$data`.
  74. */
  75. public function set($data, array $options = array()) {
  76. return $data;
  77. }
  78. /**
  79. * Called by `Auth` when a user session is terminated. Not implemented in the `Form` adapter.
  80. *
  81. * @param array $options Adapter-specific options. Not implemented in the `Form` adapter.
  82. * @return void
  83. */
  84. public function clear(array $options = array()) {}
  85. /**
  86. * Handler for HTTP Basic Authentication
  87. *
  88. * @param string $request a `\lithium\action\Request` object
  89. * @return void
  90. */
  91. protected function _basic($request) {
  92. $users = $this->_config['users'];
  93. $username = $request->env('PHP_AUTH_USER');
  94. $auth = $this->_classes['auth'];
  95. $basic = $auth::encode($username, $request->env('PHP_AUTH_PW'));
  96. $encoded = array('response' => null);
  97. if (isset($users[$username])) {
  98. $encoded = $auth::encode($username, $users[$username]);
  99. }
  100. if ($basic['response'] !== $encoded['response']) {
  101. $this->_writeHeader("WWW-Authenticate: Basic realm=\"{$this->_config['realm']}\"");
  102. return;
  103. }
  104. return compact('username', 'password');
  105. }
  106. /**
  107. * Handler for HTTP Digest Authentication
  108. *
  109. * @param string $request a `\lithium\action\Request` object
  110. * @return void
  111. */
  112. protected function _digest($request) {
  113. $username = $password = null;
  114. $auth = $this->_classes['auth'];
  115. $data = $auth::decode($request->env('PHP_AUTH_DIGEST'));
  116. $data['realm'] = $this->_config['realm'];
  117. $data['method'] = $request->method;
  118. $users = $this->_config['users'];
  119. if (!empty($data['username']) && !empty($users[$data['username']])) {
  120. $username = $data['username'];
  121. $password = $users[$data['username']];
  122. }
  123. $encoded = $auth::encode($username, $password, $data);
  124. if ($encoded['response'] !== $data['response']) {
  125. $nonce = uniqid();
  126. $opaque = md5($data['realm']);
  127. $message = "WWW-Authenticate: Digest realm=\"{$data['realm']}\",qop=\"auth\",";
  128. $message .= "nonce=\"{$nonce}\",opaque=\"{$opaque}\"";
  129. $this->_writeHeader($message);
  130. return false;
  131. }
  132. return array('username' => $username, 'password' => $password);
  133. }
  134. /**
  135. * Helper method for writing headers. Mainly used to override the output while testing.
  136. *
  137. * @param string $string the string the send as a header
  138. * @return void
  139. */
  140. protected function _writeHeader($string) {
  141. header($string, true);
  142. }
  143. }
  144. ?>