Skip to content

Commit

Permalink
endpoints PHP example and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bshaffer committed Apr 28, 2016
1 parent bbb4790 commit f2199fe
Show file tree
Hide file tree
Showing 17 changed files with 1,999 additions and 0 deletions.
1 change: 1 addition & 0 deletions appengine/flexible/endpoints/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
endpoints
6 changes: 6 additions & 0 deletions appengine/flexible/endpoints/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This file will go away once gcloud implements fingerprinting.
FROM gcr.io/php-mvm-a/php-nginx:latest

# The docker image will configure the document root according to this
# environment variable.
ENV DOCUMENT_ROOT /app
141 changes: 141 additions & 0 deletions appengine/flexible/endpoints/EndpointsCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?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\Cloud\Samples\Appengine\Endpoints;

use Google\Auth\OAuth2;
use GuzzleHttp\Client as HttpClient;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\Question;

class EndpointsCommand extends Command
{
protected function configure()
{
$this
->setName('make-request')
->setDescription('Send in a request to endpoints')
->addArgument(
'host',
InputArgument::REQUIRED,
'Your API host, e.g. https://your-project.appspot.com.'
)
->addArgument(
'api_key',
InputArgument::REQUIRED,
'Your API key.'
)
->addArgument(
'credentials',
InputArgument::OPTIONAL,
'The path to your credentials file. This can be service account credentials, client secrets, or omitted.'
)
->addOption(
'message',
'm',
InputOption::VALUE_REQUIRED,
'The message to send in',
'TEST MESSAGE (change this with -m)'
);
}

protected function execute(InputInterface $input, OutputInterface $output)
{
$api_key = $input->getArgument('api_key');
$host = $input->getArgument('host');
$message = $input->getOption('message');

$http = new HttpClient(['base_uri' => $host]);
$headers = [];
$body = null;

if ($credentials = $input->getArgument('credentials')) {
if (!file_exists($credentials)) {
throw new InvalidArgumentException('file does not exist');
}
if (!$config = json_decode(file_get_contents($credentials), true)) {
throw new LogicException('invalid json for auth config');
}

$oauth = new OAuth2([
'issuer' => 'jwt-client.endpoints.sample.google.com',
'audience' => 'echo.endpoints.sample.google.com',
'scope' => 'email',
'authorizationUri' => 'https://accounts.google.com/o/oauth2/auth',
'tokenCredentialUri' => 'https://www.googleapis.com/oauth2/v4/token',
]);

if (isset($config['type']) && $config['type'] == 'service_account') {
// return the "jwt" info from the request
$method = 'GET';
$path = '/auth/info/googlejwt';

$oauth->setSub('123456');
$oauth->setSigningKey($config['private_key']);
$oauth->setSigningAlgorithm('RS256');
$oauth->setClientId($config['client_id']);
$jwt = $oauth->toJwt();

$headers['Authorization'] = sprintf('Bearer %s', $jwt);
} else {
// return the "idtoken" info from the request
$method = 'GET';
$path = '/auth/info/googleidtoken';

// open the URL
$oauth->setClientId($config['installed']['client_id']);
$oauth->setClientSecret($config['installed']['client_secret']);
$oauth->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
$authUrl = $oauth->buildFullAuthorizationUri(['access_type' => 'offline']);
`open '$authUrl'`;

// prompt for the auth code
$q = new Question('Please enter the authorization code:');
$helper = new QuestionHelper();
$authCode = $helper->ask($input, $output, $q);
$oauth->setCode($authCode);

$token = $oauth->fetchAuthToken();
if (empty($token['id_token'])) {
return $output->writeln("<error>unable to retrieve ID token</error>");
}
$headers['Authorization'] = sprintf('Bearer %s', $token['id_token']);
}
} else {
// return just the message we sent in
$method = 'POST';
$path = '/echo';
$body = json_encode([ 'message' => $message ]);
$headers['Content-Type'] = 'application/json';
}

$output->writeln(sprintf('requesting "%s"...', $path));

$response = $http->request($method, $path, [
'query' => ['key' => $api_key],
'body' => $body,
'headers' => $headers
]);

$output->writeln((string) $response->getBody());
}
}
93 changes: 93 additions & 0 deletions appengine/flexible/endpoints/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Google Cloud Endpoints & App Engine Flexible Environment & PHP

This sample demonstrates how to use Google Cloud Endpoints on Google App Engine Flexible Environment using PHP.

This sample consists of two parts:

1. The backend
2. The clients

## Running locally

### Running the backend

For more info on running Flexible applications locally, see [the getting started documentation](https://cloud.google.com/php/getting-started/hello-world).

Install all the dependencies:

$ composer install

Run the application:

$ php -S localhost:8080

In your web browser, go to the following address: http://localhost:8080.

### Using the echo client

With the app running locally, you can execute the simple echo client using:

$ php endpoints.php make-request http://localhost:8080 APIKEY

The `APIKEY` doesn't matter as the endpoint proxy is not running to do authentication.

## Deploying to Google App Engine

Open the `swagger.yaml` file and in the `host` property, replace
`YOUR-PROJECT-ID` with your project's ID.

Then, deploy the sample using `gcloud`:

gcloud preview app deploy app.yaml

Once deployed, you can access the application at https://YOUR-PROJECT-ID.appspot.com/.

### Using the echo client

With the project deployed, you'll need to create an API key to access the API.

1. Open the Credentials page of the API Manager in the [Cloud Console](https://console.cloud.google.com/apis/credentials).
2. Click 'Create credentials'.
3. Select 'API Key'.
4. Choose 'Server Key'

With the API key, you can use the echo client to access the API:

$ php endpoints.php make-request https://YOUR-PROJECT-ID.appspot.com YOUR-API-KEY

### Using the JWT client.

The JWT client demonstrates how to use service accounts to authenticate to endpoints. To use the client, you'll need both an API key (as described in the echo client section) and a service account. To create a service account:

1. Open the Credentials page of the API Manager in the [Cloud Console](https://console.cloud.google.com/apis/credentials).
2. Click 'Create credentials'.
3. Select 'Service account key'.
4. In the 'Select service account' dropdown, select 'Create new service account'.
5. Choose 'JSON' for the key type.

To use the service account for authentication:

1. Update the `google_jwt`'s `x-jwks_uri` in `swagger.yaml` with your service account's email address.
2. Redeploy your application.

Now you can use the JWT client to make requests to the API:

$ php endpoints.php make-request https://YOUR-PROJECT-ID.appspot.com YOUR-API-KEY /path/to/service-account.json

### Using the ID Token client.

The ID Token client demonstrates how to use user credentials to authenticate to endpoints. To use the client, you'll need both an API key (as described in the echo client section) and a OAuth2 client ID. To create a client ID:

1. Open the Credentials page of the API Manager in the [Cloud Console](https://console.cloud.google.com/apis/credentials).
2. Click 'Create credentials'.
3. Select 'OAuth client ID'.
4. Choose 'Other' for the application type.

To use the client ID for authentication:

1. Update the `/auth/info/googleidtoken`'s `audiences` in `swagger.yaml` with your client ID.
2. Redeploy your application.

Now you can use the client ID to make requests to the API:

$ php endpoints.php make-request https://YOUR-PROJECT-ID.appspot.com YOUR-API-KEY /path/to/client-secrets.json
92 changes: 92 additions & 0 deletions appengine/flexible/endpoints/app.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?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.
*/

/**
* Google Cloud Endpoints sample application.
*
* Demonstrates how to create a simple echo API as well as how to deal with
* various authentication methods.
*/

use Silex\Application;
use Silex\Provider\TwigServiceProvider;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Yaml\Yaml;

// create the Silex application
$app = new Application();
$app->register(new TwigServiceProvider());
$app['twig.path'] = [ __DIR__ ];

$app->get('/', function () use ($app) {
/** @var Twig_Environment $twig */
$twig = $app['twig'];

// Shows the index page
return $app['twig']->render('endpoints.html.twig');
});

$app->get('/api-docs', function () use ($app) {
// Serves up the Swagger spec for the API.
$swaggerText = file_get_contents(__DIR__ . '/swagger.yaml');
$swaggerArray = Yaml::parse($swaggerText);

return $app->json($swaggerArray);
});

$app->post('/echo', function () use ($app) {
// Simple echo service.
$message = $app['request']->get('message');
return $app->json(['message' => $message]);
});

$app->get('/auth/info/googlejwt', function () use ($app) {
// Auth info with Google signed JWT.
return $app->json($app['auth_info']);
});


$app->get('/auth/info/googleidtoken', function () use ($app) {
// Auth info with Google ID token.
return $app->json($app['auth_info']);
});

$app['auth_info'] = function () use ($app) {
/** @var Symfony\Component\HttpFoundation\Request $request */
$request = $app['request'];
// Retrieves the authenication information from Google Cloud Endpoints.
$encoded_info = $request->headers->get('X-Endpoint-API-UserInfo');

if ($encoded_info) {
$info_json = utf8_decode(base64_decode($encoded_info));
$user_info = json_decode($info_json);
} else {
$user_info = ['id' => 'anonymous'];
}

return $user_info;
};

// Accept JSON requests
$app->before(function (Request $request) {
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
$data = json_decode($request->getContent(), true);
$request->request->replace(is_array($data) ? $data : array());
}
});

return $app;
8 changes: 8 additions & 0 deletions appengine/flexible/endpoints/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
runtime: custom
vm: true

beta_settings:
# Enable Google Cloud Endpoints API management.
use_endpoints_api_management: true
# Specify the Swagger API specification.
endpoints_swagger_spec_file: swagger.yaml
18 changes: 18 additions & 0 deletions appengine/flexible/endpoints/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"require": {
"silex/silex": " ^1.3",
"twig/twig": "~1.8|~2.0",
"symfony/twig-bridge": " ~2.7|3.0.*",
"symfony/yaml": "^3.0",
"symfony/console": " ^3.0",
"google/auth": " 0.7"
},
"require-dev": {
"symfony/browser-kit": " ^3.0"
},
"autoload": {
"psr-4": {
"Google\\Cloud\\Samples\\Appengine\\Endpoints\\": ""
}
}
}
Loading

0 comments on commit f2199fe

Please sign in to comment.