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

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
639
            $errtxt = "Missing or empty scope parameter.";
640
        } elseif (empty($client_id)) {
0 ignored issues
show
Bug introduced by
The variable $client_id seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
641
            $errtxt = "Missing or empty client_id parameter.";
642
        } elseif (empty($response_type)) {
0 ignored issues
show
Bug introduced by
The variable $response_type seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
643
            $errtxt = "Missing or empty response_type parameter.";
644
        } elseif (preg_match('/[\+%"\']/', $scope)) {
645
            $errtxt = "Invalid characters found in scope parameter, may be URL encoded twice.";
646
        } elseif (preg_match('/[A-Z]/', $scope)) {
647
            $errtxt = "Upper case characters found in scope parameter.";
648
        } elseif ($response_type != 'code') {
649
            $errtxt = "Unsupported response_type parameter. Only code is supported.";
650
        } elseif ((!empty($prompt)) && ($prompt != 'login') && ($prompt != 'select_account')) {
0 ignored issues
show
Bug introduced by
The variable $prompt seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
651
            $errtxt = "Unsupported prompt parameter. Only login and select_account are supported.";
652
        } elseif (
653
            (!empty($response_mode)) &&
0 ignored issues
show
Bug introduced by
The variable $response_mode seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
654
            ($response_mode != 'query') &&
655
            ($response_mode != 'fragment') &&
656
            ($response_mode != 'form_post')
657
        ) {
658
            $errtxt = "Unsupported response_mode parameter.";
659
        }
660
661
        // CIL-697 The OA4MP code should eventually return an
662
        // "error_description=..." field that can give detailed error text to
663
        // replace the default text associated with STATUS_INTERNAL_ERROR.
664
        // CIL-909 Use the error_description field only if $errtxt is still
665
        // empty, OR if the $errstr was STATUS_CREATE_TRANSACTION_FAILED
666
        // (i.e., "Failed to initialize OIDC flow.").
667
        if (
668
            ((strlen($errtxt) == 0) ||
669
             ($errstr == 'STATUS_CREATE_TRANSACTION_FAILED')) &&
670
            (preg_match('/error_description=([^\r\n]+)/', $output, $matches))
671
        ) {
672
            $errtxt = urldecode($matches[1]);
673
        }
674
    }
675
676
    return $errtxt;
677
}
678