Passed
Push — master ( 8355af...b6ea7c )
by Terrence
15:07
created

Util::isEduGAINAndGetCert()   C

Complexity

Conditions 13
Paths 24

Size

Total Lines 48
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 182

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 25
c 1
b 0
f 0
nc 24
nop 2
dl 0
loc 48
ccs 0
cts 0
cp 0
crap 182
rs 6.6166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace CILogon\Service;
4
5
use CILogon\Service\CSRF;
6
use CILogon\Service\Loggit;
7
use CILogon\Service\IdpList;
8
use CILogon\Service\DBService;
9
use CILogon\Service\SessionMgr;
10
use CILogon\Service\Skin;
11
use CILogon\Service\TimeIt;
12
use CILogon\Service\PortalCookie;
13
use PEAR;
14
use Config;
15
16
// Full path to the php.ini-style config file for the CILogon Service
17
define('CILOGON_INI_FILE', '/var/www/config/cilogon.ini');
18
19
/**
20
 * Util
21
 *
22
 * This class contains a bunch of static (class) utility
23
 * methods, for example getting and setting server environment
24
 * variables and handling cookies. See the header for each function for
25
 * detailed description.
26
 */
27
class Util
28
{
29
    /**
30
     * @var array $ini_array Read the cilogon.ini file into an array
31
     */
32
    public static $ini_array = null;
33
34
    /**
35
     * @var TimeIt $timeit Initialize by calling static::startTiming() in
36
     * init().
37
     */
38
    public static $timeit;
39
40
    /**
41
     * @var IdPList $idplist A 'global' IdpList object since dplist.xml is
42
     *      large and expensive to create multiple times.
43
     */
44
    public static $idplist = null;
45
46
    /**
47
     * @var CSRF $csrf A 'global' CSRF token object to set the CSRF cookie
48
     * and print the hidden CSRF form element. Needs to be set only once
49
     * to keep the same CSRF value through the session.
50
     */
51
    public static $csrf = null;
52
53
    /**
54
     * @var Skin $skin A 'global' Skin object for skin configuration.
55
     */
56
    public static $skin = null;
57
58
    /**
59
     * @var array $oauth2idps An array of OAuth2 Identity Providers.
60
     */
61
    public static $oauth2idps = ['Google', 'GitHub', 'ORCID'];
62
63
64
    /**
65
     * getIdPList
66
     *
67
     * This function initializes the class $idplist object (if not yet
68
     * created) and returns it. This allows for a single 'global'
69
     * $idplist to be used by other classes (since creating an IdPList
70
     * object is expensive).
71
     *
72
     * @return IdPList The class instantiated IdPList object.
73
     **/
74
    public static function getIdpList()
75
    {
76
        if (is_null(static::$idplist)) {
77
            static::$idplist = new IdpList();
78
        }
79
        return static::$idplist;
80
    }
81
82
    /**
83
     * getCsrf
84
     *
85
     * This function initializes the class $csrf object (if not yet
86
     * created) and returns it. This allows for a single 'global'
87
     * $csrf to be used by other classes (since we want the CSRV value
88
     * to be consistent for the current page load).
89
     *
90
     * @return CSRF The class instantiated CSRF object.
91
     */
92
    public static function getCsrf()
93
    {
94
        if (is_null(static::$csrf)) {
95
            static::$csrf = new CSRF();
96
        }
97
        return static::$csrf;
98
    }
99
100
    /**
101
     * getSkin
102
     *
103
     * This function initializes the class $skin object (if not yet
104
     * created) and returns it. This allows for a single 'global'
105
     * $skin to be used by other classes (since loading the skin is
106
     * potentially expensive).
107
     *
108
     * @return The class instantiated Skin object.
0 ignored issues
show
Bug introduced by
The type CILogon\Service\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
109
     */
110
    public static function getSkin()
111
    {
112
        if (is_null(static::$skin)) {
113
            static::$skin = new Skin();
114
        }
115
        return static::$skin;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::skin returns the type CILogon\Service\Skin which is incompatible with the documented return type CILogon\Service\The.
Loading history...
116
    }
117
118
    /**
119
     * getConfigVar
120
     *
121
     * This function returns a sinle configuration vale from the
122
     * CILOGON_INI_FILE, or empty string if no such configuration
123
     * value is found in the file.
124
     *
125
     * @param string $config The config parameter to read from the
126
     *        cilogon.ini file.
127
     * @return string The value of the config parameter, or empty string
128
     *         if no such parameter found in config.ini.
129
     */
130
    public static function getConfigVar($config)
131
    {
132
        $retval = '';
133
        // Read in the config file into an array
134
        if (is_null(static::$ini_array)) {
0 ignored issues
show
introduced by
The condition is_null(static::ini_array) is always false.
Loading history...
135
            static::$ini_array = @parse_ini_file(CILOGON_INI_FILE);
136
        }
137
        if ((is_array(static::$ini_array)) &&
138
            (array_key_exists($config, static::$ini_array))) {
139
            $retval = static::$ini_array[$config];
140
        }
141
        return $retval;
142
    }
143
144
    /**
145
     * startTiming
146
     *
147
     * This function initializes the class variable $timeit which is
148
     * used for timing/benchmarking purposes.
149
     */
150
    public static function startTiming()
151
    {
152
        static::$timeit = new TimeIt(TimeIt::DEFAULTFILENAME, true);
153
    }
154
155
    /**
156
     * getServerVar
157
     *
158
     * This function queries a given $_SERVER variable (which is set
159
     * by the Apache server) and returns the value.
160
     *
161
     * @param string $serv The $_SERVER variable to query.
162
     * @return string The value of the $_SERVER variable or empty string
163
     *         if that variable is not set.
164
     */
165
    public static function getServerVar($serv)
166
    {
167
        $retval = '';
168
        if (isset($_SERVER[$serv])) {
169
            $retval = $_SERVER[$serv];
170
        }
171
        return $retval;
172
    }
173
174
    /**
175
     * getGetVar
176
     *
177
     * This function queries a given $_GET parameter (which is set in
178
     * the URL via a '?parameter=value' parameter) and returns the
179
     * value.
180
     *
181
     * @param string $get The $_GET variable to query.
182
     * @return string The value of the $_GET variable or empty string if
183
     *         that variable is not set.
184
     */
185
    public static function getGetVar($get)
186
    {
187
        $retval = '';
188
        if (isset($_GET[$get])) {
189
            $retval = $_GET[$get];
190
        }
191
        return $retval;
192
    }
193
194
    /**
195
     * getPostVar
196
     *
197
     * This function queries a given $_POST variable (which is set when
198
     * the user submits a form, for example) and returns the value.
199
     *
200
     * @param string $post The $_POST variable to query.
201
     * @return string The value of the $_POST variable or empty string if
202
     *         that variable is not set.
203
     */
204
    public static function getPostVar($post)
205
    {
206
        $retval = '';
207
        if (isset($_POST[$post])) {
208
            $retval = $_POST[$post];
209
        }
210
        return $retval;
211
    }
212
213
    /**
214
     * getGetOrPostVar
215
     *
216
     * This function looks for a $_GET or $_POST variable, with
217
     * preference given to $_GET if both are present.
218
     *
219
     * @param string $var The $_GET or $_POST variable to query.
220
     * @return string The value of the $_GET or $_POST variable
221
     *         if present. Empty string if variable is not set.
222
     */
223
    public static function getGetOrPostVar($var)
224
    {
225
        $retval = static::getGetVar($var);
226
        if (empty($retval)) {
227
            $retval = static::getPostVar($var);
228
        }
229
        return $retval;
230
    }
231
232
    /**
233
     * getCookieVar
234
     *
235
     * This function returns the value of a given cookie.
236
     *
237
     * @param string $cookie he $_COOKIE variable to query.
238
     * @return string The value of the $_COOKIE variable or empty string
239
     *         if that variable is not set.
240
     */
241
    public static function getCookieVar($cookie)
242
    {
243
        $retval = '';
244
        if (isset($_COOKIE[$cookie])) {
245
            $retval = $_COOKIE[$cookie];
246
        }
247
        return $retval;
248
    }
249
250
    /**
251
     * setCookieVar
252
     *
253
     * This function sets a cookie.
254
     *
255
     * @param string $cookie The name of the cookie to set.
256
     * @param string $value (Optional) The value to set for the cookie.
257
     *        Defaults to empty string.
258
     * @param int $exp The future expiration time (in seconds) of the
259
     *        cookie. Defaults to 1 year from now. If set to 0,
260
     *        the cookie expires at the end of the session.
261
     */
262
    public static function setCookieVar($cookie, $value = '', $exp = 31536000)
263
    {
264
        if ($exp > 0) {
265
            $exp += time();
266
        }
267
        setcookie($cookie, $value, $exp, '/', '.'.static::getDN(), true);
268
        $_COOKIE[$cookie] = $value;
269
    }
270
271
    /**
272
     * unsetCookieVar
273
     *
274
     * This function unsets a cookie. Strictly speaking, the cookie is
275
     * not removed, rather it is set to an empty value with an expired
276
     * time.
277
     *
278
     * @param string $cookie The name of the cookie to unset (delete).
279
     */
280
    public static function unsetCookieVar($cookie)
281
    {
282
        setcookie($cookie, '', 1, '/', '.'.static::getDN(), true);
283
        unset($_COOKIE[$cookie]);
284
    }
285
286
    /**
287
     * getPortalOrNormalCookieVar
288
     *
289
     * This is a convenience function which first checks if there is a
290
     * OAuth 1.0a ('delegate') or OIDC ('authorize') session active.
291
     * If so, it attempts to get the requested cookie from the
292
     * associated portalcookie. If there is not an OAuth/OIDC session
293
     * active, it looks for a 'normal' cookie. If you need a
294
     * portalcookie object to do multiple get/set method calls from
295
     * one function, it is probably better NOT to use this method since
296
     * creating the portalcookie object is potentially expensive.
297
     *
298
     * @param string $cookie The name of the cookie to get.
299
     * @return string The cookie value from either the portalcookie
300
     *         (in the case of an active OAuth session) or the
301
     *         'normal' cookie. Return empty string if no matching
302
     *         cookie in either place.
303
     */
304
    public static function getPortalOrNormalCookieVar($cookie)
305
    {
306
        $retval = '';
307
        $pc = new PortalCookie();
308
        $pn = $pc->getPortalName();
309
        if (strlen($pn) > 0) {
310
            $retval = $pc->get($cookie);
311
        } else {
312
            $retval = static::getCookieVar($cookie);
313
        }
314
        return $retval;
315
    }
316
317
    /**
318
     * getSessionVar
319
     *
320
     * This function returns the value of a given PHP Session variable.
321
     *
322
     * @param string $sess The $_SESSION variable to query.
323
     * @return string The value of the $_SESSION variable or empty string
324
     *         if that variable is not set.
325
     */
326
    public static function getSessionVar($sess)
327
    {
328
        $retval = '';
329
        if (isset($_SESSION[$sess])) {
330
            $retval = $_SESSION[$sess];
331
        }
332
        return $retval;
333
    }
334
335
    /**
336
     * setSessionVar
337
     *
338
     * This function can set or unset a given PHP session variable.
339
     * The first parameter is the PHP session variable to set/unset.
340
     * If the second parameter is the empty string, then the session
341
     * variable is unset.  Otherwise, the session variable is set to
342
     * the second parameter.  The function returns true if the session
343
     * variable was set to a non-empty value, false otherwise.
344
     * Normally, the return value can be ignored.
345
     *
346
     * @param string $key The name of the PHP session variable to set
347
     *        (or unset).
348
     * @param string $value (Optional) The value of the PHP session variable
349
     *        (to set), or empty string (to unset). Defaults to empty
350
     *        string (implies unset the session variable).
351
     * @return bool True if the PHP session variable was set to a
352
     *         non-empty string, false if variable was unset or if
353
     *         the specified session variable was not previously set.
354
     */
355
    public static function setSessionVar($key, $value = '')
356
    {
357
        $retval = false;  // Assume we want to unset the session variable
358
        if (strlen($key) > 0) {  // Make sure session var name was passed in
359
            if (strlen($value) > 0) {
360
                $_SESSION[$key] = $value;
361
                $retval = true;
362
            } else {
363
                static::unsetSessionVar($key);
364
            }
365
        }
366
        return $retval;
367
    }
368
369
    /**
370
     * unsetSessionVar
371
     *
372
     * This function clears the given PHP session variable by first
373
     * setting it to null and then unsetting it entirely.
374
     *
375
     * @param string $sess The $_SESSION variable to erase.
376
     */
377
    public static function unsetSessionVar($sess)
378
    {
379
        if (isset($_SESSION[$sess])) {
380
            $_SESSION[$sess] = null;
381
            unset($_SESSION[$sess]);
382
        }
383
    }
384
385
    /**
386
     * removeShibCookies
387
     *
388
     * This function removes all '_shib*' cookies currently in the
389
     * user's browser session. In effect, this logs the user out of
390
     * any IdP. Note that you must call this before you output any
391
     * HTML. Strictly speaking, the cookies are not removed, rather
392
     * they are set to empty values with expired times.
393
     */
394
    public static function removeShibCookies()
395
    {
396
        while (list($key, $val) = each($_COOKIE)) {
0 ignored issues
show
Deprecated Code introduced by
The function each() has been deprecated: 7.2 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

396
        while (list($key, $val) = /** @scrutinizer ignore-deprecated */ each($_COOKIE)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
397
            if (strncmp($key, '_shib', strlen('_shib')) == 0) {
398
                static::unsetCookieVar($key);
399
            }
400
        }
401
    }
402
403
    /**
404
     * startPHPSession
405
     *
406
     * This function starts a secure PHP session and should be called
407
     * at the beginning of each script before any HTML is output.  It
408
     * does a trick of setting a 'lastaccess' time so that the
409
     * $_SESSION variable does not expire without warning.
410
     *
411
     * @param string $storetype (Optional) Storage location of the PHP
412
     *        session data, one of 'file' or 'mysql'. Defaults to null,
413
     *        which means use the value of storage.phpsessions from the
414
     *        cilogon.ini config file, or 'file' if no such
415
     *        parameter configured.
416
     */
417
    public static function startPHPSession($storetype = null)
0 ignored issues
show
Unused Code introduced by
The parameter $storetype is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

417
    public static function startPHPSession(/** @scrutinizer ignore-unused */ $storetype = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
418
    {
419
        // No parameter given? Use the value read in from cilogon.ini file.
420
        // If storage.phpsessions == 'mysql', create a sessionmgr().
421
        $storetype = static::getConfigVar('storage.phpsessions');
422
423
        if (preg_match('/^mysql/', $storetype)) {
424
            $sessionmgr = new SessionMgr();
0 ignored issues
show
Unused Code introduced by
The assignment to $sessionmgr is dead and can be removed.
Loading history...
425
        }
426
427
        ini_set('session.cookie_secure', true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type string expected by parameter $newvalue of ini_set(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

427
        ini_set('session.cookie_secure', /** @scrutinizer ignore-type */ true);
Loading history...
428
        ini_set('session.cookie_domain', '.'.static::getDN());
429
        session_start();
430
        if ((!isset($_SESSION['lastaccess']) ||
431
            (time() - $_SESSION['lastaccess']) > 60)) {
432
            $_SESSION['lastaccess'] = time();
433
        }
434
    }
435
436
    /**
437
     * getScriptDir
438
     *
439
     * This function returns the directory (or full url) of the script
440
     * that is currently running.  The returned directory/url is
441
     * terminated by a '/' character (unless the second parameter is
442
     * set to true). This function is useful for those scripts named
443
     * index.php where we don't want to actually see 'index.php' in the
444
     * address bar (again, unless the second parameter is set to true).
445
     *
446
     * @param bool $prependhttp (Optional) Boolean to prepend 'http(s)://' to
447
     *        the script name. Defaults to false.
448
     * @param bool $stripfile (Optional) Boolean to strip off the trailing
449
     *        filename (e.g. index.php) from the path.
450
     *        Defaults to true (i.e., defaults to directory
451
     *        only without the trailing filename).
452
     * @return string The directory or url of the current script, with or
453
     *         without the trailing .php filename.
454
     */
455
    public static function getScriptDir($prependhttp = false, $stripfile = true)
456
    {
457
        $retval = static::getServerVar('SCRIPT_NAME');
458
        if ($stripfile) {
459
            $retval = dirname($retval);
460
        }
461
        if ($retval == '.') {
462
            $retval = '';
463
        }
464
        if ((strlen($retval) == 0) ||
465
            ($stripfile && ($retval[strlen($retval)-1] != '/'))) {
466
            $retval .= '/';  // Append a slash if necessary
467
        }
468
        if ($prependhttp) {  // Prepend http(s)://hostname
469
            $retval = 'http' .
470
                      ((strtolower(static::getServerVar('HTTPS')) == 'on')?'s':'') .
471
                      '://' . static::getServerVar('HTTP_HOST') . $retval;
472
        }
473
        return $retval;
474
    }
475
476
    /**
477
     * readArrayFromFile
478
     *
479
     * This function reads in the contents of a file into an array. It
480
     * is assumed that the file contains lines of the form:
481
     *     key value
482
     * where 'key' and 'value' are separated by whitespace.  The 'key'
483
     * portion of the string may not contain any whitespace, but the
484
     * 'value' part of the line may contain whitespace. Any empty lines
485
     * or lines starting with '#' (comments, without leading spaces)
486
     * in the file are skipped.  Note that this assumes that each 'key'
487
     * in the file is unique.  If there is any problem reading the
488
     * file, the resulting array will be empty.
489
     *
490
     * @param string $filename The name of the file to read.
491
     * @return array An array containing the contents of the file.
492
     */
493
    public static function readArrayFromFile($filename)
494
    {
495
        $retarray = array();
496
        if (is_readable($filename)) {
497
            $lines = file(
498
                $filename,
499
                FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES
500
            );
501
            foreach ($lines as $line) {
502
                if (substr($line, 0, 1) != '#') { // Skip '#' comment lines
503
                    $values = preg_split('/\s+/', $line, 2);
504
                    $retarray[$values[0]] = @$values[1];
505
                }
506
            }
507
        }
508
509
        return $retarray;
510
    }
511
512
    /**
513
     * writeArrayToFile
514
     *
515
     * This funtion writes an array (with key=>value pairs) to a file,
516
     * each line will be of the form:
517
     *     key value
518
     * The 'key' and 'value' strings are separated by a space. Note
519
     * that a 'key' may not contain any whitespace (e.g. tabs), but a
520
     * 'value' may contain whitespace. To be super safe, the array is
521
     * first written to a temporary file, which is then renamed to the
522
     * final desired filename.
523
     *
524
     * @param string $filename The name of the file to write.
525
     * @param array $thearray The array to be written to the file.
526
     * @return bool True if successfully wrote file, false otherwise.
527
     */
528
    public static function writeArrayToFile($filename, $thearray)
529
    {
530
        $retval = false;  // Assume write failed
531
        $tmpfnmae = tempnam('/tmp', 'ARR');
0 ignored issues
show
Unused Code introduced by
The assignment to $tmpfnmae is dead and can be removed.
Loading history...
532
        if ($fh = fopen($tmpfname, 'w')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $tmpfname does not exist. Did you maybe mean $tmpfnmae?
Loading history...
533
            if (flock($fh, LOCK_EX)) {
534
                foreach ($thearray as $key => $value) {
535
                    fwrite($fh, "$key $value\n");
536
                }
537
                flock($fh, LOCK_UN);
538
            }
539
            fclose($fh);
540
            if (@rename($tmpfname, $filename)) {
541
                $retval = true;
542
            } else {
543
                @unlink($tmpfname);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

543
                /** @scrutinizer ignore-unhandled */ @unlink($tmpfname);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
544
            }
545
        }
546
547
        return $retval;
548
    }
549
550
    /**
551
     * parseGridShibConf
552
     *
553
     * This function parses the gridshib-ca.conf file and returns an
554
     * array containing the various options. It uses the PHP
555
     * PEAR::Config package to parse the config file. The
556
     * gridshib-ca.conf file is MOSTLY an Apache-style config file.
557
     * However, each option has an extra ' = ' prepended, so you will
558
     * need to strip these off each config option. For example, to get
559
     * the 'MaximumCredLifetime' value which is in the 'CA' section,
560
     * you would do the following:
561
     *     $gridshibconf = Util::parseGridShibConf();
562
     *     $life = preg_replace('%^\s*=\s*%','',
563
     *             $gridshibconf['root']['CA']['MaximumCredLifetime']);
564
     *
565
     * @param string $conffile (Optional) Full path location of
566
     *        gridshib-ca.conf file. Defaults to
567
     *        '/usr/local/gridshib-ca/conf/gridshib-ca.conf'.
568
     * @return array An array containing the various configuration
569
     *         parameters in the gridshib-ca.conf file.
570
     */
571
    public static function parseGridShibConf(
572
        $conffile = '/usr/local/gridshib-ca/conf/gridshib-ca.conf'
573
    ) {
574
        $conf = new Config;
575
        $root = $conf->parseConfig($conffile, 'Apache');
576
        $gridshibconf = array();
577
        if (!(PEAR::isError($root))) {
578
            $gridshibconf = $root->toArray();
579
        }
580
        return $gridshibconf;
581
    }
582
583
    /**
584
     * tempDir
585
     *
586
     * This function creates a temporary subdirectory within the
587
     * specified subdirectory. The new directory name is composed of
588
     * 16 hexadecimal letters, plus any prefix if you specify one. The
589
     * full path of the the newly created directory is returned.
590
     *
591
     * @param string $dir The full path to the containing directory.
592
     * @param string $prefix (Optional) A prefix for the new temporary
593
     *        directory. Defaults to empty string.
594
     * @param int $mode (Optional) Access permissions for the new
595
     *        temporary directory. Defaults to 0775.
596
     * @return string Full path to the newly created temporary directory.
597
     */
598
    public static function tempDir($dir, $prefix = '', $mode = 0775)
599
    {
600
        if (substr($dir, -1) != '/') {
601
            $dir .= '/';
602
        }
603
604
        $path = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $path is dead and can be removed.
Loading history...
605
        do {
606
            $path = $dir . $prefix . sprintf("%08X%08X", mt_rand(), mt_rand());
607
        } while (!mkdir($path, $mode, true));
608
609
        return $path;
610
    }
611
612
    /**
613
     * deleteDir
614
     *
615
     * This function deletes a directory and all of its contents.
616
     *
617
     * @param string $dir The (possibly non-empty) directory to delete.
618
     * @param bool $shred (Optional) Shred the file before deleting?
619
     *        Defaults to false.
620
     */
621
    public static function deleteDir($dir, $shred = false)
622
    {
623
        if (is_dir($dir)) {
624
            $objects = scandir($dir);
625
            foreach ($objects as $object) {
626
                if ($object != "." && $object != "..") {
627
                    if (filetype($dir."/".$object) == "dir") {
628
                        static::deleteDir($dir."/".$object);
629
                    } else {
630
                        if ($shred) {
631
                            @exec('/bin/env /usr/bin/shred -u -z '.$dir."/".$object);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for exec(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

631
                            /** @scrutinizer ignore-unhandled */ @exec('/bin/env /usr/bin/shred -u -z '.$dir."/".$object);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
632
                        } else {
633
                            @unlink($dir."/".$object);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

633
                            /** @scrutinizer ignore-unhandled */ @unlink($dir."/".$object);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
634
                        }
635
                    }
636
                }
637
            }
638
            reset($objects);
0 ignored issues
show
Bug introduced by
It seems like $objects can also be of type false; however, parameter $array of reset() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

638
            reset(/** @scrutinizer ignore-type */ $objects);
Loading history...
639
            @rmdir($dir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for rmdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

639
            /** @scrutinizer ignore-unhandled */ @rmdir($dir);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
640
        }
641
    }
642
643
    /**
644
     * htmlent
645
     *
646
     * This method is necessary since htmlentities() does not seem to
647
     * obey the default arguments as documented in the PHP manual, and
648
     * instead encodes accented characters incorrectly. By specifying
649
     * the flags and encoding, the problem is solved.
650
     *
651
     * @param string $str : A string to process with htmlentities().
652
     * @return string The input string processed by htmlentities with
653
     *         specific options.
654
     */
655
    public static function htmlent($str)
656
    {
657
        return htmlentities($str, ENT_COMPAT|ENT_HTML401, 'UTF-8');
658
    }
659
660
    /**
661
     * sendErrorAlert
662
     *
663
     * Use this function to send an error message. The $summary should
664
     * be a short description of the error since it is placed in the
665
     * subject of the email. Put a more verbose description of the
666
     * error in the $detail parameter. Any session variables available
667
     * are appended to the body of the message.
668
     *
669
     * @param string $summary A brief summary of the error (in email subject)
670
     * @param string $detail A detailed description of the error (in the
671
     *        email body)
672
     * @param string $mailto (Optional) The destination email address.
673
     *        Defaults to '[email protected]'.
674
     */
675
    public static function sendErrorAlert(
676
        $summary,
677
        $detail,
678
        $mailto = '[email protected]'
679
    ) {
680
        $sessionvars = array(
681
            'idp'          => 'IdP ID',
682
            'idpname'      => 'IdP Name',
683
            'uid'          => 'Database UID',
684
            'dn'           => 'Cert DN',
685
            'firstname'    => 'First Name',
686
            'lastname'     => 'Last Name',
687
            'displayname'  => 'Display Name',
688
            'ePPN'         => 'ePPN',
689
            'ePTID'        => 'ePTID',
690
            'openID'       => 'OpenID ID',
691
            'oidcID'       => 'OIDC ID',
692
            'loa'          => 'LOA',
693
            'affiliation'  => 'Affiliation',
694
            'ou'           => 'OU',
695
            'memberof'     => 'MemberOf',
696
            'acr'          => 'AuthnContextClassRef',
697
            'entitlement'  => 'Entitlement',
698
            'itrustuin'    => 'iTrustUIN',
699
            'cilogon_skin' => 'Skin Name',
700
            'twofactor'    => 'Two-Factor',
701
            'authntime'    => 'Authn Time'
702
        );
703
704
        $remoteaddr = static::getServerVar('REMOTE_ADDR');
705
        $remotehost = gethostbyaddr($remoteaddr);
706
        $mailfrom = 'From: [email protected]' . "\r\n" .
707
                    'X-Mailer: PHP/' . phpversion();
708
        $mailsubj = 'CILogon Service on ' . php_uname('n') .
709
                    ' - ' . $summary;
710
        $mailmsg  = '
711
CILogon Service - ' . $summary . '
712
-----------------------------------------------------------
713
' . $detail . '
714
715
Session Variables
716
-----------------
717
Timestamp     = ' . date(DATE_ATOM) . '
718
Server Host   = ' . static::getHN() . '
719
Remote Address= ' . $remoteaddr . '
720
' . (($remotehost !== false) ? "Remote Host   = $remotehost" : '') . '
721
';
722
723
        foreach ($sessionvars as $svar => $sname) {
724
            if (strlen($val = static::getSessionVar($svar)) > 0) {
725
                $mailmsg .= sprintf("%-14s= %s\n", $sname, $val);
726
            }
727
        }
728
729
        mail($mailto, $mailsubj, $mailmsg, $mailfrom);
730
    }
731
732
    /**
733
     * getFirstAndLastName
734
     *
735
     * This function attempts to get the first and last name of a user
736
     * extracted from the 'full name' (displayName) of the user.
737
     * Simply pass in all name info (full, first, and last) and the
738
     * function first tries to break up the full name into first/last.
739
     * If this is not sufficient, the function checks first and last
740
     * name. Finally, if either first or last is blank, the function
741
     * duplicates first <=> last so both names have the same value.
742
     * Note that even with all this, you still need to check if the
743
     * returned (first,last) names are blank.
744
     *
745
     * @param string $full The 'full name' of the user
746
     * @param string $first (Optional) The 'first name' of the user
747
     * @param string $last (Optional) The 'last name' of the user
748
     * @return array An array 'list(firstname,lastname)'
749
     */
750
    public static function getFirstAndLastName($full, $first = '', $last = '')
751
    {
752
        $firstname = '';
753
        $lastname = '';
754
755
        # Try to split the incoming $full name into first and last names
756
        if (strlen($full) > 0) {
757
            $names = preg_split('/\s+/', $full, 2);
758
            $firstname = @$names[0];
759
            $lastname =  @$names[1];
760
        }
761
762
        # If either first or last name blank, then use incoming $first and $last
763
        if (strlen($firstname) == 0) {
764
            $firstname = $first;
765
        }
766
        if (strlen($lastname) == 0) {
767
            $lastname = $last;
768
        }
769
770
        # Finally, if only a single name, copy first name <=> last name
771
        if (strlen($lastname) == 0) {
772
            $lastname = $firstname;
773
        }
774
        if (strlen($firstname) == 0) {
775
            $firstname = $lastname;
776
        }
777
778
        # Return both names as an array (i.e., use list($first,last)=...)
779
        return array($firstname,$lastname);
780
    }
781
782
    /**
783
     * getHN
784
     *
785
     * This function calculates and returns the 'hostname' for the
786
     * server. It first checks HTTP_HOST. If not set, it returns
787
     * 'cilogon.org'. This is needed by command line scripts.
788
     *
789
     * @return string The 'Hostname' for the web server.
790
     */
791
    public static function getHN()
792
    {
793
        $thehostname = static::getServerVar('HTTP_HOST');
794
        if (strlen($thehostname) == 0) {
795
            $thehostname = 'cilogon.org';
796
        }
797
        return $thehostname;
798
    }
799
800
    /**
801
     * getDN
802
     *
803
     * This function calculates and returns the 'domainname' for the
804
     * server. It uses the hostname value calculated by getHN() and
805
     * uses the last two segments.
806
     *
807
     * @return string The 'Domainname' for the web server.
808
     */
809
    public static function getDN()
810
    {
811
        $thedomainname = static::getHN();
812
        if (preg_match('/[^\.]+\.[^\.]+$/', $thedomainname, $matches)) {
813
            $thedomainname = $matches[0];
814
        }
815
        return $thedomainname;
816
    }
817
818
    /**
819
     * getAuthzUrl
820
     *
821
     * This funtion takes in the name of an IdP (e.g., 'Google') and
822
     * returns the assoicated OAuth2 authorization URL.
823
     *
824
     * @param string $idp The name of an OAuth2 Identity Provider.
825
     * @return string The authorization URL for the given IdP.
826
     */
827
    public static function getAuthzUrl($idp)
828
    {
829
        $url = null;
830
        $idptourl = array(
831
            'Google' => 'https://accounts.google.com/o/oauth2/auth',
832
            'GitHub' => 'https://github.com/login/oauth/authorize',
833
            'ORCID'  => 'https://orcid.org/oauth/authorize',
834
        );
835
        if (array_key_exists($idp, $idptourl)) {
836
            $url = $idptourl[$idp];
837
        }
838
        return $url;
839
    }
840
841
    /**
842
     * getAuthzIdP
843
     *
844
     * This function takes in the OAuth2 authorization URL and returns
845
     * the associated pretty-print name of the IdP.
846
     *
847
     * @param string $url The authorization URL of an OAuth2 Identity Provider.
848
     * @return string The name of the IdP.
849
     */
850
    public static function getAuthzIdP($url)
851
    {
852
        $idp = null;
853
        $urltoidp = array(
854
            'https://accounts.google.com/o/oauth2/auth' => 'Google',
855
            'https://github.com/login/oauth/authorize'  => 'GitHub',
856
            'https://orcid.org/oauth/authorize'         => 'ORCID',
857
        );
858
        if (array_key_exists($url, $urltoidp)) {
859
            $idp = $urltoidp[$url];
860
        }
861
        return $idp;
862
    }
863
864
    /**
865
     * saveUserToDataStore
866
     *
867
     * This function is called when a user logs on to save identity
868
     * information to the datastore. As it is used by both Shibboleth
869
     * and OpenID Identity Providers, some parameters passed in may
870
     * be blank (empty string). If the function verifies that the minimal
871
     * sets of parameters are valid, the dbservice servlet is called
872
     * to save the user info. Then various session variables are set
873
     * for use by the program later on. In case of error, an email
874
     * alert is sent showing the missing parameters.
875
     *
876
     * @param mixed $args Variable number of paramters ordered as follows:
877
     *     remoteuser -The REMOTE_USER from HTTP headers
878
     *     idp - The provider IdP Identifier / URL endpoint
879
     *     idpname - The pretty print provider IdP name
880
     *     firstname - The user's first name
881
     *     lastname - The user's last name
882
     *     displayname - The user's display name
883
     *     emailaddr-  The user's email address
884
     *     loa - The level of assurance (e.g., openid/basic/silver)
885
     *     ePPN - User's ePPN (for SAML IdPs)
886
     *     ePTID - User's ePTID (for SAML IdPs)
887
     *     openidID - User's OpenID 2.0 Identifier (Google deprecated)
888
     *     oidcID - User's OpenID Connect Identifier
889
     *     affiliation - User's affiliation
890
     *     ou - User's organizational unit (OU)
891
     *     memberof - User's isMemberOf group info
892
     *     acr - Authentication Context Class Ref
893
     *     entitlement - User's entitlement
894
     *     itrustuin - User's univerity ID number
895
     */
896
    public static function saveUserToDataStore(...$args)
897
    {
898
        $dbs = new DBService();
899
900
        // Save the passed-in variables to the session for later use
901
        // (e.g., by the error handler in handleGotUser). Then get these
902
        // session variables into local vars for ease of use.
903
        static::setUserAttributeSessionVars(...$args);
904
        $remoteuser  = static::getSessionVar('remoteuser');
905
        $idp         = static::getSessionVar('idp');
906
        $idpname     = static::getSessionVar('idpname');
907
        $firstname   = static::getSessionVar('firstname');
908
        $lastname    = static::getSessionVar('lastname');
909
        $displayname = static::getSessionVar('displayname');
910
        $emailaddr   = static::getSessionvar('emailaddr');
911
        $loa         = static::getSessionVar('loa');
912
        $ePPN        = static::getSessionVar('ePPN');
913
        $ePTID       = static::getSessionVar('ePTID');
914
        $openidID    = static::getSessionVar('openidID');
915
        $oidcID      = static::getSessionVar('oidcID');
916
        $affiliation = static::getSessionVar('affiliation');
917
        $ou          = static::getSessionVar('ou');
918
        $memberof    = static::getSessionVar('memberof');
919
        $acr         = static::getSessionVar('acr');
920
        $entitlement = static::getSessionVar('entitlement');
921
        $itrustuin   = static::getSessionVar('itrustuin');
922
923
        static::setSessionVar('submit', static::getSessionVar('responsesubmit'));
924
925
        // Make sure parameters are not empty strings, and email is valid
926
        // Must have at least one of remoteuser/ePPN/ePTID/openidID/oidcID
927
        if (((strlen($remoteuser) > 0) ||
928
               (strlen($ePPN) > 0) ||
929
               (strlen($ePTID) > 0) ||
930
               (strlen($openidID) > 0) ||
931
               (strlen($oidcID) > 0)) &&
932
            (strlen($idp) > 0) &&
933
            (strlen($idpname) > 0)  &&
934
            (strlen($firstname) > 0) &&
935
            (strlen($lastname) > 0) &&
936
            (strlen($emailaddr) > 0) &&
937
            (filter_var($emailaddr, FILTER_VALIDATE_EMAIL))) {
938
            // For the new Google OAuth 2.0 endpoint, we want to keep the
939
            // old Google OpenID endpoint URL in the database (so user does
940
            // not get a new certificate subject DN). Change the idp
941
            // and idpname to the old Google OpenID values.
942
            if (($idpname == 'Google+') ||
943
                ($idp == static::getAuthzUrl('Google'))) {
944
                $idpname = 'Google';
945
                $idp = 'https://www.google.com/accounts/o8/id';
946
            }
947
948
            // In the database, keep a consistent ProviderId format: only
949
            // allow 'http' (not 'https') and remove any 'www.' prefix.
950
            if ($loa == 'openid') {
951
                $idp = preg_replace('%^https://(www\.)?%', 'http://', $idp);
952
            }
953
954
            $result = $dbs->getUser(
955
                $remoteuser,
956
                $idp,
957
                $idpname,
958
                $firstname,
959
                $lastname,
960
                $displayname,
961
                $emailaddr,
962
                $ePPN,
963
                $ePTID,
964
                $openidID,
965
                $oidcID,
966
                $affiliation,
967
                $ou,
968
                $memberof,
969
                $acr,
970
                $entitlement,
971
                $itrustuin
972
            );
973
            static::setSessionVar('uid', $dbs->user_uid);
974
            static::setSessionVar('dn', $dbs->distinguished_name);
975
            static::setSessionVar('twofactor', $dbs->two_factor);
976
            static::setSessionVar('status', $dbs->status);
977
            if (!$result) {
978
                static::sendErrorAlert(
979
                    'dbService Error',
980
                    'Error calling dbservice action "getUser" in ' .
981
                    'saveUserToDatastore() method.'
982
                );
983
            }
984
        } else { // Missing one or more required attributes
985
            static::setSessionVar(
986
                'status',
987
                DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']
988
            );
989
        }
990
991
        // If 'status' is not STATUS_OK*, then send an error email
992
        $status = static::getSessionVar('status');
993
        if ($status & 1) { // Bad status codes are odd
994
            // For missing parameter errors, log an error message
995
            if ($status ==
996
                DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']) {
997
                $log = new Loggit();
998
                $log->error('STATUS_MISSING_PARAMETER_ERROR', true);
999
            }
1000
1001
            // For other dbservice errors OR for any error involving
1002
            // LIGO (e.g., missing parameter error), send email alert.
1003
            if (($status !=
1004
                    DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']) ||
1005
                (preg_match('/ligo\.org/', $idp))) {
1006
                $mailto = '[email protected]';
1007
1008
                // Set $disableligoalerts = true to stop LIGO failures
1009
                // from being sent to '[email protected]', but still
1010
                // sent to '[email protected]'.
1011
                $disableligoalerts = false;
1012
1013
                // Fixes CIL-205 - Notify LIGO about IdP login errors
1014
                if (preg_match('/ligo\.org/', $idp)) {
1015
                    if ($disableligoalerts) {
0 ignored issues
show
introduced by
The condition $disableligoalerts is always false.
Loading history...
1016
                        $mailto = '';
1017
                    }
1018
                    $mailto .= ((strlen($mailto) > 0) ? ',' : '') .
1019
                        '[email protected]';
1020
                }
1021
1022
                static::sendErrorAlert(
1023
                    'Failure in ' .
1024
                        (($loa == 'openid') ? '' : '/secure') . '/getuser/',
1025
                    'Remote_User   = ' . ((strlen($remoteuser) > 0) ?
1026
                        $remoteuser : '<MISSING>') . "\n" .
1027
                    'IdP ID        = ' . ((strlen($idp) > 0) ?
1028
                        $idp : '<MISSING>') . "\n" .
1029
                    'IdP Name      = ' . ((strlen($idpname) > 0) ?
1030
                        $idpname : '<MISSING>') . "\n" .
1031
                    'First Name    = ' . ((strlen($firstname) > 0) ?
1032
                        $firstname : '<MISSING>') . "\n" .
1033
                    'Last Name     = ' . ((strlen($lastname) > 0) ?
1034
                        $lastname : '<MISSING>') . "\n" .
1035
                    'Display Name  = ' . ((strlen($displayname) > 0) ?
1036
                        $displayname : '<MISSING>') . "\n" .
1037
                    'Email Address = ' . ((strlen($emailaddr) > 0) ?
1038
                        $emailaddr : '<MISSING>') . "\n" .
1039
                    'ePPN          = ' . ((strlen($ePPN) > 0) ?
1040
                        $ePPN : '<MISSING>') . "\n" .
1041
                    'ePTID         = ' . ((strlen($ePTID) > 0) ?
1042
                        $ePTID : '<MISSING>') . "\n" .
1043
                    'OpenID ID     = ' . ((strlen($openidID) > 0) ?
1044
                        $openidID : '<MISSING>') . "\n" .
1045
                    'OIDC ID       = ' . ((strlen($oidcID) > 0) ?
1046
                        $oidcID : '<MISSING>') . "\n" .
1047
                    'Affiliation   = ' . ((strlen($affiliation) > 0) ?
1048
                        $affiliation : '<MISSING>') . "\n" .
1049
                    'OU            = ' . ((strlen($ou) > 0) ?
1050
                        $ou : '<MISSING>') . "\n" .
1051
                    'MemberOf      = ' . ((strlen($memberof) > 0) ?
1052
                        $memberof : '<MISSING>') . "\n" .
1053
                    'ACR           = ' . ((strlen($acr) > 0) ?
1054
                        $acr : '<MISSING>') . "\n" .
1055
                    'Entitlement   = ' . ((strlen($entitlement) > 0) ?
1056
                        $entitlement : '<MISSING>') . "\n" .
1057
                    'iTrustUIN     = ' . ((strlen($itrustuin) > 0) ?
1058
                        $itrustuin : '<MISSING>') . "\n" .
1059
                    'Database UID  = ' . ((strlen(
1060
                        $i = static::getSessionVar('uid')
1061
                    ) > 0) ?  $i : '<MISSING>') . "\n" .
1062
                    'Status Code   = ' . ((strlen(
0 ignored issues
show
Bug introduced by
Are you sure strlen($i = array_search... > 0 ? $i : '<MISSING>' of type false|integer|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1062
                    'Status Code   = ' . (/** @scrutinizer ignore-type */ (strlen(
Loading history...
1063
                        $i = array_search(
0 ignored issues
show
Bug introduced by
It seems like $i = array_search($statu...vice\DBService::STATUS) can also be of type false; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1063
                        /** @scrutinizer ignore-type */ $i = array_search(
Loading history...
1064
                            $status,
1065
                            DBService::$STATUS
1066
                        )
1067
                    ) > 0) ?  $i : '<MISSING>'),
1068
                    $mailto
1069
                );
1070
            }
1071
            static::unsetSessionVar('authntime');
1072
        } else { // status is okay, set authntime
1073
            static::setSessionVar('authntime', time());
1074
        }
1075
1076
        static::unsetSessionVar('responsesubmit');
1077
        static::unsetSessionVar('requestsilver');
1078
1079
        static::getCsrf()->setCookieAndSession();
1080
    }
1081
1082
    /**
1083
     * setUserAttributeSessionVars
1084
     *
1085
     * This method is called by saveUserToDatastore to put the passsed-in
1086
     * variables into the PHP session for later use.
1087
     *
1088
     * @param mixed $args Variable number of user attribute paramters
1089
     *        ordered as shown in the $attrs array below.
1090
     */
1091
    public static function setUserAttributeSessionVars(...$args)
1092
    {
1093
        $attrs = array('remoteuser', 'idp', 'idpname', 'firstname',
1094
                       'lastname', 'displayname', 'emailaddr',
1095
                       'loa', 'ePPN', 'ePITD', 'openidID', 'oidcID',
1096
                       'affiliation', 'ou', 'memberof', 'acr',
1097
                       'entitlement', 'itrustuin');
1098
        $numargs = count($args);
1099
        for ($i = 0; $i < $numargs; $i++) {
1100
            static::setSessionVar($attrs[$i], $args[$i]);
1101
        }
1102
1103
        // CACC-238 - Set loa to "silver" if the following are true:
1104
        // (1) loa contains  https://refeds.org/assurance/profile/cappuccino
1105
        // (2) acr is either https://refeds.org/profile/sfa or
1106
        //                   https://refeds.org/profile/mfa
1107
        if ((preg_match('%https://refeds.org/assurance/profile/cappuccino%', static::getSessionVar('loa'))) &&
1108
            (preg_match('%https://refeds.org/profile/[ms]fa%', static::getSessionVar('acr')))) {
1109
            static::setSessionVar('loa', 'http://incommonfederation.org/assurance/silver');
1110
        }
1111
    }
1112
1113
    /**
1114
     * unsetClientSessionVars
1115
     *
1116
     * This function removes all of the PHP session variables related to
1117
     * the client session.
1118
     */
1119
    public static function unsetClientSessionVars()
1120
    {
1121
        static::unsetSessionVar('submit');
1122
1123
        // Specific to 'Download Certificate' page
1124
        static::unsetSessionVar('activation');
1125
        static::unsetSessionVar('p12');
1126
        static::unsetSessionVar('p12lifetime');
1127
        static::unsetSessionVar('p12multiplier');
1128
1129
        // Specific to OAuth 1.0a flow
1130
        static::unsetSessionVar('portalstatus');
1131
        static::unsetSessionVar('callbackuri');
1132
        static::unsetSessionVar('successuri');
1133
        static::unsetSessionVar('failureuri');
1134
        static::unsetSessionVar('portalname');
1135
        static::unsetSessionVar('tempcred');
1136
1137
        // Specific to OIDC flow
1138
        static::unsetSessionVar('clientparams');
1139
    }
1140
1141
    /**
1142
     * unsetUserSessionVars
1143
     *
1144
     * This function removes all of the PHP session variables related to
1145
     * the user's session.  This will force the user to log on (again)
1146
     * with their IdP and call the 'getuser' script to repopulate the PHP
1147
     * session.
1148
     */
1149
    public static function unsetUserSessionVars()
1150
    {
1151
        // Needed for verifyCurrentUserSession
1152
        static::unsetSessionVar('idp');
1153
        static::unsetSessionVar('idpname');
1154
        static::unsetSessionVar('status');
1155
        static::unsetSessionVar('uid');
1156
        static::unsetSessionVar('dn');
1157
        static::unsetSessionVar('authntime');
1158
1159
        // Specific to 2FA
1160
        static::unsetSessionVar('twofactor');
1161
1162
        // Variables set by getuser
1163
        static::unsetSessionVar('firstname');
1164
        static::unsetSessionVar('lastname');
1165
        static::unsetSessionVar('displayname');
1166
        static::unsetSessionVar('emailaddr');
1167
        static::unsetSessionVar('loa');
1168
        static::unsetSessionVar('ePPN');
1169
        static::unsetSessionVar('ePTID');
1170
        static::unsetSessionVar('openidID');
1171
        static::unsetSessionVar('oidcID');
1172
        static::unsetSessionVar('affiliation');
1173
        static::unsetSessionVar('ou');
1174
        static::unsetSessionVar('memberof');
1175
        static::unsetSessionVar('acr');
1176
        static::unsetSessionVar('entitlement');
1177
        static::unsetSessionVar('itrustuin');
1178
1179
        // Current skin
1180
        static::unsetSessionVar('cilogon_skin');
1181
    }
1182
1183
    /**
1184
     * unsetAllUserSessionVars
1185
     *
1186
     * This is a convenience method to clear all session variables related
1187
     * to the client and the user.
1188
     */
1189
    public static function unsetAllUserSessionVars()
1190
    {
1191
        static::unsetClientSessionVars();
1192
        static::unsetUserSessionVars();
1193
    }
1194
1195
    /**
1196
     * verifySessionAndCall
1197
     *
1198
     * This function is a convenience method called by several cases in the
1199
     * main 'switch' call at the top of the index.php file. I noticed
1200
     * a pattern where verifyCurrentUserSession() was called to verify the
1201
     * current user session. Upon success, one or two functions were called
1202
     * to continue program, flow. Upon failure, cookies and session
1203
     * variables were cleared, and the main Logon page was printed. This
1204
     * function encapsulates that pattern. If the user's session is valid,
1205
     * the passed-in $func is called, possibly with parameters passed in as
1206
     * an array. The function returns true if the session is verified, so
1207
     * that other functions may be called upon return.
1208
     *
1209
     * @param function $func The function to call if the current session is
0 ignored issues
show
Bug introduced by
The type CILogon\Service\function was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1210
     *        successfully verified.
1211
     * @param array $params (Optional) An array of parameters to pass to the
1212
     8        function. Defaults to empty array, meaning zero parameters.
1213
     */
1214
    public static function verifySessionAndCall($func, $params = array())
1215
    {
1216
        $retval = false;
1217
        if (Content::verifyCurrentUserSession()) { // Verify PHP session is valid
1218
            $retval = true;
1219
            call_user_func_array($func, $params);
1220
        } else {
1221
            printLogonPage(true); // Clear cookies and session vars too
0 ignored issues
show
Bug introduced by
The function printLogonPage was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1221
            /** @scrutinizer ignore-call */ 
1222
            printLogonPage(true); // Clear cookies and session vars too
Loading history...
1222
        }
1223
        return $retval;
1224
    }
1225
1226
    /**
1227
     * isEduGAINAndGetCert
1228
     *
1229
     * This function checks to see if the current session IdP is an
1230
     * eduGAIN IdP (i.e., not Registered By InCommon) and the IdP does not
1231
     * have both the REFEDS R&S and SIRTFI extensions in metadata. If so,
1232
     * check to see if the transaction could be used to fetch a
1233
     * certificate. (The only time the transaction is not used to fetch
1234
     * a cert is during OIDC without the 'getcert' scope.) If all that is
1235
     * true, then return true. Otherwise return false.
1236
     *
1237
     * @param string $idp (optional) The IdP entityID. If empty, read value
1238
     *        from PHP session.
1239
     * @param string $idpname (optional) The IdP display name. If empty,
1240
     *        read value from PHP session.
1241
     * @return bool True if the current IdP is an eduGAIN IdP without
1242
     *         both REFEDS R&S and SIRTFI, AND the session could be
1243
     *         used to get a certificate.
1244
     */
1245
    public static function isEduGAINAndGetCert($idp = '', $idpname = '')
1246
    {
1247
        $retval = false; // Assume not eduGAIN IdP and getcert
1248
1249
        // If $idp or $idpname not passed in, get from current session.
1250
        if (strlen($idp) == 0) {
1251
            $idp = static::getSessionVar('idp');
1252
        }
1253
        if (strlen($idpname) == 0) {
1254
            $idpname = static::getSessionVar('idpname');
1255
        }
1256
1257
        // Check if this was an OIDC transaction, and if the
1258
        // 'getcert' scope was requested.
1259
        $oidcscopegetcert = false;
1260
        $oidctrans = false;
1261
        $clientparams = json_decode(static::getSessionVar('clientparams'), true);
1262
        if (isset($clientparams['scope'])) {
1263
            $oidctrans = true;
1264
            if (preg_match(
1265
                '/edu\.uiuc\.ncsa\.myproxy\.getcert/',
1266
                $clientparams['scope']
1267
            )) {
1268
                $oidcscopegetcert = true;
1269
            }
1270
        }
1271
1272
        // First, make sure $idp was set and is not an OAuth2 IdP.
1273
        $idplist = static::getIdpList();
1274
        if (((strlen($idp) > 0) &&
1275
            (strlen($idpname) > 0) &&
1276
            (!in_array($idpname, static::$oauth2idps))) &&
1277
                (
1278
                // Next, check for eduGAIN without REFEDS R&S and SIRTFI
1279
                ((!$idplist->isRegisteredByInCommon($idp)) &&
1280
                       ((!$idplist->isREFEDSRandS($idp)) ||
1281
                        (!$idplist->isSIRTFI($idp))
1282
                       )
1283
                ) &&
1284
                // Next, check if user could get X509 cert,
1285
                // i.e., OIDC getcert scope, or a non-OIDC
1286
                // transaction such as PKCS12, JWS, or OAuth 1.0a
1287
                ($oidcscopegetcert || !$oidctrans)
1288
                )
1289
            ) {
1290
            $retval = true;
1291
        }
1292
        return $retval;
1293
    }
1294
}
1295