Completed
Push — master ( 858192...c8ca48 )
by Terrence
28:17 queued 12:56
created

index-functions.php ➔ printOIDCConsent()   C

Complexity

Conditions 10
Paths 128

Size

Total Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
nc 128
nop 0
dl 0
loc 71
rs 6.5793
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
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
/**
16
 * printLogonPage
17
 *
18
 * This function prints out the HTML for the main cilogon.org page.
19
 * Explanatory text is shown as well as a button to log in to an IdP
20
 * and get rerouted to the Shibboleth protected getuser script.
21
 */
22
function printLogonPage()
23
{
24
    $log = new Loggit();
25
    $log->info('Welcome page hit.');
26
27
    Util::setSessionVar('stage', 'logon'); // For Show/Hide Help button clicks
28
29
    Content::printHeader(
30
        'Welcome To The CILogon OpenID Connect Authorization Service'
31
    );
32
33
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
34
35
    // If the <hideportalinfo> option is set, do not show the portal info
36
    // if the OIDC redirect_uri or client_id is in the portal list.
37
    $showportalinfo = true;
38
    $skin = Util::getSkin();
39
    if (
40
        ((int)$skin->getConfigOption('portallistaction', 'hideportalinfo') == 1) &&
41
        (
42
            ($skin->inPortalList($clientparams['redirect_uri'])) ||
43
            ($skin->inPortalList($clientparams['client_id']))
44
        )
45
    ) {
46
        $showportalinfo = false;
47
    }
48
49
    if ($showportalinfo) {
50
        printOIDCConsent();
51
    }
52
    Content::printWAYF();
53
    Content::printFooter();
54
}
55
56
/**
57
 * printOIDCErrorPage
58
 *
59
 * This function prints out the HTML for the page when the the various
60
 * OIDC parameters sent by the client are missing or bad.
61
 */
62
function printOIDCErrorPage()
63
{
64
    $log = new Loggit();
65
    $log->warn('Missing or invalid OIDC parameters.');
66
67
    Content::printHeader('CILogon Authorization Endpoint');
68
    Content::printCollapseBegin('oidcdefault', 'CILogon OIDC Authorization Endpoint', false);
69
70
    echo '
71
        <div class="card-body px-5">
72
          <div class="card-text my-2">
73
            You have reached the CILogon OAuth2/OpenID Connect (OIDC)
74
            Authorization Endpoint. This service is for use by OAuth2/OIDC
75
            Relying Parties (RPs) to authorize users of the CILogon Service.
76
            End users should not normally see this page.
77
          </div> <!-- end row -->
78
    ';
79
80
    $client_error_msg = Util::getSessionVar('client_error_msg');
81
    Util::unsetSessionVar('client_error_msg');
82
    if (strlen($client_error_msg) > 0) {
83
        echo '<div class="alert alert-danger" role="alert">', $client_error_msg, '</div>';
84
    } else {
85
        echo '
86
          <div class="card-text my-2">
87
            Possible reasons for seeing this page include:
88
          </div> <!-- end row -->
89
          <div class="card-text my-2">
90
            <ul>
91
              <li>You navigated directly to this page.</li>
92
              <li>You clicked your browser\'s "Back" button.</li>
93
              <li>There was a problem with the OpenID Connect client.</li>
94
            </ul>
95
          </div> <!-- end row -->
96
        ';
97
    }
98
99
    echo '
100
          <div class="card-text my-2">
101
            For assistance, please contact us at the email address at the
102
            bottom of the page.
103
          </div>
104
          <div class="card-text my-2">
105
            <strong>Note:</strong> You must enable cookies in your web
106
            browser to use this site.
107
          </div>
108
        </div> <!-- end card-body -->
109
    ';
110
111
    Content::printCollapseEnd();
112
    Content::printFooter();
113
}
114
115
/**
116
 * printMainPage
117
 *
118
 * This function is poorly named for the OIDC case, but is called by
119
 * gotUserSuccess, so the name stays. This function is called once the
120
 * user has successfully logged on at the selected IdP. In the OIDC
121
 * case, the user's UID is then paired with the OIDC 'code' and
122
 * 'authntime' in the datastore so that it can be fetched later when
123
 * the OIDC client wants to get userinfo or a certificate. There
124
 * really isn't anything 'printed' to the user here. Control is
125
 * simply redirected to the OIDC client with appropriate success or
126
 * error response.
127
 */
128
function printMainPage()
129
{
130
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
131
    $redirect = 'Location: ' . $clientparams['redirect_url'];
132
133
    $log = new Loggit();
134
    $log->info('Calling setTransactionState dbService method...');
135
136
    $dbs = new DBService();
137
    if (
138
        ($dbs->setTransactionState(
139
            $clientparams['code'],
140
            Util::getSessionVar('user_uid'),
141
            Util::getSessionVar('authntime'),
142
            Util::getLOA(),
143
            Util::getSessionVar('myproxyinfo')
144
        )) && (!($dbs->status & 1))
145
    ) { // STATUS_OK codes are even
146
        // CIL-360 - Check for Response Mode
147
        // http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes
148
        if (isset($clientparams['response_mode'])) {
149
            $responsemode = $clientparams['response_mode'];
150
            if ($responsemode == 'query') {
151
                // This is the default mode for 'code' response
152
            } elseif ($responsemode == 'fragment') {
153
                // Replace '?' with '#'
154
                $redirect = str_replace('?', '#', $redirect);
155
            } elseif ($responsemode == 'form_post') {
156
                // https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
157
                // At this point, $clientparams['redirect_url'] contains
158
                // both the callback uri and all query string parameters
159
                // that should be passed to the callback uri. We need
160
                // to separate the two so we can put the query parameters
161
                // into hidden <input> fields in the output form.
162
                $orig_redirect_uri = $clientparams['redirect_uri'];
163
                $full_redirect_url = $clientparams['redirect_url'];
164
                $queryparams = str_replace(
165
                    $orig_redirect_uri . '?',
166
                    '',
167
                    $full_redirect_url
168
                );
169
                Util::unsetClientSessionVars();
170
                // Util::unsetAllUserSessionVars();
171
                // Get the components of the response (split by '&')
172
                $comps = explode('&', $queryparams);
173
                $outform = '<html>
174
  <head><title>Submit This Form</title></head>
175
  <body onload="javascript:document.forms[0].submit()">
176
    <form method="post" action="' . $orig_redirect_uri . '">
177
    ';
178
                foreach ($comps as $value) {
179
                    $params = explode('=', $value);
180
                    $outform .= '<input type="hidden" name="' . $params[0] .
181
                         '" value="' . html_entity_decode($params[1]) . '"/>';
182
                }
183
                $outform .= '
184
    </form>
185
  </body>
186
</html>';
187
                $log->info(
188
                    'response_mode=form_post; outputting form' . "\n" .
189
                    $outform
190
                );
191
                echo $outform;
192
                exit; // No further processing necessary
193
            }
194
        }
195
        $log->info('setTransactionState succeeded, redirect to ' . $redirect);
196
        // CIL-507 Special log message for XSEDE
197
        $log->info('USAGE email="' . Util::getSessionVar('email') .
198
                   '" client="' . $clientparams['client_name'] . '"');
199
    } else { // dbservice error
200
        $errstr = '';
201
        if (!is_null($dbs->status)) {
202
            $errstr = array_search($dbs->status, DBService::$STATUS);
203
        }
204
        $redirect = 'Location: ' . $clientparams['redirect_uri'] .
205
            (preg_match('/\?/', $clientparams['redirect_uri']) ? '&' : '?') .
206
            'error=server_error&error_description=' .
207
            'Unable%20to%20associate%20user%20UID%20with%20OIDC%20code' .
208
            ((isset($clientparams['state'])) ?
209
                '&state=' . $clientparams['state'] : '');
210
        $log->info("setTransactionState failed $errstr, redirect to $redirect");
211
        Util::sendErrorAlert(
212
            'dbService Error',
213
            'Error calling dbservice action "setTransactionState" in ' .
214
            'OIDC authorization endpoint\'s printMainPage() method. ' .
215
            $errstr . ' Redirected to ' . $redirect
216
        );
217
        Util::unsetUserSessionVars();
218
    }
219
220
    Util::unsetClientSessionVars();
221
    // Util::unsetAllUserSessionVars();
222
    header($redirect);
223
    exit; // No further processing necessary
224
}
225
226
/**
227
 * printOIDCConsent
228
 *
229
 * This function prints out the block showing the scopes requested by the
230
 * OIDC client.
231
 */
232
function printOIDCConsent()
233
{
234
    // Look in the 'scope' OIDC parameter to see which attributes are
235
    // being requested. The values we care about are 'email', 'profile'
236
    // (for first/last name), and 'edu.uiuc.ncsa.myproxy.getcert'
237
    // (which gives a certificate containing first/last name AND email).
238
    // Anything else should just be output as-is.
239
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
240
    $scopes = preg_split("/[\s\+]+/", $clientparams['scope']);
241
    $scopes = array_unique($scopes); // Remove any duplicates
242
243
    // CIL-779 Show only those scopes which have been registered, i.e.,
244
    // compute the set intersection of requested and registered scopes.
245
    $client_scopes = json_decode($clientparams['client_scopes'], true);
246
    if (!is_null($client_scopes)) {
247
        $scopes = array_intersect($scopes, $client_scopes);
248
    }
249
250
    Content::printCollapseBegin('oidcconsent', 'Consent to Attribute Release', false);
251
252
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
253
    echo '
254
        <div class="card-body px-5">
255
          <div class="card-text my-2">
256
            <a target="_blank" href="' ,
257
            htmlspecialchars($clientparams['client_home_url']) , '">',
258
            htmlspecialchars($clientparams['client_name']) , '</a>' ,
259
            ' requests access to the following information.
260
            If you do not approve this request, do not proceed.
261
          </div> <!-- end row -->
262
          <ul>
263
    ';
264
265
    if (in_array('openid', $scopes)) {
266
        echo '<li>Your CILogon user identifier</li>';
267
        $scopes = array_diff($scopes, ['openid']);
268
    }
269
    if (
270
        (in_array('profile', $scopes)) ||
271
        (in_array('edu.uiuc.ncsa.myproxy.getcert', $scopes))
272
    ) {
273
        echo '<li>Your name</li>';
274
        $scopes = array_diff($scopes, ['profile']);
275
    }
276
    if (
277
        (in_array('email', $scopes)) ||
278
        (in_array('edu.uiuc.ncsa.myproxy.getcert', $scopes))
279
    ) {
280
        echo '<li>Your email address</li>';
281
        $scopes = array_diff($scopes, ['email']);
282
    }
283
    if (in_array('org.cilogon.userinfo', $scopes)) {
284
        echo '<li>Your username and affiliation from your identity provider</li>';
285
        $scopes = array_diff($scopes, ['org.cilogon.userinfo']);
286
    }
287
    if (in_array('edu.uiuc.ncsa.myproxy.getcert', $scopes)) {
288
        echo '<li>A certificate that allows "' ,
289
        htmlspecialchars($clientparams['client_name']) ,
290
        '" to act on your behalf</li>';
291
        $scopes = array_diff($scopes, ['edu.uiuc.ncsa.myproxy.getcert']);
292
    }
293
    // Output any remaining scopes as-is
294
    foreach ($scopes as $value) {
295
        echo '<li>', $value , '</li>';
296
    }
297
    echo '</ul>
298
        </div> <!-- end card-body -->
299
    ';
300
301
    Content::printCollapseEnd();
302
}
303
304
/**
305
 * verifyOIDCParams
306
 *
307
 * This function verifies that all of the various OIDC parameters are
308
 * set in the PHP session. First, the function checks if an OIDC
309
 * client has passed appropriate parameters to the authorization
310
 * endpoint. If so, we call the 'real' OA4MP OIDC authorization
311
 * endpoint and let it verify the client parameters. Upon successful
312
 * return, we read the database to get the OIDC client information
313
 * to display to the user. All client parameters (including the ones
314
 * passed in) are saved to the 'clientparams' PHP session variable,
315
 * which is encoded as a JSON token to preserve arrays. If there are
316
 * any errors, false is returned and an email is sent. In some cases
317
 * the session variable 'client_error_msg' is set so it can be
318
 * displayed by the printOIDCErrorPage() function.
319
 *
320
 * @return bool True if the various parameters related to the OIDC
321
 *         session are present. False otherwise.
322
 */
323
function verifyOIDCParams()
324
{
325
    $retval = false; // Assume OIDC session info is not valid
326
327
    // Combine the $_GET and $_POST arrays into a single array which can be
328
    // stored in the 'clientparams' session variable as a JSON object.
329
    $clientparams = array();
330
    foreach ($_GET as $key => $value) {
331
        $clientparams[$key] = $value;
332
    }
333
    foreach ($_POST as $key => $value) {
334
        $clientparams[$key] = $value;
335
    }
336
337
    // CIL-624 If X509 certs are disabled, check for 'getcert' scope.
338
    // If found, show an error message.
339
    $scope = Util::getGetVar('scope');
340
    if (
341
        (defined('DISABLE_X509')) &&
342
        (DISABLE_X509 === true) &&
343
        (preg_match('/edu.uiuc.ncsa.myproxy.getcert/', $scope))
344
    ) {
345
        Util::sendErrorAlert(
346
            'CILogon OIDC authz endpoint error',
347
            'The CILogon OIDC authorization endpoint received a request ' .
348
            'including the "edu.ncsa.uiuc.myproxy.getcert" scope, ' .
349
            'but the server is configured with DISABLE_X509 to prevent ' .
350
            'downloading certificates. ' .
351
            "\n\n" .
352
            'clientparams = ' . print_r($clientparams, true) .
353
            "\n"
354
        );
355
        Util::setSessionVar(
356
            'client_error_msg',
357
            'The CILogon Service is currently configured to prevent ' .
358
            'downloading X.509 certificates, but the incoming request ' .
359
            'included the "edu.ncsa.uiuc.myproxy.getcert" scope. ' .
360
            'CILogon system administrators have been notified.'
361
        );
362
        $clientparams = array();
363
364
    // If the 'redirect_uri' parameter was passed in then let the 'real'
365
    // OA4MP OIDC authz endpoint handle parse the request since it might be
366
    // possible to return an error code to the client.
367
    } elseif (isset($clientparams['redirect_uri'])) {
368
        $ch = curl_init();
369
        if ($ch !== false) {
370
            $url = OAUTH2_CREATE_TRANSACTION_URL;
371
            if (count($_GET) > 0) {
372
                // CIL-658 Look for double-encoded spaces in 'scope'
373
                if (strlen($scope) > 0) {
374
                    $_GET['scope'] = preg_replace('/\+/', ' ', $scope);
375
                }
376
                $url .= (preg_match('/\?/', $url) ? '&' : '?') .
377
                    http_build_query($_GET);
378
            }
379
            if (count($_POST) > 0) {
380
                curl_setopt($ch, CURLOPT_POST, true);
381
                curl_setopt($ch, CUROPT_POSTFIELDS, http_build_query($_POST));
382
            }
383
            curl_setopt($ch, CURLOPT_URL, $url);
384
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
385
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
386
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // Catch redirects
387
            $output = curl_exec($ch);
388
            if (curl_errno($ch)) { // Send alert on curl errors
389
                Util::sendErrorAlert(
390
                    'cUrl Error',
391
                    'cUrl Error    = ' . curl_error($ch) . "\n" .
392
                    "URL Accessed  = $url" .
393
                    "\n\n" .
394
                    'clientparams = ' . print_r($clientparams, true)
395
                );
396
                $clientparams = array();
397
            } else {
398
                $info = curl_getinfo($ch);
399
                if ($info !== false) {
400
                    if (
401
                        (isset($info['http_code'])) &&
402
                        ($info['http_code'] == 200)
403
                    ) {
404
                        // The OA4MP OIDC authz endpoint responded with 200
405
                        // (success). The body of the message should be a
406
                        // JSON token containing the appropriate parameters
407
                        // such as the 'code'.
408
                        $json = json_decode($output, true);
409
                        if (isset($json['code'])) {
410
                            // Got 'code' - save to session and read OIDC
411
                            // client info from the database to display
412
                            // to the user
413
                            $clientparams['redirect_url'] =
414
                                $clientparams['redirect_uri'] .
415
                                (preg_match('/\?/', $clientparams['redirect_uri']) ? '&' : '?') .
416
                                http_build_query($json);
417
                            $clientparams['code'] = $json['code'];
418
                            // CIL-618 Read OIDC client info from database
419
                            if (!Util::getOIDCClientParams($clientparams)) {
420
                                Util::sendErrorAlert(
421
                                    'getOIDCClientParams Error',
422
                                    'Error getting OIDC client parameters ' .
423
                                    'in verifyOIDCParams() function for ' .
424
                                    'client_id="' .
425
                                    $clientparams['client_id'] . '".'
426
                                );
427
                                $clientparams = array();
428
                            }
429
                        } else {
430
                            // Either the output returned was not a valid
431
                            // JSON token, or there was no 'code' found in
432
                            // the returned JSON token.
433
                            // CIL-575 Check for a "status=..." line in the
434
                            // returned $output to print a useful error
435
                            // message to the user (and in the error email).
436
                            $errortxt = '';
437
                            if (
438
                                preg_match(
439
                                    '/status=(\d+)/',
440
                                    $output,
441
                                    $matches
442
                                )
443
                            ) {
444
                                $errornum = $matches[1];
445
                                $errstr = array_search(
446
                                    $errornum,
447
                                    DBService::$STATUS
448
                                );
449
                                $errortxt = @DBService::$STATUS_TEXT[$errstr];
450
                            }
451
452
                            Util::sendErrorAlert(
453
                                'OA4MP OIDC authz endpoint error',
454
                                (!empty($errortxt) ? $errortxt :
455
                                'The OA4MP OIDC authorization endpoint ' .
456
                                'returned an HTTP response 200, but either ' .
457
                                'the output was not a valid JSON token, or ' .
458
                                'there was no "code" in the JSON token. ' .
459
                                ((strlen($output) > 0) ?
460
                                    "\n\nReturned output =\n$output" : '')) .
461
                                "\n\n" .
462
                                'curl_getinfo = ' . print_r($info, true) . "\n\n" .
463
                                'clientparams = ' . print_r($clientparams, true) .
464
                                "\n"
465
                            );
466
                            Util::setSessionVar(
467
                                'client_error_msg',
468
                                'There was an unrecoverable error during the transaction. ' .
469
                                'CILogon system administrators have been notified. ' .
470
                                (!empty($errortxt) ? "<p><b>Error message: $errortxt</b><p>" : '')
471
                            );
472
                            $clientparams = array();
473
                        }
474
                    } elseif (
475
                        (isset($info['http_code'])) &&
476
                        ($info['http_code'] == 302)
477
                    ) {
478
                        // The OA4MP OIDC authz endpoint responded with 302
479
                        // (redirect) which indicates an OIDC error was
480
                        // detected. We need to check the response for an
481
                        // 'error' and simply redirect error to OIDC client.
482
                        $redirect_url = '';
483
                        if (isset($info['redirect_url'])) {
484
                            $redirect_url = $info['redirect_url'];
485
                            $clientparams['redirect_url'] = $redirect_url;
486
                            // CIL-407 - In case of two question marks '?'
487
                            // in redirect_url (caused by OIDC authz endpoint
488
                            // blindly appending "?error=..."), change all
489
                            // but the first '?' to '&'.
490
                            // https://stackoverflow.com/a/37150213
491
                            if (substr_count($redirect_url, '?') > 1) {
492
                                $arr = explode('?', $redirect_url, 2);
493
                                $arr[1] = str_replace('?', '&', $arr[1]);
494
                                $redirect_url = implode('?', $arr);
495
                            }
496
                        }
497
                        // Get components of redirect_url - need 'query'
498
                        $comps = parse_url($redirect_url);
499
                        if ($comps !== false) {
500
                            // Look for 'error' in query
501
                            $query = '';
502
                            if (isset($comps['query'])) {
503
                                $query = $comps['query'];
504
                                $query = html_entity_decode($query);
505
                            }
506
                            $queries = explode('&', $query);
507
                            $params = array();
508
                            foreach ($queries as $value) {
509
                                $x = explode('=', $value);
510
                                $params[$x[0]] = $x[1];
511
                            }
512
                            if (isset($params['error'])) {
513
                                // Got 'error' - simply return to OIDC client
514
                                Util::unsetAllUserSessionVars();
515
                                header("Location: $redirect_url");
516
                                exit; // No further processing necessary
517
                            } else { // Weird params - Should never get here!
518
                                Util::sendErrorAlert(
519
                                    'OA4MP OIDC 302 Error',
520
                                    'The OA4MP OIDC authz endpoint ' .
521
                                    'returned a 302 redirect (error) ' .
522
                                    'response, but there was no "error" ' .
523
                                    "query parameter.\n\n" .
524
                                    "redirect_url = $redirect_url\n\n" .
525
                                    'clientparams = ' .
526
                                    print_r($clientparams, true) .
527
                                    "\n"
528
                                );
529
                                $clientparams = array();
530
                            }
531
                        } else { // parse_url($redirect_url) gave error
532
                            Util::sendErrorAlert(
533
                                'parse_url(redirect_url) error',
534
                                'There was an error when attempting to ' .
535
                                'parse the redirect_url. This should never ' .
536
                                "happen.\n\n" .
537
                                "redirect_url = $redirect_url\n\n" .
538
                                'clientparams = ' . print_r($clientparams, true) .
539
                                "\n"
540
                            );
541
                            $clientparams = array();
542
                        }
543
                    } else {
544
                        // An HTTP return code other than 200 (success) or
545
                        // 302 (redirect) means that the OA4MP OIDC authz
546
                        // endpoint tried to handle an unrecoverable error,
547
                        // possibly by outputting HTML. If so, then we
548
                        // ignore it and output our own error message to the
549
                        // user.
550
                        Util::sendErrorAlert(
551
                            'OA4MP OIDC authz endpoint error',
552
                            'The OA4MP OIDC authorization endpoint returned ' .
553
                            'an HTTP response other than 200 or 302. ' .
554
                            ((strlen($output) > 0) ?
555
                                "\n\nReturned output =\n$output" : '') .
556
                            "\n\n" .
557
                            'curl_getinfo = ' . print_r($info, true) . "\n\n" .
558
                            'clientparams = ' . print_r($clientparams, true) .
559
                            "\n"
560
                        );
561
                        // CIL-423 Better end-user error output for errors.
562
                        // Scan output for ServletException message.
563
                        $errstr = '';
564
                        if (
565
                            preg_match(
566
                                '/javax.servlet.ServletException:\s?(.*)/',
567
                                $output,
568
                                $matches
569
                            )
570
                        ) {
571
                            $output = '';
572
                            $errstr = '
573
                            <div>
574
                            <p>Error Message: <b>' .
575
                            $matches[1] . '</b>.</p>
576
                            <ul>
577
                            <li>Did you <b>register</b> your OAuth2/OIDC client? If not, go
578
                            <b><a target="_blank" href="https://' .
579
                            Util::getHN()
580
                            . '/oauth2/register">here</a></b> to do so.</li>
581
                            <li>Did you receive confirmation that your OAuth2/OIDC client
582
                            was <b>approved</b>? If not, please wait up to 48 hours for an
583
                            approval email from CILogon administrators.</li>
584
                            <li>Did you configure your OAuth2/OIDC client with the
585
                            registered <b>client ID and secret</b>?</li>
586
                            </ul>
587
                            </div>';
588
                        }
589
                        Util::setSessionVar(
590
                            'client_error_msg',
591
                            'There was an unrecoverable error during the transaction. ' .
592
                            'CILogon system administrators have been notified.' .
593
                            ((strlen($errstr) > 0) ? $errstr : '') .
594
                            ((strlen($output) > 0) ?
595
                            '<br/><pre>' .
596
                            preg_replace('/\+/', ' ', $output) .
597
                            '</pre>' : '')
598
                        );
599
                        $clientparams = array();
600
                    }
601
                } else { // curl_getinfo() returned false - should not happen
602
                    Util::sendErrorAlert(
603
                        'curl_getinfo error',
604
                        'When attempting to talk to the OA4MP OIDC ' .
605
                        'authorization endpoint, curl_getinfo() returned ' .
606
                        "false. This should never happen.\n\n" .
607
                        'clientparams = ' . print_r($clientparams, true) . "\n"
608
                    );
609
                    $clientparams = array();
610
                }
611
            }
612
            curl_close($ch);
613
        } else { // curl_init() returned false - should not happen
614
            Util::sendErrorAlert(
615
                'curl_init error',
616
                'When attempting to talk to the OA4MP OIDC authorization ' .
617
                'endpoint, curl_init() returned false. This should never ' .
618
                "happen.\n\n" .
619
                'clientparams = ' . print_r($clientparams, true) . "\n"
620
            );
621
            $clientparams = array();
622
        }
623
624
    // If redirect_uri was not passed in, but one of the other required OIDC
625
    // parameters WAS passed in, then assume that this was an attempt by an
626
    // OIDC client to use the authz endpoint, and display an error message
627
    // that at least one parameter (redirect_uri) was missing from the
628
    // request. Note that since we don't have a redirect_uri, we cannot
629
    // return code flow back to the OIDC client.
630
    } elseif (
631
        (isset($clientparams['scope'])) ||
632
        (isset($clientparams['response_type'])) ||
633
        (isset($clientparams['client_id']))
634
    ) {
635
        Util::sendErrorAlert(
636
            'CILogon OIDC authz endpoint error',
637
            'The CILogon OIDC authorization endpoint received a request ' .
638
            'from an OIDC client, but at least one of the required ' .
639
            'parameters (redirect_uri) was missing. ' .
640
            "\n\n" .
641
            'clientparams = ' . print_r($clientparams, true) .
642
            "\n"
643
        );
644
        Util::setSessionVar(
645
            'client_error_msg',
646
            'It appears that an OpenID Connect client attempted to ' .
647
            'initiate a session with the CILogon Service, but at least ' .
648
            'one of the requried parameters was missing. CILogon ' .
649
            'system administrators have been notified.'
650
        );
651
        $clientparams = array();
652
653
    // If none of the required OIDC authz endpoint parameters were passed
654
    // in, then this might be a later step in the authz process. So check
655
    // the session variable array 'clientparams' for the required
656
    // information.
657
    } else {
658
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
659
    }
660
661
    // Now check to verify all variables have data
662
    if (
663
        (isset($clientparams['redirect_uri'])) &&
664
        (isset($clientparams['scope'])) &&
665
        (isset($clientparams['response_type'])) &&
666
        (isset($clientparams['client_id'])) &&
667
        (isset($clientparams['code'])) &&
668
        (isset($clientparams['client_name'])) &&
669
        (isset($clientparams['client_home_url'])) &&
670
        (isset($clientparams['client_callback_uri'])) &&
671
        (isset($clientparams['client_scopes'])) & 
672
        (isset($clientparams['redirect_url'])) &&
673
        (isset($clientparams['clientstatus'])) &&
674
        (!($clientparams['clientstatus'] & 1))
675
    ) { // STATUS_OK* are even
676
        $retval = true;
677
        Util::setSessionVar('clientparams', json_encode($clientparams));
678
    }
679
680
    return $retval;
681
}
682