Issues (141)

src/Service/DBService.php (13 issues)

1
<?php
2
3
namespace CILogon\Service;
4
5
use CILogon\Service\Util;
6
7
/**
8
 * DBService
9
 *
10
 * This class is a wrapper for the dbService servlet.  The dbService
11
 * servlet acts as a frontend to the database that stores info on users,
12
 * portal parameters, and IdPs. This was created to allow for fast
13
 * access to the database by keeping a connection open.  This class is a
14
 * rework of the old store.php class.
15
 *
16
 * Example usage:
17
 *     // For authentication, we have a bunch of attributes from an
18
 *     // identity provider. Thus get the database uid for the user
19
 *     // by using the multi-parameter version of getUser().
20
 *     $uid = '';
21
 *     $dbservice = new DBService();
22
 *     $dbservice->getUser('[email protected]',
23
 *                         'urn:mace:incommon:uiuc.edu',
24
 *                         'University of Illinois at Urbana-Champaign',
25
 *                         'John','Smith','John Smith,
26
 *                          '[email protected]');
27
 *     if (!($dbservice->status & 1)) { // OK status codes are even
28
 *         $uid = $dbservice->user_uid;
29
 *     }
30
 *
31
 *     // Later in the code, re-fetch the user using this uid
32
 *     // and print out the stored attributes.
33
 *     if (strlen($uid) > 0) {
34
 *         $dbservice->getUser($uid);
35
 *         echo 'Name = ' . $dbservice->first_name . ' ' .
36
 *                          $dbservice->last_name  . "\n";
37
 *         echo 'DN = '   . $dbservice->distinguished_name . "\n";
38
 *     }
39
 *
40
 *     // For getting/setting the Shibboleth-based IdPs, use the
41
 *     // getIdps()/setIdps() methods.  These methods utilize the
42
 *     // class member array $idp_uids for reading/writing. Two
43
 *     // convenience methods (setIdpsFromKeys($array) and
44
 *     // setIdpsFromValues($array)) are provided to populate the
45
 *     // $idp_uids array from the passed-in $array.
46
 *     $dbservice->getIdps();
47
 *     foreach($dbservice->idp_uids as $value) {
48
 *         echo "$value\n";
49
 *     }
50
 *
51
 *     $idps = array('urn:mace:incommon:ucsd.edu',
52
 *                   'urn:mace:incommon:uiuc.edu');
53
 *     $dbservice->setIdpsFromValues($idps);
54
 *     //   --- OR ---
55
 *     $idps = array('urn:mace:incommon:ucsd.edu' => 1,
56
 *                   'urn:mace:incommon:uiuc.edu' => 1);
57
 *     $dbservice->setIdpsFromKeys($idps);
58
 */
59
60
class DBService
61
{
62
    /**
63
     * @var array $STATUS The various STATUS_* constants, originally from
64
     *      Store.pm. See cilogon2-server-loader-oauth2/src/main/java/org/cilogon/oauth2/servlet/impl/DBService2.java
65
     *      in the https://github.com/cilogon/cilogon-java/ repo for the
66
     *      definitive list of oauth2 return status codes.
67
     *      The keys of the array are strings corresponding to the
68
     *      constant names. The values of the array are the integer (hex)
69
     *      values. For example, DBService::$STATUS['STATUS_OK'] = 0;
70
     *      Use 'array_search($this->status,DBService::$STATUS)' to look
71
     *      up the STATUS_* name given the status integer value.
72
     */
73
    public static $STATUS = array(
74
        'STATUS_OK'                        => 0x0,
75
        'STATUS_ACTION_NOT_FOUND'          => 0x1,
76
        'STATUS_NEW_USER'                  => 0x2,
77
        'STATUS_USER_UPDATED'              => 0x4,
78
        'STATUS_USER_NOT_FOUND'            => 0x6,
79
        'STATUS_USER_EXISTS'               => 0x8,
80
        'STATUS_USER_EXISTS_ERROR'         => 0xFFFA1, // 1048481
81
        'STATUS_USER_NOT_FOUND_ERROR'      => 0xFFFA3, // 1048483
82
        'STATUS_TRANSACTION_NOT_FOUND'     => 0xFFFA5, // 1048485
83
        'STATUS_IDP_SAVE_FAILED'           => 0xFFFA7, // 1048487
84
        'STATUS_DUPLICATE_PARAMETER_FOUND' => 0xFFFF1, // 1048561
85
        'STATUS_INTERNAL_ERROR'            => 0xFFFF3, // 1048563
86
        'STATUS_SAVE_IDP_FAILED'           => 0xFFFF5, // 1048565
87
        'STATUS_MALFORMED_INPUT_ERROR'     => 0xFFFF7, // 1048567
88
        'STATUS_MISSING_PARAMETER_ERROR'   => 0xFFFF9, // 1048569
89
        'STATUS_NO_REMOTE_USER'            => 0xFFFFB, // 1048571
90
        'STATUS_NO_IDENTITY_PROVIDER'      => 0xFFFFD, // 1048573
91
        'STATUS_CLIENT_NOT_FOUND'          => 0xFFFFF, // 1048575
92
        'STATUS_TRANSACTION_NOT_FOUND'     => 0x10001, //   65537
93
        'STATUS_EPTID_MISMATCH'            => 0x100001,// 1048577
94
        'STATUS_PAIRWISE_ID_MISMATCH'      => 0x100003,// 1048579
95
        'STATUS_SUBJECT_ID_MISMATCH'       => 0x100005,// 1048581
96
        'STATUS_EXPIRED_TOKEN'             => 0x10003, //   65539
97
        'STATUS_CREATE_TRANSACTION_FAILED' => 0x10005, //   65541
98
        'STATUS_UNKNOWN_CALLBACK'          => 0x10007, //   65543
99
        'STATUS_MISSING_CLIENT_ID'         => 0x10009, //   65545
100
        'STATUS_NO_REGISTERED_CALLBACKS'   => 0x1000B, //   65547
101
        'STATUS_UNKNOWN_CLIENT'            => 0x1000D, //   65549
102
        'STATUS_UNAPPROVED_CLIENT'         => 0x1000F, //   65551
103
        'STATUS_NO_SCOPES'                 => 0x10011, //   65553
104
        'STATUS_MALFORMED_SCOPE'           => 0x10013, //   65555
105
    );
106
107
    public static $STATUS_TEXT = array(
108
        'STATUS_OK'                        => 'Status OK.',
109
        'STATUS_ACTION_NOT_FOUND'          => 'Action not found.',
110
        'STATUS_NEW_USER'                  => 'New user created.',
111
        'STATUS_USER_UPDATED'              => 'User data updated.',
112
        'STATUS_USER_NOT_FOUND'            => 'User not found.',
113
        'STATUS_USER_EXISTS'               => 'User exists.',
114
        'STATUS_USER_EXISTS_ERROR'         => 'User already exists.',
115
        'STATUS_USER_NOT_FOUND_ERROR'      => 'User not found.',
116
        'STATUS_TRANSACTION_NOT_FOUND'     => 'Transaction not found.',
117
        'STATUS_IDP_SAVE_FAILED'           => 'Could not save IdPs.',
118
        'STATUS_DUPLICATE_PARAMETER_FOUND' => 'Duplicate parameter.',
119
        'STATUS_INTERNAL_ERROR'            => 'Internal error.',
120
        'STATUS_SAVE_IDP_FAILED'           => 'Could not save IdP.',
121
        'STATUS_MALFORMED_INPUT_ERROR'     => 'Malformed input.',
122
        'STATUS_MISSING_PARAMETER_ERROR'   => 'Missing parameter.',
123
        'STATUS_NO_REMOTE_USER'            => 'Missing Remote User.',
124
        'STATUS_NO_IDENTITY_PROVIDER'      => 'Missing IdP.',
125
        'STATUS_CLIENT_NOT_FOUND'          => 'Missing client.',
126
        'STATUS_TRANSACTION_NOT_FOUND'     => 'Transaction not found.',
127
        'STATUS_EPTID_MISMATCH'            => 'EPTID mismatch.',
128
        'STATUS_PAIRWISE_ID_MISMATCH'      => 'Pairwise ID mismatch.',
129
        'STATUS_SUBJECT_ID_MISMATCH'       => 'Subject ID mismatch.',
130
        'STATUS_EXPIRED_TOKEN'             => 'Expired token.',
131
        'STATUS_CREATE_TRANSACTION_FAILED' => 'Failed to initialize OIDC flow.',
132
        'STATUS_UNKNOWN_CALLBACK'          => 'The redirect_uri does not match a registered callback URI.',
133
        'STATUS_MISSING_CLIENT_ID'         => 'Missing client_id parameter.',
134
        'STATUS_NO_REGISTERED_CALLBACKS'   => 'No registered callback URIs.',
135
        'STATUS_UNKNOWN_CLIENT'            => 'Unknown client_id.',
136
        'STATUS_UNAPPROVED_CLIENT'         => 'Client has not been approved.',
137
        'STATUS_NO_SCOPES'                 => 'Missing or empty scope parameter.',
138
        'STATUS_MALFORMED_SCOPE'           => 'Malformed scope parameter.',
139
    );
140
141
    /**
142
     * @var array $user_attrs An array of all the user attributes that
143
     *      get passed to the getUser function. This is available to other
144
     *      function since these user attributes are set frequently
145
     *      throughout the code.
146
     */
147
    public static $user_attrs = [
148
        'remote_user',
149
        'idp',
150
        'idp_display_name',
151
        'first_name',
152
        'last_name',
153
        'display_name',
154
        'email',
155
        'loa',
156
        'eppn',
157
        'eptid',
158
        'open_id',
159
        'oidc',
160
        'subject_id',
161
        'pairwise_id',
162
        'affiliation',
163
        'ou',
164
        'member_of',
165
        'acr',
166
        'amr',
167
        'entitlement',
168
        'itrustuin',
169
    ];
170
171
    /**
172
     * @var int|null $status The returned status code from dbService calls
173
     */
174
    public $status;
175
176
    /**
177
     * @var string|null $user_uid The CILogon UID
178
     */
179
    public $user_uid;
180
181
    /**
182
     * @var string|null $remote_user The HTTP session REMOTE_USER
183
     */
184
    public $remote_user;
185
186
    /**
187
     * @var string|null $idp The Identity Provider's entityId
188
     */
189
    public $idp;
190
191
    /**
192
     * @var string|null $idp_display_name The Identity Provider's name
193
     */
194
    public $idp_display_name;
195
196
    /**
197
     * @var string|null $first_name User's given name
198
     */
199
    public $first_name;
200
201
    /**
202
     * @var string|null $last_name User's family name
203
     */
204
    public $last_name;
205
206
    /**
207
     * @var string|null $display_name User's full name
208
     */
209
    public $display_name;
210
211
    /**
212
     * @var string|null $email User's email address
213
     */
214
    public $email;
215
216
    /**
217
     * @var string|null $loa Level of Assurance (Note: not saved in database)
218
     */
219
    public $loa;
220
221
    /**
222
     * @var string|null $distinguished_name X.509 DN + email address
223
     */
224
    public $distinguished_name;
225
226
    /**
227
     * @var string|null $eppn eduPersonPrincipalName
228
     */
229
    public $eppn;
230
231
    /**
232
     * @var string|null $eptid eduPersonTargetedID
233
     */
234
    public $eptid;
235
236
    /**
237
     * @var string|null $open_id Old Google OpenID 2.0 identifier
238
     */
239
    public $open_id;
240
241
    /**
242
     * @var string|null $oidc OpenID Connect identifier
243
     */
244
    public $oidc;
245
246
    /**
247
     * @var string|null $affiliation eduPersonScopedAffiliation
248
     */
249
    public $affiliation;
250
251
    /**
252
     * @var string|null $ou Organizational Unit
253
     */
254
    public $ou;
255
256
    /**
257
     * @var string|null $member_of isMemberOf group information
258
     */
259
    public $member_of;
260
261
    /**
262
     * @var string|null $acr Authentication Context Class Ref
263
     */
264
    public $acr;
265
266
    /**
267
     * @var string|null $amr Authentication Method Reference from ORCID
268
     */
269
    public $amr;
270
271
    /**
272
     * @var string|null $entitlement eduPersonEntitlement
273
     */
274
    public $entitlement;
275
276
    /**
277
     * @var string|null $itrustuin Person's univeristy ID number
278
     */
279
    public $itrustuin;
280
281
    /**
282
     * @var string|null $subject_id Person's univeristy subject identifier
283
     */
284
    public $subject_id;
285
286
    /**
287
     * @var string|null $pairwise_id Person's univeristy pairwise identifier
288
     */
289
    public $pairwise_id;
290
291
    /**
292
     * @var string|null $serial_string CILogon serial string (e.g., A34201)
293
     */
294
    public $serial_string;
295
296
    /**
297
     * @var string|null $create_time Time user entry was created
298
     */
299
    public $create_time;
300
301
    /**
302
     * @var string|null $oauth_token OAuth 2.0 token
303
     */
304
    public $oauth_token;
305
306
    /**
307
     * @var string|null $cilogon_callback OAuth 1.0a callback URL
308
     */
309
    public $cilogon_callback;
310
311
    /**
312
     * @var string|null $cilogon_success OAuth 1.0a success URL
313
     */
314
    public $cilogon_success;
315
316
    /**
317
     * @var string|null $cilogon_failure OAuth 1.0a failure URL
318
     */
319
    public $cilogon_failure;
320
321
    /**
322
     * @var string|null $cilogon_portal_name OAuth client name
323
     */
324
    public $cilogon_portal_name;
325
326
    /**
327
     * @var string|null $client_id OAuth 2.0 client_id
328
     */
329
    public $client_id;
330
331
    /**
332
     * @var string|null $user_code OAuth 2.0 Device Authz Grant flow user_code
333
     */
334
    public $user_code;
335
336
    /**
337
     * @var string|null $scope Space-separated list of OAuth 2.0 scopes
338
     *      associated with the user_code
339
     */
340
    public $scope;
341
342
    /**
343
     * @var array $idp_uids IdPs stored in the 'values' of the array
344
     */
345
    public $idp_uids;
346
347
    /**
348
     * @var string|null $dbservice URL The URL to use for the dbService
349
     */
350
    private $dbserviceurl;
351
352
    /**
353
     * __construct
354
     *
355
     * Default constructor.  All of the various class members are
356
     * initialized to 'null' or empty arrays.
357
     *
358
     * @param string $serviceurl (Optional) The URL of the database service
359
     *        servlet
360
     */
361
    public function __construct($serviceurl = DEFAULT_DBSERVICE_URL)
0 ignored issues
show
The constant CILogon\Service\DEFAULT_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
362
    {
363
        $this->clear();
364
        $this->setDBServiceURL($serviceurl);
365
    }
366
367
    /**
368
     * getDBServiceURL
369
     *
370
     * Returns the full URL of the database servlet used by the call()
371
     * function.
372
     *
373
     * @return string The URL of the database service servlet
374
     */
375
    public function getDBServiceURL()
376
    {
377
        return $this->dbserviceurl;
378
    }
379
380
    /**
381
     * setDBServiceURL
382
     *
383
     * Set the private variable $dbserviceurl to the full URL of the
384
     * database servlet, which is used by the call() function.
385
     *
386
     * @param string $serviceurl The URL of the database service servlet.
387
     */
388
    public function setDBServiceURL($serviceurl)
389
    {
390
        $this->dbserviceurl = $serviceurl;
391
    }
392
393
    /**
394
     * clear
395
     *
396
     * Set all of the class members to 'null' or empty arrays.
397
     */
398
    public function clear()
399
    {
400
        $this->clearUser();
401
        $this->clearPortal();
402
        $this->clearUserCode();
403
        $this->clearIdps();
404
    }
405
406
    /**
407
     * clearUser
408
     *
409
     * Set all of the class member variables associated with getUser()
410
     * to 'null'.
411
     */
412
    public function clearUser()
413
    {
414
        foreach (static::$user_attrs as $value) {
415
            $this->$value = null;
416
        }
417
        $this->status = null;
418
        $this->user_uid = null;
419
        $this->distinguished_name = null;
420
        $this->serial_string = null;
421
        $this->create_time = null;
422
    }
423
424
    /**
425
     * clearPortal
426
     *
427
     * Set all of the class member variables associated with
428
     * getPortalParameters() to 'null'.
429
     */
430
    public function clearPortal()
431
    {
432
        $this->status = null;
433
        $this->oauth_token = null;
434
        $this->cilogon_callback = null;
435
        $this->cilogon_success = null;
436
        $this->cilogon_failure = null;
437
        $this->cilogon_portal_name = null;
438
    }
439
440
    /**
441
     * clearUserCode
442
     *
443
     * Set the class member variables associated with
444
     * checkUserCode() to 'null'
445
     */
446
    public function clearUserCode()
447
    {
448
        $this->status = null;
449
        $this->user_code = null;
450
        $this->client_id = null;
451
        $this->scope = null;
452
    }
453
454
    /**
455
     * clearIdps
456
     *
457
     * Set the class member variable $idp_uids to an empty array.
458
     */
459
    public function clearIdps()
460
    {
461
        $this->status = null;
462
        $this->idp_uids = array();
463
    }
464
465
    /**
466
     * getUser
467
     *
468
     * This method calls the 'getUser' action of the servlet and sets
469
     * the class member variables associated with user info
470
     * appropriately.  If the servlet returns correctly (i.e. an HTTP
471
     * status code of 200), this method returns true.
472
     *
473
     * @param mixed $args Variable number of parameters: 1, or more.
474
     *        For 1 parameter : $uid (database user identifier)
475
     *        For more than 1 parameter, parameters can include:
476
     *            $remote_user, $idp, $idp_display_name,
477
     *            $first_name, $last_name, $display_name, $email,
478
     *            $eppn, $eptid, $openid, $oidc,
479
     *            $subject_id, $pairwise_id, $affiliation,
480
     *            $ou, $member_of, $acr, $amr, $entitlement,
481
     *            $itrustuin
482
     *
483
     * @return bool True if the servlet returned correctly. Else false.
484
     */
485
    public function getUser(...$args)
486
    {
487
        $retval = false;
488
        $this->clearUser();
489
        $this->setDBServiceURL(DEFAULT_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\DEFAULT_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
490
        $numargs = count($args);
491
        if ($numargs == 1) {
492
            $retval = $this->call('action=getUser&user_uid=' .
493
                urlencode($args[0]));
494
        } elseif ($numargs > 1) {
495
            $cmd = 'action=getUser';
496
            $attr_arr = array();
497
            $ou_pos = array_search('ou', static::$user_attrs);
498
            for ($i = 0; $i < $numargs; $i++) {
499
                $arg = $args[$i];
500
                if (strlen($arg) > 0) {
501
                    if ($i > $ou_pos) {
502
                        // Put params after $ou into JSON object
503
                        $attr_arr[static::$user_attrs[$i]] = $arg;
504
                    } else {
505
                        $cmd .= '&' . static::$user_attrs[$i] . '=' . urlencode($arg);
506
                    }
507
                }
508
            }
509
            // If any elements in $attr_arr, append converted JSON object
510
            if (count($attr_arr) > 0) {
511
                if (
512
                    ($attr_json = json_encode(
513
                        $attr_arr,
514
                        JSON_FORCE_OBJECT | JSON_UNESCAPED_SLASHES
515
                    )
516
                    ) !== false
517
                ) {
518
                    $cmd .= '&attr_json=' . urlencode($attr_json);
519
                }
520
            }
521
            // Add 'us_idp' parameter for InCommon/Google (1) or eduGAIN (0)
522
            $us_idp = 0;
523
            $idp = $args[1];
524
            $idp_display_name = $args[2];
525
            if (
526
                (Util::getIdpList()->isRegisteredByInCommon($idp)) ||
527
                (in_array($idp_display_name, Util::$oauth2idps))
528
            ) {
529
                $us_idp = 1;
530
            }
531
            $cmd .= "&us_idp=$us_idp";
532
533
            $retval = $this->call($cmd);
534
        }
535
        return $retval;
536
    }
537
538
    /**
539
     * removeUser
540
     *
541
     * This method calls the 'removeUser' action of the servlet and
542
     * sets the class member variable $status appropriately.  If the
543
     * servlet returns correctly (i.e. an HTTP status code of 200),
544
     * this method returns true.
545
     *
546
     * @param string $uid The database user identifier
547
     * @return bool True if the servlet returned correctly. Else false.
548
     */
549
    public function removeUser($uid)
550
    {
551
        $this->clearUser();
552
        $this->setDBServiceURL(DEFAULT_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\DEFAULT_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
553
        return $this->call('action=removeUser&user_uid=' .
554
            urlencode($uid));
555
    }
556
557
    /**
558
     * getPortalParameters
559
     *
560
     * This method calls the 'getPortalParameter' action of the servlet
561
     * and sets the class member variables associated with the portal
562
     * parameters appropriately. If the servlet returns correctly (i.e.
563
     * an HTTP status code of 200), this method returns true.
564
     *
565
     * @param string $oauth_token The database OAuth identifier token
566
     * @return bool True if the servlet returned correctly. Else false.
567
     */
568
    public function getPortalParameters($oauth_token)
569
    {
570
        $this->clearPortal();
571
        $this->setDBServiceURL(OAUTH1_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\OAUTH1_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
572
        return $this->call('action=getPortalParameter&oauth_token=' .
573
            urlencode($oauth_token));
574
    }
575
576
    /**
577
     * getIdps
578
     *
579
     * This method calls the 'getAllIdps' action of the servlet and
580
     * sets the class member array $idp_uris to contain all of the
581
     * Idps in the database, stored in the 'values' of the array.  If
582
     * the servlet returns correctly (i.e. an HTTP status code of 200),
583
     * this method returns true.
584
     *
585
     * @return bool True if the servlet returned correctly. Else false.
586
     */
587
    public function getIdps()
588
    {
589
        $this->clearIdps();
590
        $this->setDBServiceURL(DEFAULT_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\DEFAULT_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
591
        return $this->call('action=getAllIdps');
592
    }
593
594
    /**
595
     * setIdps
596
     *
597
     * This method calls the 'setAllIdps' action of the servlet using
598
     * the class memeber array $idp_uris as the source for the Idps to
599
     * be stored to the database.  Note that if this array is empty,
600
     * an error code will be returned in the status since at least one
601
     * IdP should be saved to the database.  If you want to pass an
602
     * array of Idps to be saved, see the setIdpsFromKeys($array) and
603
     * setIdpsFromValues($array) methods.  If the servlet returns
604
     * correctly (i.e. an HTTP status code of 200), this method
605
     * returns true.
606
     *
607
     * @return bool True if the servlet returned correctly. Else false.
608
     */
609
    public function setIdps()
610
    {
611
        $retval = false;
612
        $this->setDBServiceURL(DEFAULT_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\DEFAULT_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
613
        $idpcount = count($this->idp_uids);
614
        $idpidx = 0;
615
        if ($idpcount > 0) {
616
            // Loop through the idp_uids in chunks of 50 to deal
617
            // with query parameter limit of http browsers/servers.
618
            while ($idpidx < $idpcount) { // Loop through all IdPs
619
                $fiftyidx = 0;
620
                $idplist = '';
621
                while (
622
                    ($fiftyidx < 50) && // Send 50 IdPs at a time
623
                       ($idpidx < $idpcount)
624
                ) {
625
                    $idplist .=  '&idp_uid=' .
626
                                 urlencode($this->idp_uids[$idpidx]);
627
                    $fiftyidx++;
628
                    $idpidx++;
629
                }
630
                $cmd = 'action=setAllIdps' . $idplist;
631
                $retval = $this->call($cmd);
632
            }
633
        }
634
        return $retval;
635
    }
636
637
    /**
638
     * setIdpsFromKeys
639
     *
640
     * This is a convenience method which calls setIdps using a
641
     * passed-in array of IdPs stored as the keys of the array.  It
642
     * first sets the class member array $idp_uids appropriately and
643
     * then calls the setIdps() method. If the servlet returns
644
     * correctly (i.e. an HTTP status code of 200), this method
645
     * returns true.  See also setIdpsFromValues().
646
     *
647
     * @param array $idps An array of IdPs to be saved, stored in the
648
     *       'keys' of the array.
649
     * @return bool True if the servlet returned correctly. Else false.
650
     */
651
    public function setIdpsFromKeys($idps)
652
    {
653
        $this->clearIdps();
654
        foreach ($idps as $key => $value) {
655
            $this->idp_uids[] = $key;
656
        }
657
        return $this->setIdps();
658
    }
659
660
    /**
661
     * setIdpsFromValues
662
     *
663
     * This is a convenience method which calls setIdps using a
664
     * passed-in array of IdPs stored as the values of the array.  It
665
     * first sets the class member array $idp_uids appropriately and
666
     * then calls the setIdps() method. If the servlet returns
667
     * correctly (i.e. an HTTP status code of 200), this method
668
     * returns true.  See also setIdpsFromKeys().
669
     *
670
     * @param array $idps An array of IdPs to be saved, stored in the
671
     *        'values' of the array.
672
     * @return bool True if the servlet returned correctly. Else false.
673
     */
674
    public function setIdpsFromValues($idps)
675
    {
676
        $this->clearIdps();
677
        foreach ($idps as $value) {
678
            $this->idp_uids[] = $value;
679
        }
680
        return $this->setIdps();
681
    }
682
683
    /**
684
     * setTransactionState
685
     *
686
     * This method calls the 'setTransactionState' action of the OAuth
687
     * 2.0 servlet to associate the OAuth 2.0 'code' with the database
688
     * user UID. This is necessary for the OAuth 2.0 server to be able
689
     * to return information about the user (name, email address) as
690
     * well as return a certificate for the user. If the servlet
691
     * returns correctly (i.e., an HTTP status code of 200), this method
692
     * returns true. Check the 'status' return value to verify that
693
     * the transaction state was set successfully.
694
     *
695
     * @param string $code The 'code' as returned by the OAuth 2.0 server.
696
     * @param string $uid The database user UID.
697
     * @param int $authntime The Unix timestamp of the user authentication.
698
     * @param string $loa (Optional) The Level of Assurance: '' = basic,
699
     *        'openid' =  OpenID Connect (e.g., Google),
700
     *        'http://incommonfederation.org/assurance/silver' = silver
701
     * @param string $myproxyinfo (Optional) the 'info:...' string to be
702
     *        passed to MyProxy.
703
     * @return bool True if the servlet returned correctly. Else false.
704
     */
705
    public function setTransactionState(
706
        $code,
707
        $uid,
708
        $authntime,
709
        $loa = '',
710
        $myproxyinfo = ''
711
    ) {
712
        $this->setDBServiceURL(OAUTH2_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\OAUTH2_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
713
        return $this->call(
714
            'action=setTransactionState' .
715
            '&code=' . urlencode($code) .
716
            '&user_uid=' . urlencode($uid) .
717
            '&auth_time=' . urlencode($authntime) .
718
            '&loa=' . urlencode($loa) .
719
            ((strlen($myproxyinfo) > 0) ?
720
                ('&cilogon_info=' . urlencode($myproxyinfo)) : '')
721
        );
722
    }
723
724
    /**
725
     * checkUserCode
726
     *
727
     * This method calls the 'checkUserCode' action of the OAuth 2.0 servlet
728
     * to fetch a client_id associated with a user_code entered by the end
729
     * user as part of an OAuth2 Device Authorization Grant flow. If the
730
     * servlet returns correctly (i.e., an HTTP status code of 200), this
731
     * method returns true. Check the 'status' return value to verify that
732
     * the user_code is correct. The client_id and 'original' user_code
733
     * will be available if the input user_code was valid.
734
     *
735
     * @param string $user_code The OAuth 2.0 Device Authorization Grant
736
     *        flow code entered by the user.
737
     * @return bool True if the servlet returned correctly. client_id and
738
     *         originally generated user_code will be available.
739
     *        Return false if user_code was expired or not found.
740
     */
741
    public function checkUserCode($user_code)
0 ignored issues
show
The parameter $user_code is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

741
    public function checkUserCode(/** @scrutinizer ignore-unused */ $user_code)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
742
    {
743
        $this->setDBServiceURL(OAUTH2_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\OAUTH2_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
744
        /*
745
        return $this->call(
746
            'action=userCodeApproved' .
747
            '&user_code=' . urlencode($user_code)
748
        );
749
        */
750
        // DEBUG PLACEHOLDER - return some dummy values
751
        $this->status = 0;
752
        $this->user_code = 'ABCD-JKLM';
753
        $this->client_id = 'cilogon:/client_id/100c74e105fb9652d80817d4106b5696';
754
        $this->scope = 'openid profile email';
755
        return true;
756
    }
757
758
    /**
759
     * userCodeApproved
760
     *
761
     * This method calls the 'userCodeApproved' action of the OAuth 2.0
762
     * servlet to let the OA4MP code know that a user has approved a
763
     * user_code associated with a Device Authorization Grant transaction.
764
     * If the servlet returns correctly (i.e.,  an HTTP status code of 200),
765
     * this method returns true. Check the 'status' return value to verify
766
     * that the user_code is correct and is not expired.
767
     *
768
     * @param string $user_code The OAuth 2.0 Device Authorization Grant
769
     *        flow code entered by the user.
770
     * @param int $approved (Optional) =1 if the user_code has been approved
771
     *        by the user (default). =0 if the user clicks 'Cancel' to
772
     *        deny the user_code approval.
773
     * @return bool True if the servlet returned correctly. Else false.
774
     */
775
    public function userCodeApproved($user_code, $approved = 1)
0 ignored issues
show
The parameter $user_code is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

775
    public function userCodeApproved(/** @scrutinizer ignore-unused */ $user_code, $approved = 1)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $approved is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

775
    public function userCodeApproved($user_code, /** @scrutinizer ignore-unused */ $approved = 1)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
776
    {
777
        $this->setDBServiceURL(OAUTH2_DBSERVICE_URL);
0 ignored issues
show
The constant CILogon\Service\OAUTH2_DBSERVICE_URL was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
778
        /*
779
        return $this->call(
780
            'action=userCodeApproved' .
781
            '&user_code=' . urlencode($user_code) .
782
            '&approved=' . $approved
783
        );
784
        */
785
        // DEBUG PLACEHOLDER - return some dummy values
786
        $this->status = 0;
787
        return true;
788
    }
789
790
    /**
791
     * call
792
     *
793
     * This method does the brunt of the work for calling the
794
     * dbService servlet.  The single parameter is a string of
795
     * 'key1=value1&key2=value2&...' containing all of the parameters
796
     * for the dbService.  If the servlet returns an HTTP status code
797
     * of 200, then this method will return true.  It parses the return
798
     * output for various 'key=value' lines and stores then in the
799
     * appropriate member variables, urldecoded of course.
800
     *
801
     * @param string $params A string containing 'key=value' pairs,
802
     *        separated by ampersands ('&') as appropriate for passing to a
803
     *        URL for a GET query.
804
     * @return bool True if the servlet returned correctly. Else false.
805
     */
806
    public function call($params)
807
    {
808
        $success = false;
809
810
        $attr_json = '';
811
        $ch = curl_init();
812
        if ($ch !== false) {
813
            $url = $this->getDBServiceURL() . '?' . $params;
814
            curl_setopt($ch, CURLOPT_URL, $url);
815
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
816
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
817
            $output = curl_exec($ch);
818
            if (curl_errno($ch)) { // Send alert on curl errors
819
                Util::sendErrorAlert(
820
                    'cUrl Error',
821
                    'cUrl Error    = ' . curl_error($ch) . "\n" .
822
                    "URL Accessed  = $url"
823
                );
824
            }
825
            if (!empty($output)) {
826
                $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
827
                if ($httpcode == 200) {
828
                    $success = true;
829
                    if (preg_match('/status=([^\r\n]+)/', $output, $match)) {
0 ignored issues
show
It seems like $output can also be of type true; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

829
                    if (preg_match('/status=([^\r\n]+)/', /** @scrutinizer ignore-type */ $output, $match)) {
Loading history...
830
                        $this->status = (int)(urldecode($match[1]));
831
                    }
832
                    if (preg_match('/user_uid=([^\r\n]+)/', $output, $match)) {
833
                        $this->user_uid = urldecode($match[1]);
834
                    }
835
                    if (preg_match('/remote_user=([^\r\n]+)/', $output, $match)) {
836
                        $this->remote_user = urldecode($match[1]);
837
                    }
838
                    if (preg_match('/idp=([^\r\n]+)/', $output, $match)) {
839
                        $this->idp = urldecode($match[1]);
840
                    }
841
                    if (preg_match('/idp_display_name=([^\r\n]+)/', $output, $match)) {
842
                        $this->idp_display_name = urldecode($match[1]);
843
                    }
844
                    if (preg_match('/first_name=([^\r\n]+)/', $output, $match)) {
845
                        $this->first_name = urldecode($match[1]);
846
                    }
847
                    if (preg_match('/last_name=([^\r\n]+)/', $output, $match)) {
848
                        $this->last_name = urldecode($match[1]);
849
                    }
850
                    if (preg_match('/[^_]display_name=([^\r\n]+)/', $output, $match)) {
851
                        $this->display_name = urldecode($match[1]);
852
                    }
853
                    if (preg_match('/email=([^\r\n]+)/', $output, $match)) {
854
                        $this->email = urldecode($match[1]);
855
                    }
856
                    if (preg_match('/distinguished_name=([^\r\n]+)/', $output, $match)) {
857
                        $this->distinguished_name = urldecode($match[1]);
858
                    }
859
                    if (preg_match('/eppn=([^\r\n]+)/', $output, $match)) {
860
                        $this->eppn = urldecode($match[1]);
861
                    }
862
                    if (preg_match('/eptid=([^\r\n]+)/', $output, $match)) {
863
                        $this->eptid = urldecode($match[1]);
864
                    }
865
                    if (preg_match('/open_id=([^\r\n]+)/', $output, $match)) {
866
                        $this->open_id = urldecode($match[1]);
867
                    }
868
                    if (preg_match('/oidc=([^\r\n]+)/', $output, $match)) {
869
                        $this->oidc = urldecode($match[1]);
870
                    }
871
                    if (preg_match('/subject_id=([^\r\n]+)/', $output, $match)) {
872
                        $this->subject_id = urldecode($match[1]);
873
                    }
874
                    if (preg_match('/pairwise_id=([^\r\n]+)/', $output, $match)) {
875
                        $this->pairwise_id = urldecode($match[1]);
876
                    }
877
                    if (preg_match('/affiliation=([^\r\n]+)/', $output, $match)) {
878
                        $this->affiliation = urldecode($match[1]);
879
                    }
880
                    if (preg_match('/ou=([^\r\n]+)/', $output, $match)) {
881
                        $this->ou = urldecode($match[1]);
882
                    }
883
                    if (preg_match('/attr_json=([^\r\n]+)/', $output, $match)) {
884
                        // Decode $attr_json into class members later
885
                        $attr_json = urldecode($match[1]);
886
                    }
887
                    if (preg_match('/serial_string=([^\r\n]+)/', $output, $match)) {
888
                        $this->serial_string = urldecode($match[1]);
889
                    }
890
                    if (preg_match('/create_time=([^\r\n]+)/', $output, $match)) {
891
                        $this->create_time = urldecode($match[1]);
892
                    }
893
                    if (preg_match('/oauth_token=([^\r\n]+)/', $output, $match)) {
894
                        $this->oauth_token = urldecode($match[1]);
895
                    }
896
                    if (preg_match('/cilogon_callback=([^\r\n]+)/', $output, $match)) {
897
                        $this->cilogon_callback = urldecode($match[1]);
898
                    }
899
                    if (preg_match('/cilogon_success=([^\r\n]+)/', $output, $match)) {
900
                        $this->cilogon_success = urldecode($match[1]);
901
                    }
902
                    if (preg_match('/cilogon_failure=([^\r\n]+)/', $output, $match)) {
903
                        $this->cilogon_failure = urldecode($match[1]);
904
                    }
905
                    if (preg_match('/cilogon_portal_name=([^\r\n]+)/', $output, $match)) {
906
                        $this->cilogon_portal_name = urldecode($match[1]);
907
                    }
908
                    if (preg_match('/user_code=([^\r\n]+)/', $output, $match)) {
909
                        $this->user_code = urldecode($match[1]);
910
                    }
911
                    if (preg_match('/client_id=([^\r\n]+)/', $output, $match)) {
912
                        $this->client_id = urldecode($match[1]);
913
                    }
914
                    if (preg_match('/scope=([^\r\n]+)/', $output, $match)) {
915
                        $this->scope = urldecode($match[1]);
916
                    }
917
                    if (preg_match_all('/idp_uid=([^\r\n]+)/', $output, $match)) {
918
                        foreach ($match[1] as $value) {
919
                            $this->idp_uids[] = urldecode($value);
920
                        }
921
                    }
922
                }
923
            }
924
            curl_close($ch);
925
        }
926
927
        // Convert $attr_json into array and extract elements into class members
928
        if (strlen($attr_json) > 0) {
929
            $attr_arr = json_decode($attr_json, true);
930
            if (!is_null($attr_arr)) {
931
                if (isset($attr_arr['member_of'])) {
932
                    $this->member_of = $attr_arr['member_of'];
933
                }
934
                if (isset($attr_arr['acr'])) {
935
                    $this->acr = $attr_arr['acr'];
936
                }
937
                if (isset($attr_arr['amr'])) {
938
                    $this->amr = $attr_arr['amr'];
939
                }
940
                if (isset($attr_arr['entitlement'])) {
941
                    $this->entitlement = $attr_arr['entitlement'];
942
                }
943
                if (isset($attr_arr['itrustuin'])) {
944
                    $this->itrustuin = $attr_arr['itrustuin'];
945
                }
946
            }
947
        }
948
949
        return $success;
950
    }
951
952
    /**
953
     * dump
954
     *
955
     * This is a convenience method which prints out all of the
956
     * non-null / non-empty member variables to stdout.
957
     */
958
    public function dump()
959
    {
960
        if (!is_null($this->status)) {
961
            echo "status=$this->status (" .
962
            (string)(array_search($this->status, static::$STATUS)) . ")\n";
963
        }
964
        if (!is_null($this->user_uid)) {
965
            echo "user_uid=$this->user_uid\n";
966
        }
967
        if (!is_null($this->remote_user)) {
968
            echo "remote_user=$this->remote_user\n";
969
        }
970
        if (!is_null($this->idp)) {
971
            echo "idp=$this->idp\n";
972
        }
973
        if (!is_null($this->idp_display_name)) {
974
            echo "idp_display_name=$this->idp_display_name\n";
975
        }
976
        if (!is_null($this->first_name)) {
977
            echo "first_name=$this->first_name\n";
978
        }
979
        if (!is_null($this->last_name)) {
980
            echo "last_name=$this->last_name\n";
981
        }
982
        if (!is_null($this->display_name)) {
983
            echo "display_name=$this->display_name\n";
984
        }
985
        if (!is_null($this->email)) {
986
            echo "email=$this->email\n";
987
        }
988
        if (!is_null($this->distinguished_name)) {
989
            echo "distinguished_name=$this->distinguished_name\n";
990
        }
991
        if (!is_null($this->eppn)) {
992
            echo "eppn=$this->eppn\n";
993
        }
994
        if (!is_null($this->eptid)) {
995
            echo "eptid=$this->eptid\n";
996
        }
997
        if (!is_null($this->open_id)) {
998
            echo "open_id=$this->open_id\n";
999
        }
1000
        if (!is_null($this->oidc)) {
1001
            echo "oidc=$this->oidc\n";
1002
        }
1003
        if (!is_null($this->affiliation)) {
1004
            echo "affiliation=$this->affiliation\n";
1005
        }
1006
        if (!is_null($this->ou)) {
1007
            echo "ou=$this->ou\n";
1008
        }
1009
        if (!is_null($this->member_of)) {
1010
            echo "member_of=$this->member_of\n";
1011
        }
1012
        if (!is_null($this->acr)) {
1013
            echo "acr=$this->acr\n";
1014
        }
1015
        if (!is_null($this->amr)) {
1016
            echo "amr=$this->amr\n";
1017
        }
1018
        if (!is_null($this->entitlement)) {
1019
            echo "entitlement=$this->entitlement\n";
1020
        }
1021
        if (!is_null($this->itrustuin)) {
1022
            echo "itrustuin=$this->itrustuin\n";
1023
        }
1024
        if (!is_null($this->subject_id)) {
1025
            echo "subject_id=$this->subject_id\n";
1026
        }
1027
        if (!is_null($this->pairwise_id)) {
1028
            echo "pairwise_id=$this->pairwise_id\n";
1029
        }
1030
        if (!is_null($this->serial_string)) {
1031
            echo "serial_string=$this->serial_string\n";
1032
        }
1033
        if (!is_null($this->create_time)) {
1034
            echo "create_time=$this->create_time\n";
1035
        }
1036
        if (!is_null($this->oauth_token)) {
1037
            echo "oauth_token=$this->oauth_token\n";
1038
        }
1039
        if (!is_null($this->cilogon_callback)) {
1040
            echo "cilogon_callback=$this->cilogon_callback\n";
1041
        }
1042
        if (!is_null($this->cilogon_success)) {
1043
            echo "cilogon_success=$this->cilogon_success\n";
1044
        }
1045
        if (!is_null($this->cilogon_failure)) {
1046
            echo "cilogon_failure=$this->cilogon_failure\n";
1047
        }
1048
        if (!is_null($this->cilogon_portal_name)) {
1049
            echo "cilogon_portal_name=$this->cilogon_portal_name\n";
1050
        }
1051
        if (!is_null($this->user_code)) {
1052
            echo "user_code=$this->user_code\n";
1053
        }
1054
        if (!is_null($this->client_id)) {
1055
            echo "client_id=$this->client_id\n";
1056
        }
1057
        if (!is_null($this->scope)) {
1058
            echo "scope=$this->scope\n";
1059
        }
1060
        if (count($this->idp_uids) > 0) {
1061
            uasort($this->idp_uids, 'strcasecmp');
1062
            echo "idp_uids={\n";
1063
            foreach ($this->idp_uids as $value) {
1064
                echo "    $value\n";
1065
            }
1066
            echo "}\n";
1067
        }
1068
    }
1069
}
1070