signer = new Google_Signer_P12( file_get_contents(__DIR__.'/'.self::PRIVATE_KEY_FILE, true), "notasecret" ); $this->pem = file_get_contents(__DIR__.'/'.self::PUBLIC_KEY_FILE, true); $this->verifier = new Google_Verifier_Pem($this->pem); } public function testDirectInject() { $privateKeyString = <<fail("Should have thrown"); } catch (Google_Auth_Exception $e) { $this->assertContains("mac verify failure", $e->getMessage()); } try { new Google_Signer_P12( file_get_contents(__DIR__.'/'.self::PRIVATE_KEY_FILE, true) . "foo", "badpassword" ); $this->fail("Should have thrown"); } catch (Exception $e) { $this->assertContains("Unable to parse", $e->getMessage()); } } public function testVerifySignature() { $binary_data = "\x00\x01\x02\x66\x6f\x6f"; $signature = $this->signer->sign($binary_data); $this->assertTrue($this->verifier->verify($binary_data, $signature)); $empty_string = ""; $signature = $this->signer->sign($empty_string); $this->assertTrue($this->verifier->verify($empty_string, $signature)); $text = "foobar"; $signature = $this->signer->sign($text); $this->assertTrue($this->verifier->verify($text, $signature)); $this->assertFalse($this->verifier->verify($empty_string, $signature)); } // Creates a signed JWT similar to the one created by google authentication. private function makeSignedJwt($payload) { $header = array("typ" => "JWT", "alg" => "RS256"); $segments = array(); $segments[] = Google_Utils::urlSafeB64Encode(json_encode($header)); $segments[] = Google_Utils::urlSafeB64Encode(json_encode($payload)); $signing_input = implode(".", $segments); $signature = $this->signer->sign($signing_input); $segments[] = Google_Utils::urlSafeB64Encode($signature); return implode(".", $segments); } // Returns certificates similar to the ones used by google authentication. private function getSignonCerts() { return array("keyid" => $this->pem); } public function testVerifySignedJwtWithCerts() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "sub" => self::USER_ID, "iat" => time(), "exp" => time() + 3600 ) ); $certs = $this->getSignonCerts(); $oauth2 = new Google_Auth_OAuth2($this->getClient()); $ticket = $oauth2->verifySignedJwtWithCerts($id_token, $certs, "client_id"); $this->assertEquals(self::USER_ID, $ticket->getUserId()); // Check that payload and envelope got filled in. $attributes = $ticket->getAttributes(); $this->assertEquals("JWT", $attributes["envelope"]["typ"]); $this->assertEquals("client_id", $attributes["payload"]["aud"]); } // Checks that the id token fails to verify with the expected message. private function checkIdTokenFailure($id_token, $msg, $issuer = null) { $certs = $this->getSignonCerts(); $oauth2 = new Google_Auth_OAuth2($this->getClient()); try { $oauth2->verifySignedJwtWithCerts($id_token, $certs, "client_id", $issuer); $this->fail("Should have thrown for $id_token"); } catch (Google_Auth_Exception $e) { $this->assertContains($msg, $e->getMessage()); } } public function testVerifySignedJwtWithMultipleIssuers() { $id_token = $this->makeSignedJwt( array( "iss" => "system.gserviceaccount.com", "aud" => "client_id", "sub" => self::USER_ID, "iat" => time(), "exp" => time() + 3600 ) ); $certs = $this->getSignonCerts(); $oauth2 = new Google_Auth_OAuth2($this->getClient()); $ticket = $oauth2->verifySignedJwtWithCerts( $id_token, $certs, "client_id", array('system.gserviceaccount.com', 'https://system.gserviceaccount.com') ); $this->assertEquals(self::USER_ID, $ticket->getUserId()); // Check that payload and envelope got filled in. $attributes = $ticket->getAttributes(); $this->assertEquals("JWT", $attributes["envelope"]["typ"]); $this->assertEquals("client_id", $attributes["payload"]["aud"]); } public function testVerifySignedJwtWithBadIssuer() { $id_token = $this->makeSignedJwt( array( "iss" => "fake.gserviceaccount.com", "aud" => "client_id", "sub" => self::USER_ID, "iat" => time(), "exp" => time() + 3600 ) ); $issuers = array('system.gserviceaccount.com', 'https://system.gserviceaccount.com'); $this->checkIdTokenFailure($id_token, 'Invalid issuer', $issuers[0]); $this->checkIdTokenFailure($id_token, 'Invalid issuer', $issuers); } public function testVerifySignedJwtWithBadJwt() { $this->checkIdTokenFailure("foo", "Wrong number of segments"); $this->checkIdTokenFailure("foo.bar", "Wrong number of segments"); $this->checkIdTokenFailure( "foo.bar.baz", "Can't parse token envelope: foo" ); } public function testVerifySignedJwtWithBadSignature() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "id" => self::USER_ID, "iat" => time(), "exp" => time() + 3600 ) ); $id_token = $id_token . "a"; $this->checkIdTokenFailure($id_token, "Invalid token signature"); } public function testVerifySignedJwtWithNoIssueTime() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "id" => self::USER_ID, "exp" => time() + 3600 ) ); $this->checkIdTokenFailure($id_token, "No issue time"); } public function testVerifySignedJwtWithNoExpirationTime() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "id" => self::USER_ID, "iat" => time() ) ); $this->checkIdTokenFailure($id_token, "No expiration time"); } public function testVerifySignedJwtWithTooEarly() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "id" => self::USER_ID, "iat" => time() + 1800, "exp" => time() + 3600 ) ); $this->checkIdTokenFailure($id_token, "Token used too early"); } public function testVerifySignedJwtWithTooLate() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "id" => self::USER_ID, "iat" => time() - 3600, "exp" => time() - 1800 ) ); $this->checkIdTokenFailure($id_token, "Token used too late"); } public function testVerifySignedJwtWithLifetimeTooLong() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "client_id", "id" => self::USER_ID, "iat" => time(), "exp" => time() + 3600 * 25 ) ); $this->checkIdTokenFailure($id_token, "Expiration time too far in future"); } public function testVerifySignedJwtWithBadAudience() { $id_token = $this->makeSignedJwt( array( "iss" => "federated-signon@system.gserviceaccount.com", "aud" => "wrong_client_id", "id" => self::USER_ID, "iat" => time(), "exp" => time() + 3600 ) ); $this->checkIdTokenFailure($id_token, "Wrong recipient"); } public function testNoAuth() { /** @var $noAuth Google_Auth_Simple */ $noAuth = new Google_Auth_Simple($this->getClient()); $oldAuth = $this->getClient()->getAuth(); $this->getClient()->setAuth($noAuth); $this->getClient()->setDeveloperKey(null); $req = new Google_Http_Request("http://example.com"); $resp = $noAuth->sign($req); $this->assertEquals("http://example.com", $resp->getUrl()); $this->getClient()->setAuth($oldAuth); } public function testAssertionCredentials() { $assertion = new Google_Auth_AssertionCredentials( 'name', 'scope', file_get_contents(__DIR__.'/'.self::PRIVATE_KEY_FILE, true) ); $token = explode(".", $assertion->generateAssertion()); $this->assertEquals('{"typ":"JWT","alg":"RS256"}', base64_decode($token[0])); $jwt = json_decode(base64_decode($token[1]), true); $this->assertEquals('https://accounts.google.com/o/oauth2/token', $jwt['aud']); $this->assertEquals('scope', $jwt['scope']); $this->assertEquals('name', $jwt['iss']); $key = $assertion->getCacheKey(); $this->assertTrue($key != false); $assertion = new Google_Auth_AssertionCredentials( 'name2', 'scope', file_get_contents(__DIR__.'/'.self::PRIVATE_KEY_FILE, true) ); $this->assertNotEquals($key, $assertion->getCacheKey()); } public function testVerifySignedJWT() { $assertion = new Google_Auth_AssertionCredentials( 'issuer', 'scope', file_get_contents(__DIR__.'/'.self::PRIVATE_KEY_FILE, true) ); $client = $this->getClient(); $this->assertInstanceOf( 'Google_Auth_LoginTicket', $client->verifySignedJwt( $assertion->generateAssertion(), __DIR__ . DIRECTORY_SEPARATOR . self::PUBLIC_KEY_FILE_JSON, 'https://accounts.google.com/o/oauth2/token', 'issuer' ) ); } }