Skip to content

Commit e18f820

Browse files
committed
endpoints PHP example and tests (GoogleCloudPlatform#95)
1 parent 7ee3f97 commit e18f820

File tree

16 files changed

+1994
-0
lines changed

16 files changed

+1994
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
endpoints
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
/**
3+
* Copyright 2015 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+
namespace Google\Cloud\Samples\Appengine\Endpoints;
19+
20+
use Google\Auth\OAuth2;
21+
use GuzzleHttp\Client as HttpClient;
22+
use Symfony\Component\Console\Command\Command;
23+
use Symfony\Component\Console\Helper\QuestionHelper;
24+
use Symfony\Component\Console\Input\InputInterface;
25+
use Symfony\Component\Console\Input\InputOption;
26+
use Symfony\Component\Console\Input\InputArgument;
27+
use Symfony\Component\Console\Output\OutputInterface;
28+
use Symfony\Component\Console\Question\Question;
29+
30+
class EndpointsCommand extends Command
31+
{
32+
protected function configure()
33+
{
34+
$this
35+
->setName('make-request')
36+
->setDescription('Send in a request to endpoints')
37+
->addArgument(
38+
'host',
39+
InputArgument::REQUIRED,
40+
'Your API host, e.g. https://your-project.appspot.com.'
41+
)
42+
->addArgument(
43+
'api_key',
44+
InputArgument::REQUIRED,
45+
'Your API key.'
46+
)
47+
->addArgument(
48+
'credentials',
49+
InputArgument::OPTIONAL,
50+
'The path to your credentials file. This can be service account credentials, client secrets, or omitted.'
51+
)
52+
->addOption(
53+
'message',
54+
'm',
55+
InputOption::VALUE_REQUIRED,
56+
'The message to send in',
57+
'TEST MESSAGE (change this with -m)'
58+
);
59+
}
60+
61+
protected function execute(InputInterface $input, OutputInterface $output)
62+
{
63+
$api_key = $input->getArgument('api_key');
64+
$host = $input->getArgument('host');
65+
$message = $input->getOption('message');
66+
67+
$http = new HttpClient(['base_uri' => $host]);
68+
$headers = [];
69+
$body = null;
70+
71+
if ($credentials = $input->getArgument('credentials')) {
72+
if (!file_exists($credentials)) {
73+
throw new InvalidArgumentException('file does not exist');
74+
}
75+
if (!$config = json_decode(file_get_contents($credentials), true)) {
76+
throw new LogicException('invalid json for auth config');
77+
}
78+
79+
$oauth = new OAuth2([
80+
'issuer' => 'jwt-client.endpoints.sample.google.com',
81+
'audience' => 'echo.endpoints.sample.google.com',
82+
'scope' => 'email',
83+
'authorizationUri' => 'https://accounts.google.com/o/oauth2/auth',
84+
'tokenCredentialUri' => 'https://www.googleapis.com/oauth2/v4/token',
85+
]);
86+
87+
if (isset($config['type']) && $config['type'] == 'service_account') {
88+
// return the "jwt" info from the request
89+
$method = 'GET';
90+
$path = '/auth/info/googlejwt';
91+
92+
$oauth->setSub('123456');
93+
$oauth->setSigningKey($config['private_key']);
94+
$oauth->setSigningAlgorithm('RS256');
95+
$oauth->setClientId($config['client_id']);
96+
$jwt = $oauth->toJwt();
97+
98+
$headers['Authorization'] = sprintf('Bearer %s', $jwt);
99+
} else {
100+
// return the "idtoken" info from the request
101+
$method = 'GET';
102+
$path = '/auth/info/googleidtoken';
103+
104+
// open the URL
105+
$oauth->setClientId($config['installed']['client_id']);
106+
$oauth->setClientSecret($config['installed']['client_secret']);
107+
$oauth->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
108+
$authUrl = $oauth->buildFullAuthorizationUri(['access_type' => 'offline']);
109+
`open '$authUrl'`;
110+
111+
// prompt for the auth code
112+
$q = new Question('Please enter the authorization code:');
113+
$helper = new QuestionHelper();
114+
$authCode = $helper->ask($input, $output, $q);
115+
$oauth->setCode($authCode);
116+
117+
$token = $oauth->fetchAuthToken();
118+
if (empty($token['id_token'])) {
119+
return $output->writeln("<error>unable to retrieve ID token</error>");
120+
}
121+
$headers['Authorization'] = sprintf('Bearer %s', $token['id_token']);
122+
}
123+
} else {
124+
// return just the message we sent in
125+
$method = 'POST';
126+
$path = '/echo';
127+
$body = json_encode([ 'message' => $message ]);
128+
$headers['Content-Type'] = 'application/json';
129+
}
130+
131+
$output->writeln(sprintf('requesting "%s"...', $path));
132+
133+
$response = $http->request($method, $path, [
134+
'query' => ['key' => $api_key],
135+
'body' => $body,
136+
'headers' => $headers
137+
]);
138+
139+
$output->writeln((string) $response->getBody());
140+
}
141+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Google Cloud Endpoints & App Engine Flexible Environment & PHP
2+
3+
This sample demonstrates how to use Google Cloud Endpoints on Google App Engine Flexible Environment using PHP.
4+
5+
This sample consists of two parts:
6+
7+
1. The backend
8+
2. The clients
9+
10+
## Running locally
11+
12+
### Running the backend
13+
14+
For more info on running Flexible applications locally, see [the getting started documentation](https://cloud.google.com/php/getting-started/hello-world).
15+
16+
Install all the dependencies:
17+
18+
$ composer install
19+
20+
Run the application:
21+
22+
$ php -S localhost:8080
23+
24+
In your web browser, go to the following address: http://localhost:8080.
25+
26+
### Using the echo client
27+
28+
With the app running locally, you can execute the simple echo client using:
29+
30+
$ php endpoints.php make-request http://localhost:8080 APIKEY
31+
32+
The `APIKEY` can be any string as the local endpoint proxy doesn't need authentication.
33+
34+
## Deploying to Google App Engine
35+
36+
Open the `swagger.yaml` file and in the `host` property, replace
37+
`YOUR-PROJECT-ID` with your project's ID.
38+
39+
Then, deploy the sample using `gcloud`:
40+
41+
gcloud preview app deploy
42+
43+
Once deployed, you can access the application at https://YOUR-PROJECT-ID.appspot.com/
44+
or run the command `gcloud preview app browse`.
45+
46+
### Using the echo client
47+
48+
With the project deployed, you'll need to create an API key to access the API.
49+
50+
1. Open the Credentials page of the API Manager in the [Cloud Console](https://console.cloud.google.com/apis/credentials).
51+
2. Click 'Create credentials'.
52+
3. Select 'API Key'.
53+
4. Choose 'Server Key'
54+
55+
With the API key, you can use the echo client to access the API:
56+
57+
$ php endpoints.php make-request https://YOUR-PROJECT-ID.appspot.com YOUR-API-KEY
58+
59+
### Using the JWT client.
60+
61+
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:
62+
63+
1. Open the Credentials page of the API Manager in the [Cloud Console](https://console.cloud.google.com/apis/credentials).
64+
2. Click 'Create credentials'.
65+
3. Select 'Service account key'.
66+
4. In the 'Select service account' dropdown, select 'Create new service account'.
67+
5. Choose 'JSON' for the key type.
68+
69+
To use the service account for authentication:
70+
71+
1. Update the `google_jwt`'s `x-jwks_uri` in `swagger.yaml` with your service account's email address.
72+
2. Redeploy your application.
73+
74+
Now you can use the JWT client to make requests to the API:
75+
76+
$ php endpoints.php make-request https://YOUR-PROJECT-ID.appspot.com YOUR-API-KEY /path/to/service-account.json
77+
78+
### Using the ID Token client.
79+
80+
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:
81+
82+
1. Open the Credentials page of the API Manager in the [Cloud Console](https://console.cloud.google.com/apis/credentials).
83+
2. Click 'Create credentials'.
84+
3. Select 'OAuth client ID'.
85+
4. Choose 'Other' for the application type.
86+
87+
To use the client ID for authentication:
88+
89+
1. Update the `/auth/info/googleidtoken`'s `audiences` in `swagger.yaml` with your client ID.
90+
2. Redeploy your application.
91+
92+
Now you can use the client ID to make requests to the API:
93+
94+
$ php endpoints.php make-request https://YOUR-PROJECT-ID.appspot.com YOUR-API-KEY /path/to/client-secrets.json
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
/**
3+
* Copyright 2015 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+
/**
19+
* Google Cloud Endpoints sample application.
20+
*
21+
* Demonstrates how to create a simple echo API as well as how to deal with
22+
* various authentication methods.
23+
*/
24+
25+
use Silex\Application;
26+
use Silex\Provider\TwigServiceProvider;
27+
use Symfony\Component\HttpFoundation\Request;
28+
use Symfony\Component\Yaml\Yaml;
29+
30+
// create the Silex application
31+
$app = new Application();
32+
$app->register(new TwigServiceProvider());
33+
$app['twig.path'] = [ __DIR__ ];
34+
35+
$app->get('/', function () use ($app) {
36+
/** @var Twig_Environment $twig */
37+
$twig = $app['twig'];
38+
39+
// Shows the index page
40+
return $app['twig']->render('endpoints.html.twig');
41+
});
42+
43+
$app->get('/api-docs', function () use ($app) {
44+
// Serves up the Swagger spec for the API.
45+
$swaggerText = file_get_contents(__DIR__ . '/swagger.yaml');
46+
$swaggerArray = Yaml::parse($swaggerText);
47+
48+
return $app->json($swaggerArray);
49+
});
50+
51+
$app->post('/echo', function () use ($app) {
52+
// Simple echo service.
53+
$message = $app['request']->get('message');
54+
return $app->json(['message' => $message]);
55+
});
56+
57+
$app->get('/auth/info/googlejwt', function () use ($app) {
58+
// Auth info with Google signed JWT.
59+
return $app->json($app['auth_info']);
60+
});
61+
62+
63+
$app->get('/auth/info/googleidtoken', function () use ($app) {
64+
// Auth info with Google ID token.
65+
return $app->json($app['auth_info']);
66+
});
67+
68+
$app['auth_info'] = function () use ($app) {
69+
/** @var Symfony\Component\HttpFoundation\Request $request */
70+
$request = $app['request'];
71+
// Retrieves the authenication information from Google Cloud Endpoints.
72+
$encoded_info = $request->headers->get('X-Endpoint-API-UserInfo');
73+
74+
if ($encoded_info) {
75+
$info_json = utf8_decode(base64_decode($encoded_info));
76+
$user_info = json_decode($info_json);
77+
} else {
78+
$user_info = ['id' => 'anonymous'];
79+
}
80+
81+
return $user_info;
82+
};
83+
84+
// Accept JSON requests
85+
$app->before(function (Request $request) {
86+
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
87+
$data = json_decode($request->getContent(), true);
88+
$request->request->replace(is_array($data) ? $data : array());
89+
}
90+
});
91+
92+
return $app;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
runtime: php
2+
vm: true
3+
4+
beta_settings:
5+
# Enable Google Cloud Endpoints API management.
6+
use_endpoints_api_management: true
7+
# Specify the Swagger API specification.
8+
endpoints_swagger_spec_file: swagger.yaml
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"require": {
3+
"silex/silex": " ^1.3",
4+
"twig/twig": "~1.8|~2.0",
5+
"symfony/twig-bridge": " ~2.7|3.0.*",
6+
"symfony/yaml": "^3.0",
7+
"symfony/console": " ^3.0",
8+
"google/auth": " 0.7"
9+
},
10+
"require-dev": {
11+
"symfony/browser-kit": " ^3.0"
12+
},
13+
"autoload": {
14+
"psr-4": {
15+
"Google\\Cloud\\Samples\\Appengine\\Endpoints\\": ""
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)