Completed
Push — master ( 0db328...7ae14e )
by Terrence
21:23 queued 06:24
created

index-functions.php ➔ printOIDCErrorPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 52
rs 9.0472
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
/**
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);
0 ignored issues
show
Bug introduced by
The method printCollapseBegin() does not seem to exist on object<CILogon\Service\Content>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
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();
0 ignored issues
show
Bug introduced by
The method printCollapseEnd() does not seem to exist on object<CILogon\Service\Content>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
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(),
0 ignored issues
show
Bug introduced by
The method getLOA() does not seem to exist on object<CILogon\Service\Util>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
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
    Content::printCollapseBegin('oidcconsent', 'Consent to Attribute Release', false);
0 ignored issues
show
Bug introduced by
The method printCollapseBegin() does not seem to exist on object<CILogon\Service\Content>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
244
245
    $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
246
    echo '
247
        <div class="card-body px-5">
248
          <div class="card-text my-2">
249
            <a target="_blank" href="' ,
250
            htmlspecialchars($clientparams['client_home_url']) , '">',
251
            htmlspecialchars($clientparams['client_name']) , '</a>' ,
252
            ' requests access to the following information.
253
            If you do not approve this request, do not proceed.
254
          </div> <!-- end row -->
255
          <ul>
256
    ';
257
258
    if (in_array('openid', $scopes)) {
259
        echo '<li>Your CILogon user identifier</li>';
260
        $scopes = array_diff($scopes, ['openid']);
261
    }
262
    if (
263
        (in_array('profile', $scopes)) ||
264
        (in_array('edu.uiuc.ncsa.myproxy.getcert', $scopes))
265
    ) {
266
        echo '<li>Your name</li>';
267
        $scopes = array_diff($scopes, ['profile']);
268
    }
269
    if (
270
        (in_array('email', $scopes)) ||
271
        (in_array('edu.uiuc.ncsa.myproxy.getcert', $scopes))
272
    ) {
273
        echo '<li>Your email address</li>';
274
        $scopes = array_diff($scopes, ['email']);
275
    }
276
    if (in_array('org.cilogon.userinfo', $scopes)) {
277
        echo '<li>Your username and affiliation from your identity provider</li>';
278
        $scopes = array_diff($scopes, ['org.cilogon.userinfo']);
279
    }
280
    if (in_array('edu.uiuc.ncsa.myproxy.getcert', $scopes)) {
281
        echo '<li>A certificate that allows "' ,
282
        htmlspecialchars($clientparams['client_name']) ,
283
        '" to act on your behalf</li>';
284
        $scopes = array_diff($scopes, ['edu.uiuc.ncsa.myproxy.getcert']);
285
    }
286
    // Output any remaining scopes as-is
287
    foreach ($scopes as $value) {
288
        echo '<li>', $value , '</li>';
289
    }
290
    echo '</ul>
291
        </div> <!-- end card-body -->
292
    ';
293
294
    Content::printCollapseEnd();
0 ignored issues
show
Bug introduced by
The method printCollapseEnd() does not seem to exist on object<CILogon\Service\Content>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
295
}
296
297
/**
298
 * verifyOIDCParams
299
 *
300
 * This function verifies that all of the various OIDC parameters are
301
 * set in the PHP session. First, the function checks if an OIDC
302
 * client has passed appropriate parameters to the authorization
303
 * endpoint. If so, we call the 'real' OA4MP OIDC authorization
304
 * endpoint and let it verify the client parameters. Upon successful
305
 * return, we call the getClient() function of the dbService to get
306
 * the OIDC client name and homepage for display to the user. All
307
 * client parameters (including the ones passed in) are saved to the
308
 * 'clientparams' PHP session variable, which is encoded as a JSON
309
 * token to preserve arrays. If there are any errors, false is returned
310
 * and an email is sent. In some cases the session variable
311
 * 'client_error_msg' is set so it can be displayed by the
312
 * printOIDCErrorPage() function.
313
 *
314
 * @return bool True if the various parameters related to the OIDC
315
 *         session are present. False otherwise.
316
 */
317
function verifyOIDCParams()
318
{
319
    $retval = false; // Assume OIDC session info is not valid
320
321
    // Combine the $_GET and $_POST arrays into a single array which can be
322
    // stored in the 'clientparams' session variable as a JSON object.
323
    $clientparams = array();
324
    foreach ($_GET as $key => $value) {
325
        $clientparams[$key] = $value;
326
    }
327
    foreach ($_POST as $key => $value) {
328
        $clientparams[$key] = $value;
329
    }
330
331
    // CIL-624 If X509 certs are disabled, check for 'getcert' scope.
332
    // If found, show an error message.
333
    $scope = getGetVar('scope');
334
    if (
335
        (defined('DISABLE_X509')) &&
336
        (DISABLE_X509 === true) &&
337
        (preg_match('/edu\.ncsa\.uiuc\.myproxy\.getcert/', $scope))
338
    ) {
339
        Util::sendErrorAlert(
340
            'CILogon OIDC authz endpoint error',
341
            'The CILogon OIDC authorization endpoint received a request ' .
342
            'including the "edu.ncsa.uiuc.myproxy.getcert" scope, ' .
343
            'but the server is configured with DISABLE_X509 to prevent ' .
344
            'downloading certificates. ' .
345
            "\n\n" .
346
            'clientparams = ' . print_r($clientparams, true) .
347
            "\n"
348
        );
349
        Util::setSessionVar(
350
            'client_error_msg',
351
            'The CILogon Service is currently configured to prevent ' .
352
            'downloading X.509 certificates, but the incoming request ' .
353
            'included the "edu.ncsa.uiuc.myproxy.getcert" scope. ' .
354
            'CILogon system administrators have been notified.'
355
        );
356
        $clientparams = array();
357
358
    // If the 'redirect_uri' parameter was passed in then let the 'real'
359
    // OA4MP OIDC authz endpoint handle parse the request since it might be
360
    // possible to return an error code to the client.
361
    } elseif (isset($clientparams['redirect_uri'])) {
362
        $ch = curl_init();
363
        if ($ch !== false) {
364
            $url = OAUTH2_CREATE_TRANSACTION_URL;
365
            if (count($_GET) > 0) {
366
                // CIL-658 Look for double-encoded spaces in 'scope'
367
                if (strlen($scope) > 0) {
368
                    $_GET['scope'] = preg_replace('/\+/', ' ', $scope);
369
                }
370
                $url .= (preg_match('/\?/', $url) ? '&' : '?') .
371
                    http_build_query($_GET);
372
            }
373
            if (count($_POST) > 0) {
374
                curl_setopt($ch, CURLOPT_POST, true);
375
                curl_setopt($ch, CUROPT_POSTFIELDS, http_build_query($_POST));
376
            }
377
            curl_setopt($ch, CURLOPT_URL, $url);
378
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
379
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
380
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); // Catch redirects
381
            $output = curl_exec($ch);
382
            if (curl_errno($ch)) { // Send alert on curl errors
383
                Util::sendErrorAlert(
384
                    'cUrl Error',
385
                    'cUrl Error    = ' . curl_error($ch) . "\n" .
386
                    "URL Accessed  = $url" .
387
                    "\n\n" .
388
                    'clientparams = ' . print_r($clientparams, true)
389
                );
390
                $clientparams = array();
391
            } else {
392
                $info = curl_getinfo($ch);
393
                if ($info !== false) {
394
                    if (
395
                        (isset($info['http_code'])) &&
396
                        ($info['http_code'] == 200)
397
                    ) {
398
                        // The OA4MP OIDC authz endpoint responded with 200
399
                        // (success). The body of the message should be a
400
                        // JSON token containing the appropriate parameters
401
                        // such as the 'code'.
402
                        $json = json_decode($output, true);
403
                        if (isset($json['code'])) {
404
                            // Got 'code' - save to session and call
405
                            // dbService 'getClient' to get info about
406
                            // OIDC client to display to user
407
                            $clientparams['redirect_url'] =
408
                                $clientparams['redirect_uri'] .
409
                                (preg_match('/\?/', $clientparams['redirect_uri']) ? '&' : '?') .
410
                                http_build_query($json);
411
                            $clientparams['code'] = $json['code'];
412
                            // CIL-618 Read OIDC client info from database
413
                            if (!Util::getOIDCClientParams($clientparams)) {
0 ignored issues
show
Bug introduced by
The method getOIDCClientParams() does not seem to exist on object<CILogon\Service\Util>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
414
                                Util::sendErrorAlert(
415
                                    'getOIDCClientParams Error',
416
                                    'Error getting OIDC client parameters ' .
417
                                    'in verifyOIDCParams() function for ' .
418
                                    'client_id="' .
419
                                    $clientparams['client_id'] . '".'
420
                                );
421
                                $clientparams = array();
422
                            }
423
                        } else {
424
                            // Either the output returned was not a valid
425
                            // JSON token, or there was no 'code' found in
426
                            // the returned JSON token.
427
                            // CIL-575 Check for a "status=..." line in the
428
                            // returned $output to print a useful error
429
                            // message to the user (and in the error email).
430
                            $errortxt = '';
431
                            if (
432
                                preg_match(
433
                                    '/status=(\d+)/',
434
                                    $output,
435
                                    $matches
436
                                )
437
                            ) {
438
                                $errornum = $matches[1];
439
                                $errstr = array_search(
440
                                    $errornum,
441
                                    DBService::$STATUS
442
                                );
443
                                $errortxt = @DBService::$STATUS_TEXT[$errstr];
444
                            }
445
446
                            Util::sendErrorAlert(
447
                                'OA4MP OIDC authz endpoint error',
448
                                (!empty($errortxt) ? $errortxt :
449
                                'The OA4MP OIDC authorization endpoint ' .
450
                                'returned an HTTP response 200, but either ' .
451
                                'the output was not a valid JSON token, or ' .
452
                                'there was no "code" in the JSON token. ' .
453
                                ((strlen($output) > 0) ?
454
                                    "\n\nReturned output =\n$output" : '')) .
455
                                "\n\n" .
456
                                'curl_getinfo = ' . print_r($info, true) . "\n\n" .
457
                                'clientparams = ' . print_r($clientparams, true) .
458
                                "\n"
459
                            );
460
                            Util::setSessionVar(
461
                                'client_error_msg',
462
                                'There was an unrecoverable error during the transaction. ' .
463
                                'CILogon system administrators have been notified. ' .
464
                                (!empty($errortxt) ? "<p><b>Error message: $errortxt</b><p>" : '')
465
                            );
466
                            $clientparams = array();
467
                        }
468
                    } elseif (
469
                        (isset($info['http_code'])) &&
470
                        ($info['http_code'] == 302)
471
                    ) {
472
                        // The OA4MP OIDC authz endpoint responded with 302
473
                        // (redirect) which indicates an OIDC error was
474
                        // detected. We need to check the response for an
475
                        // 'error' and simply redirect error to OIDC client.
476
                        $redirect_url = '';
477
                        if (isset($info['redirect_url'])) {
478
                            $redirect_url = $info['redirect_url'];
479
                            $clientparams['redirect_url'] = $redirect_url;
480
                            // CIL-407 - In case of two question marks '?'
481
                            // in redirect_url (caused by OIDC authz endpoint
482
                            // blindly appending "?error=..."), change all
483
                            // but the first '?' to '&'.
484
                            // https://stackoverflow.com/a/37150213
485
                            if (substr_count($redirect_url, '?') > 1) {
486
                                $arr = explode('?', $redirect_url, 2);
487
                                $arr[1] = str_replace('?', '&', $arr[1]);
488
                                $redirect_url = implode('?', $arr);
489
                            }
490
                        }
491
                        // Get components of redirect_url - need 'query'
492
                        $comps = parse_url($redirect_url);
493
                        if ($comps !== false) {
494
                            // Look for 'error' in query
495
                            $query = '';
496
                            if (isset($comps['query'])) {
497
                                $query = $comps['query'];
498
                                $query = html_entity_decode($query);
499
                            }
500
                            $queries = explode('&', $query);
501
                            $params = array();
502
                            foreach ($queries as $value) {
503
                                $x = explode('=', $value);
504
                                $params[$x[0]] = $x[1];
505
                            }
506
                            if (isset($params['error'])) {
507
                                // Got 'error' - simply return to OIDC client
508
                                Util::unsetAllUserSessionVars();
509
                                header("Location: $redirect_url");
510
                                exit; // No further processing necessary
511
                            } else { // Weird params - Should never get here!
512
                                Util::sendErrorAlert(
513
                                    'OA4MP OIDC 302 Error',
514
                                    'The OA4MP OIDC authz endpoint ' .
515
                                    'returned a 302 redirect (error) ' .
516
                                    'response, but there was no "error" ' .
517
                                    "query parameter.\n\n" .
518
                                    "redirect_url = $redirect_url\n\n" .
519
                                    'clientparams = ' .
520
                                    print_r($clientparams, true) .
521
                                    "\n"
522
                                );
523
                                $clientparams = array();
524
                            }
525
                        } else { // parse_url($redirect_url) gave error
526
                            Util::sendErrorAlert(
527
                                'parse_url(redirect_url) error',
528
                                'There was an error when attempting to ' .
529
                                'parse the redirect_url. This should never ' .
530
                                "happen.\n\n" .
531
                                "redirect_url = $redirect_url\n\n" .
532
                                'clientparams = ' . print_r($clientparams, true) .
533
                                "\n"
534
                            );
535
                            $clientparams = array();
536
                        }
537
                    } else {
538
                        // An HTTP return code other than 200 (success) or
539
                        // 302 (redirect) means that the OA4MP OIDC authz
540
                        // endpoint tried to handle an unrecoverable error,
541
                        // possibly by outputting HTML. If so, then we
542
                        // ignore it and output our own error message to the
543
                        // user.
544
                        Util::sendErrorAlert(
545
                            'OA4MP OIDC authz endpoint error',
546
                            'The OA4MP OIDC authorization endpoint returned ' .
547
                            'an HTTP response other than 200 or 302. ' .
548
                            ((strlen($output) > 0) ?
549
                                "\n\nReturned output =\n$output" : '') .
550
                            "\n\n" .
551
                            'curl_getinfo = ' . print_r($info, true) . "\n\n" .
552
                            'clientparams = ' . print_r($clientparams, true) .
553
                            "\n"
554
                        );
555
                        // CIL-423 Better end-user error output for errors.
556
                        // Scan output for ServletException message.
557
                        $errstr = '';
558
                        if (
559
                            preg_match(
560
                                '/javax.servlet.ServletException:\s?(.*)/',
561
                                $output,
562
                                $matches
563
                            )
564
                        ) {
565
                            $output = '';
566
                            $errstr = '
567
                            <div>
568
                            <p>Error Message: <b>' .
569
                            $matches[1] . '</b>.</p>
570
                            <ul>
571
                            <li>Did you <b>register</b> your OAuth2/OIDC client? If not, go
572
                            <b><a target="_blank" href="https://' .
573
                            Util::getHN()
574
                            . '/oauth2/register">here</a></b> to do so.</li>
575
                            <li>Did you receive confirmation that your OAuth2/OIDC client
576
                            was <b>approved</b>? If not, please wait up to 48 hours for an
577
                            approval email from CILogon administrators.</li>
578
                            <li>Did you configure your OAuth2/OIDC client with the
579
                            registered <b>client ID and secret</b>?</li>
580
                            </ul>
581
                            </div>';
582
                        }
583
                        Util::setSessionVar(
584
                            'client_error_msg',
585
                            'There was an unrecoverable error during the transaction. ' .
586
                            'CILogon system administrators have been notified.' .
587
                            ((strlen($errstr) > 0) ? $errstr : '') .
588
                            ((strlen($output) > 0) ?
589
                            '<br/><pre>' .
590
                            preg_replace('/\+/', ' ', $output) .
591
                            '</pre>' : '')
592
                        );
593
                        $clientparams = array();
594
                    }
595
                } else { // curl_getinfo() returned false - should not happen
596
                    Util::sendErrorAlert(
597
                        'curl_getinfo error',
598
                        'When attempting to talk to the OA4MP OIDC ' .
599
                        'authorization endpoint, curl_getinfo() returned ' .
600
                        "false. This should never happen.\n\n" .
601
                        'clientparams = ' . print_r($clientparams, true) . "\n"
602
                    );
603
                    $clientparams = array();
604
                }
605
            }
606
            curl_close($ch);
607
        } else { // curl_init() returned false - should not happen
608
            Util::sendErrorAlert(
609
                'curl_init error',
610
                'When attempting to talk to the OA4MP OIDC authorization ' .
611
                'endpoint, curl_init() returned false. This should never ' .
612
                "happen.\n\n" .
613
                'clientparams = ' . print_r($clientparams, true) . "\n"
614
            );
615
            $clientparams = array();
616
        }
617
618
    // If redirect_uri was not passed in, but one of the other required OIDC
619
    // parameters WAS passed in, then assume that this was an attempt by an
620
    // OIDC client to use the authz endpoint, and display an error message
621
    // that at least one parameter (redirect_uri) was missing from the
622
    // request. Note that since we don't have a redirect_uri, we cannot
623
    // return code flow back to the OIDC client.
624
    } elseif (
625
        (isset($clientparams['scope'])) ||
626
        (isset($clientparams['response_type'])) ||
627
        (isset($clientparams['client_id']))
628
    ) {
629
        Util::sendErrorAlert(
630
            'CILogon OIDC authz endpoint error',
631
            'The CILogon OIDC authorization endpoint received a request ' .
632
            'from an OIDC client, but at least one of the required ' .
633
            'parameters (redirect_uri) was missing. ' .
634
            "\n\n" .
635
            'clientparams = ' . print_r($clientparams, true) .
636
            "\n"
637
        );
638
        Util::setSessionVar(
639
            'client_error_msg',
640
            'It appears that an OpenID Connect client attempted to ' .
641
            'initiate a session with the CILogon Service, but at least ' .
642
            'one of the requried parameters was missing. CILogon ' .
643
            'system administrators have been notified.'
644
        );
645
        $clientparams = array();
646
647
    // If none of the required OIDC authz endpoint parameters were passed
648
    // in, then this might be a later step in the authz process. So check
649
    // the session variable array 'clientparams' for the required
650
    // information.
651
    } else {
652
        $clientparams = json_decode(Util::getSessionVar('clientparams'), true);
653
    }
654
655
    // Now check to verify all variables have data
656
    if (
657
        (isset($clientparams['redirect_uri'])) &&
658
        (isset($clientparams['scope'])) &&
659
        (isset($clientparams['response_type'])) &&
660
        (isset($clientparams['client_id'])) &&
661
        (isset($clientparams['code'])) &&
662
        (isset($clientparams['client_name'])) &&
663
        (isset($clientparams['client_home_url'])) &&
664
        (isset($clientparams['client_callback_uri'])) &&
665
        (isset($clientparams['redirect_url'])) &&
666
        (isset($clientparams['clientstatus'])) &&
667
        (!($clientparams['clientstatus'] & 1))
668
    ) { // STATUS_OK* are even
669
        $retval = true;
670
        Util::setSessionVar('clientparams', json_encode($clientparams));
671
    }
672
673
    return $retval;
674
}
675