-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Getting Started: Authenticate Users (#207)
- Loading branch information
Showing
10 changed files
with
350 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
vendor | ||
composer.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Authenticating users with PHP on Google Cloud Platform | ||
|
||
This directory contains the complete sample code for authenticating users with | ||
PHP on Google Cloud Platform. Follow the tutorial to run the code: | ||
|
||
* [Authenticating users on PHP][authenticate-users] | ||
|
||
[authenticate-users]: http://cloud.google.com/php/getting-started/authenticate-users |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
runtime: php72 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"require": { | ||
"php": ">=7.1", | ||
"google/cloud-core": "^1.32", | ||
"kelvinmo/simplejwt": "^0.2.5", | ||
"ralouphie/getallheaders": "^3.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
<?php | ||
/* | ||
* Copyright 2019 Google LLC | ||
* | ||
* 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. | ||
*/ | ||
|
||
# [START getting_started_auth_all] | ||
require_once __DIR__ . '/vendor/autoload.php'; | ||
|
||
# [START getting_started_auth_certs] | ||
/** | ||
* Returns a dictionary of current Google public key certificates for | ||
* validating Google-signed JWTs. | ||
*/ | ||
function certs() : string | ||
{ | ||
$client = new GuzzleHttp\Client(); | ||
$response = $client->get( | ||
'https://www.gstatic.com/iap/verify/public_key-jwk' | ||
); | ||
return $response->getBody(); | ||
} | ||
# [END getting_started_auth_certs] | ||
|
||
# [START getting_started_auth_audience] | ||
/** | ||
* Returns the audience value (the JWT 'aud' property) for the current | ||
* running instance. Since this involves a metadata lookup, the result is | ||
* cached when first requested for faster future responses. | ||
*/ | ||
function audience() : string | ||
{ | ||
$metadata = new Google\Cloud\Core\Compute\Metadata(); | ||
$projectNumber = $metadata->getNumericProjectId(); | ||
$projectId = $metadata->getProjectId(); | ||
$audience = sprintf('/projects/%s/apps/%s', $projectNumber, $projectId); | ||
return $audience; | ||
} | ||
# [END getting_started_auth_audience] | ||
|
||
# [START getting_started_auth_validate_assertion] | ||
/** | ||
* Checks that the JWT assertion is valid (properly signed, for the | ||
* correct audience) and if so, returns strings for the requesting user's | ||
* email and a persistent user ID. If not valid, returns null for each field. | ||
* | ||
* @param string $assertion The JWT string to assert. | ||
* @param string $certs The certificates to use for the assertion validation. | ||
* @param string $audience The required audience of the JWT. | ||
* @return array containing [$email, $id], or [null, null] on failed validation. | ||
*/ | ||
function validate_assertion(string $assertion, string $certs, string $audience) : array | ||
{ | ||
$jwkset = new SimpleJWT\Keys\KeySet(); | ||
$jwkset->load($certs); | ||
try { | ||
$info = SimpleJWT\JWT::decode( | ||
$assertion, | ||
$jwkset, | ||
'ES256' | ||
); | ||
if ($info->getClaim('aud') != $audience) { | ||
throw new Exception('Audience did not match'); | ||
} | ||
return [$info->getClaim('email'), $info->getClaim('sub')]; | ||
} catch (Exception $e) { | ||
printf('Failed to validate assertion: %s', $e->getMessage()); | ||
return [null, null]; | ||
} | ||
} | ||
# [END getting_started_auth_validate_assertion] | ||
|
||
# [START getting_started_auth_front_controller] | ||
/** | ||
* This is an example of a front controller for a flat file PHP site. Using a | ||
* static list provides security against URL injection by default. | ||
*/ | ||
switch (@parse_url($_SERVER['REQUEST_URI'])['path']) { | ||
case '/': | ||
$assertion = getallheaders()['X-Goog-Iap-Jwt-Assertion'] ?? ''; | ||
list($email, $id) = validate_assertion($assertion, certs(), audience()); | ||
if ($email) { | ||
printf("<h1>Hello %s</h1>", $email); | ||
} | ||
break; | ||
case ''; break; // Nothing to do, we're running our tests | ||
default: | ||
http_response_code(404); | ||
exit('Not Found'); | ||
} | ||
# [END getting_started_auth_front_controller] | ||
# [END getting_started_auth_all] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
Copyright 2019 Google LLC | ||
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. | ||
--> | ||
<phpunit bootstrap="vendor/autoload.php" convertWarningsToExceptions="false"> | ||
<testsuites> | ||
<testsuite name="PHP Authenticate Users Test Suite"> | ||
<directory>test</directory> | ||
</testsuite> | ||
</testsuites> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php | ||
/* | ||
* Copyright 2019 Google LLC | ||
* | ||
* 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. | ||
*/ | ||
|
||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* Test for the application controller. | ||
*/ | ||
class ControllersTest extends TestCase | ||
{ | ||
/** | ||
* Test private/public keys generated from http://jwt.io | ||
* | ||
* Private Key: | ||
* -----BEGIN PUBLIC KEY----- | ||
* MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9 | ||
* q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg== | ||
* -----END PUBLIC KEY----- | ||
* | ||
* Public Key: | ||
* -----BEGIN PRIVATE KEY----- | ||
* MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2 | ||
* OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r | ||
* 1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G | ||
* -----END PRIVATE KEY----- | ||
*/ | ||
private static $testCert = [ | ||
'kty' => 'EC', | ||
'crv' => 'P-256', | ||
'x' => 'EVs_o5-uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf84', | ||
'y' => 'kGe5DgSIycKp8w9aJmoHhB1sB3QTugfnRWm5nU_TzsY', | ||
'kid' => '19J8y7Z', | ||
]; | ||
|
||
public static function setUpBeforeClass() : void | ||
{ | ||
require_once __DIR__ . '/../index.php'; | ||
} | ||
|
||
public function testInvalidJwt() | ||
{ | ||
validate_assertion('fake_jwt', '{"keys":[]}', ''); | ||
$this->expectOutputRegex('/Failed to validate assertion: Cannot decode compact serialisation/'); | ||
} | ||
|
||
public function testInvalidAudience() | ||
{ | ||
$testAssertion = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImF1ZCI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiYXVkIjoiZm9vIiwiZW1haWwiOiJmb29AZ29vZ2xlLmNvbSJ9.rKr6N3u3inkeTIlVaJ24iIb_8C-x-WKcDw65cwaoxb27ZclFSFQktFCGLW1ochruuL0OD8-GViv1vOSyKpXb_g'; | ||
$testAudience = 'invalidaudience'; | ||
|
||
list($email, $id) = validate_assertion( | ||
$testAssertion, | ||
json_encode(['keys' => [self::$testCert]]), | ||
$testAudience | ||
); | ||
|
||
$this->expectOutputRegex('/Failed to validate assertion: Audience did not match/'); | ||
} | ||
|
||
public function testValidAssertion() | ||
{ | ||
$testAssertion = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImF1ZCI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiYXVkIjoiZm9vIiwiZW1haWwiOiJmb29AZ29vZ2xlLmNvbSJ9.rKr6N3u3inkeTIlVaJ24iIb_8C-x-WKcDw65cwaoxb27ZclFSFQktFCGLW1ochruuL0OD8-GViv1vOSyKpXb_g'; | ||
$testAudience = 'foo'; | ||
|
||
list($email, $id) = validate_assertion( | ||
$testAssertion, | ||
json_encode(['keys' => [self::$testCert]]), | ||
$testAudience | ||
); | ||
|
||
$this->assertEquals('[email protected]', $email); | ||
$this->assertEquals('1234567890', $id); | ||
$this->expectOutputRegex('//'); | ||
} | ||
|
||
public function testCerts() | ||
{ | ||
$certs = certs(); | ||
$this->assertTrue(false !== $json = json_decode($certs, true)); | ||
$this->assertArrayHasKey('keys', $json); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php | ||
/* | ||
* Copyright 2019 Google LLC | ||
* | ||
* 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. | ||
*/ | ||
|
||
use PHPUnit\Framework\TestCase; | ||
|
||
/** | ||
* Test for application controllers | ||
*/ | ||
class indexTest extends TestCase | ||
{ | ||
/** | ||
* Test private/public keys generated from http://jwt.io | ||
* | ||
* Private Key: | ||
* -----BEGIN PUBLIC KEY----- | ||
* MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9 | ||
* q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg== | ||
* -----END PUBLIC KEY----- | ||
* | ||
* Public Key: | ||
* -----BEGIN PRIVATE KEY----- | ||
* MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2 | ||
* OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r | ||
* 1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G | ||
* -----END PRIVATE KEY----- | ||
*/ | ||
private static $testCert = [ | ||
'kty' => 'EC', | ||
'crv' => 'P-256', | ||
'x' => 'EVs_o5-uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf84', | ||
'y' => 'kGe5DgSIycKp8w9aJmoHhB1sB3QTugfnRWm5nU_TzsY', | ||
'kid' => '19J8y7Z', | ||
]; | ||
|
||
public static function setUpBeforeClass() : void | ||
{ | ||
require_once __DIR__ . '/../index.php'; | ||
} | ||
|
||
public function testInvalidJwt() | ||
{ | ||
validate_assertion('fake_jwt', '{"keys":[]}', ''); | ||
$this->expectOutputRegex('/Failed to validate assertion: Cannot decode compact serialisation/'); | ||
} | ||
|
||
public function testInvalidAudience() | ||
{ | ||
$testAssertion = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImF1ZCI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiYXVkIjoiZm9vIiwiZW1haWwiOiJmb29AZ29vZ2xlLmNvbSJ9.rKr6N3u3inkeTIlVaJ24iIb_8C-x-WKcDw65cwaoxb27ZclFSFQktFCGLW1ochruuL0OD8-GViv1vOSyKpXb_g'; | ||
$testAudience = 'invalidaudience'; | ||
|
||
list($email, $id) = validate_assertion( | ||
$testAssertion, | ||
json_encode(['keys' => [self::$testCert]]), | ||
$testAudience | ||
); | ||
|
||
$this->expectOutputRegex('/Failed to validate assertion: Audience did not match/'); | ||
} | ||
|
||
public function testValidAssertion() | ||
{ | ||
$testAssertion = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImF1ZCI6ImZvbyJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiYXVkIjoiZm9vIiwiZW1haWwiOiJmb29AZ29vZ2xlLmNvbSJ9.rKr6N3u3inkeTIlVaJ24iIb_8C-x-WKcDw65cwaoxb27ZclFSFQktFCGLW1ochruuL0OD8-GViv1vOSyKpXb_g'; | ||
$testAudience = 'foo'; | ||
|
||
list($email, $id) = validate_assertion( | ||
$testAssertion, | ||
json_encode(['keys' => [self::$testCert]]), | ||
$testAudience | ||
); | ||
|
||
$this->assertEquals('[email protected]', $email); | ||
$this->assertEquals('1234567890', $id); | ||
$this->expectOutputRegex('//'); | ||
} | ||
|
||
public function testCerts() | ||
{ | ||
$certs = certs(); | ||
$this->assertTrue(false !== $json = json_decode($certs, true)); | ||
$this->assertArrayHasKey('keys', $json); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Getting Started with PHP on Google Cloud Platform | ||
|
||
This directory contains the code for deploying a basic PHP app to Google Cloud | ||
Platform. Follow the tutorial to use this sample. | ||
|
||
* [Getting started with PHP][getting-started] | ||
|
||
[getting-started]: http://cloud.google.com/php/getting-started |