auth.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <?php
  2. /*
  3. Copyright (c) 2009-2018 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. //! Custom compare function
  30. $func;
  31. /**
  32. * Jig storage handler
  33. * @return bool
  34. * @param $id string
  35. * @param $pw string
  36. * @param $realm string
  37. **/
  38. protected function _jig($id,$pw,$realm) {
  39. $success = (bool)
  40. call_user_func_array(
  41. [$this->mapper,'load'],
  42. [
  43. array_merge(
  44. [
  45. '@'.$this->args['id'].'==?'.
  46. ($this->func?'':' AND @'.$this->args['pw'].'==?').
  47. (isset($this->args['realm'])?
  48. (' AND @'.$this->args['realm'].'==?'):''),
  49. $id
  50. ],
  51. ($this->func?[]:[$pw]),
  52. (isset($this->args['realm'])?[$realm]:[])
  53. )
  54. ]
  55. );
  56. if ($success && $this->func)
  57. $success = call_user_func($this->func,$pw,$this->mapper->get($this->args['pw']));
  58. return $success;
  59. }
  60. /**
  61. * MongoDB storage handler
  62. * @return bool
  63. * @param $id string
  64. * @param $pw string
  65. * @param $realm string
  66. **/
  67. protected function _mongo($id,$pw,$realm) {
  68. $success = (bool)
  69. $this->mapper->load(
  70. [$this->args['id']=>$id]+
  71. ($this->func?[]:[$this->args['pw']=>$pw])+
  72. (isset($this->args['realm'])?
  73. [$this->args['realm']=>$realm]:[])
  74. );
  75. if ($success && $this->func)
  76. $success = call_user_func($this->func,$pw,$this->mapper->get($this->args['pw']));
  77. return $success;
  78. }
  79. /**
  80. * SQL storage handler
  81. * @return bool
  82. * @param $id string
  83. * @param $pw string
  84. * @param $realm string
  85. **/
  86. protected function _sql($id,$pw,$realm) {
  87. $success = (bool)
  88. call_user_func_array(
  89. [$this->mapper,'load'],
  90. [
  91. array_merge(
  92. [
  93. $this->args['id'].'=?'.
  94. ($this->func?'':' AND '.$this->args['pw'].'=?').
  95. (isset($this->args['realm'])?
  96. (' AND '.$this->args['realm'].'=?'):''),
  97. $id
  98. ],
  99. ($this->func?[]:[$pw]),
  100. (isset($this->args['realm'])?[$realm]:[])
  101. )
  102. ]
  103. );
  104. if ($success && $this->func)
  105. $success = call_user_func($this->func,$pw,$this->mapper->get($this->args['pw']));
  106. return $success;
  107. }
  108. /**
  109. * LDAP storage handler
  110. * @return bool
  111. * @param $id string
  112. * @param $pw string
  113. **/
  114. protected function _ldap($id,$pw) {
  115. $port=(int)($this->args['port']?:389);
  116. $filter=$this->args['filter']=$this->args['filter']?:"uid=".$id;
  117. $this->args['attr']=$this->args['attr']?:["uid"];
  118. array_walk($this->args['attr'],
  119. function($attr)use(&$filter,$id) {
  120. $filter=str_ireplace($attr."=*",$attr."=".$id,$filter);});
  121. $dc=@ldap_connect($this->args['dc'],$port);
  122. if ($dc &&
  123. ldap_set_option($dc,LDAP_OPT_PROTOCOL_VERSION,3) &&
  124. ldap_set_option($dc,LDAP_OPT_REFERRALS,0) &&
  125. ldap_bind($dc,$this->args['rdn'],$this->args['pw']) &&
  126. ($result=ldap_search($dc,$this->args['base_dn'],
  127. $filter,$this->args['attr'])) &&
  128. ldap_count_entries($dc,$result) &&
  129. ($info=ldap_get_entries($dc,$result)) &&
  130. $info['count']==1 &&
  131. @ldap_bind($dc,$info[0]['dn'],$pw) &&
  132. @ldap_close($dc)) {
  133. return in_array($id,(array_map(function($value){return $value[0];},
  134. array_intersect_key($info[0],
  135. array_flip($this->args['attr'])))),TRUE);
  136. }
  137. user_error(self::E_LDAP,E_USER_ERROR);
  138. }
  139. /**
  140. * SMTP storage handler
  141. * @return bool
  142. * @param $id string
  143. * @param $pw string
  144. **/
  145. protected function _smtp($id,$pw) {
  146. $socket=@fsockopen(
  147. (strtolower($this->args['scheme'])=='ssl'?
  148. 'ssl://':'').$this->args['host'],
  149. $this->args['port']);
  150. $dialog=function($cmd=NULL) use($socket) {
  151. if (!is_null($cmd))
  152. fputs($socket,$cmd."\r\n");
  153. $reply='';
  154. while (!feof($socket) &&
  155. ($info=stream_get_meta_data($socket)) &&
  156. !$info['timed_out'] && $str=fgets($socket,4096)) {
  157. $reply.=$str;
  158. if (preg_match('/(?:^|\n)\d{3} .+\r\n/s',
  159. $reply))
  160. break;
  161. }
  162. return $reply;
  163. };
  164. if ($socket) {
  165. stream_set_blocking($socket,TRUE);
  166. $dialog();
  167. $fw=Base::instance();
  168. $dialog('EHLO '.$fw->HOST);
  169. if (strtolower($this->args['scheme'])=='tls') {
  170. $dialog('STARTTLS');
  171. stream_socket_enable_crypto(
  172. $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT);
  173. $dialog('EHLO '.$fw->HOST);
  174. }
  175. // Authenticate
  176. $dialog('AUTH LOGIN');
  177. $dialog(base64_encode($id));
  178. $reply=$dialog(base64_encode($pw));
  179. $dialog('QUIT');
  180. fclose($socket);
  181. return (bool)preg_match('/^235 /',$reply);
  182. }
  183. user_error(self::E_SMTP,E_USER_ERROR);
  184. }
  185. /**
  186. * Login auth mechanism
  187. * @return bool
  188. * @param $id string
  189. * @param $pw string
  190. * @param $realm string
  191. **/
  192. function login($id,$pw,$realm=NULL) {
  193. return $this->{'_'.$this->storage}($id,$pw,$realm);
  194. }
  195. /**
  196. * HTTP basic auth mechanism
  197. * @return bool
  198. * @param $func callback
  199. **/
  200. function basic($func=NULL) {
  201. $fw=Base::instance();
  202. $realm=$fw->REALM;
  203. $hdr=NULL;
  204. if (isset($_SERVER['HTTP_AUTHORIZATION']))
  205. $hdr=$_SERVER['HTTP_AUTHORIZATION'];
  206. elseif (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']))
  207. $hdr=$_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
  208. if (!empty($hdr))
  209. list($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])=
  210. explode(':',base64_decode(substr($hdr,6)));
  211. if (isset($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW']) &&
  212. $this->login(
  213. $_SERVER['PHP_AUTH_USER'],
  214. $func?
  215. $fw->call($func,$_SERVER['PHP_AUTH_PW']):
  216. $_SERVER['PHP_AUTH_PW'],
  217. $realm
  218. ))
  219. return TRUE;
  220. if (PHP_SAPI!='cli')
  221. header('WWW-Authenticate: Basic realm="'.$realm.'"');
  222. $fw->status(401);
  223. return FALSE;
  224. }
  225. /**
  226. * Instantiate class
  227. * @return object
  228. * @param $storage string|object
  229. * @param $args array
  230. * @param $func callback
  231. **/
  232. function __construct($storage,array $args=NULL,$func=NULL) {
  233. if (is_object($storage) && is_a($storage,'DB\Cursor')) {
  234. $this->storage=$storage->dbtype();
  235. $this->mapper=$storage;
  236. unset($ref);
  237. }
  238. else
  239. $this->storage=$storage;
  240. $this->args=$args;
  241. $this->func=$func;
  242. }
  243. }