PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/phpmyadmin/libraries/plugins/auth/swekey/swekey.php

https://github.com/Linaida/Projet_mabox
PHP | 536 lines | 353 code | 41 blank | 142 comment | 39 complexity | b4ffcf6c4b1b4bc499cf80ba7507bade MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0, Apache-2.0
  1. <?php
  2. /**
  3. * Library that provides common functions that are used to help integrating Swekey Authentication in a PHP web site
  4. * Version 1.0
  5. *
  6. * History:
  7. * 1.2 Use curl (widely installed) to query the server
  8. * Fixed a possible tempfile race attack
  9. * Random token cache can now be disabled
  10. * 1.1 Added Swekey_HttpGet function that support faulty servers
  11. * Support for custom servers
  12. * 1.0 First release
  13. *
  14. * @package Swekey
  15. */
  16. /**
  17. * Errors codes
  18. */
  19. define("SWEKEY_ERR_INVALID_DEV_STATUS", 901); // The satus of the device is not SWEKEY_STATUS_OK
  20. define("SWEKEY_ERR_INTERNAL", 902); // Should never occurd
  21. define("SWEKEY_ERR_OUTDATED_RND_TOKEN", 910); // You random token is too old
  22. define("SWEKEY_ERR_INVALID_OTP", 911); // The otp was not correct
  23. /**
  24. * Those errors are considered as an attack and your site will be blacklisted during one minute
  25. * if you receive one of those errors
  26. */
  27. define("SWEKEY_ERR_BADLY_ENCODED_REQUEST", 920);
  28. define("SWEKEY_ERR_INVALID_RND_TOKEN", 921);
  29. define("SWEKEY_ERR_DEV_NOT_FOUND", 922);
  30. /**
  31. * Default values for configuration.
  32. */
  33. define('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net');
  34. define('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net');
  35. define('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net');
  36. /**
  37. * The last error of an operation is alway put in this global var
  38. */
  39. global $gSwekeyLastError;
  40. $gSwekeyLastError = 0;
  41. global $gSwekeyLastResult;
  42. $gSwekeyLastResult = "<not set>";
  43. /**
  44. * Servers addresses
  45. * Use the Swekey_SetXxxServer($server) functions to set them
  46. */
  47. global $gSwekeyCheckServer;
  48. if (! isset($gSwekeyCheckServer)) {
  49. $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
  50. }
  51. global $gSwekeyRndTokenServer;
  52. if (! isset($gSwekeyRndTokenServer)) {
  53. $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
  54. }
  55. global $gSwekeyStatusServer;
  56. if (! isset($gSwekeyStatusServer)) {
  57. $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
  58. }
  59. global $gSwekeyCA;
  60. global $gSwekeyTokenCacheEnabled;
  61. if (! isset($gSwekeyTokenCacheEnabled)) {
  62. $gSwekeyTokenCacheEnabled = true;
  63. }
  64. /**
  65. * Change the address of the Check server.
  66. * If $server is empty the default value 'http://auth-check.musbe.net' will be used
  67. *
  68. * @param int $server The protocol and hostname to use
  69. *
  70. * @access public
  71. */
  72. function Swekey_SetCheckServer($server)
  73. {
  74. global $gSwekeyCheckServer;
  75. if (empty($server)) {
  76. $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
  77. } else {
  78. $gSwekeyCheckServer = $server;
  79. }
  80. }
  81. /**
  82. * Change the address of the Random Token Generator server.
  83. * If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used
  84. *
  85. * @param int $server The protocol and hostname to use
  86. *
  87. * @access public
  88. */
  89. function Swekey_SetRndTokenServer($server)
  90. {
  91. global $gSwekeyRndTokenServer;
  92. if (empty($server)) {
  93. $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
  94. } else {
  95. $gSwekeyRndTokenServer = $server;
  96. }
  97. }
  98. /**
  99. * Change the address of the Satus server.
  100. * If $server is empty the default value 'http://auth-status.musbe.net' will be used
  101. *
  102. * @param int $server The protocol and hostname to use
  103. *
  104. * @access public
  105. */
  106. function Swekey_SetStatusServer($server)
  107. {
  108. global $gSwekeyStatusServer;
  109. if (empty($server)) {
  110. $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
  111. } else {
  112. $gSwekeyStatusServer = $server;
  113. }
  114. }
  115. /**
  116. * Change the certificat file in case of the the severs use https instead of http
  117. *
  118. * @param string $cafile The path of the crt file to use
  119. *
  120. * @access public
  121. */
  122. function Swekey_SetCAFile($cafile)
  123. {
  124. global $gSwekeyCA;
  125. $gSwekeyCA = $cafile;
  126. }
  127. /**
  128. * Enable or disable the random token caching
  129. * Because everybody has full access to the cache file, it can be a DOS vulnerability
  130. * So disable it if you are running in a non secure enviromnement
  131. *
  132. * @param $enable
  133. *
  134. * @access public
  135. */
  136. function Swekey_EnableTokenCache($enable)
  137. {
  138. global $gSwekeyTokenCacheEnabled;
  139. $gSwekeyTokenCacheEnabled = ! empty($enable);
  140. }
  141. /**
  142. * Return the last error.
  143. *
  144. * @return string The Last Error
  145. * @access public
  146. */
  147. function Swekey_GetLastError()
  148. {
  149. global $gSwekeyLastError;
  150. return $gSwekeyLastError;
  151. }
  152. /**
  153. * Return the last result.
  154. *
  155. * @return string The Last Error
  156. * @access public
  157. */
  158. function Swekey_GetLastResult()
  159. {
  160. global $gSwekeyLastResult;
  161. return $gSwekeyLastResult;
  162. }
  163. /**
  164. * Send a synchronous request to the server.
  165. * This function manages timeout then will not block if one of the server is down
  166. *
  167. * @param string $url The url to get
  168. * @param string $response_code The response code
  169. *
  170. * @return string The body of the response or "" in case of error
  171. * @access private
  172. */
  173. function Swekey_HttpGet($url, &$response_code)
  174. {
  175. global $gSwekeyLastError;
  176. $gSwekeyLastError = 0;
  177. global $gSwekeyLastResult;
  178. $gSwekeyLastResult = "<not set>";
  179. // use curl if available
  180. if (function_exists('curl_init')) {
  181. $sess = curl_init($url);
  182. if (substr($url, 0, 8) == "https://") {
  183. global $gSwekeyCA;
  184. if (! empty($gSwekeyCA)) {
  185. if (file_exists($gSwekeyCA)) {
  186. if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA)) {
  187. error_log(
  188. "SWEKEY_ERROR:Could not set CA file : ".curl_error($sess)
  189. );
  190. } else {
  191. $caFileOk = true;
  192. }
  193. } else {
  194. error_log(
  195. "SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url"
  196. );
  197. }
  198. }
  199. curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2');
  200. curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '2');
  201. curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20');
  202. curl_setopt($sess, CURLOPT_TIMEOUT, '20');
  203. } else {
  204. curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3');
  205. curl_setopt($sess, CURLOPT_TIMEOUT, '5');
  206. }
  207. curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1');
  208. $res=curl_exec($sess);
  209. $response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE);
  210. $curlerr = curl_error($sess);
  211. curl_close($sess);
  212. if ($response_code == 200) {
  213. $gSwekeyLastResult = $res;
  214. return $res;
  215. }
  216. if (! empty($response_code)) {
  217. $gSwekeyLastError = $response_code;
  218. error_log(
  219. "SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url"
  220. );
  221. return "";
  222. }
  223. $response_code = 408; // Request Timeout
  224. $gSwekeyLastError = $response_code;
  225. error_log("SWEKEY_ERROR:Error $curlerr getting $url");
  226. return "";
  227. }
  228. // use pecl_http if available
  229. if (class_exists('HttpRequest')) {
  230. // retry if one of the server is down
  231. for ($num=1; $num <= 3; $num++ ) {
  232. $r = new HttpRequest($url);
  233. $options = array('timeout' => '3');
  234. if (substr($url, 0, 6) == "https:") {
  235. $sslOptions = array();
  236. $sslOptions['verifypeer'] = true;
  237. $sslOptions['verifyhost'] = true;
  238. $capath = __FILE__;
  239. $name = strrchr($capath, '/');
  240. // windows
  241. if (empty($name)) {
  242. $name = strrchr($capath, '\\');
  243. }
  244. $capath = substr($capath, 0, strlen($capath) - strlen($name) + 1)
  245. . 'musbe-ca.crt';
  246. if (! empty($gSwekeyCA)) {
  247. $sslOptions['cainfo'] = $gSwekeyCA;
  248. }
  249. $options['ssl'] = $sslOptions;
  250. }
  251. $r->setOptions($options);
  252. /*
  253. try
  254. {
  255. */
  256. $reply = $r->send();
  257. $res = $reply->getBody();
  258. $info = $r->getResponseInfo();
  259. $response_code = $info['response_code'];
  260. if ($response_code != 200) {
  261. $gSwekeyLastError = $response_code;
  262. error_log(
  263. "SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url
  264. );
  265. return "";
  266. }
  267. $gSwekeyLastResult = $res;
  268. return $res;
  269. /*
  270. }
  271. catch (HttpException $e)
  272. {
  273. error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url);
  274. }
  275. */
  276. }
  277. $response_code = 408; // Request Timeout
  278. $gSwekeyLastError = $response_code;
  279. error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
  280. return "";
  281. }
  282. global $http_response_header;
  283. $res = @file_get_contents($url);
  284. $response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0
  285. if ($response_code == 200) {
  286. $gSwekeyLastResult = $res;
  287. return $res;
  288. }
  289. $gSwekeyLastError = $response_code;
  290. error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url);
  291. return "";
  292. }
  293. /**
  294. * Get a Random Token from a Token Server
  295. * The RT is a 64 vhars hexadecimal value
  296. * You should better use Swekey_GetFastRndToken() for performance
  297. * @access public
  298. */
  299. function Swekey_GetRndToken()
  300. {
  301. global $gSwekeyRndTokenServer;
  302. return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code);
  303. }
  304. /**
  305. * Get a Half Random Token from a Token Server
  306. * The RT is a 64 vhars hexadecimal value
  307. * Use this value if you want to make your own Swekey_GetFastRndToken()
  308. * @access public
  309. */
  310. function Swekey_GetHalfRndToken()
  311. {
  312. global $gSwekeyRndTokenServer;
  313. return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code);
  314. }
  315. /**
  316. * Get a Half Random Token
  317. * The RT is a 64 vhars hexadecimal value
  318. * This function get a new random token and reuse it.
  319. * Token are refetched from the server only once every 30 seconds.
  320. * You should always use this function to get half random token.
  321. * @access public
  322. */
  323. function Swekey_GetFastHalfRndToken()
  324. {
  325. global $gSwekeyTokenCacheEnabled;
  326. $res = "";
  327. $cachefile = "";
  328. // We check if we have a valid RT is the session
  329. if (isset($_SESSION['rnd-token-date'])) {
  330. if (time() - $_SESSION['rnd-token-date'] < 30) {
  331. $res = $_SESSION['rnd-token'];
  332. }
  333. }
  334. // If not we try to get it from a temp file (PHP >= 5.2.1 only)
  335. if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled) {
  336. if (function_exists('sys_get_temp_dir')) {
  337. $tempdir = sys_get_temp_dir();
  338. $cachefile = $tempdir."/swekey-rnd-token-".get_current_user();
  339. $modif = filemtime($cachefile);
  340. if ($modif != false) {
  341. if (time() - $modif < 30) {
  342. $res = @file_get_contents($cachefile);
  343. if (strlen($res) != 32) {
  344. $res = "";
  345. } else {
  346. $_SESSION['rnd-token'] = $res;
  347. $_SESSION['rnd-token-date'] = $modif;
  348. }
  349. }
  350. }
  351. }
  352. }
  353. // If we don't have a valid RT here we have to get it from the server
  354. if (strlen($res) != 32) {
  355. $res = substr(Swekey_GetHalfRndToken(), 0, 32);
  356. $_SESSION['rnd-token'] = $res;
  357. $_SESSION['rnd-token-date'] = time();
  358. if (! empty($cachefile)) {
  359. // we unlink the file so no possible tempfile race attack
  360. unlink($cachefile);
  361. $file = fopen($cachefile, "x");
  362. if ($file != false) {
  363. @fwrite($file, $res);
  364. @fclose($file);
  365. }
  366. }
  367. }
  368. return $res."00000000000000000000000000000000";
  369. }
  370. /**
  371. * Get a Random Token
  372. * The RT is a 64 vhars hexadecimal value
  373. * This function generates a unique random token for each call but call the
  374. * server only once every 30 seconds.
  375. * You should always use this function to get random token.
  376. * @access public
  377. */
  378. function Swekey_GetFastRndToken()
  379. {
  380. $res = Swekey_GetFastHalfRndToken();
  381. if (strlen($res) == 64) {
  382. return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" . mt_rand() . date(DATE_ATOM)));
  383. }
  384. return "";
  385. }
  386. /**
  387. * Checks that an OTP generated by a Swekey is valid
  388. *
  389. * @param mixed $id The id of the swekey
  390. * @param mixed $rt The random token used to generate the otp
  391. * @param mixed $otp The otp generated by the swekey
  392. *
  393. * @return boolean Success
  394. * @access public
  395. */
  396. function Swekey_CheckOtp($id, $rt, $otp)
  397. {
  398. global $gSwekeyCheckServer;
  399. $res = Swekey_HttpGet(
  400. $gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp,
  401. $response_code
  402. );
  403. return $response_code == 200 && $res == "OK";
  404. }
  405. /**
  406. * Values that are associated with a key.
  407. * The following values can be returned by the Swekey_GetStatus() function
  408. */
  409. define("SWEKEY_STATUS_OK", 0);
  410. define("SWEKEY_STATUS_NOT_FOUND", 1); // The key does not exist in the db
  411. define("SWEKEY_STATUS_INACTIVE", 2); // The key has never been activated
  412. define("SWEKEY_STATUS_LOST", 3); // The user has lost his key
  413. define("SWEKEY_STATUS_STOLEN", 4); // The key was stolen
  414. define("SWEKEY_STATUS_FEE_DUE", 5); // The annual fee was not paid
  415. define("SWEKEY_STATUS_OBSOLETE", 6); // The hardware is no longer supported
  416. define("SWEKEY_STATUS_UNKOWN", 201); // We could not connect to the authentication server
  417. /**
  418. * Values that are associated with a key.
  419. * The Javascript Api can also return the following values
  420. */
  421. define("SWEKEY_STATUS_REPLACED", 100); // This key has been replaced by a backup key
  422. define("SWEKEY_STATUS_BACKUP_KEY", 101); // This key is a backup key that is not activated yet
  423. define("SWEKEY_STATUS_NOTPLUGGED", 200); // This key is not plugged in the computer
  424. /**
  425. * Return the text corresponding to the integer status of a key
  426. *
  427. * @param int $status The status
  428. *
  429. * @return string The text corresponding to the status
  430. * @access public
  431. */
  432. function Swekey_GetStatusStr($status)
  433. {
  434. switch($status)
  435. {
  436. case SWEKEY_STATUS_OK :
  437. return 'OK';
  438. case SWEKEY_STATUS_NOT_FOUND :
  439. return 'Key does not exist in the db';
  440. case SWEKEY_STATUS_INACTIVE :
  441. return 'Key not activated';
  442. case SWEKEY_STATUS_LOST :
  443. return 'Key was lost';
  444. case SWEKEY_STATUS_STOLEN :
  445. return 'Key was stolen';
  446. case SWEKEY_STATUS_FEE_DUE :
  447. return 'The annual fee was not paid';
  448. case SWEKEY_STATUS_OBSOLETE :
  449. return 'Key no longer supported';
  450. case SWEKEY_STATUS_REPLACED :
  451. return 'This key has been replaced by a backup key';
  452. case SWEKEY_STATUS_BACKUP_KEY :
  453. return 'This key is a backup key that is not activated yet';
  454. case SWEKEY_STATUS_NOTPLUGGED :
  455. return 'This key is not plugged in the computer';
  456. case SWEKEY_STATUS_UNKOWN :
  457. return 'Unknow Status, could not connect to the authentication server';
  458. }
  459. return 'unknown status '.$status;
  460. }
  461. /**
  462. * If your web site requires a key to login you should check that the key
  463. * is still valid (has not been lost or stolen) before requiring it.
  464. * A key can be authenticated only if its status is SWEKEY_STATUS_OK
  465. *
  466. * @param mixed $id The id of the swekey
  467. *
  468. * @return int The status of the swekey
  469. * @access public
  470. */
  471. function Swekey_GetStatus($id)
  472. {
  473. global $gSwekeyStatusServer;
  474. $res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code);
  475. if ($response_code == 200) {
  476. return intval($res);
  477. }
  478. return SWEKEY_STATUS_UNKOWN;
  479. }