Project

General

Profile

1 2 Manuela
<?php
2
3
/*
4
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
/**
21
 * SecureTokens.php
22
 *
23
 * @category      Core
24
 * @package       Core_Security
25
 * @subpackage    WB-2.8.4 and up
26
 * @copyright     Manuela v.d.Decken <manuela@isteam.de>
27
 * @author        Manuela v.d.Decken <manuela@isteam.de>
28
 * @license       http://www.gnu.org/licenses/gpl.html   GPL License
29
 * @
30
 * @version       0.1.2
31
 * @revision      $Revision$
32
 * @link          $HeadURL$
33
 * @lastmodified $Date$
34
 * @since         File available since 12.09.2015
35
 * @description
36
 * This class is a replacement for the former class SecureForm using the SecureTokensInterface
37
 *
38
 * Settings for this class
39
 * TYPE    KONSTANTE                    REGISTY-VAR                       DEFAULTWERT
40
 * boolean SEC_TOKEN_FINGERPRINT        ($oReg->SecTokenFingerprint)      [default=true]
41
 * integer SEC_TOKEN_IPV4_NETMASK       ($oReg->SecTokenIpv4Netmask)      0-255 [default=24]
42
 * integer SEC_TOKEN_IPV6_PREFIX_LENGTH ($oReg->SecTokenIpv6PrefixLength) 0-128 [default=64]
43
 * integer SEC_TOKEN_LIFE_TIME          ($oReg->SecTokenLifeTime)         1800 | 2700 | 3600[default] | 7200
44
*/
45
46
class SecureTokens
47
{
48
/**
49
 * possible settings for TokenLifeTime in seconds
50
 * @description seconds for 30min / 45min / 1h / 75min / 90min / 105min / 2h
51
 */
52
/** minimum lifetime in seconds */
53
    const LIFETIME_MIN  = 1800; // 30min
54
/** maximum lifetime in seconds */
55
    const LIFETIME_MAX  = 7200; // 120min (2h)
56
/** stepwidth between min and max */
57
    const LIFETIME_STEP =  900; // 15min
58
/** lifetime in seconds to use in DEBUG mode if negative value is given (-1) */
59
    const DEBUG_LIFETIME = 300; // 5
60
/** array to hold all tokens from the session */
61
    private $aTokens = array(
62
        'default' => array('value' => 0, 'expire' => 0, 'instance' => 0)
63
    );
64
/** the salt for this instance */
65
    private $sSalt             = '';
66
/** fingerprint of the current connection */
67
    private $sFingerprint      = '';
68
/** the FTAN token which is valid for this instance */
69
    private $aLastCreatedFtan  = null;
70
/** the time when tokens expired if they created in this instance */
71
    private $iExpireTime       = 0;
72
/** remove selected tokens only and update all others */
73
    private $bPreserveAllOtherTokens = false;
74
/** id of the current instance */
75
    private $sCurrentInstance  = null;
76
/** id of the instance to remove */
77
    private $sInstanceToDelete = null;
78
/** id of the instance to update expire time */
79
    private $sInstanceToUpdate = null;
80
/* --- settings for SecureTokens ------------------------------------------------------ */
81
/** use fingerprinting to encode */
82
    private $bUseFingerprint   = true;
83
/** maximum lifetime of a token in seconds */
84
    private $iTokenLifeTime    = 1800; // between LIFETIME_MIN and LIFETIME_MAX (default = 30min)
85
/** bit length of the IPv4 Netmask (0-32 // 0 = off  default = 24) */
86
    private $iNetmaskLengthV4  = 0;
87
/** bit length of the IPv6 Netmask (0-128 // 0 = off  default = 64) */
88
    private $iNetmaskLengthV6  = 0;
89
90
    private static $oInstance = null;
91
/**
92
 * constructor
93
 * @param (void)
94
 */
95
    protected function __construct()
96
    {
97
    // load settings if available
98
        $this->getSettings();
99
    // generate salt for calculations in this instance
100
        $this->sSalt            = $this->generateSalt();
101
    // generate fingerprint for the current connection
102
        $this->sFingerprint     = $this->buildFingerprint();
103
    // define the expiretime for this instance
104
        $this->iExpireTime      = time() + $this->iTokenLifeTime;
105
    // calculate the instance id for this instance
106
        $this->sCurrentInstance = $this->encodeHash(md5($this->iExpireTime.$this->sSalt));
107
    // load array of tokens from session
108
        $this->loadTokens();
109
    // at first of all remove expired tokens
110
        $this->removeExpiredTokens();
111
    }
112
113
    public static function getInstance()
114
    {
115
        if (self::$oInstance == null) {
116
            $sClass = __CLASS__;
117
            self::$oInstance = new $sClass();
118
        }
119
        return self::$oInstance;
120
    }
121
122
    private function __clone() {}
123
124
/**
125
 * destructor
126
 */
127
    final public function __destruct()
128
    {
129
        foreach ($this->aTokens as $sKey => $aToken) {
130
            if ($aToken['instance'] == $this->sInstanceToUpdate) {
131
                $this->aTokens[$sKey]['instance'] = $this->sCurrentInstance;
132
                $this->aTokens[$sKey]['expire']   = $this->iExpireTime;
133
            } elseif ($aToken['instance'] == $this->sInstanceToDelete) {
134
                unset($this->aTokens[$sKey]);
135
            }
136
        }
137
        $this->saveTokens();
138
    }
139
140
/**
141
 * returns the current FTAN
142
 * @param bool $mode: true or POST returns a complete prepared, hidden HTML-Input-Tag (default)
143
 *                     false or GET returns an GET argument 'key=value'
144
 * @return mixed:     array or string
145
 * @deprecated the param $mMode is set deprecated
146
 *              string retvals are set deprecated. From versions after 2.8.4 retval will be array only
147
 */
148
    final public function getFTAN($mMode = 'POST')
149
    {
150
        if (is_null($this->aLastCreatedFtan)) {
151
            $sFtan = md5($this->sSalt);
152
            $this->aLastCreatedFtan = $this->addToken(
153
                substr($sFtan, rand(0,15), 16),
154
                substr($sFtan, rand(0,15), 16)
155
            );
156
        }
157
        $aFtan = $this->aTokens[$this->aLastCreatedFtan];
158
        $aFtan['name']  = $this->aLastCreatedFtan;
159
        $aFtan['value'] = $this->encodeHash(md5($aFtan['value'].$this->sFingerprint));
160
        if (is_string($mMode)) {
161
            $mMode = strtoupper($mMode);
162
        } else {
163
            $mMode = $mMode === true ? 'POST' : 'GET';
164
        }
165
        switch ($mMode):
166
            case 'POST':
167
                return '<input type="hidden" name="'.$aFtan['name'].'" value="'
168
                      .$aFtan['value'].'" title="">';
169
                break;
170
            case 'GET':
171
                return $aFtan['name'].'='.$aFtan['value'];
172
                break;
173
            default:
174
                return array('name' => $aFtan['name'], 'value' => $aFtan['value']);
175
        endswitch;
176
    }
177
178
/**
179
 * checks received form-transactionnumbers against session-stored one
180
 * @param string $mode: requestmethode POST(default) or GET
181
 * @param bool $bPreserve (default=false)
182
 * @return bool:    true if numbers matches against stored ones
183
 *
184
 * requirements: an active session must be available
185
 * this check will prevent from multiple sending a form. history.back() also will never work
186
 */
187
    final public function checkFTAN($mMode = 'POST')
188
    {
189
        $bRetval = false;
190
        // get the POST/GET arguments
191
        $aArguments = (strtoupper($mMode) == 'POST' ? $_POST : $_GET);
192
        // encode the value of all matching tokens
193
        $aMatchingTokens = array_map(
194
            array($this, 'checkFtanCallback'),
195
    //            function ($aToken) {
196
    //                return $this->encode64(md5($aToken['value'].$this->sFingerprint));
197
    //            },
198
                // extract all matching tokens from $this->aTokens
199
                array_intersect_key($this->aTokens, $aArguments)
200
        );
201
//echo "<pre>".print_r(debug_backtrace(0),true)."</pre>";
202
        // extract all matching arguments from $aArguments
203
        $aMatchingArguments = array_intersect_key($aArguments, $this->aTokens);
204
        // get all tokens with matching values from match lists
205
        $aHits = array_intersect($aMatchingTokens, $aMatchingArguments);
206
        foreach ($aHits as $sTokenName => $sValue) {
207
            $bRetval = true;
208
            $this->removeToken($sTokenName);
209
        }
210
        return $bRetval;
211
    }
212
/**
213
 * store value in session and returns an accesskey to it
214
 * @param mixed $mValue can be numeric, string or array
215
 * @return string
216
 */
217
    final public function getIDKEY($mValue)
218
    {
219
        if (is_array($mValue) == true) {
220
            // serialize value, if it's an array
221
            $mValue = serialize($mValue);
222
        }
223
        // crypt value with salt into md5-hash and return a 16-digit block from random start position
224
        $sTokenName = $this->addToken(
225
            substr(md5($this->sSalt.(string)$mValue), rand(0,15), 16),
226
            $mValue
227
        );
228
        return $sTokenName;
229
    }
230
231
/*
232
 * search for key in session and returns the original value
233
 * @param string $sFieldname: name of the POST/GET-Field containing the key or hex-key itself
234
 * @param mixed $mDefault: returnvalue if key not exist (default 0)
235
 * @param string $sRequest: requestmethode can be POST or GET or '' (default POST)
236
 * @param bool $bPreserve (default=false)
237
 * @return mixed: the original value (string, numeric, array) or DEFAULT if request fails
238
 * @description: each IDKEY can be checked only once. Unused Keys stay in list until they expire
239
 */
240
    final public function checkIDKEY($sFieldname, $mDefault = 0, $sRequest = 'POST', $bPreserve = false)
241
    {
242
        $mReturnValue = $mDefault; // set returnvalue to default
243
        $this->bPreserveAllOtherTokens = $bPreserve ?: $this->bPreserveAllOtherTokens;
244
        $sRequest = strtoupper($sRequest);
245
        switch ($sRequest) {
246
            case 'POST':
247
                $sTokenName = $_POST[$sFieldname] ?: $sFieldname;
248
                break;
249
            case 'GET':
250
                $sTokenName = $_GET[$sFieldname] ?: $sFieldname;
251
                break;
252
            default:
253
                $sTokenName = $sFieldname;
254
        }
255
        if (preg_match('/^[0-9a-f]{16}$/i', $sTokenName)) {
256
        // key must be a 16-digit hexvalue
257
            if (array_key_exists($sTokenName, $this->aTokens)) {
258
            // check if key is stored in IDKEYs-list
259
                $mReturnValue = $this->aTokens[$sTokenName]['value']; // get stored value
260
                $this->removeToken($sTokenName);   // remove from list to prevent multiuse
261
                if (preg_match('/.*(?<!\{).*(\d:\{.*;\}).*(?!\}).*/', $mReturnValue)) {
262
                // if value is a serialized array, then deserialize it
263
                    $mReturnValue = unserialize($mReturnValue);
264
                }
265
            }
266
        }
267
        return $mReturnValue;
268
    }
269
270
/**
271
 * make a valid LifeTime value from given integer on the rules of class SecureTokens
272
 * @param integer  $iLifeTime
273
 * @return integer
274
 */
275
    final public function sanitizeLifeTime($iLifeTime)
276
    {
277
        $iLifeTime = intval($iLifeTime);
278
        for ($i = self::LIFETIME_MIN; $i <= self::LIFETIME_MAX; $i += self::LIFETIME_STEP) {
279
            $aLifeTimes[] = $i;
280
        }
281
        $iRetval = array_pop($aLifeTimes);
282
        foreach ($aLifeTimes as $iValue) {
283
            if ($iLifeTime <= $iValue) {
284
                $iRetval = $iValue;
285
                break;
286
            }
287
        }
288
        return $iRetval;
289
    }
290
291
/**
292
 * returns all TokenLifeTime values
293
 * @return array
294
 */
295
    final public function getTokenLifeTime()
296
    {
297
        return array(
298
            'min'   => self::LIFETIME_MIN,
299
            'max'   => self::LIFETIME_MAX,
300
            'step'  => self::LIFETIME_STEP,
301
            'value' => $this->iTokenLifeTime
302
        );
303
    }
304
305
/* ************************************************************************************ */
306
/* *** from here private methods only                                               *** */
307
/* ************************************************************************************ */
308
/**
309
 * load all tokens from session
310
 */
311
    private function loadTokens()
312
    {
313
        if (isset($_SESSION['TOKENS'])) {
314
            $this->aTokens = unserialize($_SESSION['TOKENS']);
315
        } else {
316
            $this->saveTokens();
317
        }
318
    }
319
320
/**
321
 * save all tokens into session
322
 */
323
    private function saveTokens()
324
    {
325
        $_SESSION['TOKENS'] = serialize($this->aTokens);
326
    }
327
328
/**
329
 * add new token to the list
330
 * @param string $sTokenName
331
 * @param string $sValue
332
 * @return string  name(index) of the token
333
 */
334
    private function addToken($sTokenName, $sValue)
335
    {
336
        // limit TokenName to 16 digits
337
        $sTokenName = substr(str_pad($sTokenName, 16, '0', STR_PAD_LEFT), -16);
338
        // make sure, first digit is a alpha char [a-f]
339
        $sTokenName[0] = dechex(10 + (hexdec($sTokenName[0]) % 5));
340
        // loop as long the generated TokenName already exists in list
341
        while (isset($this->aTokens[$sTokenName])) {
342
            // split TokenName into 4 words
343
            $aWords = str_split($sTokenName, 4);
344
            // get lowest word and increment it
345
            $iWord = hexdec($aWords[3]) + 1;
346
            // reformat integer into a 4 digit hex string
347
            $aWords[3] = sprintf('%04x', ($iWord > 0xffff ? 1 : $iWord));
348
            // rebuild the TokenName
349
            $sTokenName = implode('', $aWords);
350
        }
351
        // store Token in list
352
        $this->aTokens[$sTokenName] = array(
353
            'value'    => $sValue,
354
            'expire'   => $this->iExpireTime,
355
            'instance' => $this->sCurrentInstance
356
        );
357
        return $sTokenName;
358
    }
359
360
/**
361
 * remove the token, called sTokenName from list
362
 * @param type $sTokenName
363
 */
364
    private function removeToken($sTokenName)
365
    {
366
        if (isset($this->aTokens[$sTokenName])) {
367
            if ($this->bPreserveAllOtherTokens) {
368
                if ($this->sInstanceToDelete) {
369
                    $this->sInstanceToUpdate = $this->sInstanceToDelete;
370
                    $this->sInstanceToDelete = null;
371
                } else {
372
                    $this->sInstanceToUpdate = $this->aTokens[$sTokenName]['instance'];
373
                }
374
            } else {
375
                $this->sInstanceToDelete = $this->aTokens[$sTokenName]['instance'];
376
            }
377
            unset($this->aTokens[$sTokenName]);
378
        }
379
    }
380
381
/**
382
 * remove all expired tokens from list
383
 */
384
    private function removeExpiredTokens()
385
    {
386
        $iTimestamp = time();
387
        foreach ($this->aTokens as $sTokenName => $aToken) {
388
            if ($aToken['expire'] <= $iTimestamp && $aToken['expire'] != 0){
389
                unset($this->aTokens[$sTokenName]);
390
            }
391
        }
392
    }
393
394
/**
395
 * generate a runtime depended hash
396
 * @return string  md5 hash
397
 */
398
    private function generateSalt()
399
    {
400
        list($fUsec, $fSec) = explode(" ", microtime());
401
        $sSalt = (string)rand(10000, 99999)
402
               . (string)((float)$fUsec + (float)$fSec)
403
               . (string)rand(10000, 99999);
404
        return md5($sSalt);
405
    }
406
407
/**
408
 * build a simple fingerprint
409
 * @return string
410
 */
411
    private function buildFingerprint()
412
    {
413
        if (!$this->bUseFingerprint) { return md5('this_is_a_dummy_only'); }
414
        $sClientIp = '127.0.0.1';
415
        if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)){
416
            $aTmp = preg_split('/\s*,\s*/', $_SERVER['HTTP_X_FORWARDED_FOR'], null, PREG_SPLIT_NO_EMPTY);
417
            $sClientIp = array_pop($aTmp);
418
        }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
419
            $sClientIp = $_SERVER['REMOTE_ADDR'];
420
        }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
421
            $sClientIp = $_SERVER['HTTP_CLIENT_IP'];
422
        }
423
        $aTmp = array_chunk(stat(__FILE__), 11);
424
        unset($aTmp[0][8]);
425
        return md5(
426
            __FILE__ . PHP_VERSION . implode('', $aTmp[0])
427
            . (array_key_exists('HTTP_USER_AGENT', $_SERVER) ? $_SERVER['HTTP_USER_AGENT'] : 'AGENT')
428
            . $this->calcClientIpHash($sClientIp)
429
        );
430
    }
431
432
/**
433
 * mask IPv4 as well IPv6 addresses with netmask and make a md5 hash from
434
 * @param string $sClientIp IP as string from $_SERVER['REMOTE_ADDR']
435
 * @return md5 value of masked ip
436
 * @description this method does not accept the IPv6/IPv4 mixed format
437
 *               like "2222:3333:4444:5555:6666:7777:192.168.1.200"
438
 */
439
    private function calcClientIpHash($sRawIp)
440
    {
441
        // clean address from netmask/prefix and port
442
        $sPattern = '/^\[?([.:a-f0-9]*)(?:\/[0-1]*)?(?:\]?.*)$/im';
443
        $sRawIp = preg_replace($sPattern, '$1', $sRawIp);
444
        if (strpos($sRawIp, ':') === false) {
445
// sanitize IPv4 ---------------------------------------------------------------------- //
446
            $iIpV4 = ip2long($sRawIp);
447
            // calculate netmask
448
            $iMask = ($this->iNetmaskLengthV4 < 1)
449
                ? 0
450
                : bindec(
451
                    str_repeat('1', $this->iNetmaskLengthV4).
452
                    str_repeat('0', 32 - $this->iNetmaskLengthV4)
453
                );
454
            // apply mask and reformat to IPv4 string notation.
455
            $sIp = long2ip($iIpV4 & $iMask);
456
        } else {
457
// sanitize IPv6 ---------------------------------------------------------------------- //
458
            // check if IP includes a IPv4 part and convert this into IPv6 format
459
            $sPattern = '/^([:a-f0-9]*?)\:([0-9]{1,3}(?:\.[0-9]{1,3}){3})$/is';
460
            if (preg_match($sPattern, $sRawIp, $aMatches)) {
461
                // convert IPv4 into full size 32bit binary string
462
                $sIpV4Bin = str_pad((string)decbin(ip2long($aMatches[2])), 32, '0', STR_PAD_LEFT) ;
463
                // split into 2 parts of 16bit
464
                $aIpV6Hex = str_split($sIpV4Bin, 16);
465
                // concate the IPv6/96 part and hex of both IPv4 parts
466
                $sRawIp = $aMatches[1].':'.dechex(bindec($aIpV6Hex[0])).':'.dechex(bindec($aIpV6Hex[1]));
467
            }
468
            // calculate number of missing IPv6 words
469
            $iWords = 8 - count(preg_split('/:/', $sRawIp, null, PREG_SPLIT_NO_EMPTY));
470
            // build multiple ':0000:' replacements for '::'
471
            $sReplacement = $iWords ? implode(':', array_fill(0, $iWords, '0000')) : '';
472
            // insert replacements and remove trailing/leading ':'
473
            $sClientIp = trim(preg_replace('/\:\:/', ':'.$sReplacement.':', $sRawIp), ':');
474
            // split all 8 parts from IP into an array
475
            $aIpV6 = array_map(
476
                function($sPart) {
477
                    // expand all parts to 4 hex digits using leading '0'
478
                    return str_pad($sPart, 4, '0', STR_PAD_LEFT);
479
                },
480
                preg_split('/:/', $sClientIp)
481
            );
482
            // build binary netmask from iNetmaskLengthV6
483
            // and split all 8 parts into an array
484
            if ($this->iNetmaskLengthV6 < 1) {
485
                $aMask = array_fill(0, 8, str_repeat('0', 16));
486
            } else {
487
                $aMask = str_split(
488
                    str_repeat('1', $this->iNetmaskLengthV6).
489
                    str_repeat('0', 128 - $this->iNetmaskLengthV6),
490
                    16
491
                );
492
            }
493
            // iterate all IP parts, apply its mask and reformat to IPv6 string notation.
494
            array_walk(
495
                $aIpV6,
496
                function(&$sWord, $iIndex) use ($aMask) {
497
                    $sWord = sprintf('%04x', hexdec($sWord) & bindec($aMask[$iIndex]));
498
                }
499
            );
500
            // reformat to IPv6 string notation.
501
            $sIp = implode(':', $aIpV6);
502
// ------------------------------------------------------------------------------------ //
503
        }
504
        return md5($sIp); // return the hashed IP string
505
    }
506
507
/**
508
 * encode a hex string into a 64char based string
509
 * @param string $sMd5Hash
510
 * @return string
511
 * @description reduce the 32char length of a MD5 to 22 chars
512
 */
513
    private function encodeHash($sMd5Hash)
514
    {
515
         return preg_replace('/[^a-zA-Z0-9]/', '_', rtrim(base64_encode(pack('h*',$sMd5Hash)), '='));
516
//        return rtrim(base64_encode(pack('h*',$sMd5Hash)), '+-= ');
517
    }
518
519
// callback method, needed for PHP-5.3.x only
520
    private function checkFtanCallback($aToken)
521
    {
522
        return $this->encodeHash(md5($aToken['value'].$this->sFingerprint));
523
    }
524
525
/**
526
 * read settings if available
527
 */
528
    private function getSettings()
529
    {
530
        if (!class_exists('WbAdaptor', false)) {
531
        // for WB before 2.8.4
532
            $this->bUseFingerprint  = defined('SEC_TOKEN_FINGERPRINT')
533
                                      ? SEC_TOKEN_FINGERPRINT
534
                                      : $this->bUseFingerprint;
535
            $this->iNetmaskLengthV4 = defined('SEC_TOKEN_NETMASK4')
536
                                      ? SEC_TOKEN_NETMASK4
537
                                      : $this->iNetmaskLengthV4;
538
            $this->iNetmaskLengthV6 = defined('SEC_TOKEN_NETMASK6')
539
                                      ? SEC_TOKEN_NETMASK6
540
                                      : $this->iNetmaskLengthV6;
541
            $this->iTokenLifeTime   = defined('SEC_TOKEN_LIFE_TIME')
542
                                      ? SEC_TOKEN_LIFE_TIME
543
                                      : $this->iTokenLifeTime;
544
        } else {
545
        // for WB from 2.8.4 and up
546
            $oReg = WbAdaptor::getInstance();
547
            $this->bUseFingerprint  = isset($oReg->SecTokenFingerprint)
548
                                      ? $oReg->SecTokenFingerprint
549
                                      : $this->bUseFingerprint;
550
            $this->iNetmaskLengthV4 = isset($oReg->SecTokenIpv4Netmask)
551
                                      ? $oReg->SecTokenIpv4Netmask
552
                                      : $this->iNetmaskLengthV4;
553
            $this->iNetmaskLengthV6 = isset($oReg->SecTokenIpv6PrefixLength)
554
                                      ? $oReg->SecTokenIpv6PrefixLength
555
                                      : $this->iNetmaskLengthV6;
556
            $this->iTokenLifeTime   = isset($oReg->SecTokenLifeTime)
557
                                      ? $oReg->SecTokenLifeTime
558
                                      : $this->iTokenLifeTime;
559
        }
560
        $this->iNetmaskLengthV4 = ($this->iNetmaskLengthV4 < 1 || $this->iNetmaskLengthV4 > 32)
561
                                  ? 0 :$this->iNetmaskLengthV4;
562
        $this->iNetmaskLengthV6 = ($this->iNetmaskLengthV6 < 1 || $this->iNetmaskLengthV6 > 128)
563
                                  ? 0 :$this->iNetmaskLengthV6;
564
        $this->iTokenLifeTime   = $this->sanitizeLifeTime($this->iTokenLifeTime);
565
        if ($this->iTokenLifeTime <= self::LIFETIME_MIN && DEBUG) {
566
            $this->iTokenLifeTime = self::DEBUG_LIFETIME;
567
        }
568
    }
569
570
571
} // end of class SecureTokens