PageRenderTime 22ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Authentication/src/filters/htpasswd/htpasswd_filter.php

https://github.com/Yannix/zetacomponents
PHP | 250 lines | 99 code | 14 blank | 137 comment | 11 complexity | 8385d02b4459bf9823da97cc72b939f7 MD5 | raw file
  1. <?php
  2. /**
  3. * File containing the ezcAuthenticationHtpasswdFilter class.
  4. *
  5. * Licensed to the Apache Software Foundation (ASF) under one
  6. * or more contributor license agreements. See the NOTICE file
  7. * distributed with this work for additional information
  8. * regarding copyright ownership. The ASF licenses this file
  9. * to you under the Apache License, Version 2.0 (the
  10. * "License"); you may not use this file except in compliance
  11. * with the License. You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing,
  16. * software distributed under the License is distributed on an
  17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18. * KIND, either express or implied. See the License for the
  19. * specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  23. * @filesource
  24. * @package Authentication
  25. * @version //autogen//
  26. */
  27. /**
  28. * Filter to authenticate against an Unix htpasswd file.
  29. *
  30. * It supports files created with the htpasswd command options
  31. * -m (MD5 encryption - different than the PHP md5() function)
  32. * -d (CRYPT encryption)
  33. * -s (SHA encryption)
  34. * -p (plain text)
  35. *
  36. * The encryption used for the password field in the file will be detected
  37. * automatically.
  38. *
  39. * The password property can be specified as plain text or in encrypted form,
  40. * depending on the option 'plain' in the ezcAuthenticationHtpasswdOptions object
  41. * used as options.
  42. *
  43. * Example:
  44. * <code>
  45. * $credentials = new ezcAuthenticationPasswordCredentials( 'jan.modaal', 'b1b3773a05c0ed0176787a4f1574ff0075f7521e' );
  46. * $authentication = new ezcAuthentication( $credentials );
  47. * $authentication->session = new ezcAuthenticationSession();
  48. * $authentication->addFilter( new ezcAuthenticationHtpasswdFilter( '/etc/htpasswd' ) );
  49. * // add other filters if needed
  50. * if ( !$authentication->run() )
  51. * {
  52. * // authentication did not succeed, so inform the user
  53. * $status = $authentication->getStatus();
  54. * $err = array(
  55. * 'ezcAuthenticationHtpasswdFilter' => array(
  56. * ezcAuthenticationHtpasswdFilter::STATUS_USERNAME_INCORRECT => 'Incorrect username',
  57. * ezcAuthenticationHtpasswdFilter::STATUS_PASSWORD_INCORRECT => 'Incorrect password'
  58. * )
  59. * );
  60. * foreach ( $status as $line )
  61. * {
  62. * list( $key, $value ) = each( $line );
  63. * echo $err[$key][$value] . "\n";
  64. * }
  65. * }
  66. * else
  67. * {
  68. * // authentication succeeded, so allow the user to see his content
  69. * }
  70. * </code>
  71. *
  72. * @property string $file
  73. * The path and file name of the htpasswd file to use.
  74. *
  75. * @package Authentication
  76. * @version //autogen//
  77. * @mainclass
  78. */
  79. class ezcAuthenticationHtpasswdFilter extends ezcAuthenticationFilter
  80. {
  81. /**
  82. * Username is not found in the htpasswd file.
  83. */
  84. const STATUS_USERNAME_INCORRECT = 1;
  85. /**
  86. * Password is incorrect.
  87. */
  88. const STATUS_PASSWORD_INCORRECT = 2;
  89. /**
  90. * Holds the properties of this class.
  91. *
  92. * @var array(string=>mixed)
  93. */
  94. private $properties = array();
  95. /**
  96. * Creates a new object of this class.
  97. *
  98. * @throws ezcBaseValueException
  99. * if the value provided is not correct for the property $file
  100. * @throws ezcBaseFileNotFoundException
  101. * if $file does not exist
  102. * @throws ezcBaseFilePermissionException
  103. * if $file cannot be opened for reading
  104. * @param string $file The path and file name of the htpasswd file to use
  105. * @param ezcAuthenticationHtpasswdOptions $options Options for this class
  106. */
  107. public function __construct( $file, ezcAuthenticationHtpasswdOptions $options = null )
  108. {
  109. $this->file = $file;
  110. $this->options = ( $options === null ) ? new ezcAuthenticationHtpasswdOptions() : $options;
  111. }
  112. /**
  113. * Sets the property $name to $value.
  114. *
  115. * @throws ezcBasePropertyNotFoundException
  116. * if the property $name does not exist
  117. * @throws ezcBaseValueException
  118. * if $value is not correct for the property $name
  119. * @throws ezcBaseFileNotFoundException
  120. * if the $value file does not exist
  121. * @throws ezcBaseFilePermissionException
  122. * if the $value file cannot be opened for reading
  123. * @param string $name The name of the property to set
  124. * @param mixed $value The new value of the property
  125. * @ignore
  126. */
  127. public function __set( $name, $value )
  128. {
  129. switch ( $name )
  130. {
  131. case 'file':
  132. if ( !is_string( $value ) )
  133. {
  134. throw new ezcBaseValueException( $name, $value, 'string' );
  135. }
  136. if ( !file_exists( $value ) )
  137. {
  138. throw new ezcBaseFileNotFoundException( $value );
  139. }
  140. if ( !is_readable( $value ) )
  141. {
  142. throw new ezcBaseFilePermissionException( $value, ezcBaseFileException::READ );
  143. }
  144. $this->properties[$name] = $value;
  145. break;
  146. default:
  147. throw new ezcBasePropertyNotFoundException( $name );
  148. }
  149. }
  150. /**
  151. * Returns the value of the property $name.
  152. *
  153. * @throws ezcBasePropertyNotFoundException
  154. * if the property $name does not exist
  155. * @param string $name The name of the property for which to return the value
  156. * @return mixed
  157. * @ignore
  158. */
  159. public function __get( $name )
  160. {
  161. switch ( $name )
  162. {
  163. case 'file':
  164. return $this->properties[$name];
  165. default:
  166. throw new ezcBasePropertyNotFoundException( $name );
  167. }
  168. }
  169. /**
  170. * Returns true if the property $name is set, otherwise false.
  171. *
  172. * @param string $name The name of the property to test if it is set
  173. * @return bool
  174. * @ignore
  175. */
  176. public function __isset( $name )
  177. {
  178. switch ( $name )
  179. {
  180. case 'file':
  181. return isset( $this->properties[$name] );
  182. default:
  183. return false;
  184. }
  185. }
  186. /**
  187. * Runs the filter and returns a status code when finished.
  188. *
  189. * @param ezcAuthenticationPasswordCredentials $credentials Authentication credentials
  190. * @return int
  191. */
  192. public function run( $credentials )
  193. {
  194. $fh = fopen( $this->file, 'r' );
  195. $found = false;
  196. while ( $line = fgets( $fh ) )
  197. {
  198. if ( substr( $line, 0, strlen( $credentials->id ) + 1 ) === $credentials->id . ':' )
  199. {
  200. $found = true;
  201. break;
  202. }
  203. }
  204. fclose( $fh );
  205. if ( $found )
  206. {
  207. $parts = explode( ':', $line );
  208. $hashFromFile = trim( $parts[1] );
  209. if ( substr( $hashFromFile, 0, 6 ) === '$apr1$' )
  210. {
  211. $password = ( $this->options->plain ) ? ezcAuthenticationMath::apr1( $credentials->password, $hashFromFile ) :
  212. '$apr1$' . $credentials->password;
  213. }
  214. elseif ( substr( $hashFromFile, 0, 5 ) === '{SHA}' )
  215. {
  216. $password = ( $this->options->plain ) ? '{SHA}' . base64_encode( pack( 'H40', sha1( $credentials->password ) ) ) :
  217. '{SHA}' . $credentials->password;
  218. }
  219. else
  220. {
  221. $password = ( $this->options->plain ) ? crypt( $credentials->password, $hashFromFile ) :
  222. $credentials->password;
  223. }
  224. if ( $password === $hashFromFile )
  225. {
  226. return self::STATUS_OK;
  227. }
  228. else
  229. {
  230. return self::STATUS_PASSWORD_INCORRECT;
  231. }
  232. }
  233. return self::STATUS_USERNAME_INCORRECT;
  234. }
  235. }
  236. ?>