auth.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <?php
  2. /*
  3. Copyright (c) 2009-2017 F3::Factory/Bong Cosca, All rights reserved.
  4. This file is part of the Fat-Free Framework (http://fatfreeframework.com).
  5. This is free software: you can redistribute it and/or modify it under the
  6. terms of the GNU General Public License as published by the Free Software
  7. Foundation, either version 3 of the License, or later.
  8. Fat-Free Framework is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with Fat-Free Framework. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. //! Authorization/authentication plug-in
  16. class Auth {
  17. //@{ Error messages
  18. const
  19. E_LDAP='LDAP connection failure',
  20. E_SMTP='SMTP connection failure';
  21. //@}
  22. protected
  23. //! Auth storage
  24. $storage,
  25. //! Mapper object
  26. $mapper,
  27. //! Storage options
  28. $args;
  29. /**
  30. * Jig storage handler
  31. * @return bool
  32. * @param $id string
  33. * @param $pw string
  34. * @param $realm string
  35. **/
  36. protected function _jig($id,$pw,$realm) {
  37. return (bool)
  38. call_user_func_array(
  39. [$this->mapper,'load'],
  40. [
  41. array_merge(
  42. [
  43. '@'.$this->args['id'].'==? AND '.
  44. '@'.$this->args['pw'].'==?'.
  45. (isset($this->args['realm'])?
  46. (' AND @'.$this->args['realm'].'==?'):''),
  47. $id,$pw
  48. ],
  49. (isset($this->args['realm'])?[$realm]:[])
  50. )
  51. ]
  52. );
  53. }
  54. /**
  55. * MongoDB storage handler
  56. * @return bool
  57. * @param $id string
  58. * @param $pw string
  59. * @param $realm string
  60. **/
  61. protected function _mongo($id,$pw,$realm) {
  62. return (bool)
  63. $this->mapper->load(
  64. [
  65. $this->args['id']=>$id,
  66. $this->args['pw']=>$pw
  67. ]+
  68. (isset($this->args['realm'])?
  69. [$this->args['realm']=>$realm]:[])
  70. );
  71. }
  72. /**
  73. * SQL storage handler
  74. * @return bool
  75. * @param $id string
  76. * @param $pw string
  77. * @param $realm string
  78. **/
  79. protected function _sql($id,$pw,$realm) {
  80. return (bool)
  81. call_user_func_array(
  82. [$this->mapper,'load'],
  83. [
  84. array_merge(
  85. [
  86. $this->args['id'].'=? AND '.
  87. $this->args['pw'].'=?'.
  88. (isset($this->args['realm'])?
  89. (' AND '.$this->args['realm'].'=?'):''),
  90. $id,$pw
  91. ],
  92. (isset($this->args['realm'])?[$realm]:[])
  93. )
  94. ]
  95. );
  96. }
  97. /**
  98. * LDAP storage handler
  99. * @return bool
  100. * @param $id string
  101. * @param $pw string
  102. **/
  103. protected function _ldap($id,$pw) {
  104. $port=(int)($this->args['port']?:389);
  105. $filter=$this->args['filter']=$this->args['filter']?:"uid=".$id;
  106. $this->args['attr']=$this->args['attr']?:["uid"];
  107. array_walk($this->args['attr'],
  108. function($attr)use(&$filter,$id) {
  109. $filter=str_ireplace($attr."=*",$attr."=".$id,$filter);});
  110. $dc=@ldap_connect($this->args['dc'],$port);
  111. if ($dc &&
  112. ldap_set_option($dc,LDAP_OPT_PROTOCOL_VERSION,3) &&
  113. ldap_set_option($dc,LDAP_OPT_REFERRALS,0) &&
  114. ldap_bind($dc,$this->args['rdn'],$this->args['pw']) &&
  115. ($result=ldap_search($dc,$this->args['base_dn'],
  116. $filter,$this->args['attr'])) &&
  117. ldap_count_entries($dc,$result) &&
  118. ($info=ldap_get_entries($dc,$result)) &&
  119. $info['count']==1 &&
  120. @ldap_bind($dc,$info[0]['dn'],$pw) &&
  121. @ldap_close($dc)) {
  122. return in_array($id,(array_map(function($value){return $value[0];},
  123. array_intersect_key($info[0],
  124. array_flip($this->args['attr'])))),TRUE);
  125. }
  126. user_error(self::E_LDAP,E_USER_ERROR);
  127. }
  128. /**
  129. * SMTP storage handler
  130. * @return bool
  131. * @param $id string
  132. * @param $pw string
  133. **/
  134. protected function _smtp($id,$pw) {
  135. $socket=@fsockopen(
  136. (strtolower($this->args['scheme'])=='ssl'?
  137. 'ssl://':'').$this->args['host'],
  138. $this->args['port']);
  139. $dialog=function($cmd=NULL) use($socket) {
  140. if (!is_null($cmd))
  141. fputs($socket,$cmd."\r\n");
  142. $reply='';
  143. while (!feof($socket) &&
  144. ($info=stream_get_meta_data($socket)) &&
  145. !$info['timed_out'] && $str=fgets($socket,4096)) {
  146. $reply.=$str;
  147. if (preg_match('/(?:^|\n)\d{3} .+\r\n/s',
  148. $reply))
  149. break;
  150. }
  151. return $reply;
  152. };
  153. if ($socket) {
  154. stream_set_blocking($socket,TRUE);
  155. $dialog();
  156. $fw=Base::instance();
  157. $dialog('EHLO '.$fw->HOST);
  158. if (strtolower($this->args['scheme'])=='tls') {
  159. $dialog('STARTTLS');
  160. stream_socket_enable_crypto(
  161. $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT);
  162. $dialog('EHLO '.$fw->HOST);
  163. }
  164. // Authenticate
  165. $dialog('AUTH LOGIN');
  166. $dialog(base64_encode($id));
  167. $reply=$dialog(base64_encode($pw));
  168. $dialog('QUIT');
  169. fclose($socket);
  170. return (bool)preg_match('/^235 /',$reply);
  171. }
  172. user_error(self::E_SMTP,E_USER_ERROR);
  173. }
  174. /**
  175. * Login auth mechanism
  176. * @return bool
  177. * @param $id string
  178. * @param $pw string
  179. * @param $realm string
  180. **/
  181. function login($id,$pw,$realm=NULL) {
  182. return $this->{'_'.$this->storage}($id,$pw,$realm);
  183. }
  184. /**
  185. * HTTP basic auth mechanism
  186. * @return bool
  187. * @param $func callback
  188. **/
  189. function basic($func=NULL) {
  190. $fw=Base::instance();
  191. $realm=$fw->REALM;
  192. $hdr=NULL;
  193. if (isset($_SERVER['HTTP_AUTHORIZATION']))
  194. $hdr=$_SERVER['HTTP_AUTHORIZATION'];
  195. elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
  196. $hdr=$_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
  197. if (!empty($hdr))
  198. list($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])=
  199. explode(':',base64_decode(substr($hdr,6)));
  200. if (isset($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']) &&
  201. $this->login(
  202. $_SERVER['PHP_AUTH_USER'],
  203. $func?
  204. $fw->call($func,$_SERVER['PHP_AUTH_PW']):
  205. $_SERVER['PHP_AUTH_PW'],
  206. $realm
  207. ))
  208. return TRUE;
  209. if (PHP_SAPI!='cli')
  210. header('WWW-Authenticate: Basic realm="'.$realm.'"');
  211. $fw->status(401);
  212. return FALSE;
  213. }
  214. /**
  215. * Instantiate class
  216. * @return object
  217. * @param $storage string|object
  218. * @param $args array
  219. **/
  220. function __construct($storage,array $args=NULL) {
  221. if (is_object($storage) && is_a($storage,'DB\Cursor')) {
  222. $this->storage=$storage->dbtype();
  223. $this->mapper=$storage;
  224. unset($ref);
  225. }
  226. else
  227. $this->storage=$storage;
  228. $this->args=$args;
  229. }
  230. }