Passed
Push — master ( 2cf605...27303a )
by Terrence
11:38
created

Util::parseGridShibConf()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 10
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
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
     * tempDir
552
     *
553
     * This function creates a temporary subdirectory within the
554
     * specified subdirectory. The new directory name is composed of
555
     * 16 hexadecimal letters, plus any prefix if you specify one. The
556
     * full path of the the newly created directory is returned.
557
     *
558
     * @param string $dir The full path to the containing directory.
559
     * @param string $prefix (Optional) A prefix for the new temporary
560
     *        directory. Defaults to empty string.
561
     * @param int $mode (Optional) Access permissions for the new
562
     *        temporary directory. Defaults to 0775.
563
     * @return string Full path to the newly created temporary directory.
564
     */
565
    public static function tempDir($dir, $prefix = '', $mode = 0775)
566
    {
567
        if (substr($dir, -1) != '/') {
568
            $dir .= '/';
569
        }
570
571
        $path = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $path is dead and can be removed.
Loading history...
572
        do {
573
            $path = $dir . $prefix . sprintf("%08X%08X", mt_rand(), mt_rand());
574
        } while (!mkdir($path, $mode, true));
575
576
        return $path;
577
    }
578
579
    /**
580
     * deleteDir
581
     *
582
     * This function deletes a directory and all of its contents.
583
     *
584
     * @param string $dir The (possibly non-empty) directory to delete.
585
     * @param bool $shred (Optional) Shred the file before deleting?
586
     *        Defaults to false.
587
     */
588
    public static function deleteDir($dir, $shred = false)
589
    {
590
        if (is_dir($dir)) {
591
            $objects = scandir($dir);
592
            foreach ($objects as $object) {
593
                if ($object != "." && $object != "..") {
594
                    if (filetype($dir . "/" . $object) == "dir") {
595
                        static::deleteDir($dir . "/" . $object);
596
                    } else {
597
                        if ($shred) {
598
                            @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

598
                            /** @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...
599
                        } else {
600
                            @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

600
                            /** @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...
601
                        }
602
                    }
603
                }
604
            }
605
            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

605
            reset(/** @scrutinizer ignore-type */ $objects);
Loading history...
606
            @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

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

1029
                    'Status Code   = ' . (/** @scrutinizer ignore-type */ (strlen(
Loading history...
1030
                        $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

1030
                        /** @scrutinizer ignore-type */ $i = array_search(
Loading history...
1031
                            $status,
1032
                            DBService::$STATUS
1033
                        )
1034
                    ) > 0) ?  $i : '<MISSING>'),
1035
                    $mailto
1036
                );
1037
            }
1038
            static::unsetSessionVar('authntime');
1039
        } else { // status is okay, set authntime
1040
            static::setSessionVar('authntime', time());
1041
        }
1042
1043
        static::unsetSessionVar('responsesubmit');
1044
        static::unsetSessionVar('requestsilver');
1045
1046
        static::getCsrf()->setCookieAndSession();
1047
    }
1048
1049
    /**
1050
     * setUserAttributeSessionVars
1051
     *
1052
     * This method is called by saveUserToDatastore to put the passsed-in
1053
     * variables into the PHP session for later use.
1054
     *
1055
     * @param mixed $args Variable number of user attribute paramters
1056
     *        ordered as shown in the $attrs array below.
1057
     */
1058
    public static function setUserAttributeSessionVars(...$args)
1059
    {
1060
        $attrs = array('remoteuser', 'idp', 'idpname', 'firstname',
1061
                       'lastname', 'displayname', 'emailaddr',
1062
                       'loa', 'ePPN', 'ePTID', 'openidID', 'oidcID',
1063
                       'affiliation', 'ou', 'memberof', 'acr',
1064
                       'entitlement', 'itrustuin');
1065
        $numargs = count($args);
1066
        for ($i = 0; $i < $numargs; $i++) {
1067
            static::setSessionVar($attrs[$i], $args[$i]);
1068
        }
1069
1070
        // CACC-238 - Set loa to "silver" if the following are true:
1071
        // (1) loa contains  https://refeds.org/assurance/profile/cappuccino
1072
        // (2) acr is either https://refeds.org/profile/sfa or
1073
        //                   https://refeds.org/profile/mfa
1074
        if ((preg_match('%https://refeds.org/assurance/profile/cappuccino%', static::getSessionVar('loa'))) &&
1075
            (preg_match('%https://refeds.org/profile/[ms]fa%', static::getSessionVar('acr')))) {
1076
            static::setSessionVar('loa', 'http://incommonfederation.org/assurance/silver');
1077
        }
1078
    }
1079
1080
    /**
1081
     * unsetClientSessionVars
1082
     *
1083
     * This function removes all of the PHP session variables related to
1084
     * the client session.
1085
     */
1086
    public static function unsetClientSessionVars()
1087
    {
1088
        static::unsetSessionVar('submit');
1089
1090
        // Specific to 'Download Certificate' page
1091
        static::unsetSessionVar('p12');
1092
        static::unsetSessionVar('p12lifetime');
1093
        static::unsetSessionVar('p12multiplier');
1094
1095
        // Specific to OAuth 1.0a flow
1096
        static::unsetSessionVar('portalstatus');
1097
        static::unsetSessionVar('callbackuri');
1098
        static::unsetSessionVar('successuri');
1099
        static::unsetSessionVar('failureuri');
1100
        static::unsetSessionVar('portalname');
1101
        static::unsetSessionVar('tempcred');
1102
1103
        // Specific to OIDC flow
1104
        static::unsetSessionVar('clientparams');
1105
    }
1106
1107
    /**
1108
     * unsetUserSessionVars
1109
     *
1110
     * This function removes all of the PHP session variables related to
1111
     * the user's session.  This will force the user to log on (again)
1112
     * with their IdP and call the 'getuser' script to repopulate the PHP
1113
     * session.
1114
     */
1115
    public static function unsetUserSessionVars()
1116
    {
1117
        // Needed for verifyCurrentUserSession
1118
        static::unsetSessionVar('idp');
1119
        static::unsetSessionVar('idpname');
1120
        static::unsetSessionVar('status');
1121
        static::unsetSessionVar('uid');
1122
        static::unsetSessionVar('dn');
1123
        static::unsetSessionVar('authntime');
1124
1125
        // Specific to 2FA
1126
        static::unsetSessionVar('twofactor');
1127
1128
        // Variables set by getuser
1129
        static::unsetSessionVar('firstname');
1130
        static::unsetSessionVar('lastname');
1131
        static::unsetSessionVar('displayname');
1132
        static::unsetSessionVar('emailaddr');
1133
        static::unsetSessionVar('loa');
1134
        static::unsetSessionVar('ePPN');
1135
        static::unsetSessionVar('ePTID');
1136
        static::unsetSessionVar('openidID');
1137
        static::unsetSessionVar('oidcID');
1138
        static::unsetSessionVar('affiliation');
1139
        static::unsetSessionVar('ou');
1140
        static::unsetSessionVar('memberof');
1141
        static::unsetSessionVar('acr');
1142
        static::unsetSessionVar('entitlement');
1143
        static::unsetSessionVar('itrustuin');
1144
1145
        // Current skin
1146
        static::unsetSessionVar('cilogon_skin');
1147
    }
1148
1149
    /**
1150
     * unsetAllUserSessionVars
1151
     *
1152
     * This is a convenience method to clear all session variables related
1153
     * to the client and the user.
1154
     */
1155
    public static function unsetAllUserSessionVars()
1156
    {
1157
        static::unsetClientSessionVars();
1158
        static::unsetUserSessionVars();
1159
    }
1160
1161
    /**
1162
     * verifySessionAndCall
1163
     *
1164
     * This function is a convenience method called by several cases in the
1165
     * main 'switch' call at the top of the index.php file. I noticed
1166
     * a pattern where verifyCurrentUserSession() was called to verify the
1167
     * current user session. Upon success, one or two functions were called
1168
     * to continue program, flow. Upon failure, cookies and session
1169
     * variables were cleared, and the main Logon page was printed. This
1170
     * function encapsulates that pattern. If the user's session is valid,
1171
     * the passed-in $func is called, possibly with parameters passed in as
1172
     * an array. The function returns true if the session is verified, so
1173
     * that other functions may be called upon return.
1174
     *
1175
     * @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...
1176
     *        successfully verified.
1177
     * @param array $params (Optional) An array of parameters to pass to the
1178
     *        function. Defaults to empty array, meaning zero parameters.
1179
     */
1180
    public static function verifySessionAndCall($func, $params = array())
1181
    {
1182
        $retval = false;
1183
        if (Content::verifyCurrentUserSession()) { // Verify PHP session is valid
1184
            $retval = true;
1185
            call_user_func_array($func, $params);
1186
        } else {
1187
            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

1187
            /** @scrutinizer ignore-call */ 
1188
            printLogonPage(true); // Clear cookies and session vars too
Loading history...
1188
        }
1189
        return $retval;
1190
    }
1191
1192
    /**
1193
     * isEduGAINAndGetCert
1194
     *
1195
     * This function checks to see if the current session IdP is an
1196
     * eduGAIN IdP (i.e., not Registered By InCommon) and the IdP does not
1197
     * have both the REFEDS R&S and SIRTFI extensions in metadata. If so,
1198
     * check to see if the transaction could be used to fetch a
1199
     * certificate. (The only time the transaction is not used to fetch
1200
     * a cert is during OIDC without the 'getcert' scope.) If all that is
1201
     * true, then return true. Otherwise return false.
1202
     *
1203
     * @param string $idp (optional) The IdP entityID. If empty, read value
1204
     *        from PHP session.
1205
     * @param string $idpname (optional) The IdP display name. If empty,
1206
     *        read value from PHP session.
1207
     * @return bool True if the current IdP is an eduGAIN IdP without
1208
     *         both REFEDS R&S and SIRTFI, AND the session could be
1209
     *         used to get a certificate.
1210
     */
1211
    public static function isEduGAINAndGetCert($idp = '', $idpname = '')
1212
    {
1213
        $retval = false; // Assume not eduGAIN IdP and getcert
1214
1215
        // If $idp or $idpname not passed in, get from current session.
1216
        if (strlen($idp) == 0) {
1217
            $idp = static::getSessionVar('idp');
1218
        }
1219
        if (strlen($idpname) == 0) {
1220
            $idpname = static::getSessionVar('idpname');
1221
        }
1222
1223
        // Check if this was an OIDC transaction, and if the
1224
        // 'getcert' scope was requested.
1225
        $oidcscopegetcert = false;
1226
        $oidctrans = false;
1227
        $clientparams = json_decode(static::getSessionVar('clientparams'), true);
1228
        if (isset($clientparams['scope'])) {
1229
            $oidctrans = true;
1230
            if (preg_match(
1231
                '/edu\.uiuc\.ncsa\.myproxy\.getcert/',
1232
                $clientparams['scope']
1233
            )) {
1234
                $oidcscopegetcert = true;
1235
            }
1236
        }
1237
1238
        // First, make sure $idp was set and is not an OAuth2 IdP.
1239
        $idplist = static::getIdpList();
1240
        if (((strlen($idp) > 0) &&
1241
            (strlen($idpname) > 0) &&
1242
            (!in_array($idpname, static::$oauth2idps))) &&
1243
                (
1244
                // Next, check for eduGAIN without REFEDS R&S and SIRTFI
1245
                ((!$idplist->isRegisteredByInCommon($idp)) &&
1246
                       ((!$idplist->isREFEDSRandS($idp)) ||
1247
                        (!$idplist->isSIRTFI($idp))
1248
                       )
1249
                ) &&
1250
                // Next, check if user could get X509 cert,
1251
                // i.e., OIDC getcert scope, or a non-OIDC
1252
                // transaction such as PKCS12, JWS, or OAuth 1.0a
1253
                ($oidcscopegetcert || !$oidctrans)
1254
                )
1255
            ) {
1256
            $retval = true;
1257
        }
1258
        return $retval;
1259
    }
1260
}
1261