/** * @param string $publicKeyFile /full/path/to/the/public/key * @return SAML2_Certificate_X509 */ public function loadPublicKeyFromFile($publicKeyFile) { $this->publicKeyLoader->loadCertificateFile($publicKeyFile); $keyCollection = $this->publicKeyLoader->getKeys(); $publicKey = $keyCollection->getOnlyElement(); // remove it from the collection so we can reuse the publicKeyLoader for consecutive signing $keyCollection->remove($publicKey); return $publicKey; }
/** * @group certificate * * @test */ public function loading_a_certificate_from_file_creates_a_key() { $file = dirname(__FILE__) . '/File/example.org.crt'; $this->keyLoader->loadCertificateFile($file); $loadedKeys = $this->keyLoader->getKeys(); $loadedKey = $loadedKeys->get(0); $fileContents = file_get_contents($file); preg_match(SAML2_Utilities_Certificate::CERTIFICATE_PATTERN, $fileContents, $matches); $expected = preg_replace('~\\s+~', '', $matches[1]); $this->assertTrue($this->keyLoader->hasKeys()); $this->assertCount(1, $loadedKeys); $this->assertEquals($expected, $loadedKey['X509Certificate']); }
/** * @param Request $request * @return AuthnRequest * @throws \Exception * * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ public function processRequest(Request $request) { if (!$this->entityRepository) { throw new LogicException('RedirectBinding::processRequest requires a ServiceProviderRepository to be configured'); } $rawSamlRequest = $request->get(AuthnRequest::PARAMETER_REQUEST); if (!$rawSamlRequest) { throw new BadRequestHttpException(sprintf('Required GET parameter "%s" is missing', AuthnRequest::PARAMETER_REQUEST)); } if ($request->get(AuthnRequest::PARAMETER_SIGNATURE) && !$request->get(AuthnRequest::PARAMETER_SIGNATURE_ALGORITHM)) { throw new BadRequestHttpException(sprintf('The request includes a signature "%s", but does not include the signature algorithm (SigAlg) parameter', $request->get('Signature'))); } $authnRequest = AuthnRequestFactory::createFromHttpRequest($request); $currentUri = $this->getFullRequestUri($request); if (!$authnRequest->getDestination() === $currentUri) { throw new BadRequestHttpException(sprintf('Actual Destination "%s" does no match the AuthnRequest Destination "%s"', $currentUri, $authnRequest->getDestination())); } if (!$this->entityRepository->hasServiceProvider($authnRequest->getServiceProvider())) { throw new UnknownServiceProviderException($authnRequest->getServiceProvider()); } if (!$authnRequest->isSigned()) { return $authnRequest; } if (!$authnRequest->getSignatureAlgorithm()) { throw new BadRequestHttpException(sprintf('The SAMLRequest has to be signed with SHA256 algorithm: "%s"', XMLSecurityKey::RSA_SHA256)); } $serviceProvider = $this->entityRepository->getServiceProvider($authnRequest->getServiceProvider()); if (!$this->signatureVerifier->hasValidSignature($authnRequest, $serviceProvider)) { throw new BadRequestHttpException('The SAMLRequest has been signed, but the signature could not be validated'); } return $authnRequest; }
/** * @param AuthnRequest $request * @param ServiceProvider $serviceProvider * @return bool */ public function hasValidSignature(AuthnRequest $request, ServiceProvider $serviceProvider) { $this->logger->debug(sprintf('Extracting public keys for ServiceProvider "%s"', $serviceProvider->getEntityId())); $keys = $this->keyLoader->extractPublicKeys($serviceProvider); $this->logger->debug(sprintf('Found "%d" keys, filtering the keys to get X509 keys', $keys->count())); $x509Keys = $keys->filter(function (SAML2_Certificate_Key $key) { return $key instanceof SAML2_Certificate_X509; }); $this->logger->debug(sprintf('Found "%d" X509 keys, attempting to use each for signature verification', $x509Keys->count())); foreach ($x509Keys as $key) { if ($this->isSignedWith($request, $key)) { return true; } } $this->logger->debug('Signature could not be verified with any of the found X509 keys.'); return false; }
/** * @param $authnRequest */ private function verifySignature(AuthnRequest $authnRequest) { if (!$authnRequest->isSigned()) { throw new BadRequestHttpException('The SAMLRequest has to be signed'); } if (!$authnRequest->getSignatureAlgorithm()) { throw new BadRequestHttpException(sprintf('The SAMLRequest has to be signed with SHA256 algorithm: "%s"', XMLSecurityKey::RSA_SHA256)); } $serviceProvider = $this->entityRepository->getServiceProvider($authnRequest->getServiceProvider()); if (!$this->signatureVerifier->hasValidSignature($authnRequest, $serviceProvider)) { throw new BadRequestHttpException('The SAMLRequest has been signed, but the signature could not be validated'); } }
/** * @param SAML2_SignedElement $signedElement * @param SAML2_Configuration_CertificateProvider $configuration * * @return bool */ public function canValidate(SAML2_SignedElement $signedElement, SAML2_Configuration_CertificateProvider $configuration) { $this->configuredKeys = $this->keyLoader->extractPublicKeys($configuration); return !!count($this->configuredKeys); }
/** * @group certificate * * @test * @expectedException SAML2_Certificate_Exception_InvalidCertificateStructureException */ public function loading_an_invalid_certificate_file_from_configuration_throws_exception() { $file = dirname(__FILE__) . '/File/not_a_key.crt'; $this->configurationMock->shouldReceive('getKeys')->atMost()->once()->andReturnNull()->shouldReceive('getCertificateData')->atMost()->once()->andReturnNull()->shouldReceive('getCertificateFile')->once()->andReturn($file); $loadedKeys = $this->keyLoader->loadKeysFromConfiguration($this->configurationMock); }