Test Failed
Push — master ( d99c6b...fb4ca3 )
by Stiofan
15:44
created

Google_Auth_OAuth2::verifySignedJwtWithCerts()   D

Complexity

Conditions 18
Paths 192

Size

Total Lines 121
Code Lines 75

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 75
nc 192
nop 5
dl 0
loc 121
rs 4.5072
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
 * Copyright 2008 Google Inc.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
if (!class_exists('Google_Client')) {
19
  require_once dirname(__FILE__) . '/../autoload.php';
20
}
21
22
/**
23
 * Authentication class that deals with the OAuth 2 web-server authentication flow
24
 *
25
 */
26
class Google_Auth_OAuth2 extends Google_Auth_Abstract
27
{
28
  const OAUTH2_REVOKE_URI = 'https://accounts.google.com/o/oauth2/revoke';
29
  const OAUTH2_TOKEN_URI = 'https://accounts.google.com/o/oauth2/token';
30
  const OAUTH2_AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
31
  const CLOCK_SKEW_SECS = 300; // five minutes in seconds
32
  const AUTH_TOKEN_LIFETIME_SECS = 300; // five minutes in seconds
33
  const MAX_TOKEN_LIFETIME_SECS = 86400; // one day in seconds
34
  const OAUTH2_ISSUER = 'accounts.google.com';
35
36
  /** @var Google_Auth_AssertionCredentials $assertionCredentials */
37
  private $assertionCredentials;
38
39
  /**
40
   * @var string The state parameters for CSRF and other forgery protection.
41
   */
42
  private $state;
43
44
  /**
45
   * @var array The token bundle.
46
   */
47
  private $token = array();
48
49
  /**
50
   * @var Google_Client the base client
51
   */
52
  private $client;
53
54
  /**
55
   * Instantiates the class, but does not initiate the login flow, leaving it
56
   * to the discretion of the caller.
57
   */
58
  public function __construct(Google_Client $client)
59
  {
60
    $this->client = $client;
61
  }
62
63
  /**
64
   * Perform an authenticated / signed apiHttpRequest.
65
   * This function takes the apiHttpRequest, calls apiAuth->sign on it
66
   * (which can modify the request in what ever way fits the auth mechanism)
67
   * and then calls apiCurlIO::makeRequest on the signed request
68
   *
69
   * @param Google_Http_Request $request
70
   * @return Google_Http_Request The resulting HTTP response including the
71
   * responseHttpCode, responseHeaders and responseBody.
72
   */
73
  public function authenticatedRequest(Google_Http_Request $request)
74
  {
75
    $request = $this->sign($request);
76
    return $this->client->getIo()->makeRequest($request);
77
  }
78
79
  /**
80
   * @param string $code
81
   * @param boolean $crossClient
82
   * @throws Google_Auth_Exception
83
   * @return string
84
   */
85
  public function authenticate($code, $crossClient = false)
86
  {
87
    if (strlen($code) == 0) {
88
      throw new Google_Auth_Exception("Invalid code");
89
    }
90
91
    $arguments = array(
92
          'code' => $code,
93
          'grant_type' => 'authorization_code',
94
          'client_id' => $this->client->getClassConfig($this, 'client_id'),
95
          'client_secret' => $this->client->getClassConfig($this, 'client_secret')
96
    );
97
98
    if ($crossClient !== true) {
99
        $arguments['redirect_uri'] = $this->client->getClassConfig($this, 'redirect_uri');
100
    }
101
102
    // We got here from the redirect from a successful authorization grant,
103
    // fetch the access token
104
    $request = new Google_Http_Request(
105
        self::OAUTH2_TOKEN_URI,
106
        'POST',
107
        array(),
108
        $arguments
109
    );
110
    $request->disableGzip();
111
    $response = $this->client->getIo()->makeRequest($request);
112
113
    if ($response->getResponseHttpCode() == 200) {
114
      $this->setAccessToken($response->getResponseBody());
115
      $this->token['created'] = time();
116
      return $this->getAccessToken();
117
    } else {
118
      $decodedResponse = json_decode($response->getResponseBody(), true);
119
      if ($decodedResponse != null && $decodedResponse['error']) {
120
        $errorText = $decodedResponse['error'];
121
        if (isset($decodedResponse['error_description'])) {
122
          $errorText .= ": " . $decodedResponse['error_description'];
123
        }
124
      }
125
      throw new Google_Auth_Exception(
126
          sprintf(
127
              "Error fetching OAuth2 access token, message: '%s'",
128
              $errorText
129
          ),
130
          $response->getResponseHttpCode()
131
      );
132
    }
133
  }
134
135
  /**
136
   * Create a URL to obtain user authorization.
137
   * The authorization endpoint allows the user to first
138
   * authenticate, and then grant/deny the access request.
139
   * @param string $scope The scope is expressed as a list of space-delimited strings.
140
   * @return string
141
   */
142
  public function createAuthUrl($scope)
143
  {
144
    $params = array(
145
        'response_type' => 'code',
146
        'redirect_uri' => $this->client->getClassConfig($this, 'redirect_uri'),
147
        'client_id' => $this->client->getClassConfig($this, 'client_id'),
148
        'scope' => $scope,
149
        'access_type' => $this->client->getClassConfig($this, 'access_type'),
150
    );
151
152
    // Prefer prompt to approval prompt.
153
    if ($this->client->getClassConfig($this, 'prompt')) {
154
      $params = $this->maybeAddParam($params, 'prompt');
155
    } else {
156
      $params = $this->maybeAddParam($params, 'approval_prompt');
157
    }
158
    $params = $this->maybeAddParam($params, 'login_hint');
159
    $params = $this->maybeAddParam($params, 'hd');
160
    $params = $this->maybeAddParam($params, 'openid.realm');
161
    $params = $this->maybeAddParam($params, 'include_granted_scopes');
162
163
    // If the list of scopes contains plus.login, add request_visible_actions
164
    // to auth URL.
165
    $rva = $this->client->getClassConfig($this, 'request_visible_actions');
166
    if (strpos($scope, 'plus.login') && strlen($rva) > 0) {
167
        $params['request_visible_actions'] = $rva;
168
    }
169
170
    if (isset($this->state)) {
171
      $params['state'] = $this->state;
172
    }
173
174
    return self::OAUTH2_AUTH_URL . "?" . http_build_query($params, '', '&');
175
  }
176
177
  /**
178
   * @param string $token
179
   * @throws Google_Auth_Exception
180
   */
181 View Code Duplication
  public function setAccessToken($token)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
182
  {
183
    $token = json_decode($token, true);
184
    if ($token == null) {
185
      throw new Google_Auth_Exception('Could not json decode the token');
186
    }
187
    if (! isset($token['access_token'])) {
188
      throw new Google_Auth_Exception("Invalid token format");
189
    }
190
    $this->token = $token;
0 ignored issues
show
Documentation Bug introduced by
It seems like $token of type * is incompatible with the declared type array of property $token.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
191
  }
192
193
  public function getAccessToken()
194
  {
195
    return json_encode($this->token);
196
  }
197
198
  public function getRefreshToken()
199
  {
200
    if (array_key_exists('refresh_token', $this->token)) {
201
      return $this->token['refresh_token'];
202
    } else {
203
      return null;
204
    }
205
  }
206
207
  public function setState($state)
208
  {
209
    $this->state = $state;
210
  }
211
212
  public function setAssertionCredentials(Google_Auth_AssertionCredentials $creds)
213
  {
214
    $this->assertionCredentials = $creds;
215
  }
216
217
  /**
218
   * Include an accessToken in a given apiHttpRequest.
219
   * @param Google_Http_Request $request
220
   * @return Google_Http_Request
221
   * @throws Google_Auth_Exception
222
   */
223
  public function sign(Google_Http_Request $request)
224
  {
225
    // add the developer key to the request before signing it
226
    if ($this->client->getClassConfig($this, 'developer_key')) {
227
      $request->setQueryParam('key', $this->client->getClassConfig($this, 'developer_key'));
228
    }
229
230
    // Cannot sign the request without an OAuth access token.
231
    if (null == $this->token && null == $this->assertionCredentials) {
232
      return $request;
233
    }
234
235
    // Check if the token is set to expire in the next 30 seconds
236
    // (or has already expired).
237
    if ($this->isAccessTokenExpired()) {
238
      if ($this->assertionCredentials) {
239
        $this->refreshTokenWithAssertion();
240
      } else {
241
        $this->client->getLogger()->debug('OAuth2 access token expired');
242
        if (! array_key_exists('refresh_token', $this->token)) {
243
          $error = "The OAuth 2.0 access token has expired,"
244
                  ." and a refresh token is not available. Refresh tokens"
245
                  ." are not returned for responses that were auto-approved.";
246
247
          $this->client->getLogger()->error($error);
248
          throw new Google_Auth_Exception($error);
249
        }
250
        $this->refreshToken($this->token['refresh_token']);
251
      }
252
    }
253
254
    $this->client->getLogger()->debug('OAuth2 authentication');
255
256
    // Add the OAuth2 header to the request
257
    $request->setRequestHeaders(
258
        array('Authorization' => 'Bearer ' . $this->token['access_token'])
259
    );
260
261
    return $request;
262
  }
263
264
  /**
265
   * Fetches a fresh access token with the given refresh token.
266
   * @param string $refreshToken
267
   * @return void
268
   */
269
  public function refreshToken($refreshToken)
270
  {
271
    $this->refreshTokenRequest(
272
        array(
273
          'client_id' => $this->client->getClassConfig($this, 'client_id'),
274
          'client_secret' => $this->client->getClassConfig($this, 'client_secret'),
275
          'refresh_token' => $refreshToken,
276
          'grant_type' => 'refresh_token'
277
        )
278
    );
279
  }
280
281
  /**
282
   * Fetches a fresh access token with a given assertion token.
283
   * @param Google_Auth_AssertionCredentials $assertionCredentials optional.
284
   * @return void
285
   */
286
  public function refreshTokenWithAssertion($assertionCredentials = null)
287
  {
288
    if (!$assertionCredentials) {
289
      $assertionCredentials = $this->assertionCredentials;
290
    }
291
292
    $cacheKey = $assertionCredentials->getCacheKey();
293
294
    if ($cacheKey) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheKey of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
295
      // We can check whether we have a token available in the
296
      // cache. If it is expired, we can retrieve a new one from
297
      // the assertion.
298
      $token = $this->client->getCache()->get($cacheKey);
299
      if ($token) {
300
        $this->setAccessToken($token);
301
      }
302
      if (!$this->isAccessTokenExpired()) {
303
        return;
304
      }
305
    }
306
307
    $this->client->getLogger()->debug('OAuth2 access token expired');
308
    $this->refreshTokenRequest(
309
        array(
310
          'grant_type' => 'assertion',
311
          'assertion_type' => $assertionCredentials->assertionType,
312
          'assertion' => $assertionCredentials->generateAssertion(),
313
        )
314
    );
315
316
    if ($cacheKey) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheKey of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
317
      // Attempt to cache the token.
318
      $this->client->getCache()->set(
319
          $cacheKey,
320
          $this->getAccessToken()
321
      );
322
    }
323
  }
324
325
  private function refreshTokenRequest($params)
326
  {
327
    if (isset($params['assertion'])) {
328
      $this->client->getLogger()->info(
329
          'OAuth2 access token refresh with Signed JWT assertion grants.'
330
      );
331
    } else {
332
      $this->client->getLogger()->info('OAuth2 access token refresh');
333
    }
334
335
    $http = new Google_Http_Request(
336
        self::OAUTH2_TOKEN_URI,
337
        'POST',
338
        array(),
339
        $params
340
    );
341
    $http->disableGzip();
342
    $request = $this->client->getIo()->makeRequest($http);
343
344
    $code = $request->getResponseHttpCode();
345
    $body = $request->getResponseBody();
346
    if (200 == $code) {
347
      $token = json_decode($body, true);
348
      if ($token == null) {
349
        throw new Google_Auth_Exception("Could not json decode the access token");
350
      }
351
352
      if (! isset($token['access_token']) || ! isset($token['expires_in'])) {
353
        throw new Google_Auth_Exception("Invalid token format");
354
      }
355
356
      if (isset($token['id_token'])) {
357
        $this->token['id_token'] = $token['id_token'];
358
      }
359
      $this->token['access_token'] = $token['access_token'];
360
      $this->token['expires_in'] = $token['expires_in'];
361
      $this->token['created'] = time();
362
    } else {
363
      throw new Google_Auth_Exception("Error refreshing the OAuth2 token, message: '$body'", $code);
364
    }
365
  }
366
367
  /**
368
   * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
369
   * token, if a token isn't provided.
370
   * @throws Google_Auth_Exception
371
   * @param string|null $token The token (access token or a refresh token) that should be revoked.
372
   * @return boolean Returns True if the revocation was successful, otherwise False.
373
   */
374
  public function revokeToken($token = null)
375
  {
376
    if (!$token) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $token of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
377
      if (!$this->token) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->token of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
378
        // Not initialized, no token to actually revoke
379
        return false;
380
      } elseif (array_key_exists('refresh_token', $this->token)) {
381
        $token = $this->token['refresh_token'];
382
      } else {
383
        $token = $this->token['access_token'];
384
      }
385
    }
386
    $request = new Google_Http_Request(
387
        self::OAUTH2_REVOKE_URI,
388
        'POST',
389
        array(),
390
        "token=$token"
391
    );
392
    $request->disableGzip();
393
    $response = $this->client->getIo()->makeRequest($request);
394
    $code = $response->getResponseHttpCode();
395
    if ($code == 200) {
396
      $this->token = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $token.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
397
      return true;
398
    }
399
400
    return false;
401
  }
402
403
  /**
404
   * Returns if the access_token is expired.
405
   * @return bool Returns True if the access_token is expired.
406
   */
407 View Code Duplication
  public function isAccessTokenExpired()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
408
  {
409
    if (!$this->token || !isset($this->token['created'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->token of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
410
      return true;
411
    }
412
413
    // If the token is set to expire in the next 30 seconds.
414
    $expired = ($this->token['created']
415
        + ($this->token['expires_in'] - 30)) < time();
416
417
    return $expired;
418
  }
419
420
  // Gets federated sign-on certificates to use for verifying identity tokens.
421
  // Returns certs as array structure, where keys are key ids, and values
422
  // are PEM encoded certificates.
423
  private function getFederatedSignOnCerts()
424
  {
425
    return $this->retrieveCertsFromLocation(
426
        $this->client->getClassConfig($this, 'federated_signon_certs_url')
427
    );
428
  }
429
430
  /**
431
   * Retrieve and cache a certificates file.
432
   *
433
   * @param $url string location
434
   * @throws Google_Auth_Exception
435
   * @return array certificates
436
   */
437
  public function retrieveCertsFromLocation($url)
438
  {
439
    // If we're retrieving a local file, just grab it.
440
    if ("http" != substr($url, 0, 4)) {
441
      $file = file_get_contents($url);
442
      if ($file) {
443
        return json_decode($file, true);
444
      } else {
445
        throw new Google_Auth_Exception(
446
            "Failed to retrieve verification certificates: '" .
447
            $url . "'."
448
        );
449
      }
450
    }
451
452
    // This relies on makeRequest caching certificate responses.
453
    $request = $this->client->getIo()->makeRequest(
454
        new Google_Http_Request(
455
            $url
456
        )
457
    );
458
    if ($request->getResponseHttpCode() == 200) {
459
      $certs = json_decode($request->getResponseBody(), true);
460
      if ($certs) {
461
        return $certs;
462
      }
463
    }
464
    throw new Google_Auth_Exception(
465
        "Failed to retrieve verification certificates: '" .
466
        $request->getResponseBody() . "'.",
467
        $request->getResponseHttpCode()
468
    );
469
  }
470
471
  /**
472
   * Verifies an id token and returns the authenticated apiLoginTicket.
473
   * Throws an exception if the id token is not valid.
474
   * The audience parameter can be used to control which id tokens are
475
   * accepted.  By default, the id token must have been issued to this OAuth2 client.
476
   *
477
   * @param $id_token
478
   * @param $audience
479
   * @return Google_Auth_LoginTicket
480
   */
481
  public function verifyIdToken($id_token = null, $audience = null)
482
  {
483
    if (!$id_token) {
484
      $id_token = $this->token['id_token'];
485
    }
486
    $certs = $this->getFederatedSignonCerts();
487
    if (!$audience) {
488
      $audience = $this->client->getClassConfig($this, 'client_id');
489
    }
490
491
    return $this->verifySignedJwtWithCerts($id_token, $certs, $audience, self::OAUTH2_ISSUER);
492
  }
493
494
  /**
495
   * Verifies the id token, returns the verified token contents.
496
   *
497
   * @param $jwt string the token
498
   * @param $certs array of certificates
499
   * @param $required_audience string the expected consumer of the token
500
   * @param [$issuer] the expected issues, defaults to Google
501
   * @param [$max_expiry] the max lifetime of a token, defaults to MAX_TOKEN_LIFETIME_SECS
502
   * @throws Google_Auth_Exception
503
   * @return mixed token information if valid, false if not
504
   */
505
  public function verifySignedJwtWithCerts(
506
      $jwt,
507
      $certs,
508
      $required_audience,
509
      $issuer = null,
510
      $max_expiry = null
511
  ) {
512
    if (!$max_expiry) {
513
      // Set the maximum time we will accept a token for.
514
      $max_expiry = self::MAX_TOKEN_LIFETIME_SECS;
515
    }
516
517
    $segments = explode(".", $jwt);
518
    if (count($segments) != 3) {
519
      throw new Google_Auth_Exception("Wrong number of segments in token: $jwt");
520
    }
521
    $signed = $segments[0] . "." . $segments[1];
522
    $signature = Google_Utils::urlSafeB64Decode($segments[2]);
523
524
    // Parse envelope.
525
    $envelope = json_decode(Google_Utils::urlSafeB64Decode($segments[0]), true);
526
    if (!$envelope) {
527
      throw new Google_Auth_Exception("Can't parse token envelope: " . $segments[0]);
528
    }
529
530
    // Parse token
531
    $json_body = Google_Utils::urlSafeB64Decode($segments[1]);
532
    $payload = json_decode($json_body, true);
533
    if (!$payload) {
534
      throw new Google_Auth_Exception("Can't parse token payload: " . $segments[1]);
535
    }
536
537
    // Check signature
538
    $verified = false;
539
    foreach ($certs as $keyName => $pem) {
540
      $public_key = new Google_Verifier_Pem($pem);
541
      if ($public_key->verify($signed, $signature)) {
542
        $verified = true;
543
        break;
544
      }
545
    }
546
547
    if (!$verified) {
548
      throw new Google_Auth_Exception("Invalid token signature: $jwt");
549
    }
550
551
    // Check issued-at timestamp
552
    $iat = 0;
553
    if (array_key_exists("iat", $payload)) {
554
      $iat = $payload["iat"];
555
    }
556
    if (!$iat) {
557
      throw new Google_Auth_Exception("No issue time in token: $json_body");
558
    }
559
    $earliest = $iat - self::CLOCK_SKEW_SECS;
560
561
    // Check expiration timestamp
562
    $now = time();
563
    $exp = 0;
564
    if (array_key_exists("exp", $payload)) {
565
      $exp = $payload["exp"];
566
    }
567
    if (!$exp) {
568
      throw new Google_Auth_Exception("No expiration time in token: $json_body");
569
    }
570
    if ($exp >= $now + $max_expiry) {
571
      throw new Google_Auth_Exception(
572
          sprintf("Expiration time too far in future: %s", $json_body)
573
      );
574
    }
575
576
    $latest = $exp + self::CLOCK_SKEW_SECS;
577
    if ($now < $earliest) {
578
      throw new Google_Auth_Exception(
579
          sprintf(
580
              "Token used too early, %s < %s: %s",
581
              $now,
582
              $earliest,
583
              $json_body
584
          )
585
      );
586
    }
587
    if ($now > $latest) {
588
      throw new Google_Auth_Exception(
589
          sprintf(
590
              "Token used too late, %s > %s: %s",
591
              $now,
592
              $latest,
593
              $json_body
594
          )
595
      );
596
    }
597
598
    $iss = $payload['iss'];
599
    if ($issuer && $iss != $issuer) {
600
      throw new Google_Auth_Exception(
601
          sprintf(
602
              "Invalid issuer, %s != %s: %s",
603
              $iss,
604
              $issuer,
605
              $json_body
606
          )
607
      );
608
    }
609
610
    // Check audience
611
    $aud = $payload["aud"];
612
    if ($aud != $required_audience) {
613
      throw new Google_Auth_Exception(
614
          sprintf(
615
              "Wrong recipient, %s != %s:",
616
              $aud,
617
              $required_audience,
618
              $json_body
619
          )
620
      );
621
    }
622
623
    // All good.
624
    return new Google_Auth_LoginTicket($envelope, $payload);
625
  }
626
627
  /**
628
   * Add a parameter to the auth params if not empty string.
629
   */
630
  private function maybeAddParam($params, $name)
631
  {
632
    $param = $this->client->getClassConfig($this, $name);
633
    if ($param != '') {
634
      $params[$name] = $param;
635
    }
636
    return $params;
637
  }
638
}
639