Passed
Push — master ( 4efdfb...a423d2 )
by Terrence
12:03
created

Content::printCertInfo()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 34
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 3
nop 0
dl 0
loc 34
ccs 0
cts 25
cp 0
crap 12
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
namespace CILogon\Service;
4
5
use CILogon\Service\Util;
6
use CILogon\Service\MyProxy;
7
use CILogon\Service\PortalCookie;
8
use CILogon\Service\DBService;
9
use CILogon\Service\OAuth2Provider;
10
use CILogon\Service\Loggit;
11
use Net_LDAP2_Util;
12
13
/**
14
 * Content
15
 */
16
class Content
17
{
18
    /**
19
     * printHeader
20
     *
21
     * This function should be called to print out the main HTML header
22
     * block for each web page.  This gives a consistent look to the site.
23
     * Any style changes should go in the cilogon.css file.
24
     *
25
     * @param string $title The text in the window's titlebar
26
     * @param string $extra Optional extra text to go in the <head> block
27
     * @param bool $csrfcookie Set the CSRF cookie. Defaults to true.
28
     */
29
    public static function printHeader($title = '', $extra = '', $csrfcookie = true)
30
    {
31
        if ($csrfcookie) {
32
            $csrf = Util::getCsrf();
33
            $csrf->setTheCookie();
34
        }
35
36
        // Find the 'Powered By CILogon' image if specified by the skin
37
        $poweredbyimg = "/images/poweredbycilogon.png";
38
        $skin = Util::getSkin();
39
        $skinpoweredbyimg = (string)$skin->getConfigOption('poweredbyimg');
40
        if (
41
            (!is_null($skinpoweredbyimg)) &&
0 ignored issues
show
introduced by
The condition is_null($skinpoweredbyimg) is always false.
Loading history...
42
            (strlen($skinpoweredbyimg) > 0) &&
43
            (is_readable('/var/www/html' . $skinpoweredbyimg))
44
        ) {
45
            $poweredbyimg = $skinpoweredbyimg;
46
        }
47
48
        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
49
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
50
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
51
        <head><title>' , $title , '</title>
52
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
53
        <meta name="viewport" content="initial-scale=0.6" />
54
        <link rel="stylesheet" type="text/css" href="/include/cilogon.css" />
55
        ';
56
57
        $skin->printSkinLink();
58
59
        echo '
60
        <script type="text/javascript" src="/include/cilogon.js"></script>
61
        ' ;
62
63
        echo '
64
    <!--[if IE]>
65
        <style type="text/css">
66
          body { behavior: url(/include/csshover3.htc); }
67
        </style>
68
    <![endif]-->
69
        ';
70
71
        if (strlen($extra) > 0) {
72
            echo $extra;
73
        }
74
75
        echo '
76
        </head>
77
78
        <body>
79
80
        <div class="skincilogonlogo">
81
        <a target="_blank" href="http://www.cilogon.org/faq/"><img
82
        src="' , $poweredbyimg , '" alt="CILogon"
83
        title="CILogon Service" /></a>
84
        </div>
85
86
        <div class="logoheader">
87
           <h1><span>[CILogon Service]</span></h1>
88
        </div>
89
        <div class="pagecontent">
90
         ';
91
92
        if ((defined('BANNER_TEXT')) && (!empty(BANNER_TEXT))) {
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\BANNER_TEXT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
93
            echo '
94
            <div class="noticebanner">' , BANNER_TEXT , '</div>
95
            ';
96
        }
97
98
        $providerId = Util::getSessionVar('idp');
99
        if ($providerId == "urn:mace:incommon:idp.protectnetwork.org") {
100
            echo '
101
            <div class="noticebanner">Availability of the ProtectNetwork
102
            Identity Provider (IdP) will end after December 2014. Please
103
            consider using another IdP.</div>
104
            ';
105
        }
106
    }
107
108
    /**
109
     * printFooter
110
     *
111
     * This function should be called to print out the closing HTML block
112
     * for each web page.
113
     *
114
     * @param string $footer Optional extra text to be output before the
115
     * closing footer div.
116
     */
117
    public static function printFooter($footer = '')
118
    {
119
        if (strlen($footer) > 0) {
120
            echo $footer;
121
        }
122
123
        echo '
124
        <br class="clear" />
125
        <div class="footer">
126
        <a target="_blank" href="http://www.cilogon.org/faq"><img
127
        src="/images/questionIcon.png" class="floatrightclear"
128
        width="40" height="40" alt="CILogon FAQ" title="CILogon FAQ" /></a>
129
        <p>For questions about this site, please see the <a target="_blank"
130
        href="http://www.cilogon.org/faq">FAQs</a> or send email to <a
131
        href="mailto:[email protected]">help&nbsp;@&nbsp;cilogon.org</a>.</p>
132
        <p>Know <a target="_blank"
133
        href="http://ca.cilogon.org/responsibilities">your responsibilities</a>
134
        for using the CILogon Service.</p>
135
        <p>See <a target="_blank"
136
        href="http://ca.cilogon.org/acknowledgements">acknowledgements</a> of
137
        support for this site.</p>
138
        </div> <!-- Close "footer" div -->
139
        </div> <!-- Close "pagecontent" div -->
140
        </body>
141
        </html>
142
        ';
143
144
        session_write_close();
145
    }
146
147
    /**
148
     * printPageHeader
149
     *
150
     * This function prints a fancy formatted box with a single line of
151
     * text, suitable for a titlebox on each web page (to appear just below
152
     * the page banner at the very top). It prints a gradent border around
153
     * the four edges of the box and then outlines the inner box.
154
     *
155
     * @param string $text The text string to appear in the titlebox.
156
     */
157
    public static function printPageHeader($text)
158
    {
159
        echo '
160
        <div class="titlebox">' , $text , '
161
        </div>
162
        ';
163
    }
164
165
    /**
166
     * printFormHead
167
     *
168
     * This function prints out the opening <form> tag for displaying
169
     * submit buttons.  The first parameter is used for the 'action' value
170
     * of the <form>.  If omitted, getScriptDir() is called to get the
171
     * location of the current script.  This function outputs a hidden csrf
172
     * field in the form block.
173
     *
174
     * @param string $action (Optional) The value of the form's 'action'
175
     *        parameter. Defaults to getScriptDir().
176
     * @param string $method (Optional) The <form> 'method', one of 'get' or
177
     *        'post'. Defaults to 'post'.
178
     */
179
    public static function printFormHead(
180
        $action = '',
181
        $method = 'post'
182
    ) {
183
        static $formnum = 0;
184
185
        if (strlen($action) == 0) {
186
            $action = Util::getScriptDir();
187
        }
188
189
        echo '
190
        <form action="' , $action , '" method="' , $method , '"
191
         autocomplete="off" id="form' , sprintf("%02d", ++$formnum) , '">
192
        ';
193
        $csrf = Util::getCsrf();
194
        echo $csrf->hiddenFormElement();
195
    }
196
197
    /**
198
     * printWAYF
199
     *
200
     * This function prints the list of IdPs in a <select> form element
201
     * which can be printed on the main login page to allow the user to
202
     * select 'Where Are You From?'.  This function checks to see if a
203
     * cookie for the 'providerId' had been set previously, so that the
204
     * last used IdP is selected in the list.
205
     *
206
     * @param bool $showremember (Optional) Show the 'Remember this
207
     *        selection' checkbox? Defaults to true.
208
     * @param bool $samlidps (Optional) Show all SAML-based IdPs in
209
     *        selection list? Defaults to false, which means show
210
     *        only whitelisted IdPs.
211
     */
212
    public static function printWAYF($showremember = true, $samlidps = false)
213
    {
214
        $helptext = 'Check this box to bypass the welcome page on ' .
215
            'subsequent visits and proceed directly to the selected ' .
216
            'identity provider. You will need to clear your browser\'s ' .
217
            'cookies to return here.';
218
        $searchtext = "Enter characters to search for in the list above.";
219
220
        // Get an array of IdPs
221
        $idps = static::getCompositeIdPList($samlidps);
222
223
        $skin = Util::getSkin();
224
225
        // Check if the user had previously selected an IdP from the list.
226
        // First, check the portalcookie, then the 'normal' cookie.
227
        $keepidp = '';
228
        $providerId = '';
229
        $pc = new PortalCookie();
230
        $pn = $pc->getPortalName();
231
        if (strlen($pn) > 0) {
232
            $keepidp    = $pc->get('keepidp');
233
            $providerId = $pc->get('providerId');
234
        } else {
235
            $keepidp    = Util::getCookieVar('keepidp');
236
            $providerId = Util::getCookieVar('providerId');
237
        }
238
239
        // Make sure previously selected IdP is in list of available IdPs.
240
        if ((strlen($providerId) > 0) && (!isset($idps[$providerId]))) {
241
            $providerId = '';
242
        }
243
244
        // If no previous providerId, get from skin, or default to Google.
245
        if (strlen($providerId) == 0) {
246
            $initialidp = (string)$skin->getConfigOption('initialidp');
247
            if ((!is_null($initialidp)) && (isset($idps[$initialidp]))) {
0 ignored issues
show
introduced by
The condition is_null($initialidp) is always false.
Loading history...
248
                $providerId = $initialidp;
249
            } else {
250
                $providerId = Util::getAuthzUrl('Google');
251
            }
252
        }
253
254
        // Check if an OIDC client selected an IdP for the transaction.
255
        // If so, verify that the IdP is in the list of available IdPs.
256
        $useselectedidp = false;
257
        $idphintlist = static::getIdphintList($idps);
258
        if (!empty($idphintlist)) {
259
            $useselectedidp = true;
260
            $providerId = $idphintlist[0];
261
            // Update the IdP selection list to show just the idphintlist.
262
            foreach ($idphintlist as $value) {
263
                $newidps[$value] = $idps[$value];
264
            }
265
            $idps = $newidps;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $newidps seems to be defined by a foreach iteration on line 262. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
266
            // Re-sort the $idps by Display_Name for correct alphabetization.
267
            uasort($idps, function ($a, $b) {
268
                return strcasecmp(
269
                    $a['Display_Name'],
270
                    $b['Display_Name']
271
                );
272
            });
273
        }
274
275
        echo '
276
        <br />
277
        <div class="actionbox"';
278
279
        if (Util::getSessionVar('showhelp') == 'on') {
280
            echo ' style="width:92%;"';
281
        }
282
283
        echo '>
284
        <table class="helptable">
285
        <tr>
286
        <td class="actioncell">
287
288
          <form action="' , Util::getScriptDir() , '" method="post">
289
          <fieldset>
290
291
          <p>' , ($useselectedidp ? 'Selected' : 'Select An') ,
292
          ' Identity Provider:</p>
293
          ';
294
295
        // See if the skin has set a size for the IdP <select> list
296
        $selectsize = 4;
297
        $ils = $skin->getConfigOption('idplistsize');
298
        if ((!is_null($ils)) && ((int)$ils > 0)) {
299
            $selectsize = (int)$ils;
300
        }
301
302
        // When selected_idp is used, list size may be smaller
303
        if ($useselectedidp) {
304
            $selectsize = min($selectsize, count($idps));
305
        }
306
307
        echo '
308
          <p>
309
          <select name="providerId" id="providerId" size="' , $selectsize , '"
310
           onkeypress="enterKeySubmit(event)" ondblclick="doubleClickSubmit()"' ,
311
           // Hide the drop-down arrow in Firefox and Chrome
312
          ($useselectedidp ?
313
              'style="-moz-appearance:none;-webkit-appearance:none"' : '') ,
314
           '>
315
        ';
316
317
        foreach ($idps as $entityId => $names) {
318
            echo '    <option value="' , $entityId , '"';
319
            if ($entityId == $providerId) {
320
                echo ' selected="selected"';
321
            }
322
            echo '>' , Util::htmlent($names['Display_Name']) , '</option>' , "\n    ";
323
        }
324
325
        echo '  </select>
326
        </p>
327
328
        <p id="listsearch" class="zeroheight">
329
        <label for="searchlist" class="helpcursor" title="' ,
330
        $searchtext , '">Search:</label>
331
        <input type="text" name="searchlist" id="searchlist" value=""
332
        size="30" onkeyup="searchOptions(this.value)"
333
        title="' , $searchtext , '" />
334
    <!--[if IE]><input type="text" style="display:none;" disabled="disabled" size="1"/><![endif]-->
335
        </p>
336
        ';
337
338
        if ($showremember) {
339
            echo '
340
            <p>
341
            <label for="keepidp" title="' , $helptext ,
342
            '" class="helpcursor">Remember this selection:</label>
343
            <input type="checkbox" name="keepidp" id="keepidp" ' ,
344
            ((strlen($keepidp) > 0) ? 'checked="checked" ' : '') ,
345
            'title="' , $helptext , '" class="helpcursor" />
346
            </p>
347
            ';
348
        }
349
350
        echo '
351
        <p class="silvercheckbox">
352
        <label for="silveridp">Request Silver:</label>
353
        <input type="checkbox" name="silveridp" id="silveridp"/>
354
        </p>
355
356
        <p>
357
        ';
358
359
        echo Util::getCsrf()->hiddenFormElement();
360
361
        $lobtext = static::getLogOnButtonText();
362
363
        echo '
364
        <input type="submit" name="submit" class="submit helpcursor"
365
        title="Continue to the selected identity provider."
366
        value="' , $lobtext , '" id="wayflogonbutton" />
367
        <input type="hidden" name="previouspage" value="WAYF" />
368
        <input type="submit" name="submit" class="submit helpcursor"
369
        title="Cancel authentication and navigate away from this site."
370
        value="Cancel" id="wayfcancelbutton" />
371
        </p>
372
        ';
373
374
        $logonerror = Util::getSessionVar('logonerror');
375
        if (strlen($logonerror) > 0) {
376
            echo "<p class=\"logonerror\">$logonerror</p>";
377
            Util::unsetSessionVar('logonerror');
378
        }
379
380
        echo '
381
        <p class="privacypolicy">
382
        By selecting "' , $lobtext , '", you agree to <a target="_blank"
383
        href="http://ca.cilogon.org/policy/privacy">CILogon\'s privacy
384
        policy</a>.
385
        </p>
386
387
        </fieldset>
388
389
        </form>
390
      </td>
391
      ';
392
393
        if (Util::getSessionVar('showhelp') == 'on') {
394
            echo '
395
          <td class="helpcell">
396
          <div>
397
          ';
398
399
            if ($samlidps) { // SAML-based IdPs only means running from /testidp/
400
                echo '
401
                <p>
402
                CILogon facilitates secure access to CyberInfrastructure
403
                (<acronym title="CyberInfrastructure">CI</acronym>). In
404
                order to test your identity provider with the CILogon Service,
405
                you must first Log On. If your preferred identity provider is
406
                not listed, please contact <a
407
                href="mailto:[email protected]">[email protected]</a>, and
408
                we will try to add your identity provider in the future.
409
                </p>
410
                ';
411
            } else { // If not InCommon only, print help text for OpenID providers.
412
                echo '
413
                <p>
414
                CILogon facilitates secure access to CyberInfrastructure
415
                (<acronym title="CyberInfrastructure">CI</acronym>).
416
                In order to use the CILogon Service, you must first select
417
                an identity provider. An identity provider (IdP) is an
418
                organization where you have an account and can log on
419
                to gain access to online services.
420
                </p>
421
                <p>
422
                If you are a faculty, staff, or student member of a university
423
                or college, please select it for your identity provider.
424
                If your school is not listed, please contact <a
425
                href="mailto:[email protected]">[email protected]</a>, and we will
426
                try to add your school in the future.
427
                </p>
428
                ';
429
430
                $googleauthz = Util::getAuthzUrl('Google');
431
                if (isset($idps[$googleauthz])) {
432
                    echo '
433
                    <p>
434
                    If you have a <a target="_blank"
435
                    href="https://myaccount.google.com">Google</a>
436
                    account, you can select it for
437
                    authenticating to the CILogon Service.
438
                    </p>
439
                    ';
440
                }
441
                $githubauthz = Util::getAuthzUrl('GitHub');
442
                if (isset($idps[$githubauthz])) {
443
                    echo '
444
                    <p>
445
                    If you have a <a target="_blank"
446
                    href="https://github.com/settings/profile">GitHub</a>
447
                    account, you can select it for
448
                    authenticating to the CILogon Service.
449
                    </p>
450
                    ';
451
                }
452
                $orcidauthz = Util::getAuthzUrl('ORCID');
453
                if (isset($idps[$orcidauthz])) {
454
                    echo '
455
                    <p>
456
                    If you have a <a target="_blank"
457
                    href="https://orcid.org/my-orcid">ORCID</a>
458
                    account, you can select it for
459
                    authenticating to the CILogon Service.
460
                    </p>
461
                    ';
462
                }
463
            }
464
465
            echo '
466
          </div>
467
          </td>
468
          ';
469
        }
470
        echo '
471
      </tr>
472
      </table>
473
      </div>
474
      ';
475
    }
476
477
    /**
478
     * printCertInfo
479
     *
480
     * This function prints information related to the X.509 certificate
481
     * such as DN (distinguished name) and LOA (level of assurance).
482
     */
483
    public static function printCertInfo()
484
    {
485
        $dn = Util::getSessionVar('dn');
486
        // Strip off the email address from the pseudo-DN.
487
        $dn = Content::reformatDN(preg_replace('/\s+email=.+$/', '', $dn));
488
489
        echo '
490
        <table class="certinfo">
491
          <tr>
492
            <th>Certificate&nbsp;Subject:</th>
493
            <td>' , Util::htmlent($dn) , '</td>
494
          </tr>
495
          <tr>
496
            <th>Identity&nbsp;Provider:</th>
497
            <td>' , Util::getSessionVar('idpname') , '</td>
498
          </tr>
499
          <tr>
500
            <th><a target="_blank"
501
            href="http://ca.cilogon.org/loa">Level&nbsp;of&nbsp;Assurance:</a></th>
502
            <td>
503
        ';
504
505
        $loa = Util::getSessionVar('loa');
506
        if ($loa == 'openid') {
507
            echo '<a href="http://ca.cilogon.org/policy/openid"
508
                  target="_blank">OpenID</a>';
509
        } elseif ($loa == 'http://incommonfederation.org/assurance/silver') {
510
            echo '<a href="http://ca.cilogon.org/policy/silver"
511
                  target="_blank">Silver</a>';
512
        } else {
513
            echo '<a href="http://ca.cilogon.org/policy/basic"
514
                  target="_blank">Basic</a>';
515
        }
516
        echo '
517
            </td>
518
          </tr>
519
        </table>
520
        ';
521
    }
522
523
    /**
524
     * printUserAttributes
525
     *
526
     * This function shows the user the attributes released by their
527
     * selected IdP and saved in the PHP session.
528
     */
529
    public static function printUserAttributes()
530
    {
531
        $idplist = Util::getIdpList();
532
        $idp = Util::getSessionVar('idp');
533
        $gotattrs = Util::gotUserAttributes();
534
        $samlidp = ((!empty($idp)) && (!$idplist->isOAuth2($idp)));
535
536
        echo '
537
        <div class="summary">
538
            <div id="userattrs1" style="display:' ,
539
            ($gotattrs ? "inline" : "none") ,
540
            '"><span class="expander"><a
541
            href="javascript:showHideDiv(\'userattrs\',-1)"><img
542
            src="/images/triright.gif" alt="&rArr;" width="14" height="14" />
543
            User Attributes</a></span>';
544
545
        // CIL-416 Show warning for missing ePPN
546
        if (
547
            ($samlidp) &&
548
            (empty(Util::getSessionVar('ePPN'))) &&
549
            (!empty(Util::getSessionVar('ePTID')))
550
        ) {
551
            Content::printIcon('warn', 'Some CILogon clients (e.g., Globus) require ePPN.');
552
        }
553
554
        echo '
555
            </div>
556
            <div id="userattrs2" style="display:' ,
557
                ($gotattrs ? "none" : "inline") ,
558
            '"><span class="expander"><a
559
            href="javascript:showHideDiv(\'userattrs\',-1)"><img
560
            src="/images/tridown.gif" alt="&dArr;" width="14" height="14" />
561
            User Attributes</a></span>
562
            </div>
563
            <br class="clear" />
564
            <div id="userattrs3" style="display:' ,
565
                ($gotattrs ? "none" : "inline") ,
566
            '">
567
568
            <table cellpadding="5">
569
              <tr class="odd">
570
                <th>Identity Provider (entityID):</th>
571
                <td>' , $idp , '</td>
572
                <td>';
573
574
        if (empty($idp)) {
575
            Content::printIcon('error', 'Missing the entityID of the IdP.');
576
        }
577
578
        echo '
579
                </td>
580
              </tr>
581
582
              <tr>
583
                <th>ePTID:</th>
584
                <td>' , Util::getSessionVar('ePTID') , '</td>
585
                <td>';
586
587
        if (
588
            ($samlidp) &&
589
            (empty(Util::getSessionVar('ePPN'))) &&
590
            (empty(Util::getSessionVar('ePTID')))
591
        ) {
592
            Content::printIcon('error', 'Must have either ePPN -OR- ePTID.');
593
        }
594
595
        echo '
596
                </td>
597
              </tr>
598
599
              <tr class="odd">
600
                <th>ePPN:</th>
601
                <td>' , Util::getSessionVar('ePPN') , '</td>
602
                <td>';
603
604
        if (($samlidp) && empty(Util::getSessionVar('ePPN'))) {
605
            if (empty(Util::getSessionVar('ePTID'))) {
606
                Content::printIcon('error', 'Must have either ePPN -OR- ePTID.');
607
            } else {
608
                Content::printIcon('warn', 'Some CILogon clients (e.g., Globus) require ePPN.');
609
            }
610
        }
611
612
        echo '
613
                </td>
614
              </tr>
615
616
              <tr>
617
                <th>OpenID:</th>
618
                <td>' , Util::getSessionVar('oidcID'), '</td>
619
                <td>';
620
621
        if (
622
            (!empty($idp)) &&
623
            (!$samlidp) &&
624
            empty(Util::getSessionVar('oidcID'))
625
        ) {
626
            Content::printIcon('error', 'Missing the OpenID identifier.');
627
        }
628
629
        echo '
630
                </td>
631
              </tr>
632
633
              <tr class="odd">
634
                <th>First Name (givenName):</th>
635
                <td>' ,Util::getSessionVar('firstname') , '</td>
636
                <td>';
637
638
        if (
639
            (empty(Util::getSessionVar('firstname'))) &&
640
            (empty(Util::getSessionVar('displayname')))
641
        ) {
642
            Content::printIcon('error', 'Must have either givenName + sn -OR- displayName.');
643
        }
644
645
        echo '
646
                </td>
647
              </tr>
648
649
              <tr>
650
                <th>Last Name (sn):</th>
651
                <td>' , Util::getSessionVar('lastname') , '</td>
652
                <td>';
653
654
        if (
655
            (empty(Util::getSessionVar('lastname'))) &&
656
            (empty(Util::getSessionVar('displayname')))
657
        ) {
658
            Content::printIcon('error', 'Must have either givenName + sn -OR- displayName.');
659
        }
660
661
        echo '
662
                </td>
663
              </tr>
664
665
              <tr class="odd">
666
                <th>Display Name (displayName):</th>
667
                <td>' , Util::getSessionVar('displayname') , '</td>
668
                <td>';
669
670
        if (
671
            (empty(Util::getSessionVar('displayname'))) &&
672
            ((empty(Util::getSessionVar('firstname'))) ||
673
            (empty(Util::getSessionVar('lastname'))))
674
        ) {
675
            Content::printIcon('error', 'Must have either displayName -OR- givenName + sn.');
676
        }
677
678
        echo '
679
                </td>
680
              </tr>
681
682
              <tr>
683
                <th>Email Address (email):</th>
684
                <td>' , Util::getSessionVar('emailaddr') , '</td>
685
                <td>';
686
687
        $emailvalid = filter_var(Util::getSessionVar('emailaddr'), FILTER_VALIDATE_EMAIL);
688
        if ((empty(Util::getSessionVar('emailaddr'))) || (!$emailvalid)) {
689
            Content::printIcon('error', 'Missing valid email address.');
690
        }
691
692
        echo '
693
                </td>
694
              </tr>
695
696
              <tr class="odd">
697
                <th>Level of Assurance (assurance):</th>
698
                <td>' , Util::getSessionVar('loa') , '</td>
699
                <td> </td>
700
              </tr>
701
702
              <tr>
703
                <th>AuthnContextClassRef:</th>
704
                <td>' , Util::getSessionVar('acr') , '</td>
705
                <td> </td>
706
              </tr>
707
708
              <tr class="odd">
709
                <th>Affiliation (affiliation):</th>
710
                <td>' , Util::getSessionVar('affiliation') , '</td>
711
                <td> </td>
712
              </tr>
713
714
              <tr>
715
                <th>Entitlement (entitlement):</th>
716
                <td>' , Util::getSessionVar('entitlement') , '</td>
717
                <td> </td>
718
              </tr>
719
720
              <tr class="odd">
721
                <th>Organizational Unit (ou):</th>
722
                <td>' , Util::getSessionVar('ou') , '</td>
723
                <td> </td>
724
              </tr>
725
726
              <tr>
727
                <th>Member (member):</th>
728
                <td>' , Util::getSessionVar('memberof') , '</td>
729
                <td> </td>
730
              </tr>
731
732
              <tr class="odd">
733
                <th>iTrustUIN (itrustuin):</th>
734
                <td>' , Util::getSessionVar('itrustuin') , '</td>
735
                <td> </td>
736
              </tr>
737
738
739
            </table>
740
            </div> <!-- userattrs3 -->
741
        </div> <!-- summary -->
742
        ';
743
    }
744
745
    /**
746
     * printIdPMetadata
747
     *
748
     * This function shows the metadata associated with the IdP saved to
749
     * the PHP session.
750
     */
751
    public static function printIdPMetadata()
752
    {
753
        $idplist = Util::getIdpList();
754
        $idp = Util::getSessionVar('idp');
755
        $gotattrs = Util::gotUserAttributes();
756
        $samlidp = ((!empty($idp)) && (!$idplist->isOAuth2($idp)));
757
        $shibarray = $idplist->getShibInfo($idp);
758
759
        echo '
760
        <div class="summary">
761
            <div id="meta1" style="display:' ,
762
                ($gotattrs ? "inline" : "none") ,
763
            '"><span class="expander"><a
764
            href="javascript:showHideDiv(\'meta\',-1)"><img
765
            src="/images/triright.gif" alt="&rArr;" width="14" height="14" />
766
            Identity Provider Attributes</a></span>';
767
768
        // CIL-416 Check for eduGAIN IdPs without both REFEDS R&S and SIRTFI
769
        // since these IdPs are not allowed to get certificates.
770
        $eduGainWithoutRandSandSIRTFI = 0;
771
        if (
772
            ($samlidp) &&
773
            (!$idplist->isRegisteredByInCommon($idp)) &&
774
            ((!$idplist->isREFEDSRandS($idp)) ||
775
             (!$idplist->isSIRTFI($idp)))
776
        ) {
777
            $eduGainWithoutRandSandSIRTFI = 1;
778
        }
779
780
        if ($eduGainWithoutRandSandSIRTFI) {
781
            Content::printIcon('warn', 'This IdP does not support both ' .
782
                'REFEDS R&amp;S and SIRTFI. CILogon functionality may be limited.');
783
        }
784
785
        echo '
786
            </div>
787
            <div id="meta2" style="display:' ,
788
                ($gotattrs ? "none" : "inline") ,
789
            '"><span class="expander"><a
790
            href="javascript:showHideDiv(\'meta\',-1)"><img
791
            src="/images/tridown.gif" alt="&dArr;" width="14" height="14" />
792
            Identity Provider Attributes</a></span>
793
            </div>
794
            <br class="clear" />
795
            <div id="meta3" style="display:' ,
796
                ($gotattrs ? "none" : "inline") ,
797
            '">
798
799
            <table cellpadding="5">
800
              <tr class="odd">
801
                <th>Organization Name:</th>
802
                <td>' , @$shibarray['Organization Name'] , '</td>
803
                <td>';
804
805
        if (empty(@$shibarray['Organization Name'])) {
806
            Content::printIcon('error', 'Could not find ' .
807
                '&lt;OrganizationDisplayName&gt; in metadata.');
808
        }
809
810
        echo '
811
                </td>
812
              </tr>
813
              <tr>
814
                <th>Home Page:</th>
815
                <td><a target="_blank" href="' , @$shibarray['Home Page'] , '">' ,
816
                @$shibarray['Home Page'] , '</a></td>
817
                <td> </td>
818
              </tr>
819
820
              <tr class="odd">
821
                <th>Support Contact:</th>
822
        ';
823
        if (
824
            (!empty(@$shibarray['Support Name'])) ||
825
            (!empty(@$shibarray['Support Address']))
826
        ) {
827
            echo '
828
                <td>' , @$shibarray['Support Name'] , ' &lt;' ,
829
                        preg_replace('/^mailto:/', '', @$shibarray['Support Address']) , '&gt;</td>
830
                <td> </td>';
831
        }
832
        echo '
833
              </tr>
834
835
        ';
836
837
        if ($samlidp) {
838
            echo '
839
                  <tr>
840
                    <th>Technical Contact:</th>
841
            ';
842
            if (
843
                (!empty(@$shibarray['Technical Name'])) ||
844
                (!empty(@$shibarray['Technical Address']))
845
            ) {
846
                echo '
847
                    <td>' , @$shibarray['Technical Name'] , ' &lt;' ,
848
                            preg_replace('/^mailto:/', '', @$shibarray['Technical Address']) , '&gt;</td>
849
                    <td> </td>';
850
            }
851
            echo '
852
                  </tr>
853
854
                  <tr class="odd">
855
                    <th>Administrative Contact:</th>
856
            ';
857
            if (
858
                (!empty(@$shibarray['Administrative Name'])) ||
859
                (!empty(@$shibarray['Administrative Address']))
860
            ) {
861
                echo '
862
                    <td>' , @$shibarray['Administrative Name'] , ' &lt;' ,
863
                            preg_replace('/^mailto:/', '', @$shibarray['Administrative Address']) , '&gt;</td>
864
                    <td> </td>';
865
            }
866
            echo '
867
                  </tr>
868
869
                  <tr>
870
                    <th>Registered by InCommon:</th>
871
                    <td>' , ($idplist->isRegisteredByInCommon($idp) ? 'Yes' : 'No') , '</td>
872
                    <td> </td>
873
                  </tr>
874
875
                  <tr class="odd">
876
                    <th><a style="text-decoration:underline" target="_blank"
877
                    href="http://id.incommon.org/category/research-and-scholarship">InCommon R
878
                    &amp; S</a>:</th>
879
                    <td>' , ($idplist->isInCommonRandS($idp) ? 'Yes' : 'No') , '</td>
880
                    <td> </td>
881
                  </tr>
882
883
                  <tr>
884
                    <th><a style="text-decoration:underline" target="_blank"
885
                    href="http://refeds.org/category/research-and-scholarship">REFEDS
886
                    R &amp; S</a>:</th>
887
                    <td>' , ($idplist->isREFEDSRandS($idp) ? 'Yes' : 'No') , '</td>
888
                    <td>' ,
889
                    (($eduGainWithoutRandSandSIRTFI &&
890
                    !$idplist->isREFEDSRandS($idp)) ?
891
                        Content::printIcon('warn', 'This IdP does not support both ' .
0 ignored issues
show
Bug introduced by
Are you sure the usage of CILogon\Service\Content:...ality may be limited.') targeting CILogon\Service\Content::printIcon() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
892
                            'REFEDS R&amp;S and SIRTFI. CILogon functionality may be limited.') :
893
                        '') ,
894
                    '</td>
895
                  </tr>
896
897
                  <tr class="odd">
898
                    <th><a style="text-decoration:underline" target="_blank"
899
                           href="https://refeds.org/sirtfi">SIRTFI</a>:</th>
900
                    <td>' , ($idplist->isSIRTFI($idp) ? 'Yes' : 'No') , '</td>
901
                    <td>',
902
                    (($eduGainWithoutRandSandSIRTFI &&
903
                    !$idplist->isSIRTFI($idp)) ?
904
                        Content::printIcon('warn', 'This IdP does not support both ' .
0 ignored issues
show
Bug introduced by
Are you sure the usage of CILogon\Service\Content:...ality may be limited.') targeting CILogon\Service\Content::printIcon() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
905
                            'REFEDS R&amp;S and SIRTFI. CILogon functionality may be limited.') :
906
                        '') ,
907
                    '</td>
908
                  </tr>
909
910
                  <tr>
911
                    <th><a style="text-decoration:underline" target="_blank"
912
                    href="http://id.incommon.org/assurance/bronze">InCommon Bronze</a>:</th>
913
                    <td>' , ($idplist->isBronze($idp) ? 'Yes' : 'No') , '</td>
914
                    <td> </td>
915
                  </tr>
916
917
                  <tr class="odd">
918
                    <th><a style="text-decoration:underline" target="_blank"
919
                    href="http://id.incommon.org/assurance/silver">InCommon Silver</a>:</th>
920
                    <td>' , ($idplist->isSilver($idp) ? 'Yes' : 'No') , '</td>
921
                    <td> </td>
922
                  </tr>
923
924
                  <tr>
925
                    <th>Entity ID</th>
926
                    <td><a style="text-decoration:underline" target="_blank"
927
                    href="https://met.refeds.org/met/entity/',
928
                    rawurlencode($idp),
929
                    '">', $idp, '</td>
930
                    <td> </td>
931
                  </tr>
932
                  ';
933
        } // end if ($samlidp)
934
        echo '
935
              </table>
936
            </div>  <!-- meta3 -->
937
        </div>  <!-- summary -->
938
        ';
939
    }
940
941
    /**
942
     * handleLogOnButtonClicked
943
     *
944
     * This function is called when the user clicks the 'Log On' button
945
     * on the IdP selection page. It checks to see if the 'Remember this
946
     * selection' checkbox was checked and sets a cookie appropriately. It
947
     * also sets a cookie 'providerId' so the last chosen IdP will be
948
     * selected the next time the user visits the site. The function then
949
     * calls the appropriate 'redirectTo...' function to send the user
950
     * to the chosen IdP.
951
     */
952
    public static function handleLogOnButtonClicked()
953
    {
954
        // Get the list of currently available IdPs
955
        $idps = static::getCompositeIdPList();
956
957
        // Set the cookie for keepidp if the checkbox was checked
958
        $pc = new PortalCookie();
959
        $pn = $pc->getPortalName();
960
        if (strlen(Util::getPostVar('keepidp')) > 0) {
961
            if (strlen($pn) > 0) {
962
                $pc->set('keepidp', 'checked');
963
            } else {
964
                Util::setCookieVar('keepidp', 'checked');
965
            }
966
        } else {
967
            if (strlen($pn) > 0) {
968
                $pc->set('keepidp', '');
969
            } else {
970
                Util::unsetCookieVar('keepidp');
971
            }
972
        }
973
974
        // Get the user-chosen IdP from the posted form
975
        $providerId = Util::getPostVar('providerId');
976
977
        // Set the cookie for the last chosen IdP and redirect to it if in list
978
        if ((strlen($providerId) > 0) && (isset($idps[$providerId]))) {
979
            if (strlen($pn) > 0) {
980
                $pc->set('providerId', $providerId);
981
                $pc->write();
982
            } else {
983
                Util::setCookieVar('providerId', $providerId);
984
            }
985
            $providerName = Util::getAuthzIdP($providerId);
986
            if (in_array($providerName, Util::$oauth2idps)) {
987
                // Log in with an OAuth2 IdP
988
                static::redirectToGetOAuth2User($providerId);
989
            } else { // Use InCommon authn
990
                static::redirectToGetShibUser($providerId);
991
            }
992
        } else { // IdP not in list, or no IdP selected
993
            if (strlen($pn) > 0) {
994
                $pc->set('providerId', '');
995
                $pc->write();
996
            } else {
997
                Util::unsetCookieVar('providerId');
998
            }
999
            Util::setSessionVar('logonerror', 'Please select a valid IdP.');
1000
            printLogonPage();
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

1000
            /** @scrutinizer ignore-call */ 
1001
            printLogonPage();
Loading history...
1001
        }
1002
    }
1003
1004
    /**
1005
     * handleHelpButtonClicked
1006
     *
1007
     * This function is called when the user clicks on the 'Show Help' /
1008
     * 'Hide Help' button in the upper right corner of the page. It toggles
1009
     * the 'showhelp' session variable and redisplays the appropriate page
1010
     * with help now shown or hidden.
1011
     */
1012
    public static function handleHelpButtonClicked()
1013
    {
1014
        if (Util::getSessionVar('showhelp') == 'on') {
1015
            Util::unsetSessionVar('showhelp');
1016
        } else {
1017
            Util::setSessionVar('showhelp', 'on');
1018
        }
1019
1020
        $stage = Util::getSessionVar('stage');
1021
        if (static::verifyCurrentUserSession()) {
1022
            if ($stage == 'main') {
1023
                printMainPage();
0 ignored issues
show
Bug introduced by
The function printMainPage 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

1023
                /** @scrutinizer ignore-call */ 
1024
                printMainPage();
Loading history...
1024
            } else {
1025
                printLogonPage();
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

1025
                /** @scrutinizer ignore-call */ 
1026
                printLogonPage();
Loading history...
1026
            }
1027
        } else {
1028
            printLogonPage();
1029
        }
1030
    }
1031
1032
    /**
1033
     * handleNoSubmitButtonClicked
1034
     *
1035
     * This function is the 'default' case when no 'submit' button has been
1036
     * clicked, or if the submit session variable is not set. It checks
1037
     * to see if either the <forceinitialidp> option is set, or if the
1038
     * 'Remember this selection' checkbox was previously checked. If so,
1039
     * then rediret to the appropriate IdP. Otherwise, print the main
1040
     * Log On page.
1041
     */
1042
    public static function handleNoSubmitButtonClicked()
1043
    {
1044
        $providerId = '';
1045
        $keepidp = '';
1046
        $selected_idp = '';
1047
        $redirect_uri = '';
1048
        $client_id = '';
1049
        $callbackuri = Util::getSessionVar('callbackuri');
1050
        $readidpcookies = true;  // Assume config options are not set
1051
        $skin = Util::getSkin();
1052
        $forceinitialidp = (int)$skin->getConfigOption('forceinitialidp');
1053
        $initialidp = (string)$skin->getConfigOption('initialidp');
1054
1055
        // If this is a OIDC transaction, get the redirect_uri and
1056
        // client_id parameters from the session var clientparams.
1057
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
1058
        if (isset($clientparams['redirect_uri'])) {
1059
            $redirect_uri = $clientparams['redirect_uri'];
1060
        }
1061
        if (isset($clientparams['client_id'])) {
1062
            $client_id = $clientparams['client_id'];
1063
        }
1064
1065
        // Use the first element of the idphint list as the selected_idp.
1066
        $idphintlist = static::getIdphintList();
1067
        if (!empty($idphintlist)) {
1068
            $selected_idp = $idphintlist[0];
1069
        }
1070
1071
        if ((strlen($redirect_uri) > 0) || (strlen($client_id) > 0)) {
1072
            // CIL-431 - If the OAuth2/OIDC $redirect_uri or $client_id is set,
1073
            // then check for a match in the BYPASS_IDP_ARRAY to see if we
1074
            // should automatically redirect to a specific IdP. Used mainly
1075
            // by campus gateways.
1076
            $bypassidp = '';
1077
            foreach (BYPASS_IDP_ARRAY as $key => $value) {
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\BYPASS_IDP_ARRAY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1078
                if (
1079
                    (preg_match($key, $redirect_uri)) ||
1080
                    (preg_match($key, $client_id))
1081
                ) {
1082
                    $bypassidp = $value;
1083
                    break;
1084
                }
1085
            }
1086
1087
            // CIL-613 - Next, check for a match in the ALLOW_BYPASS_ARRAY.
1088
            // If found, then allow the idphint/selected_idp to be used as the
1089
            // IdP to redirect to.
1090
            if (empty($bypassidp) && (!empty($selected_idp))) {
1091
                foreach (ALLOW_BYPASS_ARRAY as $value) {
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\ALLOW_BYPASS_ARRAY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1092
                    if (
1093
                        (preg_match($value, $redirect_uri)) ||
1094
                        (preg_match($value, $client_id))
1095
                    ) {
1096
                        $bypassidp = $selected_idp;
1097
                        break;
1098
                    }
1099
                }
1100
            }
1101
1102
            if (!empty($bypassidp)) { // Match found!
1103
                $providerId = $bypassidp;
1104
                $keepidp = 'checked';
1105
                // To skip the next code blocks, unset a few variables.
1106
                $forceinitialidp = 0;     // Skip checking this option
1107
                $selected_idp = '';       // Skip any passed-in option
1108
                $readidpcookies = false;  // Don't read in the IdP cookies
1109
            }
1110
        }
1111
1112
        // If the <forceinitialidp> option is set, use either the
1113
        // <initialidp> or the selected_idp as the providerId, and use
1114
        // <forceinitialidp> as keepIdp. Otherwise, read the cookies
1115
        // 'providerId' and 'keepidp'.
1116
        if (
1117
            ($forceinitialidp == 1) &&
1118
            ((strlen($initialidp) > 0) || (strlen($selected_idp) > 0))
1119
        ) {
1120
            // If the <allowforceinitialidp> option is set, then make sure
1121
            // the callback / redirect uri is in the portal list.
1122
            $afii = $skin->getConfigOption('portallistaction', 'allowforceinitialidp');
1123
            if (
1124
                (is_null($afii)) || // Option not set, no need to check portal list
1125
                (((int)$afii == 1) &&
1126
                  (($skin->inPortalList($redirect_uri)) ||
1127
                   ($skin->inPortalList($client_id)) ||
1128
                   ($skin->inPortalList($callbackuri))))
1129
            ) {
1130
                // 'selected_idp' takes precedence over <initialidp>
1131
                if (strlen($selected_idp) > 0) {
1132
                    $providerId = $selected_idp;
1133
                } else {
1134
                    $providerId = $initialidp;
1135
                }
1136
                $keepidp = $forceinitialidp;
1137
                $readidpcookies = false; // Don't read in the IdP cookies
1138
            }
1139
        }
1140
1141
        // <initialidp> options not set, or portal not in portal list?
1142
        // Get idp and 'Remember this selection' from cookies instead.
1143
        $pc = new PortalCookie();
1144
        $pn = $pc->getPortalName();
1145
        if ($readidpcookies) {
1146
            // Check the portalcookie first, then the 'normal' cookies
1147
            if (strlen($pn) > 0) {
1148
                $keepidp    = $pc->get('keepidp');
1149
                $providerId = $pc->get('providerId');
1150
            } else {
1151
                $keepidp    = Util::getCookieVar('keepidp');
1152
                $providerId = Util::getCookieVar('providerId');
1153
            }
1154
        }
1155
1156
        // If both 'keepidp' and 'providerId' were set (and the
1157
        // providerId is a whitelisted IdP or valid OpenID provider),
1158
        // then skip the Logon page and proceed to the appropriate
1159
        // getuser script.
1160
        if ((strlen($providerId) > 0) && (strlen($keepidp) > 0)) {
1161
            // If selected_idp was specified at the OIDC authorize endpoint,
1162
            // make sure that it matches the saved providerId. If not,
1163
            // then show the Logon page and uncheck the keepidp checkbox.
1164
            if ((strlen($selected_idp) == 0) || ($selected_idp == $providerId)) {
1165
                $providerName = Util::getAuthzIdP($providerId);
1166
                if (in_array($providerName, Util::$oauth2idps)) {
1167
                    // Log in with an OAuth2 IdP
1168
                    static::redirectToGetOAuth2User($providerId);
1169
                } elseif (Util::getIdpList()->exists($providerId)) {
1170
                    // Log in with InCommon
1171
                    static::redirectToGetShibUser($providerId);
1172
                } else { // $providerId not in whitelist
1173
                    if (strlen($pn) > 0) {
1174
                        $pc->set('providerId', '');
1175
                        $pc->write();
1176
                    } else {
1177
                        Util::unsetCookieVar('providerId');
1178
                    }
1179
                    printLogonPage();
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

1179
                    /** @scrutinizer ignore-call */ 
1180
                    printLogonPage();
Loading history...
1180
                }
1181
            } else { // selected_idp does not match saved providerId
1182
                if (strlen($pn) > 0) {
1183
                    $pc->set('keepidp', '');
1184
                    $pc->write();
1185
                } else {
1186
                    Util::unsetCookieVar('keepidp');
1187
                }
1188
                printLogonPage();
1189
            }
1190
        } else { // One of providerId or keepidp was not set
1191
            printLogonPage();
1192
        }
1193
    }
1194
1195
    /**
1196
     * printIcon
1197
     *
1198
     * This function prints out the HTML for the little icons which can
1199
     * appear inline with other information.  This is accomplished via the
1200
     * use of wrapping the image in a <span> tag.
1201
     *
1202
     * @param string $icon The prefix of the '...Icon.png' image to be
1203
     *        shown. E.g., to show 'errorIcon.png', pass in 'error'.
1204
     * @param string $popuptext (Optionals) The popup 'title' text to be
1205
     *        displayed when the  mouse cursor hovers over the icon.
1206
     *        Defaults to empty string.
1207
     * @param string $class (Optionals) A CSS class for the icon. Will be
1208
     *        appended after the 'helpcursor' class. Defaults to empty
1209
     *        string.
1210
     */
1211
    public static function printIcon($icon, $popuptext = '', $class = '')
1212
    {
1213
        echo '<span';
1214
        if (strlen($popuptext) > 0) {
1215
            echo ' class="helpcursor ' , $class , '" title="' , $popuptext , '"';
1216
        }
1217
        echo '>&nbsp;<img src="/images/' , $icon , 'Icon.png"
1218
              alt="&laquo; ' , ucfirst($icon) , '"
1219
              width="14" height="14" /></span>';
1220
    }
1221
1222
    /**
1223
     * printHelpButton
1224
     *
1225
     * This function prints the 'Show Help' / 'Hide Help' button in the
1226
     * upper-right corner of the main box area on the page.
1227
     */
1228
    public static function printHelpButton()
1229
    {
1230
        echo '
1231
        <div class="helpbutton">
1232
        ';
1233
1234
        static::printFormHead();
1235
1236
        echo '
1237
          <input type="submit" name="submit" class="helpbutton" value="' ,
1238
          (Util::getSessionVar('showhelp') == 'on' ? 'Hide' : 'Show') , '&#10; Help " />
1239
          </form>
1240
        </div>
1241
        ';
1242
    }
1243
1244
    /**
1245
     * verifyCurrentUserSession
1246
     *
1247
     * This function verifies the contents of the PHP session.  It checks
1248
     * the following:
1249
     * (1) The persistent store 'uid', the Identity Provider 'idp', the
1250
     *     IdP Display Name 'idpname', and the 'status' (of getUser()) are
1251
     *     all non-empty strings.
1252
     * (2) The 'status' (of getUser()) is even (i.e. STATUS_OK).
1253
     * (3) If $providerId is passed-in, it must match 'idp'.
1254
     * If all checks are good, then this function returns true.
1255
     *
1256
     * @param string $providerId (Optional) The user-selected Identity
1257
     *        Provider. If set, make sure $providerId matches the PHP
1258
     *        session variable 'idp'.
1259
     * @return bool True if the contents of the PHP session ar valid.
1260
     *              False otherwise.
1261
     */
1262
    public static function verifyCurrentUserSession($providerId = '')
1263
    {
1264
        $retval = false;
1265
1266
        // Check for eduGAIN IdP and possible get cert context
1267
        if (Util::isEduGAINAndGetCert()) {
1268
            Util::unsetUserSessionVars();
1269
        }
1270
1271
        $idp       = Util::getSessionVar('idp');
1272
        $idpname   = Util::getSessionVar('idpname');
1273
        $uid       = Util::getSessionVar('uid');
1274
        $status    = Util::getSessionVar('status');
1275
        $dn        = Util::getSessionVar('dn');
1276
        $authntime = Util::getSessionVar('authntime');
1277
1278
1279
        if (
1280
            (strlen($uid) > 0) && (strlen($idp) > 0) &&
1281
            (strlen($idpname) > 0) && (strlen($status) > 0) &&
1282
            (strlen($dn) > 0) && (strlen($authntime) > 0) &&
1283
            (!($status & 1))
1284
        ) {  // All STATUS_OK codes are even
1285
            if ((strlen($providerId) == 0) || ($providerId == $idp)) {
1286
                $retval = true;
1287
            }
1288
        }
1289
1290
        // As a final check, see if the IdP requires a forced skin
1291
        if ($retval) {
1292
            Util::getSkin()->init();
1293
        }
1294
1295
        return $retval;
1296
    }
1297
1298
    /**
1299
     * redirectToGetShibUser
1300
     *
1301
     * This method redirects control flow to the getuser script for
1302
     * If the first parameter (a whitelisted entityId) is not specified,
1303
     * we check to see if either the providerId PHP session variable or the
1304
     * providerId cookie is set (in that order) and use one if available.
1305
     * The function then checks to see if there is a valid PHP session
1306
     * and if the providerId matches the 'idp' in the session.  If so, then
1307
     * we don't need to redirect to '/secure/getuser/' and instead we
1308
     * we display the main page.  However, if the PHP session is not valid,
1309
     * then this function redirects to the '/secure/getuser/' script so as
1310
     * to do a Shibboleth authentication via mod_shib. When the providerId
1311
     * is non-empty, the SessionInitiator will automatically go to that IdP
1312
     * (i.e. without stopping at a WAYF).  This function also sets
1313
     * several PHP session variables that are needed by the getuser script,
1314
     * including the 'responsesubmit' variable which is set as the return
1315
     * 'submit' variable in the 'getuser' script.
1316
     *
1317
     * @param string $providerId (Optional) An entityId of the
1318
     *        authenticating IdP. If not specified (or set to the empty
1319
     *        string), we check providerId PHP session variable and
1320
     *        providerId cookie (in that order) for non-empty values.
1321
     * @param string $responsesubmit (Optional) The value of the PHP session
1322
     *       'submit' variable to be set upon return from the 'getuser'
1323
     *        script.  This is utilized to control the flow of this script
1324
     *        after 'getuser'. Defaults to 'gotuser'.
1325
     * @param string responseurl (Optional) A response url for redirection
0 ignored issues
show
Bug introduced by
The type CILogon\Service\responseurl 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...
1326
     *        after successful processing at /secure/getuser/. Defaults to
1327
     *        the current script directory.
1328
     * @param bool $allowsilver Is it okay to request silver assurance in
1329
     *        the authnContextClassRef? If not, then ignore the 'Request
1330
     *        Silver' checkbox and silver certification in metadata.
1331
     *        Defaults to true.
1332
     */
1333
    public static function redirectToGetShibUser(
1334
        $providerId = '',
1335
        $responsesubmit = 'gotuser',
1336
        $responseurl = null,
1337
        $allowsilver = true
1338
    ) {
1339
1340
        // If providerId not set, try the cookie value
1341
        if (strlen($providerId) == 0) {
1342
            $providerId = Util::getPortalOrNormalCookieVar('providerId');
1343
        }
1344
1345
        // If the user has a valid 'uid' in the PHP session, and the
1346
        // providerId matches the 'idp' in the PHP session, then
1347
        // simply go to the main page.
1348
        if (static::verifyCurrentUserSession($providerId)) {
1349
            printMainPage();
0 ignored issues
show
Bug introduced by
The function printMainPage 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

1349
            /** @scrutinizer ignore-call */ 
1350
            printMainPage();
Loading history...
1350
        } else { // Otherwise, redirect to the getuser script
1351
            // Set PHP session varilables needed by the getuser script
1352
            Util::setSessionVar(
1353
                'responseurl',
1354
                (is_null($responseurl) ?
1355
                    Util::getScriptDir(true) : $responseurl)
1356
            );
1357
            Util::setSessionVar('submit', 'getuser');
1358
            Util::setSessionVar('responsesubmit', $responsesubmit);
1359
            Util::getCsrf()->setCookieAndSession();
1360
1361
            // Set up the 'header' string for redirection thru mod_shib
1362
            $mhn = static::getMachineHostname($providerId);
1363
            $redirect = "Location: https://$mhn/Shibboleth.sso/Login?target=" .
1364
                urlencode("https://$mhn/secure/getuser/");
1365
1366
            if (strlen($providerId) > 0) {
1367
                // Use special NIHLogin Shibboleth SessionInitiator for acsByIndex
1368
                if ($providerId == 'urn:mace:incommon:nih.gov') {
1369
                    $redirect = preg_replace(
1370
                        '%/Shibboleth.sso/Login%',
1371
                        '/Shibboleth.sso/NIHLogin',
1372
                        $redirect
1373
                    );
1374
                }
1375
1376
                $redirect .= '&providerId=' . urlencode($providerId);
1377
1378
                // To bypass SSO at IdP, check for session var 'forceauthn' == 1
1379
                $forceauthn = Util::getSessionVar('forceauthn');
1380
                Util::unsetSessionVar('forceauthn');
1381
                if ($forceauthn) {
1382
                    $redirect .= '&forceAuthn=true';
1383
                } elseif (strlen($forceauthn) == 0) {
1384
                    // 'forceauth' was not set to '0' in the session, so
1385
                    // check the skin's option instead.
1386
                    $forceauthn = Util::getSkin()->getConfigOption('forceauthn');
1387
                    if ((!is_null($forceauthn)) && ((int)$forceauthn == 1)) {
1388
                        $redirect .= '&forceAuthn=true';
1389
                    }
1390
                }
1391
1392
                // If Silver IdP or 'Request Silver' checked, send extra parameter
1393
                if ($allowsilver) {
1394
                    if (
1395
                        (Util::getIdpList()->isSilver($providerId)) ||
1396
                        (strlen(Util::getPostVar('silveridp')) > 0)
1397
                    ) {
1398
                        Util::setSessionVar('requestsilver', '1');
1399
                        $redirect .= '&authnContextClassRef=' .
1400
                            urlencode('http://id.incommon.org/assurance/silver');
1401
                    }
1402
                }
1403
            }
1404
1405
            $log = new Loggit();
1406
            $log->info('Shibboleth Login="' . $redirect . '"');
1407
            header($redirect);
1408
            exit; // No further processing necessary
1409
        }
1410
    }
1411
1412
    /**
1413
     * redirectToGetOAuth2User
1414
     *
1415
     * This method redirects control flow to the getuser script for
1416
     * when the user logs in via OAuth 2.0. It first checks to see
1417
     * if we have a valid session. If so, we don't need to redirect and
1418
     * instead simply show the Get Certificate page. Otherwise, we start
1419
     * an OAuth 2.0 logon by composing a parameterized GET URL using
1420
     * the OAuth 2.0 endpoint.
1421
     *
1422
     * @param string $providerId (Optional) An entityId of the
1423
     *        authenticating IdP. If not specified (or set to the empty
1424
     *        string), we check providerId PHP session variable and
1425
     *        providerId cookie (in that order) for non-empty values.
1426
     * @param string $responsesubmit (Optional) The value of the PHP session
1427
     *        'submit' variable to be set upon return from the 'getuser'
1428
     *         script.  This is utilized to control the flow of this script
1429
     *         after 'getuser'. Defaults to 'gotuser'.
1430
     */
1431
    public static function redirectToGetOAuth2User(
1432
        $providerId = '',
1433
        $responsesubmit = 'gotuser'
1434
    ) {
1435
        // If providerId not set, try the cookie value
1436
        if (strlen($providerId) == 0) {
1437
            $providerId = Util::getPortalOrNormalCookieVar('providerId');
1438
        }
1439
1440
        // If the user has a valid 'uid' in the PHP session, and the
1441
        // providerId matches the 'idp' in the PHP session, then
1442
        // simply go to the 'Download Certificate' button page.
1443
        if (static::verifyCurrentUserSession($providerId)) {
1444
            printMainPage();
0 ignored issues
show
Bug introduced by
The function printMainPage 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

1444
            /** @scrutinizer ignore-call */ 
1445
            printMainPage();
Loading history...
1445
        } else { // Otherwise, redirect to the OAuth 2.0 endpoint
1446
            // Set PHP session varilables needed by the getuser script
1447
            Util::unsetSessionVar('logonerror');
1448
            Util::setSessionVar('responseurl', Util::getScriptDir(true));
1449
            Util::setSessionVar('submit', 'getuser');
1450
            Util::setSessionVar('responsesubmit', $responsesubmit);
1451
            $csrf = Util::getCsrf();
1452
            $csrf->setCookieAndSession();
1453
            $extraparams = array();
1454
            $extraparams['state'] = $csrf->getTokenValue();
1455
1456
            // To bypass SSO at IdP, check for session var 'forceauthn' == 1
1457
            $forceauthn = Util::getSessionVar('forceauthn');
1458
            Util::unsetSessionVar('forceauthn');
1459
            if ($forceauthn) {
1460
                $extraparams['approval_prompt'] = 'force';
1461
            } elseif (strlen($forceauthn) == 0) {
1462
                // 'forceauth' was not set to '0' in the session, so
1463
                // check the skin's option instead.
1464
                $forceauthn = Util::getSkin()->getConfigOption('forceauthn');
1465
                if ((!is_null($forceauthn)) && ((int)$forceauthn == 1)) {
1466
                    $extraparams['approval_prompt'] = 'force';
1467
                }
1468
            }
1469
1470
            // Get the provider name based on the provider authz URL
1471
            $providerName = Util::getAuthzIdP($providerId);
1472
1473
            // Get the authz URL and redirect
1474
            $oauth2 = new OAuth2Provider($providerName);
1475
            if (is_null($oauth2->provider)) {
1476
                Util::setSessionVar('logonerror', 'Invalid Identity Provider.');
1477
                printLogonPage();
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

1477
                /** @scrutinizer ignore-call */ 
1478
                printLogonPage();
Loading history...
1478
            } else {
1479
                $authUrl = $oauth2->provider->getAuthorizationUrl(
1480
                    array_merge(
1481
                        $oauth2->authzUrlOpts,
1482
                        $extraparams
1483
                    )
1484
                );
1485
                header('Location: ' . $authUrl);
1486
                exit; // No further processing necessary
1487
            }
1488
        }
1489
    }
1490
1491
    /**
1492
     * printErrorBox
1493
     *
1494
     * This function prints out a bordered box with an error icon and any
1495
     * passed-in error HTML text.  The error icon and text are output to
1496
     * a <table> so as to keep the icon to the left of the error text.
1497
     *
1498
     * @param string $errortext HTML error text to be output
1499
     */
1500
    public static function printErrorBox($errortext)
1501
    {
1502
        echo '
1503
        <div class="errorbox">
1504
        <table cellpadding="5">
1505
        <tr>
1506
        <td valign="top">
1507
        ';
1508
        static::printIcon('error');
1509
        echo '&nbsp;
1510
        </td>
1511
        <td> ' , $errortext , '
1512
        </td>
1513
        </tr>
1514
        </table>
1515
        </div>
1516
        ';
1517
    }
1518
1519
    /**
1520
     * handleGotUser
1521
     *
1522
     * This function is called upon return from one of the getuser scripts
1523
     * which should have set the 'uid' and 'status' PHP session variables.
1524
     * It verifies that the status return is one of STATUS_OK (even
1525
     * values).  If not, we print an error message to the user.
1526
     */
1527
    public static function handleGotUser()
1528
    {
1529
        $log = new Loggit();
1530
        $uid = Util::getSessionVar('uid');
1531
        $status = Util::getSessionVar('status');
1532
1533
        // We must get and unset session vars BEFORE any HTML output since
1534
        // a redirect may go to another site, meaning we need to update
1535
        // the session cookie before we leave the cilogon.org domain.
1536
        $ePPN         = Util::getSessionVar('ePPN');
1537
        $ePTID        = Util::getSessionVar('ePTID');
1538
        $firstname    = Util::getSessionVar('firstname');
1539
        $lastname     = Util::getSessionVar('lastname');
1540
        $displayname  = Util::getSessionVar('displayname');
1541
        $emailaddr    = Util::getSessionVar('emailaddr');
1542
        $idp          = Util::getSessionVar('idp');
1543
        $idpname      = Util::getSessionVar('idpname');
1544
        $affiliation  = Util::getSessionVar('affiliation');
1545
        $ou           = Util::getSessionVar('ou');
1546
        $memberof     = Util::getSessionVar('memberof');
1547
        $acr          = Util::getSessionVar('acr');
1548
        $entitlement  = Util::getSessionVar('entitlement');
1549
        $itrustuin    = Util::getSessionVar('itrustuin');
1550
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
1551
        $failureuri   = Util::getSessionVar('failureuri');
1552
1553
        // Check for OIDC redirect_uri or OAuth 1.0a failureuri.
1554
        // If found, set 'Proceed' button redirect appropriately.
1555
        $redirect = '';
1556
        $redirectform = '';
1557
        // First, check for OIDC redirect_uri, with parameters in <form>
1558
        if (isset($clientparams['redirect_uri'])) {
1559
            $redirect = $clientparams['redirect_uri'];
1560
            $redirectform = '<input type="hidden" name="error" value="access_denied" />' .
1561
                '<input type="hidden" name="error_description" value="Missing attributes" />';
1562
            if (isset($clientparams['state'])) {
1563
                $redirectform .= '<input type="hidden" name="state" value="' .
1564
                    $clientparams['state'] . '" />';
1565
            }
1566
        }
1567
        // Next, check for OAuth 1.0a
1568
        if ((strlen($redirect) == 0) && (strlen($failureuri) > 0)) {
1569
            $redirect = $failureuri . "?reason=missing_attributes";
1570
        }
1571
1572
        // If empty 'uid' or 'status' or odd-numbered status code, error!
1573
        if ((strlen($uid) == 0) || (strlen($status) == 0) || ($status & 1)) {
1574
            // Got all session vars by now, so okay to unset.
1575
            Util::unsetAllUserSessionVars();
1576
1577
            $log->error('Failed to getuser.');
1578
1579
            static::printHeader('Error Logging On');
1580
1581
            echo '
1582
            <div class="boxed">
1583
            ';
1584
1585
            if ($status == DBService::$STATUS['STATUS_MISSING_PARAMETER_ERROR']) {
1586
                // Check if the problem IdP was an OAuth2 IdP;
1587
                // probably no first/last name
1588
                if ($idpname == 'Google') {
1589
                    static::printErrorBox('
1590
                    <p>
1591
                    There was a problem logging on. It appears that you have
1592
                    attempted to use Google as your identity provider, but your
1593
                    name or email address was missing. To rectify this problem,
1594
                    go to the <a target="_blank"
1595
                    href="https://myaccount.google.com/privacy#personalinfo">Google
1596
                    Account Personal Information page</a>, and enter your first
1597
                    name, last name, and email address. (All other Google
1598
                    account information is not required by the CILogon Service.)
1599
                    </p>
1600
                    <p>
1601
                    After you have updated your Google account profile, click
1602
                    the "Proceed" button below and attempt to log on
1603
                    with your Google account again. If you have any questions,
1604
                    please contact us at the email address at the bottom of the
1605
                    page.</p>
1606
                    ');
1607
1608
                    echo '
1609
                    <div>
1610
                    ';
1611
                    static::printFormHead($redirect, 'get');
1612
                    echo '
1613
                    <p class="centered">
1614
                    <input type="hidden" name="providerId" value="' ,
1615
                    Util::getAuthzUrl('Google') , '" /> ' , $redirectform , '
1616
                    <input type="submit" name="submit" class="submit"
1617
                    value="Proceed" />
1618
                    </p>
1619
                    </form>
1620
                    </div>
1621
                    ';
1622
                } elseif ($idpname == 'GitHub') {
1623
                    static::printErrorBox('
1624
                    <p>
1625
                    There was a problem logging on. It appears that you have
1626
                    attempted to use GitHub as your identity provider, but your
1627
                    name or email address was missing. To rectify this problem,
1628
                    go to the <a target="_blank"
1629
                    href="https://github.com/settings/profile">GitHub
1630
                    Public Profile page</a>, and enter your name and email address.
1631
                    (All other GitHub account information is not required by
1632
                    the CILogon Service.)
1633
                    </p>
1634
                    <p>
1635
                    After you have updated your GitHub account profile, click
1636
                    the "Proceed" button below and attempt to log on
1637
                    with your GitHub account again. If you have any questions,
1638
                    please contact us at the email address at the bottom of the
1639
                    page.</p>
1640
                    ');
1641
1642
                    echo '
1643
                    <div>
1644
                    ';
1645
                    static::printFormHead($redirect, 'get');
1646
                    echo '
1647
                    <p class="centered">
1648
                    <input type="hidden" name="providerId" value="' ,
1649
                    Util::getAuthzUrl('GitHub') , '" /> ' , $redirectform , '
1650
                    <input type="submit" name="submit" class="submit"
1651
                    value="Proceed" />
1652
                    </p>
1653
                    </form>
1654
                    </div>
1655
                    ';
1656
                } elseif ($idpname == 'ORCID') {
1657
                    static::printErrorBox('
1658
                    <p>
1659
                    There was a problem logging on. It appears that you have
1660
                    attempted to use ORCID as your identity provider, but your
1661
                    name or email address was missing. To rectify this problem,
1662
                    go to your <a target="_blank"
1663
                    href="https://orcid.org/my-orcid">ORCID
1664
                    Profile page</a>, enter your name and email address, and
1665
                    make sure they can be viewed by Everyone.
1666
                    (All other ORCID account information is not required by
1667
                    the CILogon Service.)
1668
                    </p>
1669
                    <p>
1670
                    After you have updated your ORCID account profile, click
1671
                    the "Proceed" button below and attempt to log on
1672
                    with your ORCID account again. If you have any questions,
1673
                    please contact us at the email address at the bottom of the
1674
                    page.</p>
1675
                    ');
1676
1677
                    echo '
1678
                    <div>
1679
                    ';
1680
                    static::printFormHead($redirect, 'get');
1681
                    echo '
1682
                    <p class="centered">
1683
                    <input type="hidden" name="providerId" value="' ,
1684
                    Util::getAuthzUrl('ORCID') , '" /> ' , $redirectform , '
1685
                    <input type="submit" name="submit" class="submit"
1686
                    value="Proceed" />
1687
                    </p>
1688
                    </form>
1689
                    </div>
1690
                    ';
1691
                } else { // Problem was missing SAML attribute from Shib IdP
1692
                    static::printAttributeReleaseErrorMessage(
1693
                        $ePPN,
1694
                        $ePTID,
1695
                        $firstname,
1696
                        $lastname,
1697
                        $displayname,
1698
                        $emailaddr,
1699
                        $idp,
1700
                        $idpname,
1701
                        $affiliation,
1702
                        $ou,
1703
                        $memberof,
1704
                        $acr,
1705
                        $entitlement,
1706
                        $itrustuin,
1707
                        $clientparams,
1708
                        $redirect,
1709
                        $redirectform,
1710
                        Util::isEduGAINAndGetCert($idp, $idpname)
1711
                    );
1712
                }
1713
            } else {
1714
                static::printErrorBox('An internal error has occurred. System
1715
                    administrators have been notified. This may be a temporary
1716
                    error. Please try again later, or contact us at the the email
1717
                    address at the bottom of the page.');
1718
1719
                echo '
1720
                <div>
1721
                ';
1722
                static::printFormHead($redirect, 'get');
1723
                echo $redirectform , '
1724
                <input type="submit" name="submit" class="submit" value="Proceed" />
1725
                </form>
1726
                </div>
1727
                ';
1728
            }
1729
1730
            echo '
1731
            </div>
1732
            ';
1733
            static::printFooter();
1734
        } elseif (Util::isEduGAINAndGetCert($idp, $idpname)) {
1735
            // If eduGAIN IdP and session can get a cert, then error!
1736
            // Got all session vars by now, so okay to unset.
1737
            Util::unsetAllUserSessionVars();
1738
1739
            $log->error('Failed to getuser due to eduGAIN IdP restriction.');
1740
1741
            static::printHeader('Error Logging On');
1742
1743
            echo '
1744
            <div class="boxed">
1745
            ';
1746
            static::printAttributeReleaseErrorMessage(
1747
                $ePPN,
1748
                $ePTID,
1749
                $firstname,
1750
                $lastname,
1751
                $displayname,
1752
                $emailaddr,
1753
                $idp,
1754
                $idpname,
1755
                $affiliation,
1756
                $ou,
1757
                $memberof,
1758
                $acr,
1759
                $entitlement,
1760
                $itrustuin,
1761
                $clientparams,
1762
                $redirect,
1763
                $redirectform,
1764
                true
1765
            );
1766
1767
            echo '
1768
            </div>
1769
            ';
1770
            static::printFooter();
1771
        } else { // Got one of the STATUS_OK status codes
1772
            // Extra security check: Once the user has successfully authenticated
1773
            // with an IdP, verify that the chosen IdP was actually whitelisted.
1774
            // If not, then set error message and show Select an Identity Provider
1775
            // page again.
1776
            Util::getSkin()->init();  // Check for forced skin
1777
            $idps = static::getCompositeIdPList();
1778
            $providerId = Util::getSessionVar('idp');
1779
            if ((strlen($providerId) > 0) && (!isset($idps[$providerId]))) {
1780
                Util::setSessionVar(
1781
                    'logonerror',
1782
                    'Invalid IdP selected. Please try again.'
1783
                );
1784
                Util::sendErrorAlert(
1785
                    'Authentication attempt using non-whitelisted IdP',
1786
                    'A user successfully authenticated with an IdP, however, the
1787
selected IdP was not in the list of whitelisted IdPs as determined
1788
by the current skin. This might indicate the user attempted to
1789
circumvent the security check in "handleGotUser()" for valid
1790
IdPs for the skin.'
1791
                );
1792
                Util::unsetCookieVar('providerId');
1793
                Util::unsetAllUserSessionVars();
1794
                printLogonPage();
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

1794
                /** @scrutinizer ignore-call */ 
1795
                printLogonPage();
Loading history...
1795
            } else { // Got user successfully
1796
                static::gotUserSuccess();
1797
            }
1798
        }
1799
    }
1800
1801
    /**
1802
     * gotUserSuccess
1803
     *
1804
     * This function is called after the user has been successfully
1805
     * authenticated. If the 'status' session variable is STATUS_OK
1806
     * then it checks if we have a new or changed user and logs
1807
     * that appropriately. It then continues to the MainPage.
1808
     */
1809
    public static function gotUserSuccess()
1810
    {
1811
        $log = new Loggit();
1812
        $status = Util::getSessionVar('status');
1813
1814
        // If this is the first time the user has used the CILogon Service,
1815
        // and the flow is OAuth-based, send an alert if the name contains
1816
        // any HTML entities.
1817
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
1818
        $callbackuri = Util::getSessionVar('callbackuri');
1819
1820
        if (
1821
            ($status == DBService::$STATUS['STATUS_NEW_USER']) &&
1822
            ((strlen($callbackuri) > 0) ||
1823
             (isset($clientparams['code'])))
1824
        ) {
1825
            // Extra check for new users: see if any HTML entities
1826
            // are in the user name. If so, send an email alert.
1827
            $dn = Util::getSessionVar('dn');
1828
            $dn = static::reformatDN(preg_replace('/\s+email=.+$/', '', $dn));
1829
            $htmldn = Util::htmlent($dn);
1830
            if (strcmp($dn, $htmldn) != 0) {
1831
                Util::sendErrorAlert(
1832
                    'New user DN contains HTML entities',
1833
                    "htmlentites(DN) = $htmldn\n"
1834
                );
1835
            }
1836
        }
1837
1838
        // For a new user, or if the user got new attributes, just log it.
1839
        // Then proceed to the Main Page.
1840
        if ($status == DBService::$STATUS['STATUS_NEW_USER']) {
1841
            $log->info('New User.');
1842
        } elseif ($status == DBService::$STATUS['STATUS_USER_UPDATED']) {
1843
            $log->info('User IdP attributes changed.');
1844
        }
1845
        printMainPage();
0 ignored issues
show
Bug introduced by
The function printMainPage 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

1845
        /** @scrutinizer ignore-call */ 
1846
        printMainPage();
Loading history...
1846
    }
1847
1848
    /**
1849
     * generateP12
1850
     *
1851
     * This function is called when the user clicks the 'Get New
1852
     * Certificate' button. It first reads in the password fields and
1853
     * verifies that they are valid (i.e. they are long enough and match).
1854
     * Then it gets a credential from the MyProxy server and converts that
1855
     * certificate into a PKCS12 which is written to disk.  If everything
1856
     * succeeds, the temporary pkcs12 directory and lifetime is saved to
1857
     * the 'p12' PHP session variable, which is read later when the Main
1858
     * Page HTML is shown.
1859
     */
1860
    public static function generateP12()
1861
    {
1862
        $log = new Loggit();
1863
1864
        // Get the entered p12lifetime and p12multiplier and set the cookies
1865
        list($minlifetime, $maxlifetime) =
1866
            static::getMinMaxLifetimes('pkcs12', 9516);
1867
        $p12lifetime   = Util::getPostVar('p12lifetime');
1868
        $p12multiplier = Util::getPostVar('p12multiplier');
1869
        if (strlen($p12multiplier) == 0) {
1870
            $p12multiplier = 1;  // For ECP, p12lifetime is in hours
1871
        }
1872
        $lifetime = $p12lifetime * $p12multiplier;
1873
        if ($lifetime <= 0) { // In case user entered negative number
1874
            $lifetime = $maxlifetime;
1875
            $p12lifetime = $maxlifetime;
1876
            $p12multiplier = 1;  // maxlifetime is in hours
1877
        } elseif ($lifetime < $minlifetime) {
1878
            $lifetime = $minlifetime;
1879
            $p12lifetime = $minlifetime;
1880
            $p12multiplier = 1;  // minlifetime is in hours
1881
        } elseif ($lifetime > $maxlifetime) {
1882
            $lifetime = $maxlifetime;
1883
            $p12lifetime = $maxlifetime;
1884
            $p12multiplier = 1;  // maxlifetime is in hours
1885
        }
1886
        Util::setCookieVar('p12lifetime', $p12lifetime);
1887
        Util::setCookieVar('p12multiplier', $p12multiplier);
1888
        Util::setSessionVar('p12lifetime', $p12lifetime);
1889
        Util::setSessionVar('p12multiplier', $p12multiplier);
1890
1891
        // Verify that the password is at least 12 characters long
1892
        $password1 = Util::getPostVar('password1');
1893
        $password2 = Util::getPostVar('password2');
1894
        $p12password = Util::getPostVar('p12password');  // For ECP clients
1895
        if (strlen($p12password) > 0) {
1896
            $password1 = $p12password;
1897
            $password2 = $p12password;
1898
        }
1899
        if (strlen($password1) < 12) {
1900
            Util::setSessionVar(
1901
                'p12error',
1902
                'Password must have at least 12 characters.'
1903
            );
1904
            return; // SHORT PASSWORD - NO FURTHER PROCESSING NEEDED!
1905
        }
1906
1907
        // Verify that the two password entry fields matched
1908
        if ($password1 != $password2) {
1909
            Util::setSessionVar('p12error', 'Passwords did not match.');
1910
            return; // MISMATCHED PASSWORDS - NO FURTHER PROCESSING NEEDED!
1911
        }
1912
1913
        // Set the port based on the Level of Assurance
1914
        $port = 7512;
1915
        $loa = Util::getSessionVar('loa');
1916
        if ($loa == 'http://incommonfederation.org/assurance/silver') {
1917
            $port = 7514;
1918
        } elseif ($loa == 'openid') {
1919
            $port = 7516;
1920
        }
1921
1922
        $dn = Util::getSessionVar('dn');
1923
        if (strlen($dn) > 0) {
1924
            // Append extra info, such as 'skin', to be processed by MyProxy
1925
            $myproxyinfo = Util::getSessionVar('myproxyinfo');
1926
            if (strlen($myproxyinfo) > 0) {
1927
                $dn .= " $myproxyinfo";
1928
            }
1929
            // Attempt to fetch a credential from the MyProxy server
1930
            $cert = MyProxy::getMyProxyCredential(
1931
                $dn,
1932
                '',
1933
                MYPROXY_HOST,
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\MYPROXY_HOST was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1934
                $port,
1935
                $lifetime,
1936
                '/var/www/config/hostcred.pem',
1937
                ''
1938
            );
1939
1940
            // The 'openssl pkcs12' command is picky in that the private
1941
            // key must appear BEFORE the public certificate. But MyProxy
1942
            // returns the private key AFTER. So swap them around.
1943
            $cert2 = '';
1944
            if (
1945
                preg_match(
1946
                    '/-----BEGIN CERTIFICATE-----([^-]+)' .
1947
                    '-----END CERTIFICATE-----[^-]*' .
1948
                    '-----BEGIN RSA PRIVATE KEY-----([^-]+)' .
1949
                    '-----END RSA PRIVATE KEY-----/',
1950
                    $cert,
1951
                    $match
1952
                )
1953
            ) {
1954
                $cert2 = "-----BEGIN RSA PRIVATE KEY-----" .
1955
                         $match[2] . "-----END RSA PRIVATE KEY-----\n" .
1956
                         "-----BEGIN CERTIFICATE-----" .
1957
                         $match[1] . "-----END CERTIFICATE-----";
1958
            }
1959
1960
            if (strlen($cert2) > 0) { // Successfully got a certificate!
1961
                // Create a temporary directory in /var/www/html/pkcs12/
1962
                $tdirparent = '/var/www/html/pkcs12/';
1963
                $polonum = '3';   // Prepend the polo? number to directory
1964
                if (preg_match('/(\d+)\./', php_uname('n'), $polomatch)) {
1965
                    $polonum = $polomatch[1];
1966
                }
1967
                $tdir = Util::tempDir($tdirparent, $polonum, 0770);
1968
                $p12dir = str_replace($tdirparent, '', $tdir);
1969
                $p12file = $tdir . '/usercred.p12';
1970
1971
                // Call the openssl pkcs12 program to convert certificate
1972
                exec('/bin/env ' .
1973
                     'RANDFILE=/tmp/.rnd ' .
1974
                     'CILOGON_PKCS12_PW=' . escapeshellarg($password1) . ' ' .
1975
                     '/usr/bin/openssl pkcs12 -export ' .
1976
                     '-passout env:CILOGON_PKCS12_PW ' .
1977
                     "-out $p12file " .
1978
                     '<<< ' . escapeshellarg($cert2));
1979
1980
                // Verify the usercred.p12 file was actually created
1981
                $size = @filesize($p12file);
1982
                if (($size !== false) && ($size > 0)) {
1983
                    $p12link = 'https://' . static::getMachineHostname() .
1984
                               '/pkcs12/' . $p12dir . '/usercred.p12';
1985
                    $p12 = (time() + 300) . " " . $p12link;
1986
                    Util::setSessionVar('p12', $p12);
1987
                    $log->info('Generated New User Certificate="' . $p12link . '"');
1988
                    //CIL-507 Special Log Message For XSEDE
1989
                    $log->info('USAGE email="' .
1990
                        Util::getSessionVar('emailaddr') . '" client="PKCS12"');
1991
                } else { // Empty or missing usercred.p12 file - shouldn't happen!
1992
                    Util::setSessionVar(
1993
                        'p12error',
1994
                        'Error creating certificate. Please try again.'
1995
                    );
1996
                    Util::deleteDir($tdir); // Remove the temporary directory
1997
                    $log->info('Error creating certificate - missing usercred.p12');
1998
                }
1999
            } else { // The myproxy-logon command failed - shouldn't happen!
2000
                Util::setSessionVar(
2001
                    'p12error',
2002
                    'Error! MyProxy unable to create certificate.'
2003
                );
2004
                $log->info('Error creating certificate - myproxy-logon failed');
2005
            }
2006
        } else { // Couldn't find the 'dn' PHP session value - shouldn't happen!
2007
            Util::setSessionVar(
2008
                'p12error',
2009
                'Missing username. Please enable cookies.'
2010
            );
2011
            $log->info('Error creating certificate - missing dn session variable');
2012
        }
2013
    }
2014
2015
    /**
2016
     * getLogOnButtonText
2017
     *
2018
     * This function checks the current skin to see if <logonbuttontext>
2019
     * has been configured.  If so, it returns that value.  Otherwise,
2020
     * it returns 'Log On'.
2021
     *
2022
     * @return string The text of the 'Log On' button for the WAYF, as
2023
     *         configured for the skin.  Defaults to 'Log On'.
2024
     */
2025
    public static function getLogOnButtonText()
2026
    {
2027
        $retval = 'Log On';
2028
        $lobt = Util::getSkin()->getConfigOption('logonbuttontext');
2029
        if (!is_null($lobt)) {
2030
            $retval = (string)$lobt;
2031
        }
2032
        return $retval;
2033
    }
2034
2035
    /**
2036
     * getSerialStringFromDN
2037
     *
2038
     * This function takes in a CILogon subject DN and returns just the
2039
     * serial string part (e.g., A325). This function is needed since the
2040
     * serial_string is not stored in the PHP session as a separate
2041
     * variable since it is always available in the 'dn' session variable.
2042
     *
2043
     * @param string $dn The certificate subject DN (typically found in the
2044
     *        session 'dn' variable)
2045
     * @return string The serial string extracted from the subject DN, or
2046
     *         empty string if DN is empty or wrong format.
2047
     */
2048
    public static function getSerialStringFromDN($dn)
2049
    {
2050
        $serial = ''; // Return empty string upon error
2051
2052
        // Strip off the email address, if present
2053
        $dn = preg_replace('/\s+email=.+$/', '', $dn);
2054
        // Find the 'CN=' entry
2055
        if (preg_match('%/DC=org/DC=cilogon/C=US/O=.*/CN=(.*)%', $dn, $match)) {
2056
            $cn = $match[1];
2057
            if (preg_match('/\s+([^\s]+)$/', $cn, $match)) {
2058
                $serial = $match[1];
2059
            }
2060
        }
2061
        return $serial;
2062
    }
2063
2064
    /**
2065
     * getEmailFromDN
2066
     *
2067
     * This function takes in a CILogon subject DN and returns just the
2068
     * email address part. This function is needed since the email address
2069
     * is not stored in the PHP session as a separate variable since it is
2070
     * always available in the 'dn' session variable.
2071
     *
2072
     * @param string $dn The certificate subject DN (typically found in the
2073
     *        session 'dn' variable)
2074
     * @return string The email address extracted from the subject DN, or
2075
     *         empty string if DN is empty or wrong format.
2076
     */
2077
    public static function getEmailFromDN($dn)
2078
    {
2079
        $email = ''; // Return empty string upon error
2080
        if (preg_match('/\s+email=(.+)$/', $dn, $match)) {
2081
            $email = $match[1];
2082
        }
2083
        return $email;
2084
    }
2085
2086
    /**
2087
     * reformatDN
2088
     *
2089
     * This function takes in a certificate subject DN with the email=...
2090
     * part already removed. It checks the skin to see if <dnformat> has
2091
     * been set. If so, it reformats the DN appropriately.
2092
     *
2093
     * @param string $dn The certificate subject DN (without the email=... part)
2094
     * @return string The certificate subject DN transformed according to
2095
     *         the value of the <dnformat> skin config option.
2096
     */
2097
    public static function reformatDN($dn)
2098
    {
2099
        $newdn = $dn;
2100
        $dnformat = (string)Util::getSkin()->getConfigOption('dnformat');
2101
        if (!is_null($dnformat)) {
0 ignored issues
show
introduced by
The condition is_null($dnformat) is always false.
Loading history...
2102
            if (
2103
                ($dnformat == 'rfc2253') &&
2104
                (preg_match(
2105
                    '%/DC=(.*)/DC=(.*)/C=(.*)/O=(.*)/CN=(.*)%',
2106
                    $dn,
2107
                    $match
2108
                ))
2109
            ) {
2110
                array_shift($match);
2111
                $m = array_reverse(Net_LDAP2_Util::escape_dn_value($match));
2112
                $newdn = "CN=$m[0],O=$m[1],C=$m[2],DC=$m[3],DC=$m[4]";
2113
            }
2114
        }
2115
        return $newdn;
2116
    }
2117
2118
    /**
2119
     * getMinMaxLifetimes
2120
     *
2121
     * This function checks the skin's configuration to see if either or
2122
     * both of minlifetime and maxlifetime in the specified config.xml
2123
     * block have been set. If not, default to minlifetime of 1 (hour) and
2124
     * the specified defaultmaxlifetime.
2125
     *
2126
     * @param string $section The XML section block from which to read the
2127
     *        minlifetime and maxlifetime values. Can be one of the
2128
     *        following: 'pkcs12' or 'delegate'.
2129
     * @param int $defaultmaxlifetime Default maxlifetime (in hours) for the
2130
     *        credential.
2131
     * @return array An array consisting of two entries: the minimum and
2132
     *         maximum lifetimes (in hours) for a credential.
2133
     */
2134
    public static function getMinMaxLifetimes($section, $defaultmaxlifetime)
2135
    {
2136
        $minlifetime = 1;    // Default minimum lifetime is 1 hour
2137
        $maxlifetime = $defaultmaxlifetime;
2138
        $skin = Util::getSkin();
2139
        $skinminlifetime = $skin->getConfigOption($section, 'minlifetime');
2140
        // Read the skin's minlifetime value from the specified section
2141
        if ((!is_null($skinminlifetime)) && ((int)$skinminlifetime > 0)) {
2142
            $minlifetime = max($minlifetime, (int)$skinminlifetime);
2143
            // Make sure $minlifetime is less than $maxlifetime;
2144
            $minlifetime = min($minlifetime, $maxlifetime);
2145
        }
2146
        // Read the skin's maxlifetime value from the specified section
2147
        $skinmaxlifetime = $skin->getConfigOption($section, 'maxlifetime');
2148
        if ((!is_null($skinmaxlifetime)) && ((int)$skinmaxlifetime) > 0) {
2149
            $maxlifetime = min($maxlifetime, (int)$skinmaxlifetime);
2150
            // Make sure $maxlifetime is greater than $minlifetime
2151
            $maxlifetime = max($minlifetime, $maxlifetime);
2152
        }
2153
2154
        return array($minlifetime, $maxlifetime);
2155
    }
2156
2157
    /**
2158
     * getMachineHostname
2159
     *
2160
     * This function is utilized in the formation of the URL for the
2161
     * PKCS12 credential download link and for the Shibboleth Single Sign-on
2162
     * session initiator URL. It returns a host-specific URL
2163
     * hostname by mapping the local machine hostname (as returned
2164
     * by 'uname -n') to an InCommon metadata cilogon.org hostname
2165
     * (e.g., polo2.cilogon.org). This function uses the HOSTNAME_ARRAY
2166
     * where the keys are the local machine hostname and
2167
     * the values are the external facing *.cilogon.org hostname.
2168
     * In case the local machine hostname cannot be found in the
2169
     * HOSTNAME_ARRAY, DEFAULT_HOSTNAME is returned.
2170
     *
2171
     * @param string $idp The entityID of the IdP used for potential
2172
     *        special handling (e.g., for Syngenta).
2173
     * @return string The full cilogon-specific hostname of this host.
2174
     */
2175
    public static function getMachineHostname($idp = '')
2176
    {
2177
        $retval = DEFAULT_HOSTNAME;
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\DEFAULT_HOSTNAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2178
        // CIL-439 For Syngenta, use just a single 'hostname' value to
2179
        // match their Active Directory configuration for CILogon's
2180
        // assertionConsumerService URL. Otherwise, map the local
2181
        // hostname to a *.cilogon.org domain name.
2182
        if ($idp != 'https://sts.windows.net/06219a4a-a835-44d5-afaf-3926343bfb89/') {
2183
            $localhost = php_uname('n');
2184
            if (array_key_exists($localhost, HOSTNAME_ARRAY)) {
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\HOSTNAME_ARRAY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2185
                $retval = HOSTNAME_ARRAY[$localhost];
2186
            }
2187
        }
2188
        return $retval;
2189
    }
2190
2191
    /**
2192
     * getCompositeIdPList
2193
     *
2194
     * This function generates a list of IdPs to display in the 'Select
2195
     * An Identity Provider' box on the main CILogon page or on the
2196
     * TestIdP page. For the main CILogon page, this is a filtered list of
2197
     * IdPs based on the skin's whitelist/blacklist and the global
2198
     * blacklist file. For the TestIdP page, the list is all InCommon IdPs.
2199
     *
2200
     * @param bool $samlidps (Optional) Show all SAML-based IdPs in
2201
     *        selection list? Defaults to false, which means show only
2202
     *        whitelisted IdPs.
2203
     * @return array A two-dimensional array where the primary key is the
2204
     *         entityID and the secondary key is either 'Display_Name'
2205
     *         or 'Organization_Name'.
2206
     */
2207
    public static function getCompositeIdPList($samlidps = false)
2208
    {
2209
        $retarray = array();
2210
2211
        $idplist = Util::getIdpList();
2212
        if ($samlidps) { // Get all SAML-based IdPs only
2213
            $retarray = $idplist->getSAMLIdPs();
2214
        } else { // Get the selected InCommon IdPs, plus maybe OAuth2 IdPs
2215
            $skin = Util::getSkin();
2216
2217
            // Check if the skin's config.xml has set the
2218
            // 'registeredbyincommonidps' option, which restricts the SAML-
2219
            // based IdPs to those with the <Registered_By_InCommon> tag.
2220
            // Otherwise, just get the SAML-based IdPs that have the
2221
            // <Whitelisted> tag. Note that the skin's <idpwhitelist>
2222
            // is still consulted in either case (below).
2223
            $registeredbyincommonidps = $skin->getConfigOption('registeredbyincommonidps');
2224
            if (
2225
                (!is_null($registeredbyincommonidps)) &&
2226
                ((int)$registeredbyincommonidps == 1)
2227
            ) {
2228
                $retarray = $idplist->getRegisteredByInCommonIdPs();
2229
            } else {
2230
                $retarray = $idplist->getWhitelistedIdPs();
2231
            }
2232
2233
            // Add all OAuth2 IdPs to the list
2234
            foreach (Util::$oauth2idps as $value) {
2235
                // CIL-617 Show OAuth2 IdPs only if client_id is configured
2236
                $client_id = constant(strtoupper($value) . '_OAUTH2_CLIENT_ID');
2237
                if (!empty($client_id)) {
2238
                    $retarray[Util::getAuthzUrl($value)]['Organization_Name'] =
2239
                        $value;
2240
                    $retarray[Util::getAuthzUrl($value)]['Display_Name'] =
2241
                        $value;
2242
                }
2243
            }
2244
2245
            // Check to see if the skin's config.xml has a whitelist of IDPs.
2246
            // If so, go thru master IdP list and keep only those IdPs in the
2247
            // config.xml's whitelist.
2248
            if ($skin->hasIdpWhitelist()) {
2249
                foreach ($retarray as $entityId => $names) {
2250
                    if (!$skin->idpWhitelisted($entityId)) {
2251
                        unset($retarray[$entityId]);
2252
                    }
2253
                }
2254
            }
2255
            // Next, check to see if the skin's config.xml has a blacklist of
2256
            // IdPs. If so, cull down the master IdP list removing 'bad' IdPs.
2257
            if ($skin->hasIdpBlacklist()) {
2258
                $idpblacklist = $skin->getConfigOption('idpblacklist');
2259
                foreach ($idpblacklist->idp as $blackidp) {
2260
                    unset($retarray[(string)$blackidp]);
2261
                }
2262
            }
2263
        }
2264
2265
        // Fix for CIL-174 - As suggested by Keith Hazelton, replace commas and
2266
        // hyphens with just commas.
2267
        $regex = '/(University of California)\s*[,-]\s*/';
2268
        foreach ($retarray as $entityId => $names) {
2269
            if (preg_match($regex, $names['Organization_Name'])) {
2270
                $retarray[$entityId]['Organization_Name'] =
2271
                    preg_replace($regex, '$1, ', $names['Organization_Name']);
2272
            }
2273
            if (preg_match($regex, $names['Display_Name'])) {
2274
                $retarray[$entityId]['Display_Name'] =
2275
                    preg_replace($regex, '$1, ', $names['Display_Name']);
2276
            }
2277
        }
2278
2279
        // Re-sort the retarray by Display_Name for correct alphabetization.
2280
        uasort($retarray, function ($a, $b) {
2281
            return strcasecmp(
2282
                $a['Display_Name'],
2283
                $b['Display_Name']
2284
            );
2285
        });
2286
2287
        return $retarray;
2288
    }
2289
2290
    /**
2291
     * printAttributeReleaseErrorMessage
2292
     *
2293
     * This is a convenience method called by handleGotUser to print out
2294
     * the attribute release error page to the user.
2295
     *
2296
     * @param string $ePPN
2297
     * @param string $ePTID
2298
     * @param string $firstname
2299
     * @param string $lastname
2300
     * @param string $displayname
2301
     * @param string $emailaddr
2302
     * @param string $idp
2303
     * @param string $idpname
2304
     * @param string $affiliation
2305
     * @param string $ou
2306
     * @param string $memberof
2307
     * @param string $acr
2308
     * @param string $entitlement
2309
     * @param string $itrustuin
2310
     * @param string $clientparams
2311
     * @param string $redirect
2312
     * @param string $redirectform
2313
     * @param bool   $edugainandgetcert
2314
     */
2315
    public static function printAttributeReleaseErrorMessage(
2316
        $ePPN,
2317
        $ePTID,
2318
        $firstname,
2319
        $lastname,
2320
        $displayname,
2321
        $emailaddr,
2322
        $idp,
2323
        $idpname,
2324
        $affiliation,
2325
        $ou,
0 ignored issues
show
Unused Code introduced by
The parameter $ou 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

2325
        /** @scrutinizer ignore-unused */ $ou,

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...
2326
        $memberof,
0 ignored issues
show
Unused Code introduced by
The parameter $memberof 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

2326
        /** @scrutinizer ignore-unused */ $memberof,

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...
2327
        $acr,
0 ignored issues
show
Unused Code introduced by
The parameter $acr 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

2327
        /** @scrutinizer ignore-unused */ $acr,

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...
2328
        $entitlement,
0 ignored issues
show
Unused Code introduced by
The parameter $entitlement 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

2328
        /** @scrutinizer ignore-unused */ $entitlement,

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...
2329
        $itrustuin,
0 ignored issues
show
Unused Code introduced by
The parameter $itrustuin 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

2329
        /** @scrutinizer ignore-unused */ $itrustuin,

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...
2330
        $clientparams,
0 ignored issues
show
Unused Code introduced by
The parameter $clientparams 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

2330
        /** @scrutinizer ignore-unused */ $clientparams,

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...
2331
        $redirect,
2332
        $redirectform,
2333
        $edugainandgetcert
2334
    ) {
2335
        $errorboxstr =
2336
        '<p>There was a problem logging on. Your identity
2337
        provider has not provided CILogon with required information.</p>
2338
        <blockquote><table cellpadding="5">';
2339
2340
        $missingattrs = '';
2341
        // Show user which attributes are missing
2342
        if ((strlen($ePPN) == 0) && (strlen($ePTID) == 0)) {
2343
            $errorboxstr .=
2344
            '<tr><th>ePTID:</th><td>MISSING</td></tr>
2345
            <tr><th>ePPN:</th><td>MISSING</td></tr>';
2346
            $missingattrs .= '%0D%0A    eduPersonPrincipalName' .
2347
                             '%0D%0A    eduPersonTargetedID ';
2348
        }
2349
        if ((strlen($firstname) == 0) && (strlen($displayname) == 0)) {
2350
            $errorboxstr .=
2351
            '<tr><th>First Name:</th><td>MISSING</td></tr>';
2352
            $missingattrs .= '%0D%0A    givenName (first name)';
2353
        }
2354
        if ((strlen($lastname) == 0) && (strlen($displayname) == 0)) {
2355
            $errorboxstr .=
2356
            '<tr><th>Last Name:</th><td>MISSING</td></tr>';
2357
            $missingattrs .= '%0D%0A    sn (last name)';
2358
        }
2359
        if (
2360
            (strlen($displayname) == 0) &&
2361
            ((strlen($firstname) == 0) || (strlen($lastname) == 0))
2362
        ) {
2363
            $errorboxstr .=
2364
            '<tr><th>Display Name:</th><td>MISSING</td></tr>';
2365
            $missingattrs .= '%0D%0A    displayName';
2366
        }
2367
        $emailvalid = filter_var($emailaddr, FILTER_VALIDATE_EMAIL);
2368
        if ((strlen($emailaddr) == 0) || (!$emailvalid)) {
2369
            $errorboxstr .=
2370
            '<tr><th>Email Address:</th><td>' .
2371
            ((strlen($emailaddr) == 0) ? 'MISSING' : 'INVALID') .
2372
            '</td></tr>';
2373
            $missingattrs .= '%0D%0A    mail (email address)';
2374
        }
2375
        // CIL-326/CIL-539 - For eduGAIN IdPs attempting to get a cert,
2376
        // print out missing R&S and SIRTFI values
2377
        $idplist = Util::getIdpList();
2378
        if ($edugainandgetcert) {
2379
            if (!$idplist->isREFEDSRandS($idp)) {
2380
                $errorboxstr .=
2381
                '<tr><th><a target="_blank"
2382
                href="http://refeds.org/category/research-and-scholarship">Research
2383
                and Scholarship</a>:</th><td>MISSING</td></tr>';
2384
                $missingattrs .= '%0D%0A    http://refeds.org/category/research-and-scholarship';
2385
            }
2386
            if (!$idplist->isSIRTFI($idp)) {
2387
                $errorboxstr .=
2388
                '<tr><th><a target="_blank"
2389
                href="https://refeds.org/sirtfi">SIRTFI</a>:</th><td>MISSING</td></tr>';
2390
                $missingattrs .= '%0D%0A    http://refeds.org/sirtfi';
2391
            }
2392
        }
2393
        $student = false;
2394
        $errorboxstr .= '</table></blockquote>';
2395
        if (
2396
            (strlen($emailaddr) == 0) &&
2397
            (preg_match('/student@/', $affiliation))
2398
        ) {
2399
            $student = true;
2400
            $errorboxstr .= '<p><b>If you are a student</b>, ' .
2401
            'you may need to ask your identity provider ' .
2402
            'to release your email address.</p>';
2403
        }
2404
2405
        // Get contacts from metadata for email addresses
2406
        $shibarray = $idplist->getShibInfo($idp);
2407
        $emailmsg = '?subject=Attribute Release Problem for CILogon' .
2408
        '&[email protected]' .
2409
        '&body=Hello, I am having trouble logging on to ' .
2410
        'https://' . DEFAULT_HOSTNAME . '/ using the ' . $idpname .
0 ignored issues
show
Bug introduced by
The constant CILogon\Service\DEFAULT_HOSTNAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2411
        ' Identity Provider (IdP) ' .
2412
        'due to the following missing attributes:%0D%0A' .
2413
        $missingattrs;
2414
        if ($student) {
2415
            $emailmsg .= '%0D%0A%0D%0ANote that my account is ' .
2416
            'marked "student" and thus my email address may need ' .
2417
            'to be released.';
2418
        }
2419
        $emailmsg .= '%0D%0A%0D%0APlease see ' .
2420
            'http://www.cilogon.org/service/addidp for more ' .
2421
            'details. Thank you for any help you can provide.';
2422
        $errorboxstr .= '<p>Contact your identity provider to ' .
2423
        'let them know you are having having a problem logging on ' .
2424
        'to CILogon.</p><blockquote><ul>';
2425
2426
        $addrfound = false;
2427
        $name = @$shibarray['Support Name'];
2428
        $addr = @$shibarray['Support Address'];
2429
        $addr = preg_replace('/^mailto:/', '', $addr);
2430
2431
        if (strlen($addr) > 0) {
2432
            $addrfound = true;
2433
            if (strlen($name) == 0) { // Use address if no name given
2434
                $name = $addr;
2435
            }
2436
            $errorboxstr .= '<li> Support Contact: ' .
2437
                $name . ' &lt;<a href="mailto:' .
2438
                $addr . $emailmsg . '">' .
2439
                $addr . '</a>&gt;</li>';
2440
        }
2441
2442
        if (!$addrfound) {
2443
            $name = @$shibarray['Technical Name'];
2444
            $addr = @$shibarray['Technical Address'];
2445
            $addr = preg_replace('/^mailto:/', '', $addr);
2446
            if (strlen($addr) > 0) {
2447
                $addrfound = true;
2448
                if (strlen($name) == 0) { // Use address if no name given
2449
                    $name = $addr;
2450
                }
2451
                $errorboxstr .= '<li> Technical Contact: ' .
2452
                    $name . ' &lt;<a href="mailto:' .
2453
                    $addr . $emailmsg . '">' .
2454
                    $addr . '</a>&gt;</li>';
2455
            }
2456
        }
2457
2458
        if (!$addrfound) {
2459
            $name = @$shibarray['Administrative Name'];
2460
            $addr = @$shibarray['Administrative Address'];
2461
            $addr = preg_replace('/^mailto:/', '', $addr);
2462
            if (strlen($addr) > 0) {
2463
                if (strlen($name) == 0) { // Use address if no name given
2464
                    $name = $addr;
2465
                }
2466
                $errorboxstr .= '<li>Administrative Contact: ' .
2467
                    $name . ' &lt;<a href="mailto:' .
2468
                    $addr . $emailmsg . '">' .
2469
                    $addr . '</a>&gt</li>';
2470
            }
2471
        }
2472
2473
        $errorboxstr .= '</ul></blockquote>
2474
2475
        <p> Alternatively, you can contact us at the email address
2476
        at the bottom of the page.</p>
2477
        ';
2478
2479
        static::printErrorBox($errorboxstr);
2480
2481
        echo '
2482
        <div>
2483
        ';
2484
2485
        static::printFormHead($redirect, 'get');
2486
        echo $redirectform , '
2487
        <input type="submit" name="submit" class="submit"
2488
        value="Proceed" />
2489
        </form>
2490
        </div>
2491
        ';
2492
    }
2493
2494
    /**
2495
     * getIdphintList
2496
     *
2497
     * This function adds support for AARC-G049 "IdP Hinting". It
2498
     * searches both the GET query parameters and the OIDC client
2499
     * parameters passed to the 'authorize' endpoint for a parameter
2500
     * named either 'selected_idp' or 'idphint'. This parameter can be
2501
     * a single entityId or a comma-separated list of entityIds.
2502
     * The entries in the list are processed to remove any 'chained'
2503
     * idphints and also to transform OIDC 'issuer' values into
2504
     * CILogon-specific 'entityIds' as used in the 'Select an IdP'
2505
     * list. Any idps which are not in the current skin's 'Select
2506
     * an IdP' list are removed. The resulting processed list of
2507
     * entityIds is returned, which may be an empty array.
2508
     *
2509
     * @param array $idps (Optional) A list of valid (i.e., whitelisted) IdPs.
2510
     *        If this list is empty, then use the current skin's IdP list.
2511
     * @return array A list of entityIds / OIDC provider URLs extracted from
2512
     *         a passed-in parameter 'selected_idp' or 'idphint'. This array
2513
     *         may be empty if no such parameter was found, or if the
2514
     *         entityIds in the list were not valid.
2515
     */
2516
    public static function getIdphintList($idps = [])
2517
    {
2518
        // Check for either 'selected_idp' or 'idphint' parameter that was
2519
        // passed in via a query parameter, either for an OAuth transaction
2520
        // or just 'normally'. Note that if both 'selected_idp' and
2521
        // 'idphint' were passed, 'idphint' takes priority.
2522
2523
        $hintarray = array();
2524
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
2525
2526
        $hintstr = '';
2527
        if (!empty(@$clientparams['idphint'])) {
2528
            $hintstr = $clientparams['idphint'];
2529
        } elseif (!empty(Util::getGetVar('idphint'))) {
2530
            $hintstr = Util::getGetVar('idphint');
2531
        } elseif (!empty(@$clientparams['selected_idp'])) {
2532
            $hintstr = $clientparams['selected_idp'];
2533
        } elseif (!empty(Util::getGetVar('selected_idp'))) {
2534
            $hintstr = Util::getGetVar('selected_idp');
2535
        }
2536
2537
        if (!empty($hintstr)) {
2538
            // Split on comma to account for multiple idps
2539
            $hintarray = explode(',', $hintstr);
2540
2541
            // Process the list of IdPs to transform them appropriately.
2542
            foreach ($hintarray as &$value) {
2543
                // Check for 'chained' idp hints, and remove the GET params.
2544
                if (preg_match('%([^\?]*)\?%', $value, $matches)) {
2545
                    $value = $matches[1];
2546
                }
2547
                // Also, check for OIDC issuers and transform them into
2548
                // CILogon-specific values used in the 'Select an IdP' list.
2549
                if (preg_match('%https://accounts.google.com%', $value)) {
2550
                    $value = 'https://accounts.google.com/o/oauth2/auth';
2551
                } elseif (preg_match('%https://github.com%', $value)) {
2552
                    $value = 'https://github.com/login/oauth/authorize';
2553
                } elseif (preg_match('%https://orcid.org%', $value)) {
2554
                    $value = 'https://orcid.org/oauth/authorize';
2555
                }
2556
            }
2557
            unset($value); // Break the reference with the last element.
2558
2559
            // Remove any non-whitelisted IdPs from the hintarray.
2560
            if (empty($idps)) {
2561
                $idps = static::getCompositeIdPList();
2562
            }
2563
            foreach ($hintarray as $value) {
2564
                if (!isset($idps[$value])) {
2565
                    if (($key = array_search($value, $hintarray)) !== false) {
2566
                        unset($hintarray[$key]);
2567
                    }
2568
                }
2569
            }
2570
        }
2571
        return $hintarray;
2572
    }
2573
}
2574