Completed
Push — master ( 5a053e...8eeafe )
by Terrence
10:16
created

index-functions.php ➔ printMainPage()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 98
rs 8.0436
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file contains functions called by index-site.php. The index-site.php
5
 * file should include this file with the following statement at the top:
6
 *
7
 * require_once __DIR__ . '/index-functions.php';
8
 */
9
10
use CILogon\Service\Util;
11
use CILogon\Service\Content;
12
use CILogon\Service\DBService;
13
use CILogon\Service\Loggit;
14
15
// The full URL of the 'oauth2/init' OAuth 2.0 (OIDC) script
16
define('AUTHORIZE_URL', 'http://localhost:8080/oauth2/dbService?action=createTransaction');
17
18
/**
19
 * printLogonPage
20
 *
21
 * This function prints out the HTML for the main cilogon.org page.
22
 * Explanatory text is shown as well as a button to log in to an IdP
23
 * and get rerouted to the Shibboleth protected getuser script.
24
 */
25
function printLogonPage()
26
{
27
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
28
29
    $log = new Loggit();
30
    $log->info('Welcome page hit.');
31
32
    Util::setSessionVar('stage', 'logon'); // For Show/Hide Help button clicks
33
34
    Content::printHeader(
35
        'Welcome To The CILogon OpenID Connect Authorization Service'
36
    );
37
38
    echo '
39
    <div class="boxed">
40
    ';
41
42
    // If the <hideportalinfo> option is set, do not show the portal info if
43
    // the OIDC redirect_uri or client_id is in the portal list.
44
    $showportalinfo = true;
45
    $skin = Util::getSkin();
46
    if (
47
        ((int)$skin->getConfigOption('portallistaction', 'hideportalinfo') == 1) &&
48
        (
49
            ($skin->inPortalList($clientparams['redirect_uri'])) ||
50
            ($skin->inPortalList($clientparams['client_id']))
51
        )
52
    ) {
53
        $showportalinfo = false;
54
    }
55
56
    if ($showportalinfo) {
57
        // Look in the 'scope' OIDC parameter to see which attributes are
58
        // being requested. The values we care about are 'email', 'profile'
59
        // (for first/last name), and 'edu.uiuc.ncsa.myproxy.getcert'
60
        // (which gives a certificate containing first/last name AND email).
61
        $attrs = array();
62
        $scope = $clientparams['scope'];
63
        if (preg_match('/openid/', $scope)) {
64
            $attrs['openid'] = true;
65
        }
66
        if (preg_match('/email/', $scope)) {
67
            $attrs['email'] = true;
68
        }
69
        if (preg_match('/profile/', $scope)) {
70
            $attrs['name'] = true;
71
        }
72
        if (preg_match('/org.cilogon.userinfo/', $scope)) {
73
            $attrs['cilogon'] = true;
74
        }
75
        if (preg_match('/edu.uiuc.ncsa.myproxy.getcert/', $scope)) {
76
            $attrs['email'] = true;
77
            $attrs['name'] = true;
78
            $attrs['cert'] = true;
79
        }
80
81
        echo '
82
          <br/>
83
          <p style="text-align:center"> <a target="_blank" href="' ,
84
          htmlspecialchars($clientparams['client_home_uri']) , '">',
85
          htmlspecialchars($clientparams['client_name']) , '</a>' ,
86
          ' requests access to the following information.
87
          If you do not approve this request, do not proceed.
88
          </p>
89
          ';
90
91
        echo '<ul style="max-width:660px;margin:0 auto">
92
          ';
93
        if (isset($attrs['openid'])) {
94
            echo '<li>Your CILogon username</li>';
95
        }
96
        if (isset($attrs['name'])) {
97
            echo '<li>Your name</li>';
98
        }
99
        if (isset($attrs['email'])) {
100
            echo '<li>Your email address</li>';
101
        }
102
        if (isset($attrs['cilogon'])) {
103
            echo '<li>Your username and affiliation from your identity provider</li>';
104
        }
105
        if (isset($attrs['cert'])) {
106
            echo '<li>A certificate that allows "' ,
107
            htmlspecialchars($clientparams['client_name']) ,
108
            '" to act on your behalf</li>';
109
        }
110
        echo '</ul>
111
        ';
112
    }
113
114
    Content::printWAYF(true, false);
115
116
    echo '
117
    </div> <!-- End boxed -->
118
    ';
119
120
    Content::printFooter();
121
}
122
123
/**
124
 * printOIDCErrorPage
125
 *
126
 * This function prints out the HTML for the page when the the various
127
 * OIDC parameters sent by the client are missing or bad.
128
 */
129
function printOIDCErrorPage()
130
{
131
    $log = new Loggit();
132
    $log->warn('Missing or invalid OIDC parameters.');
133
134
    Content::printHeader('CILogon Authorization Endpoint');
135
136
    echo '
137
    <div class="boxed">
138
      <br class="clear"/>
139
      <p>
140
      You have reached the CILogon OAuth2/OpenID Connect (OIDC) Authorization 
141
      Endpoint. This service is for use by OAuth2/OIDC Relying Parties (RPs)
142
      to authorize users of the CILogon Service. End users should not normally
143
      see this page.
144
      </p>
145
    ';
146
147
    $client_error_msg = Util::getSessionVar('client_error_msg');
148
    Util::unsetSessionVar('client_error_msg');
149
    if (strlen($client_error_msg) > 0) {
150
        echo "<p>$client_error_msg</p>";
151
    } else {
152
        echo '
153
          <p>
154
          Possible reasons for seeing this page include:
155
          </p>
156
          <ul>
157
          <li>You navigated directly to this page.</li>
158
          <li>You clicked your browser\'s "Back" button.</li>
159
          <li>There was a problem with the OpenID Connect client.</li>
160
          </ul>
161
        ';
162
    }
163
164
    echo '
165
      <p>
166
      For assistance, please contact us at the email address at the
167
      bottom of the page.
168
      </p>
169
      <p>
170
      <strong>Note:</strong> You must enable cookies in your web browser to
171
      use this site.
172
      </p>
173
    </div>
174
    ';
175
176
    Content::printFooter();
177
}
178
179
/**
180
 * printMainPage
181
 *
182
 * This function is poorly named for the OIDC case, but is called by
183
 * gotUserSucces, so the name stays. This function is called once the
184
 * user has successfully logged on at the selected IdP. In the OIDC
185
 * case, the user's UID is then paired with the OIDC 'code' and
186
 * 'authntime' in the datastore so that it can be fetched later when
187
 * the OIDC client wants to get userinfo or a certificate. There
188
 * really isn't anything 'printed' to the user here. Control is
189
 * simply redirected to the OIDC client with appropriate success or
190
 * error response.
191
 */
192
function printMainPage()
193
{
194
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
195
    $redirect = '';
0 ignored issues
show
Unused Code introduced by
$redirect is not used, you could remove the assignment.

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

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

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

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

Loading history...
196
197
    $log = new Loggit();
198
    $log->info('Calling setTransactionState dbService method...');
199
200
    $dbs = new DBService();
201
    if (
202
        ($dbs->setTransactionState(
203
            $clientparams['code'],
204
            Util::getSessionVar('uid'),
205
            Util::getSessionVar('authntime'),
206
            Util::getSessionVar('loa'),
207
            Util::getSessionVar('myproxyinfo')
208
        )) && (!($dbs->status & 1))
209
    ) { // STATUS_OK codes are even
210
        $redirect = 'Location: ' . $clientparams['redirect_url'];
211
        // CIL-360 - Check for Response Mode
212
        // http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
213
        if (isset($clientparams['response_mode'])) {
214
            $responsemode = $clientparams['response_mode'];
215
            if ($responsemode == 'query') {
216
                // This is the default mode for 'code' response
217
            } elseif ($responsemode == 'fragment') {
218
                // Replace '?' with '#'
219
                $redirect = str_replace('?', '#', $redirect);
220
            } elseif ($responsemode == 'form_post') {
221
                // https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
222
                // At this point, $clientparams['redirect_url'] contains
223
                // both the callback uri and all query string parameters
224
                // that should be passed to the callback uri. We need
225
                // to separate the two so we can put the query parameters
226
                // into hidden <input> fields in the output form.
227
                $orig_redirect_uri = $clientparams['redirect_uri'];
228
                $full_redirect_url = $clientparams['redirect_url'];
229
                $queryparams = str_replace(
230
                    $orig_redirect_uri . '?',
231
                    '',
232
                    $full_redirect_url
233
                );
234
                Util::unsetClientSessionVars();
235
                // Util::unsetAllUserSessionVars();
236
                // Get the components of the response (split by '&')
237
                $comps = explode('&', $queryparams);
238
                $outform = '<html>
239
  <head><title>Submit This Form</title></head>
240
  <body onload="javascript:document.forms[0].submit()">
241
    <form method="post" action="' . $orig_redirect_uri . '">
242
    ';
243
                foreach ($comps as $value) {
244
                    $params = explode('=', $value);
245
                    $outform .= '<input type="hidden" name="' . $params[0] .
246
                         '" value="' . html_entity_decode($params[1]) . '"/>';
247
                }
248
                $outform .= '
249
    </form>
250
  </body>
251
</html>';
252
                $log->info(
253
                    'response_mode=form_post; outputting form' . "\n" .
254
                    $outform
255
                );
256
                echo $outform;
257
                exit; // No further processing necessary
258
            }
259
        }
260
        $log->info('setTransactionState succeeded, redirect to ' . $redirect);
261
        // CIL-507 Special log message for XSEDE
262
        $log->info('USAGE email="' . Util::getSessionVar('emailaddr') .
263
                   '" client="' . $clientparams['client_name'] . '"');
264
    } else { // dbservice error
265
        $errstr = '';
266
        if (!is_null($dbs->status)) {
267
            $errstr = array_search($dbs->status, DBService::$STATUS);
268
        }
269
        $redirect = 'Location: ' . $clientparams['redirect_uri'] .
270
            (preg_match('/\?/', $clientparams['redirect_uri']) ? '&' : '?') .
271
            'error=server_error&error_description=' .
272
            'Unable%20to%20associate%20user%20UID%20with%20OIDC%20code' .
273
            ((isset($clientparams['state'])) ?
274
                '&state=' . $clientparams['state'] : '');
275
        $log->info("setTransactionState failed $errstr, redirect to $redirect");
276
        Util::sendErrorAlert(
277
            'dbService Error',
278
            'Error calling dbservice action "setTransactionState" in ' .
279
            'OIDC authorization endpoint\'s printMainPage() method. ' .
280
            $errstr . ' Redirected to ' . $redirect
281
        );
282
        Util::unsetUserSessionVars();
283
    }
284
285
    Util::unsetClientSessionVars();
286
    // Util::unsetAllUserSessionVars();
287
    header($redirect);
288
    exit; // No further processing necessary
289
}
290
291
/**
292
 * printPortalInfo
293
 *
294
 * This function prints out the portal information table at the top of
295
 * of the page.  The optional parameter $suffix allows you to append
296
 * a number (for example) to differentiate the portalinfo table on the
297
 * log in page from the one on the main page.
298
 *
299
 * @param string $suffix An optional suffix to append to the 'portalinfo'
300
 *        table class name.
301
 */
302
function printPortalInfo($suffix = '')
303
{
304
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
305
    $showhelp = Util::getSessionVar('showhelp');
306
    $helptext = "The Client Name is provided by the site to CILogon and has not been vetted.";
307
308
    echo '
309
    <table class="portalinfo' , $suffix , '">
310
    <tr class="inforow">
311
      <th title="' , $helptext ,'">Client&nbsp;Name:</th>
312
      <td title="' , $helptext ,'">' ,
313
      htmlspecialchars($clientparams['client_name']) , '</td>
314
    ';
315
316
    if ($showhelp == 'on') {
317
        echo ' <td class="helpcell">' , $helptext , '</td>';
318
    }
319
320
    $helptext = "The Client Home is the home page of the client and is provided for your information.";
321
322
    echo '
323
    </tr>
324
    <tr class="inforow">
325
      <th title="' , $helptext , '">Client&nbsp;Home:</th>
326
      <td title="' , $helptext , '">' ,
327
          htmlspecialchars($clientparams['client_home_uri']) , '</td>
328
    ';
329
330
    if ($showhelp == 'on') {
331
        echo '<td class="helpcell">' , $helptext , '</td>';
332
    }
333
334
    $helptext = "The Redirect URL is the location to which CILogon will send OpenID Connect response messages.";
335
336
    echo '
337
    </tr>
338
    <tr class="inforow">
339
      <th title="' , $helptext , '">Redirect&nbsp;URL:</th>
340
      <td title="' , $helptext , '">' ,
341
          htmlspecialchars($clientparams['redirect_uri']) , '</td>
342
      ';
343
344
    if ($showhelp == 'on') {
345
        echo '<td class="helpcell">' , $helptext , '</td>';
346
    }
347
348
    echo '
349
    </tr>
350
    </table>
351
    ';
352
}
353
354
/**
355
 * verifyOIDCParams
356
 *
357
 * This function verifies that all of the various OIDC parameters are
358
 * set in the PHP session. First, the function checks if an OIDC
359
 * client has passed appropriate parameters to the authorization
360
 * endpoint. If so, we call the 'real' OA4MP OIDC authorization
361
 * endpoint and let it verify the client parameters. Upon successful
362
 * return, we call the getClient() function of the dbService to get
363
 * the OIDC client name and homepage for display to the user. All
364
 * client parameters (including the ones passed in) are saved to the
365
 * 'clientparams' PHP session variable, which is encoded as a JSON
366
 * token to preserve arrays. If there are any errors, false is returned
367
 * and an email is sent. In some cases the session variable
368
 * 'client_error_msg' is set so it can be displayed by the
369
 * printOIDCErrorPage() function.
370
 *
371
 * @return bool True if the various parameters related to the OIDC
372
 *         session are present. False otherwise.
373
 */
374
function verifyOIDCParams()
375
{
376
    $retval = false; // Assume OIDC session info is not valid
377
378
    // Combine the $_GET and $_POST arrays into a single array which can be
379
    // stored in the 'clientparams' session variable as a JSON object.
380
    $clientparams = array();
381
    foreach ($_GET as $key => $value) {
382
        $clientparams[$key] = $value;
383
    }
384
    foreach ($_POST as $key => $value) {
385
        $clientparams[$key] = $value;
386
    }
387
388
    // If the 'redirect_uri' parameter was passed in then let the 'real'
389
    // OA4MP OIDC authz endpoint handle parse the request since it might be
390
    // possible to return an error code to the client.
391
    if (isset($clientparams['redirect_uri'])) {
392
        $ch = curl_init();
393
        if ($ch !== false) {
394
            $url = AUTHORIZE_URL;
395
            if (count($_GET) > 0) {
396
                $url .= (preg_match('/\?/', AUTHORIZE_URL) ? '&' : '?') .
397
                    http_build_query($_GET);
398
            }
399
            if (count($_POST) > 0) {
400
                curl_setopt($ch, CURLOPT_POST, true);
401
                curl_setopt($ch, CUROPT_POSTFIELDS, http_build_query($_POST));
402
            }
403
            curl_setopt($ch, CURLOPT_URL, $url);
404
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
405
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
406
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // Catch redirects
407
            $output = curl_exec($ch);
408
            if (curl_errno($ch)) { // Send alert on curl errors
409
                Util::sendErrorAlert(
410
                    'cUrl Error',
411
                    'cUrl Error    = ' . curl_error($ch) . "\n" .
412
                    "URL Accessed  = $url" .
413
                    "\n\n" .
414
                    'clientparams = ' . print_r($clientparams, true)
415
                );
416
                $clientparams = array();
417
            } else {
418
                $info = curl_getinfo($ch);
419
                if ($info !== false) {
420
                    if (
421
                        (isset($info['http_code'])) &&
422
                        ($info['http_code'] == 200)
423
                    ) {
424
                        // The OA4MP OIDC authz endpoint responded with 200
425
                        // (success). The body of the message should be a
426
                        // JSON token containing the appropriate parameters
427
                        // such as the 'code'.
428
                        $json = json_decode($output, true);
429
                        if (isset($json['code'])) {
430
                            // Got 'code' - save to session and call
431
                            // dbService 'getClient' to get info about
432
                            // OIDC client to display to user
433
                            $clientparams['redirect_url'] =
434
                                $clientparams['redirect_uri'] .
435
                                (preg_match('/\?/', $clientparams['redirect_uri']) ? '&' : '?') .
436
                                http_build_query($json);
437
                            $clientparams['code'] = $json['code'];
438
                            $dbs = new DBService();
439
                            if (
440
                                ($dbs->getClient(
441
                                    $clientparams['client_id']
442
                                )) && (!($dbs->status & 1))
443
                            ) {
444
                                // STATUS_OK is even
445
                                $status = $dbs->status;
446
                                $clientparams['clientstatus'] = $status;
447
                                // STATUS_OK* codes are even-numbered
448
                                if (!($status & 1)) {
449
                                    $clientparams['client_name'] =
450
                                        $dbs->client_name;
451
                                    $clientparams['client_home_uri'] =
452
                                        $dbs->client_home_uri;
453
                                    $clientparams['client_callback_uris'] =
454
                                        $dbs->client_callback_uris;
455
                                } else { // dbservice error
456
                                    $errstr = 'Unknown error.';
457
                                    if (!is_null($dbs->status)) {
458
                                        $errstr = array_search(
459
                                            $dbs->status,
460
                                            DBService::$STATUS
461
                                        );
462
                                    }
463
                                    Util::sendErrorAlert(
464
                                        'dbService Error',
465
                                        'Error calling dbservice ' .
466
                                        'action "getClient" in ' .
467
                                        'verifyOIDCParams() method. ' .
468
                                        $errstr
469
                                    );
470
                                    $clientparams = array();
471
                                }
472
                            } else {
473
                                Util::sendErrorAlert(
474
                                    'dbService Error',
475
                                    'Error calling dbservice ' .
476
                                    'action "getClient" in ' .
477
                                    'verifyOIDCParams() method.'
478
                                );
479
                                $clientparams = array();
480
                            }
481
                        } else {
482
                            // Either the output returned was not a valid
483
                            // JSON token, or there was no 'code' found in
484
                            // the returned JSON token.
485
                            // CIL-575 Check for a "status=..." line in the
486
                            // returned $output to print a useful error
487
                            // message to the user (and in the error email).
488
                            $errortxt = '';
489
                            if (
490
                                preg_match(
491
                                    '/status=(\d+)/',
492
                                    $output,
493
                                    $matches
494
                                )
495
                            ) {
496
                                $errornum = $matches[1];
497
                                $errstr = array_search(
498
                                    $errornum,
499
                                    DBService::$STATUS
500
                                );
501
                                $errortxt = @DBService::$STATUS_TEXT[$errstr];
502
                            }
503
504
                            Util::sendErrorAlert(
505
                                'OA4MP OIDC authz endpoint error',
506
                                (!empty($errortxt) ? $errortxt :
507
                                'The OA4MP OIDC authorization endpoint ' .
508
                                'returned an HTTP response 200, but either ' .
509
                                'the output was not a valid JSON token, or ' .
510
                                'there was no "code" in the JSON token. ' .
511
                                ((strlen($output) > 0) ?
512
                                    "\n\nReturned output =\n$output" : '')) .
513
                                "\n\n" .
514
                                'curl_getinfo = ' . print_r($info, true) . "\n\n" .
515
                                'clientparams = ' . print_r($clientparams, true) .
516
                                "\n"
517
                            );
518
                            Util::setSessionVar(
519
                                'client_error_msg',
520
                                'There was an unrecoverable error during the transaction. ' .
521
                                'CILogon system administrators have been notified. ' .
522
                                (!empty($errortxt) ? "<p><b>Error message: $errortxt</b><p>" : '')
523
                            );
524
                            $clientparams = array();
525
                        }
526
                    } elseif (
527
                        (isset($info['http_code'])) &&
528
                        ($info['http_code'] == 302)
529
                    ) {
530
                        // The OA4MP OIDC authz endpoint responded with 302
531
                        // (redirect) which indicates an OIDC error was
532
                        // detected. We need to check the response for an
533
                        // 'error' and simply redirect error to OIDC client.
534
                        $redirect_url = '';
535
                        if (isset($info['redirect_url'])) {
536
                            $redirect_url = $info['redirect_url'];
537
                            $clientparmas['redirect_url'] = $redirect_url;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$clientparmas was never initialized. Although not strictly required by PHP, it is generally a good practice to add $clientparmas = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
538
                            // CIL-407 - In case of two question marks '?'
539
                            // in redirect_url (caused by OIDC authz endpoint
540
                            // blindly appending "?error=..."), change all
541
                            // but the first '?' to '&'.
542
                            // https://stackoverflow.com/a/37150213
543
                            if (substr_count($redirect_url, '?') > 1) {
544
                                $arr = explode('?', $redirect_url, 2);
545
                                $arr[1] = str_replace('?', '&', $arr[1]);
546
                                $redirect_url = implode('?', $arr);
547
                            }
548
                        }
549
                        // Get components of redirect_url - need 'query'
550
                        $comps = parse_url($redirect_url);
551
                        if ($comps !== false) {
552
                            // Look for 'error' in query
553
                            $query = '';
554
                            if (isset($comps['query'])) {
555
                                $query = $comps['query'];
556
                                $query = html_entity_decode($query);
557
                            }
558
                            $queries = explode('&', $query);
559
                            $params = array();
560
                            foreach ($queries as $value) {
561
                                $x = explode('=', $value);
562
                                $params[$x[0]] = $x[1];
563
                            }
564
                            if (isset($params['error'])) {
565
                                // Got 'error' - simply return to OIDC client
566
                                $clientparams = array();
0 ignored issues
show
Unused Code introduced by
$clientparams is not used, you could remove the assignment.

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

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

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

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

Loading history...
567
                                Util::unsetAllUserSessionVars();
568
                                header("Location: $redirect_url");
569
                                exit; // No further processing necessary
570
                            } else { // Weird params - Should never get here!
571
                                Util::sendErrorAlert(
572
                                    'OA4MP OIDC 302 Error',
573
                                    'The OA4MP OIDC authz endpoint ' .
574
                                    'returned a 302 redirect (error) ' .
575
                                    'response, but there was no "error" ' .
576
                                    "query parameter.\n\n" .
577
                                    "redirect_url = $redirect_url\n\n" .
578
                                    'clientparams = ' .
579
                                    print_r($clientparams, true) .
580
                                    "\n"
581
                                );
582
                                $clientparams = array();
583
                            }
584
                        } else { // parse_url($redirect_url) gave error
585
                            Util::sendErrorAlert(
586
                                'parse_url(redirect_url) error',
587
                                'There was an error when attempting to ' .
588
                                'parse the redirect_url. This should never ' .
589
                                "happen.\n\n" .
590
                                "redirect_url = $redirect_url\n\n" .
591
                                'clientparams = ' . print_r($clientparams, true) .
592
                                "\n"
593
                            );
594
                            $clientparams = array();
595
                        }
596
                    } else {
597
                        // An HTTP return code other than 200 (success) or
598
                        // 302 (redirect) means that the OA4MP OIDC authz
599
                        // endpoint tried to handle an unrecoverable error,
600
                        // possibly by outputting HTML. If so, then we
601
                        // ignore it and output our own error message to the
602
                        // user.
603
                        Util::sendErrorAlert(
604
                            'OA4MP OIDC authz endpoint error',
605
                            'The OA4MP OIDC authorization endpoint returned ' .
606
                            'an HTTP response other than 200 or 302. ' .
607
                            ((strlen($output) > 0) ?
608
                                "\n\nReturned output =\n$output" : '') .
609
                            "\n\n" .
610
                            'curl_getinfo = ' . print_r($info, true) . "\n\n" .
611
                            'clientparams = ' . print_r($clientparams, true) .
612
                            "\n"
613
                        );
614
                        // CIL-423 Better end-user error output for errors.
615
                        // Scan output for ServletException message.
616
                        $errstr = '';
617
                        if (
618
                            preg_match(
619
                                '/javax.servlet.ServletException:\s?(.*)/',
620
                                $output,
621
                                $matches
622
                            )
623
                        ) {
624
                            $output = '';
625
                            $errstr = '
626
                            <div>
627
                            <p>Error Message: <b>' .
628
                            $matches[1] . '</b>.</p>
629
                            <ul>
630
                            <li>Did you <b>register</b> your OAuth2/OIDC client? If not, go
631
                            <b><a target="_blank" href="https://' .
632
                            Util::getHN()
633
                            . '/oauth2/register">here</a></b> to do so.</li>
634
                            <li>Did you receive confirmation that your OAuth2/OIDC client
635
                            was <b>approved</b>? If not, please wait up to 48 hours for an
636
                            approval email from CILogon administrators.</li>
637
                            <li>Did you configure your OAuth2/OIDC client with the
638
                            registered <b>client ID and secret</b>?</li>
639
                            </ul>
640
                            </div>';
641
                        }
642
                        Util::setSessionVar(
643
                            'client_error_msg',
644
                            'There was an unrecoverable error during the transaction. ' .
645
                            'CILogon system administrators have been notified.' .
646
                            ((strlen($errstr) > 0) ? $errstr : '') .
647
                            ((strlen($output) > 0) ?
648
                            '<br/><pre>' .
649
                            preg_replace('/\+/', ' ', $output) .
650
                            '</pre>' : '')
651
                        );
652
                        $clientparams = array();
653
                    }
654
                } else { // curl_getinfo() returned false - should not happen
655
                    Util::sendErrorAlert(
656
                        'curl_getinfo error',
657
                        'When attempting to talk to the OA4MP OIDC ' .
658
                        'authorization endpoint, curl_getinfo() returned ' .
659
                        "false. This should never happen.\n\n" .
660
                        'clientparams = ' . print_r($clientparams, true) . "\n"
661
                    );
662
                    $clientparams = array();
663
                }
664
            }
665
            curl_close($ch);
666
        } else { // curl_init() returned false - should not happen
667
            Util::sendErrorAlert(
668
                'curl_init error',
669
                'When attempting to talk to the OA4MP OIDC authorization ' .
670
                'endpoint, curl_init() returned false. This should never ' .
671
                "happen.\n\n" .
672
                'clientparams = ' . print_r($clientparams, true) . "\n"
673
            );
674
            $clientparams = array();
675
        }
676
677
    // If redirect_uri was not passed in, but one of the other required OIDC
678
    // parameters WAS passed in, then assume that this was an attempt by an
679
    // OIDC client to use the authz endpoint, and display an error message
680
    // that at least one parameter (redirect_uri) was missing from the
681
    // request. Note that since we don't have a redirect_uri, we cannot
682
    // return code flow back to the OIDC client.
683
    } elseif (
684
        (isset($clientparams['scope'])) ||
685
        (isset($clientparams['response_type'])) ||
686
        (isset($clientparams['client_id']))
687
    ) {
688
        Util::sendErrorAlert(
689
            'CILogon OIDC authz endpoint error',
690
            'The CILogon OIDC authorization endpoint received a request ' .
691
            'from an OIDC client, but at least one of the required ' .
692
            'parameters (redirect_uri) was missing. ' .
693
            "\n\n" .
694
            'clientparams = ' . print_r($clientparams, true) .
695
            "\n"
696
        );
697
        Util::setSessionVar(
698
            'client_error_msg',
699
            'It appears that an OpenID Connect client attempted to ' .
700
            'initiate a session with the CILogon Service, but at least ' .
701
            'one of the requried parameters was missing. CILogon ' .
702
            'system administrators have been notified.'
703
        );
704
        $clientparams = array();
705
706
    // If none of the required OIDC authz endpoint parameters were passed
707
    // in, then this might be a later step in the authz process. So check
708
    // the session variable array 'clientparams' for the required
709
    // information.
710
    } else {
711
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
712
    }
713
714
    // Now check to verify all variables have data
715
    if (
716
        (isset($clientparams['redirect_uri'])) &&
717
        (isset($clientparams['scope'])) &&
718
        (isset($clientparams['response_type'])) &&
719
        (isset($clientparams['client_id'])) &&
720
        (isset($clientparams['code'])) &&
721
        (isset($clientparams['client_name'])) &&
722
        (isset($clientparams['client_home_uri'])) &&
723
        (isset($clientparams['client_callback_uris'])) &&
724
        (isset($clientparams['redirect_url'])) &&
725
        (isset($clientparams['clientstatus'])) &&
726
        (!($clientparams['clientstatus'] & 1))
727
    ) { // STATUS_OK* are even
728
        $retval = true;
729
        Util::setSessionVar('clientparams', json_encode($clientparams));
730
    }
731
732
    return $retval;
733
}
734