Completed
Push — master ( edaaa2...d16e7d )
by Terrence
14:33
created

Util::getPostVar()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 3
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 6
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.
109
     */
110
    public static function getSkin()
111
    {
112
        if (is_null(static::$skin)) {
113
            static::$skin = new Skin();
114
        }
115
        return static::$skin;
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)) {
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)
0 ignored issues
show
Coding Style introduced by
getServerVar uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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)
0 ignored issues
show
Coding Style introduced by
getGetVar uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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)
0 ignored issues
show
Coding Style introduced by
getPostVar uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
205
    {
206
        $retval = '';
207
        if (isset($_POST[$post])) {
208
            $retval = $_POST[$post];
209
        }
210
        return $retval;
211
    }
212
213
    /**
214
     * getCookieVar
215
     *
216
     * This function returns the value of a given cookie.
217
     *
218
     * @param string $cookie he $_COOKIE variable to query.
219
     * @return string The value of the $_COOKIE variable or empty string
220
     *         if that variable is not set.
221
     */
222
    public static function getCookieVar($cookie)
0 ignored issues
show
Coding Style introduced by
getCookieVar uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
223
    {
224
        $retval = '';
225
        if (isset($_COOKIE[$cookie])) {
226
            $retval = $_COOKIE[$cookie];
227
        }
228
        return $retval;
229
    }
230
231
    /**
232
     * setCookieVar
233
     *
234
     * This function sets a cookie.
235
     *
236
     * @param string $cookie The name of the cookie to set.
237
     * @param string $value (Optional) The value to set for the cookie.
238
     *        Defaults to empty string.
239
     * @param int $exp The future expiration time (in seconds) of the
240
     *        cookie. Defaults to 1 year from now. If set to 0,
241
     *        the cookie expires at the end of the session.
242
     */
243
    public static function setCookieVar($cookie, $value = '', $exp = 31536000)
0 ignored issues
show
Coding Style introduced by
setCookieVar uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
244
    {
245
        if ($exp > 0) {
246
            $exp += time();
247
        }
248
        setcookie($cookie, $value, $exp, '/', '.'.static::getDN(), true);
249
        $_COOKIE[$cookie] = $value;
250
    }
251
252
    /**
253
     * unsetCookieVar
254
     *
255
     * This function unsets a cookie. Strictly speaking, the cookie is
256
     * not removed, rather it is set to an empty value with an expired
257
     * time.
258
     *
259
     * @param string $cookie The name of the cookie to unset (delete).
260
     */
261
    public static function unsetCookieVar($cookie)
0 ignored issues
show
Coding Style introduced by
unsetCookieVar uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
262
    {
263
        setcookie($cookie, '', 1, '/', '.'.static::getDN(), true);
264
        unset($_COOKIE[$cookie]);
265
    }
266
267
    /**
268
     * getPortalOrNormalCookieVar
269
     *
270
     * This is a convenience function which first checks if there is a
271
     * OAuth 1.0a ('delegate') or OIDC ('authorize') session active.
272
     * If so, it attempts to get the requested cookie from the
273
     * associated portalcookie. If there is not an OAuth/OIDC session
274
     * active, it looks for a 'normal' cookie. If you need a
275
     * portalcookie object to do multiple get/set method calls from
276
     * one function, it is probably better NOT to use this method since
277
     * creating the portalcookie object is potentially expensive.
278
     *
279
     * @param string $cookie The name of the cookie to get.
280
     * @return string The cookie value from either the portalcookie
281
     *         (in the case of an active OAuth session) or the
282
     *         'normal' cookie. Return empty string if no matching
283
     *         cookie in either place.
284
     */
285
    public static function getPortalOrNormalCookieVar($cookie)
286
    {
287
        $retval = '';
0 ignored issues
show
Unused Code introduced by
$retval is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
288
        $pc = new PortalCookie();
289
        $pn = $pc->getPortalName();
290
        if (strlen($pn) > 0) {
291
            $retval = $pc->get($cookie);
292
        } else {
293
            $retval = static::getCookieVar($cookie);
294
        }
295
        return $retval;
296
    }
297
298
    /**
299
     * getSessionVar
300
     *
301
     * This function returns the value of a given PHP Session variable.
302
     *
303
     * @param string $sess The $_SESSION variable to query.
304
     * @return string The value of the $_SESSION variable or empty string
305
     *         if that variable is not set.
306
     */
307
    public static function getSessionVar($sess)
0 ignored issues
show
Coding Style introduced by
getSessionVar uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
308
    {
309
        $retval = '';
310
        if (isset($_SESSION[$sess])) {
311
            $retval = $_SESSION[$sess];
312
        }
313
        return $retval;
314
    }
315
316
    /**
317
     * setSessionVar
318
     *
319
     * This function can set or unset a given PHP session variable.
320
     * The first parameter is the PHP session variable to set/unset.
321
     * If the second parameter is the empty string, then the session
322
     * variable is unset.  Otherwise, the session variable is set to
323
     * the second parameter.  The function returns true if the session
324
     * variable was set to a non-empty value, false otherwise.
325
     * Normally, the return value can be ignored.
326
     *
327
     * @param string $key The name of the PHP session variable to set
328
     *        (or unset).
329
     * @param string $value (Optional) The value of the PHP session variable
330
     *        (to set), or empty string (to unset). Defaults to empty
331
     *        string (implies unset the session variable).
332
     * @return bool True if the PHP session variable was set to a
333
     *         non-empty string, false if variable was unset or if
334
     *         the specified session variable was not previously set.
335
     */
336
    public static function setSessionVar($key, $value = '')
0 ignored issues
show
Coding Style introduced by
setSessionVar uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
337
    {
338
        $retval = false;  // Assume we want to unset the session variable
339
        if (strlen($key) > 0) {  // Make sure session var name was passed in
340
            if (strlen($value) > 0) {
341
                $_SESSION[$key] = $value;
342
                $retval = true;
343
            } else {
344
                static::unsetSessionVar($key);
345
            }
346
        }
347
        return $retval;
348
    }
349
350
    /**
351
     * unsetSessionVar
352
     *
353
     * This function clears the given PHP session variable by first
354
     * setting it to null and then unsetting it entirely.
355
     *
356
     * @param string $sess The $_SESSION variable to erase.
357
     */
358
    public static function unsetSessionVar($sess)
0 ignored issues
show
Coding Style introduced by
unsetSessionVar uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
359
    {
360
        if (isset($_SESSION[$sess])) {
361
            $_SESSION[$sess] = null;
362
            unset($_SESSION[$sess]);
363
        }
364
    }
365
366
    /**
367
     * removeShibCookies
368
     *
369
     * This function removes all '_shib*' cookies currently in the
370
     * user's browser session. In effect, this logs the user out of
371
     * any IdP. Note that you must call this before you output any
372
     * HTML. Strictly speaking, the cookies are not removed, rather
373
     * they are set to empty values with expired times.
374
     */
375
    public static function removeShibCookies()
0 ignored issues
show
Coding Style introduced by
removeShibCookies uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
376
    {
377
        while (list($key, $val) = each($_COOKIE)) {
0 ignored issues
show
Unused Code introduced by
The assignment to $val is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
378
            if (strncmp($key, '_shib', strlen('_shib')) == 0) {
379
                static::unsetCookieVar($key);
380
            }
381
        }
382
    }
383
384
    /**
385
     * startPHPSession
386
     *
387
     * This function starts a secure PHP session and should be called
388
     * at the beginning of each script before any HTML is output.  It
389
     * does a trick of setting a 'lastaccess' time so that the
390
     * $_SESSION variable does not expire without warning.
391
     *
392
     * @param string $storetype (Optional) Storage location of the PHP
393
     *        session data, one of 'file' or 'mysql'. Defaults to null,
394
     *        which means use the value of storage.phpsessions from the
395
     *        cilogon.ini config file, or 'file' if no such
396
     *        parameter configured.
397
     */
398
    public static function startPHPSession($storetype = null)
0 ignored issues
show
Unused Code introduced by
The parameter $storetype is not used and could be removed.

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

Loading history...
Coding Style introduced by
startPHPSession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
399
    {
400
        // No parameter given? Use the value read in from cilogon.ini file.
401
        // If storage.phpsessions == 'mysql', create a sessionmgr().
402
        $storetype = static::getConfigVar('storage.phpsessions');
403
404
        if ($storetype == 'mysql') {
405
            $sessionmgr = new SessionMgr();
0 ignored issues
show
Unused Code introduced by
$sessionmgr is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
406
        }
407
408
        ini_set('session.cookie_secure', true);
409
        ini_set('session.cookie_domain', '.'.static::getDN());
410
        session_start();
411
        if ((!isset($_SESSION['lastaccess']) ||
412
            (time() - $_SESSION['lastaccess']) > 60)) {
413
            $_SESSION['lastaccess'] = time();
414
        }
415
    }
416
417
    /**
418
     * getScriptDir
419
     *
420
     * This function returns the directory (or full url) of the script
421
     * that is currently running.  The returned directory/url is
422
     * terminated by a '/' character (unless the second parameter is
423
     * set to true). This function is useful for those scripts named
424
     * index.php where we don't want to actually see 'index.php' in the
425
     * address bar (again, unless the second parameter is set to true).
426
     *
427
     * @param bool $prependhttp (Optional) Boolean to prepend 'http(s)://' to
428
     *        the script name. Defaults to false.
429
     * @param bool $stripfile (Optional) Boolean to strip off the trailing
430
     *        filename (e.g. index.php) from the path.
431
     *        Defaults to true (i.e., defaults to directory
432
     *        only without the trailing filename).
433
     * @return string The directory or url of the current script, with or
434
     *         without the trailing .php filename.
435
     */
436
    public static function getScriptDir($prependhttp = false, $stripfile = true)
437
    {
438
        $retval = static::getServerVar('SCRIPT_NAME');
439
        if ($stripfile) {
440
            $retval = dirname($retval);
441
        }
442
        if ($retval == '.') {
443
            $retval = '';
444
        }
445
        if ((strlen($retval) == 0) ||
446
            ($stripfile && ($retval[strlen($retval)-1] != '/'))) {
447
            $retval .= '/';  // Append a slash if necessary
448
        }
449
        if ($prependhttp) {  // Prepend http(s)://hostname
450
            $retval = 'http' .
451
                      ((strtolower(static::getServerVar('HTTPS')) == 'on')?'s':'') .
452
                      '://' . static::getServerVar('HTTP_HOST') . $retval;
453
        }
454
        return $retval;
455
    }
456
457
    /**
458
     * readArrayFromFile
459
     *
460
     * This function reads in the contents of a file into an array. It
461
     * is assumed that the file contains lines of the form:
462
     *     key value
463
     * where 'key' and 'value' are separated by whitespace.  The 'key'
464
     * portion of the string may not contain any whitespace, but the
465
     * 'value' part of the line may contain whitespace. Any empty lines
466
     * or lines starting with '#' (comments, without leading spaces)
467
     * in the file are skipped.  Note that this assumes that each 'key'
468
     * in the file is unique.  If there is any problem reading the
469
     * file, the resulting array will be empty.
470
     *
471
     * @param string $filename The name of the file to read.
472
     * @return array An array containing the contents of the file.
473
     */
474
    public static function readArrayFromFile($filename)
475
    {
476
        $retarray = array();
477
        if (is_readable($filename)) {
478
            $lines = file(
479
                $filename,
480
                FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES
481
            );
482
            foreach ($lines as $line) {
483
                if (substr($line, 0, 1) != '#') { // Skip '#' comment lines
484
                    $values = preg_split('/\s+/', $line, 2);
485
                    $retarray[$values[0]] = @$values[1];
486
                }
487
            }
488
        }
489
490
        return $retarray;
491
    }
492
493
    /**
494
     * writeArrayToFile
495
     *
496
     * This funtion writes an array (with key=>value pairs) to a file,
497
     * each line will be of the form:
498
     *     key value
499
     * The 'key' and 'value' strings are separated by a space. Note
500
     * that a 'key' may not contain any whitespace (e.g. tabs), but a
501
     * 'value' may contain whitespace. To be super safe, the array is
502
     * first written to a temporary file, which is then renamed to the
503
     * final desired filename.
504
     *
505
     * @param string $filename The name of the file to write.
506
     * @param array $thearray The array to be written to the file.
507
     * @return bool True if successfully wrote file, false otherwise.
508
     */
509
    public static function writeArrayToFile($filename, $thearray)
510
    {
511
        $retval = false;  // Assume write failed
512
        $tmpfnmae = tempnam('/tmp', 'ARR');
0 ignored issues
show
Unused Code introduced by
$tmpfnmae is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
513
        if ($fh = fopen($tmpfname, 'w')) {
514
            if (flock($fh, LOCK_EX)) {
515
                foreach ($thearray as $key => $value) {
516
                    fwrite($fh, "$key $value\n");
517
                }
518
                flock($fh, LOCK_UN);
519
            }
520
            fclose($fh);
521
            if (@rename($tmpfname, $filename)) {
522
                $retval = true;
523
            } else {
524
                @unlink($tmpfname);
0 ignored issues
show
Bug introduced by
The variable $tmpfname does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
525
            }
526
        }
527
528
        return $retval;
529
    }
530
531
    /**
532
     * parseGridShibConf
533
     *
534
     * This function parses the gridshib-ca.conf file and returns an
535
     * array containing the various options. It uses the PHP
536
     * PEAR::Config package to parse the config file. The
537
     * gridshib-ca.conf file is MOSTLY an Apache-style config file.
538
     * However, each option has an extra ' = ' prepended, so you will
539
     * need to strip these off each config option. For example, to get
540
     * the 'MaximumCredLifetime' value which is in the 'CA' section,
541
     * you would do the following:
542
     *     $gridshibconf = Util::parseGridShibConf();
543
     *     $life = preg_replace('%^\s*=\s*%','',
544
     *             $gridshibconf['root']['CA']['MaximumCredLifetime']);
545
     *
546
     * @param string $conffile (Optional) Full path location of
547
     *        gridshib-ca.conf file. Defaults to
548
     *        '/usr/local/gridshib-ca/conf/gridshib-ca.conf'.
549
     * @return array An array containing the various configuration
550
     *         parameters in the gridshib-ca.conf file.
551
     */
552
    public static function parseGridShibConf(
553
        $conffile = '/usr/local/gridshib-ca/conf/gridshib-ca.conf'
554
    ) {
555
        $conf = new Config;
556
        $root = $conf->parseConfig($conffile, 'Apache');
557
        $gridshibconf = array();
558
        if (!(PEAR::isError($root))) {
559
            $gridshibconf = $root->toArray();
560
        }
561
        return $gridshibconf;
562
    }
563
564
    /**
565
     * tempDir
566
     *
567
     * This function creates a temporary subdirectory within the
568
     * specified subdirectory. The new directory name is composed of
569
     * 16 hexadecimal letters, plus any prefix if you specify one. The
570
     * full path of the the newly created directory is returned.
571
     *
572
     * @param string $dir The full path to the containing directory.
573
     * @param string $prefix (Optional) A prefix for the new temporary
574
     *        directory. Defaults to empty string.
575
     * @param int $mode (Optional) Access permissions for the new
576
     *        temporary directory. Defaults to 0775.
577
     * @return string Full path to the newly created temporary directory.
578
     */
579
    public static function tempDir($dir, $prefix = '', $mode = 0775)
580
    {
581
        if (substr($dir, -1) != '/') {
582
            $dir .= '/';
583
        }
584
585
        $path = '';
0 ignored issues
show
Unused Code introduced by
$path is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
586
        do {
587
            $path = $dir . $prefix . sprintf("%08X%08X", mt_rand(), mt_rand());
588
        } while (!mkdir($path, $mode, true));
589
590
        return $path;
591
    }
592
593
    /**
594
     * deleteDir
595
     *
596
     * This function deletes a directory and all of its contents.
597
     *
598
     * @param string $dir The (possibly non-empty) directory to delete.
599
     * @param bool $shred (Optional) Shred the file before deleting?
600
     *        Defaults to false.
601
     */
602
    public static function deleteDir($dir, $shred = false)
603
    {
604
        if (is_dir($dir)) {
605
            $objects = scandir($dir);
606
            foreach ($objects as $object) {
607
                if ($object != "." && $object != "..") {
608
                    if (filetype($dir."/".$object) == "dir") {
609
                        static::deleteDir($dir."/".$object);
610
                    } else {
611
                        if ($shred) {
612
                            @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 here. This can introduce security issues, and is generally not recommended.

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...
613
                        } else {
614
                            @unlink($dir."/".$object);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
615
                        }
616
                    }
617
                }
618
            }
619
            reset($objects);
620
            @rmdir($dir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

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...
621
        }
622
    }
623
624
    /**
625
     * htmlent
626
     *
627
     * This method is necessary since htmlentities() does not seem to
628
     * obey the default arguments as documented in the PHP manual, and
629
     * instead encodes accented characters incorrectly. By specifying
630
     * the flags and encoding, the problem is solved.
631
     *
632
     * @param string $str : A string to process with htmlentities().
633
     * @return string The input string processed by htmlentities with
634
     *         specific options.
635
     */
636
    public static function htmlent($str)
637
    {
638
        return htmlentities($str, ENT_COMPAT|ENT_HTML401, 'UTF-8');
639
    }
640
641
    /**
642
     * sendErrorAlert
643
     *
644
     * Use this function to send an error message. The $summary should
645
     * be a short description of the error since it is placed in the
646
     * subject of the email. Put a more verbose description of the
647
     * error in the $detail parameter. Any session variables available
648
     * are appended to the body of the message.
649
     *
650
     * @param string $summary A brief summary of the error (in email subject)
651
     * @param string $detail A detailed description of the error (in the
652
     *        email body)
653
     * @param string $mailto (Optional) The destination email address.
654
     *        Defaults to '[email protected]'.
655
     */
656
    public static function sendErrorAlert(
657
        $summary,
658
        $detail,
659
        $mailto = '[email protected]'
660
    ) {
661
        $sessionvars = array(
662
            'idp'          => 'IdP ID',
663
            'idpname'      => 'IdP Name',
664
            'uid'          => 'Database UID',
665
            'dn'           => 'Cert DN',
666
            'firstname'    => 'First Name',
667
            'lastname'     => 'Last Name',
668
            'displayname'  => 'Display Name',
669
            'ePPN'         => 'ePPN',
670
            'ePTID'        => 'ePTID',
671
            'openID'       => 'OpenID ID',
672
            'oidcID'       => 'OIDC ID',
673
            'loa'          => 'LOA',
674
            'affiliation'  => 'Affiliation',
675
            'ou'           => 'OU',
676
            'cilogon_skin' => 'Skin Name',
677
            'twofactor'    => 'Two-Factor',
678
            'authntime'    => 'Authn Time'
679
        );
680
681
        $remoteaddr = static::getServerVar('REMOTE_ADDR');
682
        $remotehost = gethostbyaddr($remoteaddr);
683
        $mailfrom = 'From: [email protected]' . "\r\n" .
684
                    'X-Mailer: PHP/' . phpversion();
685
        $mailsubj = 'CILogon Service on ' . php_uname('n') .
686
                    ' - ' . $summary;
687
        $mailmsg  = '
688
CILogon Service - ' . $summary . '
689
-----------------------------------------------------------
690
' . $detail . '
691
692
Session Variables
693
-----------------
694
Server Host   = ' . static::getHN() . '
695
Remote Address= ' . $remoteaddr . '
696
' . (($remotehost !== false) ? "Remote Host   = $remotehost" : '') . '
697
';
698
699
        foreach ($sessionvars as $svar => $sname) {
700
            if (strlen($val = static::getSessionVar($svar)) > 0) {
701
                $mailmsg .= sprintf("%-14s= %s\n", $sname, $val);
702
            }
703
        }
704
705
        mail($mailto, $mailsubj, $mailmsg, $mailfrom);
706
    }
707
708
    /**
709
     * getFirstAndLastName
710
     *
711
     * This function attempts to get the first and last name of a user
712
     * extracted from the 'full name' (displayName) of the user.
713
     * Simply pass in all name info (full, first, and last) and the
714
     * function first tries to break up the full name into first/last.
715
     * If this is not sufficient, the function checks first and last
716
     * name. Finally, if either first or last is blank, the function
717
     * duplicates first <=> last so both names have the same value.
718
     * Note that even with all this, you still need to check if the
719
     * returned (first,last) names are blank.
720
     *
721
     * @param string $full The 'full name' of the user
722
     * @param string $first (Optional) The 'first name' of the user
723
     * @param string $last (Optional) The 'last name' of the user
724
     * @return array An array 'list(firstname,lastname)'
725
     */
726
    public static function getFirstAndLastName($full, $first = '', $last = '')
727
    {
728
        $firstname = '';
729
        $lastname = '';
730
731
        # Try to split the incoming $full name into first and last names
732
        if (strlen($full) > 0) {
733
            $names = preg_split('/\s+/', $full, 2);
734
            $firstname = @$names[0];
735
            $lastname =  @$names[1];
736
        }
737
738
        # If either first or last name blank, then use incoming $first and $last
739
        if (strlen($firstname) == 0) {
740
            $firstname = $first;
741
        }
742
        if (strlen($lastname) == 0) {
743
            $lastname = $last;
744
        }
745
746
        # Finally, if only a single name, copy first name <=> last name
747
        if (strlen($lastname) == 0) {
748
            $lastname = $firstname;
749
        }
750
        if (strlen($firstname) == 0) {
751
            $firstname = $lastname;
752
        }
753
754
        # Return both names as an array (i.e., use list($first,last)=...)
755
        return array($firstname,$lastname);
756
    }
757
758
    /**
759
     * getHN
760
     *
761
     * This function calculates and returns the 'hostname' for the
762
     * server. It first checks HTTP_HOST. If not set, it returns
763
     * 'cilogon.org'. This is needed by command line scripts.
764
     *
765
     * @return string The 'Hostname' for the web server.
766
     */
767
    public static function getHN()
768
    {
769
        $thehostname = static::getServerVar('HTTP_HOST');
770
        if (strlen($thehostname) == 0) {
771
            $thehostname = 'cilogon.org';
772
        }
773
        return $thehostname;
774
    }
775
776
    /**
777
     * getDN
778
     *
779
     * This function calculates and returns the 'domainname' for the
780
     * server. It uses the hostname value calculated by getHN() and
781
     * uses the last two segments.
782
     *
783
     * @return string The 'Domainname' for the web server.
784
     */
785
    public static function getDN()
786
    {
787
        $thedomainname = static::getHN();
788
        if (preg_match('/[^\.]+\.[^\.]+$/', $thedomainname, $matches)) {
789
            $thedomainname = $matches[0];
790
        }
791
        return $thedomainname;
792
    }
793
794
    /**
795
     * getAuthzUrl
796
     *
797
     * This funtion takes in the name of an IdP (e.g., 'Google') and
798
     * returns the assoicated OAuth2 authorization URL.
799
     *
800
     * @param string $idp The name of an OAuth2 Identity Provider.
801
     * @return string The authorization URL for the given IdP.
802
     */
803
    public static function getAuthzUrl($idp)
804
    {
805
        $url = null;
806
        $idptourl = array(
807
            'Google' => 'https://accounts.google.com/o/oauth2/auth',
808
            'GitHub' => 'https://github.com/login/oauth/authorize',
809
            'ORCID'  => 'https://orcid.org/oauth/authorize',
810
        );
811
        if (array_key_exists($idp, $idptourl)) {
812
            $url = $idptourl[$idp];
813
        }
814
        return $url;
815
    }
816
817
    /**
818
     * getAuthzIdP
819
     *
820
     * This function takes in the OAuth2 authorization URL and returns
821
     * the associated pretty-print name of the IdP.
822
     *
823
     * @param string $url The authorization URL of an OAuth2 Identity Provider.
824
     * @return string The name of the IdP.
825
     */
826
    public static function getAuthzIdP($url)
827
    {
828
        $idp = null;
829
        $urltoidp = array(
830
            'https://accounts.google.com/o/oauth2/auth' => 'Google',
831
            'https://github.com/login/oauth/authorize'  => 'GitHub',
832
            'https://orcid.org/oauth/authorize'         => 'ORCID',
833
        );
834
        if (array_key_exists($url, $urltoidp)) {
835
            $idp = $urltoidp[$url];
836
        }
837
        return $idp;
838
    }
839
840
    /**
841
     * saveUserToDataStore
842
     *
843
     * This function is called when a user logs on to save identity
844
     * information to the datastore. As it is used by both Shibboleth
845
     * and OpenID Identity Providers, some parameters passed in may
846
     * be blank (empty string). The function verifies that the minimal
847
     * sets of parameters are valid, the dbservice servlet is called
848
     * to save the user info. Then various session variables are set
849
     * for use by the program later on. In case of error, an email
850
     * alert is sent showing the missing parameters.
851
     *
852
     * @param string $remoteuser The REMOTE_USER from HTTP headers
853
     * @param string $providerId The provider IdP Identifier / URL endpoint
854
     * @param string providerName The pretty print provider IdP name
855
     * @param string $firstname The user's first name
856
     * @param string $lastname The user's last name
857
     * @param string $displayname The user's display name
858
     * @param string $emailaddr The user's email address
859
     * @param string $loa The level of assurance (e.g., openid/basic/silver)
860
     * @param string $eppn (optional) User's ePPN (for SAML IdPs)
861
     * @param string $eptid (optional) User's ePTID (for SAML IdPs)
862
     * @param string $openidid (optional) User's OpenID 2.0 Identifier
863
     * @param string $oidcid (optional) User's OpenID Connect Identifier
864
     * @param string $affiliation (optional) User's affiliation
865
     * @param string $ou (optional) User's organizational unit (OU)
866
     */
867
    public static function saveUserToDataStore(
868
        $remoteuser,
869
        $providerId,
870
        $providerName,
871
        $firstname,
872
        $lastname,
873
        $displayname,
874
        $emailaddr,
875
        $loa,
876
        $eppn = '',
877
        $eptid = '',
878
        $openidid = '',
879
        $oidcid = '',
880
        $affiliation = '',
881
        $ou = ''
882
    ) {
883
        $dbs = new DBService();
884
885
        // Keep original values of providerName and providerId
886
        $databaseProviderName = $providerName;
887
        $databaseProviderId   = $providerId;
888
889
        // Save the passed-in variables to the session for later use
890
        // (e.g., by the error handler in handleGotUser).
891
        static::setSessionVar('firstname', $firstname);
892
        static::setSessionVar('lastname', $lastname);
893
        static::setSessionVar('displayname', $displayname);
894
        static::setSessionvar('emailaddr', $emailaddr);
895
        static::setSessionVar('loa', $loa);
896
        static::setSessionVar('ePPN', $eppn);
897
        static::setSessionVar('ePTID', $eptid);
898
        static::setSessionVar('openidID', $openidid);
899
        static::setSessionVar('oidcID', $oidcid);
900
        static::setSessionVar('affiliation', $affiliation);
901
        static::setSessionVar('ou', $ou);
902
        static::setSessionVar('idp', $providerId); // Enable error message
903
        static::setSessionVar('idpname', $providerName); // Enable check for Google
904
        static::setSessionVar('submit', static::getSessionVar('responsesubmit'));
905
906
        // Make sure parameters are not empty strings, and email is valid
907
        // Must have at least one of remoteuser/eppn/eptid/openidid/oidcid
908
        if (((strlen($remoteuser) > 0) ||
909
               (strlen($eppn) > 0) ||
910
               (strlen($eptid) > 0) ||
911
               (strlen($openidid) > 0) ||
912
               (strlen($oidcid) > 0)) &&
913
            (strlen($databaseProviderId) > 0) &&
914
            (strlen($databaseProviderName) > 0)  &&
915
            (strlen($firstname) > 0) &&
916
            (strlen($lastname) > 0) &&
917
            (strlen($emailaddr) > 0) &&
918
            (filter_var($emailaddr, FILTER_VALIDATE_EMAIL))) {
919
            // For the new Google OAuth 2.0 endpoint, we want to keep the
920
            // old Google OpenID endpoint URL in the database (so user does
921
            // not get a new certificate subject DN). Change the providerId
922
            // and providerName to the old Google OpenID values.
923
            if (($databaseProviderName == 'Google+') ||
924
                ($databaseProviderId == static::getAuthzUrl('Google'))) {
925
                $databaseProviderName = 'Google';
926
                $databaseProviderId = 'https://www.google.com/accounts/o8/id';
927
            }
928
929
            // In the database, keep a consistent ProviderId format: only
930
            // allow 'http' (not 'https') and remove any 'www.' prefix.
931
            if ($loa == 'openid') {
932
                $databaseProviderId = preg_replace(
933
                    '%^https://(www\.)?%',
934
                    'http://',
935
                    $databaseProviderId
936
                );
937
            }
938
939
            $result = $dbs->getUser(
940
                $remoteuser,
941
                $databaseProviderId,
942
                $databaseProviderName,
943
                $firstname,
944
                $lastname,
945
                $displayname,
946
                $emailaddr,
947
                $eppn,
948
                $eptid,
949
                $openidid,
950
                $oidcid,
951
                $affiliation,
952
                $ou
953
            );
954
            static::setSessionVar('uid', $dbs->user_uid);
955
            static::setSessionVar('dn', $dbs->distinguished_name);
956
            static::setSessionVar('twofactor', $dbs->two_factor);
957
            static::setSessionVar('status', $dbs->status);
958
            if (!$result) {
959
                static::sendErrorAlert(
960
                    'dbService Error',
961
                    'Error calling dbservice action "getUser" in ' .
962
                    'saveUserToDatastore() method.'
963
                );
964
            }
965
        } else { // Missing one or more required attributes
966
            static::setSessionVar(
967
                'status',
968
                DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']
969
            );
970
        }
971
972
        // If 'status' is not STATUS_OK*, then send an error email
973
        $status = static::getSessionVar('status');
974
        if ($status & 1) { // Bad status codes are odd
975
976
            // For missing parameter errors, log an error message
977
            if ($status ==
978
                DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']) {
979
                $log = new Loggit();
980
                $log->error('STATUS_MISSING_PARAMETER_ERROR', true);
981
            }
982
983
            // For other dbservice errors OR for any error involving
984
            // LIGO (e.g., missing parameter error), send email alert.
985
            if (($status !=
986
                    DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']) ||
987
                (preg_match('/ligo\.org/', $databaseProviderId))) {
988
                $mailto = '[email protected]';
989
990
                // Set $disableligoalerts = true to stop LIGO failures
991
                // from being sent to '[email protected]', but still
992
                // sent to '[email protected]'.
993
                $disableligoalerts = false;
994
995
                // Fixes CIL-205 - Notify LIGO about IdP login errors
996
                if (preg_match('/ligo\.org/', $databaseProviderId)) {
997
                    if ($disableligoalerts) {
998
                        $mailto = '';
999
                    }
1000
                    $mailto .= ((strlen($mailto) > 0) ? ',' : '') .
1001
                        '[email protected]';
1002
                }
1003
1004
                static::sendErrorAlert(
1005
                    'Failure in ' .
1006
                        (($loa == 'openid') ? '' : '/secure') . '/getuser/',
1007
                    'Remote_User   = ' . ((strlen($remoteuser) > 0) ?
1008
                        $remoteuser : '<MISSING>') . "\n" .
1009
                    'IdP ID        = ' . ((strlen($databaseProviderId) > 0) ?
1010
                        $databaseProviderId : '<MISSING>') . "\n" .
1011
                    'IdP Name      = ' . ((strlen($databaseProviderName) > 0) ?
1012
                        $databaseProviderName : '<MISSING>') . "\n" .
1013
                    'First Name    = ' . ((strlen($firstname) > 0) ?
1014
                        $firstname : '<MISSING>') . "\n" .
1015
                    'Last Name     = ' . ((strlen($lastname) > 0) ?
1016
                        $lastname : '<MISSING>') . "\n" .
1017
                    'Display Name  = ' . ((strlen($displayname) > 0) ?
1018
                        $displayname : '<MISSING>') . "\n" .
1019
                    'Email Address = ' . ((strlen($emailaddr) > 0) ?
1020
                        $emailaddr : '<MISSING>') . "\n" .
1021
                    'ePPN          = ' . ((strlen($eppn) > 0) ?
1022
                        $eppn : '<MISSING>') . "\n" .
1023
                    'ePTID         = ' . ((strlen($eptid) > 0) ?
1024
                        $eptid : '<MISSING>') . "\n" .
1025
                    'OpenID ID     = ' . ((strlen($openidid) > 0) ?
1026
                        $openidid : '<MISSING>') . "\n" .
1027
                    'OIDC ID       = ' . ((strlen($oidcid) > 0) ?
1028
                        $oidcid : '<MISSING>') . "\n" .
1029
                    'Affiliation   = ' . ((strlen($affiliation) > 0) ?
1030
                        $affiliation : '<MISSING>') . "\n" .
1031
                    'OU            = ' . ((strlen($ou) > 0) ?
1032
                        $ou : '<MISSING>') . "\n" .
1033
                    'Database UID  = ' . ((strlen(
1034
                        $i = static::getSessionVar('uid')
1035
                    ) > 0) ?  $i : '<MISSING>') . "\n" .
1036
                    'Status Code   = ' . ((strlen(
1037
                        $i = array_search(
1038
                            $status,
1039
                            DBService::$STATUS
1040
                        )
1041
                    ) > 0) ?  $i : '<MISSING>'),
1042
                    $mailto
1043
                );
1044
            }
1045
            static::unsetSessionVar('authntime');
1046
        } else { // status is okay, set authntime
1047
            static::setSessionVar('authntime', time());
1048
        }
1049
1050
        static::unsetSessionVar('responsesubmit');
1051
        static::unsetSessionVar('requestsilver');
1052
1053
        static::getCsrf()->setCookieAndSession();
1054
    }
1055
1056
    /**
1057
     * unsetClientSessionVars
1058
     *
1059
     * This function removes all of the PHP session variables related to
1060
     * the client session.
1061
     */
1062
    public static function unsetClientSessionVars()
1063
    {
1064
        static::unsetSessionVar('submit');
1065
1066
        // Specific to 'Download Certificate' page
1067
        static::unsetSessionVar('activation');
1068
        static::unsetSessionVar('p12');
1069
        static::unsetSessionVar('p12lifetime');
1070
        static::unsetSessionVar('p12multiplier');
1071
1072
        // Specific to OAuth 1.0a flow
1073
        static::unsetSessionVar('portalstatus');
1074
        static::unsetSessionVar('callbackuri');
1075
        static::unsetSessionVar('successuri');
1076
        static::unsetSessionVar('failureuri');
1077
        static::unsetSessionVar('portalname');
1078
        static::unsetSessionVar('tempcred');
1079
1080
        // Specific to OIDC flow
1081
        static::unsetSessionVar('clientparams');
1082
    }
1083
1084
    /**
1085
     * unsetUserSessionVars
1086
     *
1087
     * This function removes all of the PHP session variables related to
1088
     * the user's session.  This will force the user to log on (again)
1089
     * with their IdP and call the 'getuser' script to repopulate the PHP
1090
     * session.
1091
     */
1092
    public static function unsetUserSessionVars()
1093
    {
1094
        // Needed for verifyCurrentUserSession
1095
        static::unsetSessionVar('idp');
1096
        static::unsetSessionVar('idpname');
1097
        static::unsetSessionVar('status');
1098
        static::unsetSessionVar('uid');
1099
        static::unsetSessionVar('dn');
1100
        static::unsetSessionVar('authntime');
1101
1102
        // Specific to 2FA
1103
        static::unsetSessionVar('twofactor');
1104
1105
        // Variables set by getuser
1106
        static::unsetSessionVar('firstname');
1107
        static::unsetSessionVar('lastname');
1108
        static::unsetSessionVar('displayname');
1109
        static::unsetSessionVar('emailaddr');
1110
        static::unsetSessionVar('loa');
1111
        static::unsetSessionVar('ePPN');
1112
        static::unsetSessionVar('ePTID');
1113
        static::unsetSessionVar('openidID');
1114
        static::unsetSessionVar('oidcID');
1115
        static::unsetSessionVar('affiliation');
1116
        static::unsetSessionVar('ou');
1117
1118
        // Current skin
1119
        static::unsetSessionVar('cilogon_skin');
1120
    }
1121
1122
    /**
1123
     * unsetAllUserSessionVars
1124
     *
1125
     * This is a convenience method to clear all session variables related
1126
     * to the client and the user.
1127
     */
1128
    public static function unsetAllUserSessionVars()
1129
    {
1130
        static::unsetClientSessionVars();
1131
        static::unsetUserSessionVars();
1132
    }
1133
1134
    /**
1135
     * verifySessionAndCall
1136
     *
1137
     * This function is a convenience method called by several cases in the
1138
     * main 'switch' call at the top of the index.php file. I noticed
1139
     * a pattern where verifyCurrentUserSession() was called to verify the
1140
     * current user session. Upon success, one or two functions were called
1141
     * to continue program, flow. Upon failure, cookies and session
1142
     * variables were cleared, and the main Logon page was printed. This
1143
     * function encapsulates that pattern. If the user's session is valid,
1144
     * the passed-in $func is called, possibly with parameters passed in as
1145
     * an array. The function returns true if the session is verified, so
1146
     * that other functions may be called upon return.
1147
     *
1148
     * @param function $func The function to call if the current session is
1149
     *        successfully verified.
1150
     * @param array $params (Optional) An array of parameters to pass to the
1151
     8        function. Defaults to empty array, meaning zero parameters.
1152
     */
1153
    public static function verifySessionAndCall($func, $params = array())
1154
    {
1155
        $retval = false;
1156
        if (Content::verifyCurrentUserSession()) { // Verify PHP session is valid
1157
            $retval = true;
1158
            call_user_func_array($func, $params);
1159
        } else {
1160
            printLogonPage(true); // Clear cookies and session vars too
1161
        }
1162
        return $retval;
1163
    }
1164
}
1165