Welcome to mirror list, hosted at ThFree Co, Russian Federation.

swekey.php « swekey « auth « libraries - github.com/phpmyadmin/phpmyadmin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 66ce3504d879426263d58f3d96f7bff38ba2a52a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
<?php
/**
 * Library that provides common functions that are used to help integrating Swekey Authentication in a PHP web site
 * Version 1.0
 *
 * History:
 * 1.2 Use curl (widely installed) to query the server
 *     Fixed a possible tempfile race attack
 *     Random token cache can now be disabled
 * 1.1 Added Swekey_HttpGet function that support faulty servers
 *     Support for custom servers
 * 1.0 First release
 *
 * @package Swekey
 */


/**
 * Errors codes
 */
define ("SWEKEY_ERR_INVALID_DEV_STATUS",901);   // The satus of the device is not SWEKEY_STATUS_OK
define ("SWEKEY_ERR_INTERNAL",902);             // Should never occurd
define ("SWEKEY_ERR_OUTDATED_RND_TOKEN",910);   // You random token is too old
define ("SWEKEY_ERR_INVALID_OTP",911);          // The otp was not correct

/**
 * Those errors are considered as an attack and your site will be blacklisted during one minute
 * if you receive one of those errors
 */
define ("SWEKEY_ERR_BADLY_ENCODED_REQUEST",920);
define ("SWEKEY_ERR_INVALID_RND_TOKEN",921);
define ("SWEKEY_ERR_DEV_NOT_FOUND",922);

/**
 * Default values for configuration.
 */
define ('SWEKEY_DEFAULT_CHECK_SERVER', 'https://auth-check.musbe.net');
define ('SWEKEY_DEFAULT_RND_SERVER', 'https://auth-rnd-gen.musbe.net');
define ('SWEKEY_DEFAULT_STATUS_SERVER', 'https://auth-status.musbe.net');

/**
 * The last error of an operation is alway put in this global var
 */

global $gSwekeyLastError;
$gSwekeyLastError = 0;

global $gSwekeyLastResult;
$gSwekeyLastResult = "<not set>";

/**
 * Servers addresses
 * Use the  Swekey_SetXxxServer($server) functions to set them
 */

global $gSwekeyCheckServer;
if (! isset($gSwekeyCheckServer))
    $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;

global $gSwekeyRndTokenServer;
if (! isset($gSwekeyRndTokenServer))
    $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;

global $gSwekeyStatusServer;
if (! isset($gSwekeyStatusServer))
    $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;

global $gSwekeyCA;

global $gSwekeyTokenCacheEnabled;
if (! isset($gSwekeyTokenCacheEnabled))
    $gSwekeyTokenCacheEnabled = true;

/**
 *  Change the address of the Check server.
 *  If $server is empty the default value 'http://auth-check.musbe.net' will be used
 *
 *  @param  server              The protocol and hostname to use
 *  @access public
 */
function Swekey_SetCheckServer($server)
{
    global $gSwekeyCheckServer;
    if (empty($server))
        $gSwekeyCheckServer = SWEKEY_DEFAULT_CHECK_SERVER;
    else
        $gSwekeyCheckServer = $server;
}

/**
 *  Change the address of the Random Token Generator server.
 *  If $server is empty the default value 'http://auth-rnd-gen.musbe.net' will be used
 *
 *  @param  server              The protocol and hostname to use
 *  @access public
 */
function Swekey_SetRndTokenServer($server)
{
    global $gSwekeyRndTokenServer;
    if (empty($server))
        $gSwekeyRndTokenServer = SWEKEY_DEFAULT_RND_SERVER;
    else
        $gSwekeyRndTokenServer = $server;
}

/**
 *  Change the address of the Satus server.
 *  If $server is empty the default value 'http://auth-status.musbe.net' will be used
 *
 *  @param  server              The protocol and hostname to use
 *  @access public
 */
function Swekey_SetStatusServer($server)
{
    global $gSwekeyStatusServer;
    if (empty($server))
        $gSwekeyStatusServer = SWEKEY_DEFAULT_STATUS_SERVER;
    else
        $gSwekeyStatusServer = $server;
}

/**
 *  Change the certificat file in case of the the severs use https instead of http
 *
 *  @param  cafile              The path of the crt file to use
 *  @access public
 */
function Swekey_SetCAFile($cafile)
{
    global $gSwekeyCA;
   	$gSwekeyCA = $cafile;
}

/**
 *  Enable or disable the random token caching
 *  Because everybody has full access to the cache file, it can be a DOS vulnerability
 *  So disable it if you are running in a non secure enviromnement
 *
 *  @param  $enable
 *  @access public
 */
function Swekey_EnableTokenCache($enable)
{
    global $gSwekeyTokenCacheEnabled;
	$gSwekeyTokenCacheEnabled = ! empty($enable);
}


/**
 *  Return the last error.
 *
 *  @return                     The Last Error
 *  @access public
 */
function Swekey_GetLastError()
{
    global $gSwekeyLastError;
    return $gSwekeyLastError;
}

/**
 *  Return the last result.
 *
 *  @return                     The Last Error
 *  @access public
 */
function Swekey_GetLastResult()
{
    global $gSwekeyLastResult;
    return $gSwekeyLastResult;
}

/**
 *  Send a synchronous request to the  server.
 *  This function manages timeout then will not block if one of the server is down
 *
 *  @param  url                 The url to get
 *  @param  response_code       The response code
 *  @return                     The body of the response or "" in case of error
 *  @access private
 */
function Swekey_HttpGet($url, &$response_code)
{
    global $gSwekeyLastError;
    $gSwekeyLastError = 0;
    global $gSwekeyLastResult;
    $gSwekeyLastResult = "<not set>";

 	// use curl if available
	if (function_exists('curl_init'))
	{
		$sess = curl_init($url);
		if (substr($url, 0, 8) == "https://")
		{
			global $gSwekeyCA;

			if (! empty($gSwekeyCA))
			{
				if (file_exists($gSwekeyCA))
				{
					if (! curl_setopt($sess, CURLOPT_CAINFO, $gSwekeyCA))
						error_log("SWEKEY_ERROR:Could not set CA file : ".curl_error($sess));
					else
						$caFileOk = true;
				}
				else
					error_log("SWEKEY_ERROR:Could not find CA file $gSwekeyCA getting $url");
			}

			curl_setopt($sess, CURLOPT_SSL_VERIFYHOST, '2');
			curl_setopt($sess, CURLOPT_SSL_VERIFYPEER, '2');
			curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '20');
			curl_setopt($sess, CURLOPT_TIMEOUT, '20');
		}
		else
		{
			curl_setopt($sess, CURLOPT_CONNECTTIMEOUT, '3');
			curl_setopt($sess, CURLOPT_TIMEOUT, '5');
		}

		curl_setopt($sess, CURLOPT_RETURNTRANSFER, '1');
		$res=curl_exec($sess);
		$response_code = curl_getinfo($sess, CURLINFO_HTTP_CODE);
		$curlerr = curl_error($sess);
		curl_close($sess);

		if ($response_code == 200)
		{
	        $gSwekeyLastResult = $res;
	        return $res;
		}

		if (! empty($response_code))
        {
            $gSwekeyLastError = $response_code;
            error_log("SWEKEY_ERROR:Error $gSwekeyLastError ($curlerr) getting $url");
            return "";
       }

        $response_code = 408; // Request Timeout
        $gSwekeyLastError = $response_code;
        error_log("SWEKEY_ERROR:Error $curlerr getting $url");
        return "";
	}

	// use pecl_http if available
    if (class_exists('HttpRequest'))
    {
        // retry if one of the server is down
        for ($num=1; $num <= 3; $num++ )
        {
            $r = new HttpRequest($url);
            $options = array('timeout' => '3');

            if (substr($url,0, 6) == "https:")
            {
                $sslOptions = array();
                $sslOptions['verifypeer'] = true;
                $sslOptions['verifyhost'] = true;

                $capath = __FILE__;
                $name = strrchr($capath, '/');
                if (empty($name)) // windows
                    $name = strrchr($capath, '\\');
                $capath = substr($capath, 0, strlen($capath) - strlen($name) + 1).'musbe-ca.crt';

                if (! empty($gSwekeyCA))
                    $sslOptions['cainfo'] = $gSwekeyCA;

                $options['ssl'] = $sslOptions;
            }

            $r->setOptions($options);

 //           try
            {
               $reply = $r->send();
               $res = $reply->getBody();
	           $info = $r->getResponseInfo();
	           $response_code = $info['response_code'];
	           if ($response_code != 200)
	           {
                    $gSwekeyLastError = $response_code;
                    error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
                    return "";
               }


	           $gSwekeyLastResult = $res;
	           return $res;
            }
 //           catch (HttpException $e)
 //           {
 //               error_log("SWEKEY_WARNING:HttpException ".$e." getting ".$url);
 //           }
        }

        $response_code = 408; // Request Timeout
        $gSwekeyLastError = $response_code;
        error_log("SWEKEY_ERROR:Error ".$gSwekeyLastError." getting ".$url);
        return "";
    }

   	global $http_response_header;
	$res = @file_get_contents($url);
	$response_code = substr($http_response_header[0], 9, 3); //HTTP/1.0
	if ($response_code == 200)
	{
	   $gSwekeyLastResult = $res;
	   return $res;
	}

    $gSwekeyLastError = $response_code;
    error_log("SWEKEY_ERROR:Error ".$response_code." getting ".$url);
    return "";
}

/**
 *  Get a Random Token from a Token Server
 *  The RT is a 64 vhars hexadecimal value
 *  You should better use Swekey_GetFastRndToken() for performance
 *  @access public
 */
function Swekey_GetRndToken()
{
    global $gSwekeyRndTokenServer;
    return Swekey_HttpGet($gSwekeyRndTokenServer.'/FULL-RND-TOKEN', $response_code);
}

/**
 *  Get a Half Random Token from a Token Server
 *  The RT is a 64 vhars hexadecimal value
 *  Use this value if you want to make your own Swekey_GetFastRndToken()
 *  @access public
 */
function Swekey_GetHalfRndToken()
{
    global $gSwekeyRndTokenServer;
	return Swekey_HttpGet($gSwekeyRndTokenServer.'/HALF-RND-TOKEN', $response_code);
}

/**
 *  Get a Half Random Token
 *  The RT is a 64 vhars hexadecimal value
 *  This function get a new random token and reuse it.
 *  Token are refetched from the server only once every 30 seconds.
 *  You should always use this function to get half random token.
 *  @access public
 */
function Swekey_GetFastHalfRndToken()
{
    global $gSwekeyTokenCacheEnabled;

    $res = "";
    $cachefile = "";

    // We check if we have a valid RT is the session
    if (isset($_SESSION['rnd-token-date']))
       if (time() - $_SESSION['rnd-token-date'] < 30)
	   	  $res = $_SESSION['rnd-token'];

    // If not we try to get it from a temp file (PHP >= 5.2.1 only)
   if (strlen($res) != 32 && $gSwekeyTokenCacheEnabled)
   {
        if (function_exists('sys_get_temp_dir'))
        {
            $tempdir = sys_get_temp_dir();
            $cachefile = $tempdir."/swekey-rnd-token-".get_current_user();
            $modif = filemtime($cachefile);
			if ($modif != false)
                if (time() - $modif < 30)
	            {
	                $res = @file_get_contents($cachefile);
	                if (strlen($res) != 32)
	                    $res = "";
               		else
               		{
               		 	$_SESSION['rnd-token'] = $res;
               		 	$_SESSION['rnd-token-date'] = $modif;
		 			}
	            }
        }
   }

   // If we don't have a valid RT here we have to get it from the server
   if (strlen($res) != 32)
   {
        $res = substr(Swekey_GetHalfRndToken(), 0, 32);
        $_SESSION['rnd-token'] = $res;
        $_SESSION['rnd-token-date'] = time();
        if (! empty($cachefile))
        {
        	// we unlink the file so no possible tempfile race attack (thanks Thijs)
        	unlink($cachefile);
	   		$file = fopen($cachefile , "x");
	   		if ($file != FALSE)
	   		{
	   	    	@fwrite($file, $res);
    			@fclose($file);
    		}
        }
   }

   return $res."00000000000000000000000000000000";
}

/**
 *  Get a Random Token
 *  The RT is a 64 vhars hexadecimal value
 *  This function generates a unique random token for each call but call the
 *  server only once every 30 seconds.
 *  You should always use this function to get random token.
 *  @access public
 */
function Swekey_GetFastRndToken()
{
    $res = Swekey_GetFastHalfRndToken();
    if (strlen($res) == 64)
        return substr($res, 0, 32).strtoupper(md5("Musbe Authentication Key" + mt_rand() + date(DATE_ATOM)));

    return "";
}


/**
 *  Checks that an OTP generated by a Swekey is valid
 *
 *  @param  id                  The id of the swekey
 *  @param rt                   The random token used to generate the otp
 *  @param otp                  The otp generated by the swekey
 *  @return                     true or false
 *  @access public
 */
function Swekey_CheckOtp($id, $rt, $otp)
{
    global $gSwekeyCheckServer;
	$res = Swekey_HttpGet($gSwekeyCheckServer.'/CHECK-OTP/'.$id.'/'.$rt.'/'.$otp, $response_code);
	return $response_code == 200 && $res == "OK";
}

/**
 * Values that are associated with a key.
 * The following values can be returned by the Swekey_GetStatus() function
 */
define ("SWEKEY_STATUS_OK",0);
define ("SWEKEY_STATUS_NOT_FOUND",1);  // The key does not exist in the db
define ("SWEKEY_STATUS_INACTIVE",2);   // The key has never been activated
define ("SWEKEY_STATUS_LOST",3);	   // The user has lost his key
define ("SWEKEY_STATUS_STOLEN",4);	   // The key was stolen
define ("SWEKEY_STATUS_FEE_DUE",5);	   // The annual fee was not paid
define ("SWEKEY_STATUS_OBSOLETE",6);   // The hardware is no longer supported
define ("SWEKEY_STATUS_UNKOWN",201);   // We could not connect to the authentication server

/**
 * Values that are associated with a key.
 * The Javascript Api can also return the following values
 */
define ("SWEKEY_STATUS_REPLACED",100);	 // This key has been replaced by a backup key
define ("SWEKEY_STATUS_BACKUP_KEY",101); // This key is a backup key that is not activated yet
define ("SWEKEY_STATUS_NOTPLUGGED",200); // This key is not plugged in the computer


/**
 *  Return the text corresponding to the integer status of a key
 *
 *  @param  status              The status
 *  @return                     The text corresponding to the status
 *  @access public
 */
function Swekey_GetStatusStr($status)
{
	switch($status)
	{
       case SWEKEY_STATUS_OK			: return 'OK';
       case SWEKEY_STATUS_NOT_FOUND	    : return 'Key does not exist in the db';
       case SWEKEY_STATUS_INACTIVE		: return 'Key not activated';
       case SWEKEY_STATUS_LOST			: return 'Key was lost';
       case SWEKEY_STATUS_STOLEN		: return 'Key was stolen';
       case SWEKEY_STATUS_FEE_DUE		: return 'The annual fee was not paid';
       case SWEKEY_STATUS_OBSOLETE		: return 'Key no longer supported';
       case SWEKEY_STATUS_REPLACED	    : return 'This key has been replaced by a backup key';
       case SWEKEY_STATUS_BACKUP_KEY    : return 'This key is a backup key that is not activated yet';
       case SWEKEY_STATUS_NOTPLUGGED    : return 'This key is not plugged in the computer';
       case SWEKEY_STATUS_UNKOWN    	: return 'Unknow Status, could not connect to the authentication server';
	}
	return 'unknown status '.$status;
}

/**
 *  If your web site requires a key to login you should check that the key
 *  is still valid (has not been lost or stolen) before requiring it.
 *  A key can be authenticated only if its status is SWEKEY_STATUS_OK
 *  @param  id                  The id of the swekey
 *  @return                     The status of the swekey
 *  @access public
 */
function Swekey_GetStatus($id)
{
    global $gSwekeyStatusServer;
	$res = Swekey_HttpGet($gSwekeyStatusServer.'/GET-STATUS/'.$id, $response_code);
    if ($response_code == 200)
        return intval($res);

    return SWEKEY_STATUS_UNKOWN;
}

?>