Completed
Push — master ( b37bec...23b4a3 )
by Terrence
14:21
created

index-functions.php ➔ getOIDCClientParams()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

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

Let’s take a look at an example:

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

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

    // do something with $myArray
}

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

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

Loading history...
503
                            // CIL-407 - In case of two question marks '?'
504
                            // in redirect_url (caused by OIDC authz endpoint
505
                            // blindly appending "?error=..."), change all
506
                            // but the first '?' to '&'.
507
                            // https://stackoverflow.com/a/37150213
508
                            if (substr_count($redirect_url, '?') > 1) {
509
                                $arr = explode('?', $redirect_url, 2);
510
                                $arr[1] = str_replace('?', '&', $arr[1]);
511
                                $redirect_url = implode('?', $arr);
512
                            }
513
                        }
514
                        // Get components of redirect_url - need 'query'
515
                        $comps = parse_url($redirect_url);
516
                        if ($comps !== false) {
517
                            // Look for 'error' in query
518
                            $query = '';
519
                            if (isset($comps['query'])) {
520
                                $query = $comps['query'];
521
                                $query = html_entity_decode($query);
522
                            }
523
                            $queries = explode('&', $query);
524
                            $params = array();
525
                            foreach ($queries as $value) {
526
                                $x = explode('=', $value);
527
                                $params[$x[0]] = $x[1];
528
                            }
529
                            if (isset($params['error'])) {
530
                                // Got 'error' - simply return to OIDC client
531
                                $clientparams = array();
0 ignored issues
show
Unused Code introduced by
$clientparams is not used, you could remove the assignment.

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

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

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

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

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

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

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

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

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

Loading history...
718
        $dsn = array(
719
            'phptype'  => 'mysqli',
720
            'username' => MYSQLI_USERNAME,
721
            'password' => MYSQLI_PASSWORD,
722
            'database' => 'ciloa2',
723
            'hostspec' => 'localhost'
724
        );
725
726
        $opts = array(
727
            'persistent'  => true,
728
            'portability' => DB_PORTABILITY_ALL
729
        );
730
731
        $db = DB::connect($dsn, $opts);
732
        if (!PEAR::isError($db)) {
733
            $data = $db->getRow(
734
                'SELECT * from clients WHERE client_id = ?',
735
                array($clientparams['client_id']),
736
                DB_FETCHMODE_ASSOC
737
            );
738
            if (!DB::isError($data)) {
739
                if (!empty($data)) {
740
                    foreach ($data as $key => $value) {
741
                        $clientparams['client_' . $key] = $value;
742
                    }
743
                    $clientparams['clientstatus'] = DBService::$STATUS['STATUS_OK'];
744
                    $retval = true;
745
                }
746
            }
747
            $db->disconnect();
748
        }
749
    }
750
    return $retval;
751
}
752