Skip to content

Commit

Permalink
Merge pull request #75 from google/add-appidentity-subscriber
Browse files Browse the repository at this point in the history
adds AppIdentityCredentials
  • Loading branch information
bshaffer committed Oct 9, 2015
2 parents 213ca87 + 4e1a0f3 commit 5dc5bcb
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 3 deletions.
119 changes: 119 additions & 0 deletions src/AppIdentityCredentials.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php
/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Auth;

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Client;

/**
* The AppIdentityService class is automatically defined on App Engine,
* so including this dependency is not necessary, and will result in a
* PHP fatal error in the App Engine environment.
*/
use google\appengine\api\app_identity\AppIdentityService;

/**
* AppIdentityCredentials supports authorization on Google App Engine.
*
* It can be used to authorize requests using the AuthTokenFetcher, but will
* only succeed if being run on App Engine:
*
* use GuzzleHttp\Client;
* use Google\Auth\AppIdentityCredentials;
* use Google\Auth\AuthTokenFetcher;
*
* $gae = new AppIdentityCredentials('https://www.googleapis.com/auth/books');
* $subscriber = new AuthTokenFetcher($gae);
* $client = new Client([
* 'base_url' => 'https://www.googleapis.com/books/v1',
* 'defaults' => ['auth' => 'google_auth']
* ]);
* $client->setDefaultOption('verify', '/etc/ca-certificates.crt');
* $client->getEmitter()->attach($subscriber);
* $res = $client->get('volumes?q=Henry+David+Thoreau&country=US');
*
* In Guzzle 5 and below, the App Engine certificates need to be set on the
* guzzle client in order for SSL requests to succeed.
*
* $client->setDefaultOption('verify', '/etc/ca-certificates.crt');
*/
class AppIdentityCredentials extends CredentialsLoader
{
private $scope;

public function __construct($scope = array())
{
$this->scope = $scope;
}

/**
* Determines if this an App Engine instance, by accessing the SERVER_SOFTWARE
* environment variable.
*
* @return true if this an App Engine Instance, false otherwise
*/
public static function onAppEngine()
{
return (isset($_SERVER['SERVER_SOFTWARE']) &&
strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine') !== false);
}

/**
* Implements FetchAuthTokenInterface#fetchAuthToken.
*
* Fetches the auth tokens using the AppIdentityService if available.
* As the AppIdentityService uses protobufs to fetch the access token,
* the GuzzleHttp\ClientInterface instance passed in will not be used.
*
* @param $client GuzzleHttp\ClientInterface optional client.
* @return array the auth metadata:
* array(2) {
* ["access_token"]=>
* string(3) "xyz"
* ["expiration_time"]=>
* string(10) "1444339905"
* }
*/
public function fetchAuthToken(ClientInterface $unusedClient = null)
{
if (!self::onAppEngine()) {
return array();
}

if (!class_exists('google\appengine\api\app_identity\AppIdentityService')) {
throw new \Exception(
'This class must be run in App Engine, or you must include the AppIdentityService '
. 'mock class defined in tests/mocks/AppIdentityService.php'
);
}

$token = AppIdentityService::getAccessToken($this->scope);

return $token;
}

/**
* Implements FetchAuthTokenInterface#getCacheKey.
*
* @return 'GOOGLE_AUTH_PHP_APPIDENTITY'
*/
public function getCacheKey()
{
return 'GOOGLE_AUTH_PHP_APPIDENTITY';
}
}
9 changes: 6 additions & 3 deletions src/ApplicationDefaultCredentials.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,13 @@ public static function getCredentials($scope = null, $client = null)
if (!is_null($creds)) {
return $creds;
}
if (!GCECredentials::onGce($client)) {
throw new \DomainException(self::notFound());
if (AppIdentityCredentials::onAppEngine()) {
return new AppIdentityCredentials($scope);
}
return new GCECredentials();
if (GCECredentials::onGce($client)) {
return new GCECredentials();
}
throw new \DomainException(self::notFound());
}

private static function notFound()
Expand Down
86 changes: 86 additions & 0 deletions tests/AppIndentityCredentialsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
/*
* Copyright 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Auth\Tests;

use Google\Auth\AppIdentityCredentials;
use GuzzleHttp\Client;
use GuzzleHttp\Message\Response;
use GuzzleHttp\Stream\Stream;
use GuzzleHttp\Subscriber\Mock;

// included from tests\mocks\AppIdentityService.php
use google\appengine\api\app_identity\AppIdentityService;

class AppIdentityCredentialsOnAppEngineTest extends \PHPUnit_Framework_TestCase
{
public function testIsFalseByDefault()
{
$this->assertFalse(AppIdentityCredentials::onAppEngine());
}

public function testIsTrueWhenServerSoftwareIsGoogleAppEngine()
{
$_SERVER['SERVER_SOFTWARE'] = 'Google App Engine';
$this->assertTrue(AppIdentityCredentials::onAppEngine());
}
}

class AppIdentityCredentialsGetCacheKeyTest extends \PHPUnit_Framework_TestCase
{
public function testShouldNotBeEmpty()
{
$g = new AppIdentityCredentials();
$this->assertNotEmpty($g->getCacheKey());
}
}

class AppIdentityCredentialsFetchAuthTokenTest extends \PHPUnit_Framework_TestCase
{
public function testShouldBeEmptyIfNotOnAppEngine()
{
$g = new AppIdentityCredentials();
$this->assertEquals(array(), $g->fetchAuthToken());
}

/* @expectedException */
public function testTHrowsExceptionIfClassDoesntExist()
{
$_SERVER['SERVER_SOFTWARE'] = 'Google App Engine';
$g = new AppIdentityCredentials();
}

public function testReturnsExpectedToken()
{
// include the mock AppIdentityService class
require_once __DIR__ . '/mocks/AppIdentityService.php';

$wantedToken = [
'access_token' => '1/abdef1234567890',
'expires_in' => '57',
'token_type' => 'Bearer',
];

AppIdentityService::$accessToken = $wantedToken;

// AppIdentityService::$accessToken = $wantedToken;
$_SERVER['SERVER_SOFTWARE'] = 'Google App Engine';

$g = new AppIdentityCredentials();
$this->assertEquals($wantedToken, $g->fetchAuthToken());
}
}
16 changes: 16 additions & 0 deletions tests/mocks/AppIdentityService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace google\appengine\api\app_identity;

class AppIdentityService
{
public static $accessToken = array(
'access_token' => 'xyz',
'expiration_time' => '2147483646',
);

public static function getAccessToken($scope)
{
return self::$accessToken;
}
}

0 comments on commit 5dc5bcb

Please sign in to comment.