/**
  * Get the metadata for a requester, if allowed by the configuration.
  *
  * @param ServiceProvider $serviceProvider
  * @param EngineBlock_Saml2_AuthnRequestAnnotationDecorator $request
  * @param MetadataRepositoryInterface $repository
  * @return null|ServiceProvider
  */
 public static function findRequesterServiceProvider(ServiceProvider $serviceProvider, EngineBlock_Saml2_AuthnRequestAnnotationDecorator $request, MetadataRepositoryInterface $repository)
 {
     if (!$serviceProvider->isTrustedProxy) {
         return null;
     }
     if (!$request->wasSigned()) {
         return null;
     }
     // Requester IDs are appended to as they pass through a proxy, so we always want the last RequesterID
     // Note that this is not specified in the spec, but this is what we do and what SSP does.
     $requesterIds = $request->getRequesterIds();
     $lastRequesterEntityId = end($requesterIds);
     if (!$lastRequesterEntityId) {
         return null;
     }
     $lastRequesterEntity = $repository->findServiceProviderByEntityId($lastRequesterEntityId);
     if (!$lastRequesterEntity) {
         throw new EngineBlock_Exception_DissimilarServiceProviderWorkflowStates($serviceProvider, $lastRequesterEntityId);
     }
     return $lastRequesterEntity;
 }
 /**
  * Returns a custom ACS location from request or false when
  * none is specified
  *
  * @param EngineBlock_Saml2_AuthnRequestAnnotationDecorator $request
  * @param ServiceProvider $serviceProvider
  * @return null|\OpenConext\Component\EngineBlockMetadata\IndexedService
  */
 public function getCustomAssertionConsumer(EngineBlock_Saml2_AuthnRequestAnnotationDecorator $request, ServiceProvider $serviceProvider)
 {
     $requestWasSigned = $request->wasSigned();
     /** @var SAML2_AuthnRequest $request */
     // Ignore requests for bindings we don't support for responses.
     if ($request->getProtocolBinding() !== SAML2_Const::BINDING_HTTP_POST) {
         $this->_server->getSessionLog()->notice("ProtocolBinding '{$request->getProtocolBinding()}' requested is not supported, ignoring...");
         return false;
     }
     // Custom ACS Location & ProtocolBinding goes first
     if ($request->getAssertionConsumerServiceURL() && $request->getProtocolBinding()) {
         if ($requestWasSigned) {
             $this->_server->getSessionLog()->info("Using AssertionConsumerServiceLocation '{$request->getAssertionConsumerServiceURL()}' " . "and ProtocolBinding '{$request->getProtocolBinding()}' from signed request. ");
             return new Service($request->getAssertionConsumerServiceURL(), $request->getProtocolBinding());
         } else {
             $requestAcsIsRegisteredInMetadata = false;
             foreach ($serviceProvider->assertionConsumerServices as $entityAcs) {
                 $requestAcsIsRegisteredInMetadata = $entityAcs->location === $request->getAssertionConsumerServiceURL() && $entityAcs->binding === $request->getProtocolBinding();
                 if ($requestAcsIsRegisteredInMetadata) {
                     break;
                 }
             }
             if ($requestAcsIsRegisteredInMetadata) {
                 $this->_server->getSessionLog()->info("Using AssertionConsumerServiceLocation '{$request->getAssertionConsumerServiceURL()}' " . "and ProtocolBinding '{$request->getProtocolBinding()}' from unsigned request, " . "it's okay though, the ACSLocation and Binding were registered in the metadata");
                 return new Service($request->getAssertionConsumerServiceURL(), $request->getProtocolBinding());
             } else {
                 $this->_server->getSessionLog()->notice("AssertionConsumerServiceLocation '{$request->getAssertionConsumerServiceURL()}' " . "and ProtocolBinding '{$request->getProtocolBinding()}' were mentioned in request, " . "but the AuthnRequest was not signed, and the ACSLocation and Binding were not found in " . "the metadata for the SP, so I am disallowed from acting upon it." . "Trying the default endpoint..");
             }
         }
         return false;
     } else {
         if ($request->getAssertionConsumerServiceURL() || $request->getProtocolBinding()) {
             // Note that an SP is not actually required to supply both a URL and a Binding.
             // But what should we do if we don't have both? Pick out a random counterpart from the metadata?
             // Seems a little hard to predict for the SP, so we go with the default endpoint.
             $this->_server->getSessionLog()->notice("AssertionConsumerServiceLocation '{$request->getAssertionConsumerServiceURL()}' " . "or ProtocolBinding '{$request->getProtocolBinding()}' were mentioned in request, " . "but not both! Ignoring... ");
         }
     }
     if ($request->getAssertionConsumerServiceIndex()) {
         $index = (int) $request->getAssertionConsumerServiceIndex();
         // Find the indexed ACS in the metadata.
         $indexedAssertionConsumerService = null;
         foreach ($serviceProvider->assertionConsumerServices as $assertionConsumerService) {
             if ((int) $assertionConsumerService->serviceIndex === $index) {
                 $indexedAssertionConsumerService = $assertionConsumerService;
                 break;
             }
         }
         if ($indexedAssertionConsumerService) {
             $this->_server->getSessionLog()->info("Using AssertionConsumerServiceIndex '{$index}' from request");
             return $indexedAssertionConsumerService;
         } else {
             $this->_server->getSessionLog()->notice("AssertionConsumerServiceIndex was mentioned in request, but we don't know any ACS by " . "index '{$index}'? Maybe the metadata was updated and we don't have that endpoint yet? " . "Trying the default endpoint..");
         }
     }
 }