public function serve($serviceName)
 {
     $receivedResponse = $this->_server->getBindingsModule()->receiveResponse();
     $receivedRequest = $this->_server->getReceivedRequestFromResponse($receivedResponse);
     $sp = $this->_server->getRepository()->fetchServiceProviderByEntityId($receivedRequest->getIssuer());
     // Verify the SP requester chain.
     EngineBlock_SamlHelper::getSpRequesterChain($sp, $receivedRequest, $this->_server->getRepository());
     // Flush log if SP or IdP has additional logging enabled
     $idp = $this->_server->getRepository()->fetchIdentityProviderByEntityId($receivedResponse->getIssuer());
     if (EngineBlock_SamlHelper::doRemoteEntitiesRequireAdditionalLogging(array($sp, $idp))) {
         $application = EngineBlock_ApplicationSingleton::getInstance();
         $application->flushLog('Activated additional logging for the SP or IdP');
         $log = $application->getLogInstance();
         $log->info('Raw HTTP request', array('http_request' => (string) $application->getHttpRequest()));
     }
     if ($receivedRequest->isDebugRequest()) {
         $_SESSION['debugIdpResponse'] = $receivedResponse;
         $this->_server->redirect($this->_server->getUrl('debugSingleSignOnService'), 'Show original Response from IDP');
         return;
     }
     if ($receivedRequest->getKeyId()) {
         $this->_server->setKeyId($receivedRequest->getKeyId());
     }
     // Cache the response
     EngineBlock_Corto_Model_Response_Cache::cacheResponse($receivedRequest, $receivedResponse, EngineBlock_Corto_Model_Response_Cache::RESPONSE_CACHE_TYPE_IN);
     $this->_server->filterInputAssertionAttributes($receivedResponse, $receivedRequest);
     $processingEntities = $this->_server->getConfig('Processing', array());
     if (!empty($processingEntities)) {
         /** @var AbstractRole $firstProcessingEntity */
         $firstProcessingEntity = array_shift($processingEntities);
         $_SESSION['Processing'][$receivedRequest->getId()]['RemainingEntities'] = $processingEntities;
         $_SESSION['Processing'][$receivedRequest->getId()]['OriginalDestination'] = $receivedResponse->getDestination();
         $_SESSION['Processing'][$receivedRequest->getId()]['OriginalIssuer'] = $receivedResponse->getOriginalIssuer();
         $_SESSION['Processing'][$receivedRequest->getId()]['OriginalBinding'] = $receivedResponse->getOriginalBinding();
         $this->_server->setProcessingMode();
         $newResponse = $this->_server->createEnhancedResponse($receivedRequest, $receivedResponse);
         // Change the destiny of the received response
         $newResponse->setInResponseTo($receivedResponse->getInResponseTo());
         $newResponse->setDestination($firstProcessingEntity->responseProcessingService->location);
         $newResponse->setDeliverByBinding($firstProcessingEntity->responseProcessingService->binding);
         $newResponse->setReturn($this->_server->getUrl('processedAssertionConsumerService'));
         $this->_server->getBindingsModule()->send($newResponse, $firstProcessingEntity);
     } else {
         $newResponse = $this->_server->createEnhancedResponse($receivedRequest, $receivedResponse);
         $this->_server->sendResponseToRequestIssuer($receivedRequest, $newResponse);
     }
 }
 public function execute()
 {
     $logger = EngineBlock_ApplicationSingleton::getLog();
     $enforcer = new EngineBlock_Arp_AttributeReleasePolicyEnforcer();
     $attributes = $this->_responseAttributes;
     // Get the Requester chain, which starts at the oldest (farthest away from us SP) and ends with our next hop.
     $requesterChain = EngineBlock_SamlHelper::getSpRequesterChain($this->_serviceProvider, $this->_request, $this->_server->getRepository());
     // Note that though we should traverse in reverse ordering, it doesn't make a difference.
     // A then B filter or B then A filter are equivalent.
     foreach ($requesterChain as $spMetadata) {
         $spEntityId = $spMetadata->entityId;
         $arp = $this->getMetadataRepository()->fetchServiceProviderArp($spMetadata);
         if (!$arp) {
             continue;
         }
         $logger->info("Applying attribute release policy for {$spEntityId}");
         $attributes = $enforcer->enforceArp($arp, $attributes);
     }
     $this->_responseAttributes = $attributes;
 }
 public function serve($serviceName)
 {
     $response = $this->_server->getBindingsModule()->receiveResponse();
     $_SESSION['consent'][$response->getId()]['response'] = $response;
     $request = $this->_server->getReceivedRequestFromResponse($response);
     $serviceProvider = $this->_server->getRepository()->fetchServiceProviderByEntityId($request->getIssuer());
     $spMetadataChain = EngineBlock_SamlHelper::getSpRequesterChain($serviceProvider, $request, $this->_server->getRepository());
     $identityProviderEntityId = $response->getOriginalIssuer();
     $identityProvider = $this->_server->getRepository()->fetchIdentityProviderByEntityId($identityProviderEntityId);
     // Flush log if SP or IdP has additional logging enabled
     $requireAdditionalLogging = EngineBlock_SamlHelper::doRemoteEntitiesRequireAdditionalLogging(array_merge($spMetadataChain, array($identityProvider)));
     if ($requireAdditionalLogging) {
         $application = EngineBlock_ApplicationSingleton::getInstance();
         $application->flushLog('Activated additional logging for one or more SPs in the SP requester chain, or the IdP');
         $log = $application->getLogInstance();
         $log->info('Raw HTTP request', array('http_request' => (string) $application->getHttpRequest()));
     }
     if ($this->isConsentDisabled($spMetadataChain, $identityProvider)) {
         $response->setConsent(SAML2_Const::CONSENT_INAPPLICABLE);
         $response->setDestination($response->getReturn());
         $response->setDeliverByBinding('INTERNAL');
         $this->_server->getBindingsModule()->send($response, $serviceProvider);
         return;
     }
     $consentDestinationEntityMetadata = $spMetadataChain[0];
     $attributes = $response->getAssertion()->getAttributes();
     $consent = $this->_consentFactory->create($this->_server, $response, $attributes);
     $priorConsent = $consent->hasStoredConsent($consentDestinationEntityMetadata);
     if ($priorConsent) {
         $response->setConsent(SAML2_Const::CONSENT_PRIOR);
         $response->setDestination($response->getReturn());
         $response->setDeliverByBinding('INTERNAL');
         $this->_server->getBindingsModule()->send($response, $serviceProvider);
         return;
     }
     $html = $this->_server->renderTemplate('consent', array('action' => $this->_server->getUrl('processConsentService'), 'ID' => $response->getId(), 'attributes' => $attributes, 'sp' => $consentDestinationEntityMetadata, 'idp' => $identityProvider));
     $this->_server->sendOutput($html);
 }
 public function serve($serviceName)
 {
     $log = $this->_server->getSessionLog();
     $response = $this->_displayDebugResponse($serviceName);
     if ($response) {
         return;
     }
     /** @var EngineBlock_Saml2_AuthnRequestAnnotationDecorator|SAML2_AuthnRequest $request */
     $request = $this->_getRequest($serviceName);
     $log->info(sprintf("Fetching service provider matching request issuer '%s'", $request->getIssuer()));
     $sp = $this->_server->getRepository()->fetchServiceProviderByEntityId($request->getIssuer());
     // Flush log if an SP in the requester chain has additional logging enabled
     $log->info("Determining whether service provider in chain requires additional logging");
     $isAdditionalLoggingRequired = EngineBlock_SamlHelper::doRemoteEntitiesRequireAdditionalLogging(EngineBlock_SamlHelper::getSpRequesterChain($sp, $request, $this->_server->getRepository()));
     if ($isAdditionalLoggingRequired) {
         $application = EngineBlock_ApplicationSingleton::getInstance();
         $application->flushLog('Activated additional logging for one or more SPs in the SP requester chain');
         $logger = $application->getLogInstance();
         $logger->info('Raw HTTP request', array('http_request' => (string) $application->getHttpRequest()));
     } else {
         $log->info("No additional logging required");
     }
     // validate custom acs-location (only for unsolicited, normal logins
     //  fall back to default ACS location instead of showing error page)
     if ($serviceName === 'unsolicitedSingleSignOnService') {
         if (!$this->_verifyAcsLocation($request, $sp)) {
             throw new EngineBlock_Corto_Exception_InvalidAcsLocation('Unsolicited sign-on service called, but unknown or invalid ACS location requested');
         }
         $log->info('Unsolicited sign-on ACS location verified.');
     }
     // The request may specify it ONLY wants a response from specific IdPs
     // or we could have it configured that the SP may only be serviced by specific IdPs
     $scopedIdps = $this->_getScopedIdPs($request);
     $cacheResponseSent = $this->_sendCachedResponse($request, $scopedIdps);
     if ($cacheResponseSent) {
         return;
     }
     // If the scoped proxycount = 0, respond with a ProxyCountExceeded error
     if ($request->getProxyCount() === 0) {
         $log->info("Request does not allow any further proxying, responding with 'ProxyCountExceeded' status");
         $response = $this->_server->createErrorResponse($request, 'ProxyCountExceeded');
         $this->_server->sendResponseToRequestIssuer($request, $response);
         return;
     }
     // Get all registered Single Sign On Services
     // Note that we could also only get the ones that are allowed for this SP, but we may also want to show
     // those that are not allowed.
     $candidateIDPs = $this->_server->getRepository()->findAllIdentityProviderEntityIds();
     $posOfOwnIdp = array_search($this->_server->getUrl('idpMetadataService'), $candidateIDPs);
     if ($posOfOwnIdp !== false) {
         $log->info("Removed ourselves from the candidate IdP list");
         unset($candidateIDPs[$posOfOwnIdp]);
     }
     // If we have scoping, filter out every non-scoped IdP
     if (count($scopedIdps) > 0) {
         $log->info(sprintf('%d candidate IdPs before scoping', count($candidateIDPs)), array('idps' => array_values($candidateIDPs)));
         $candidateIDPs = array_intersect($scopedIdps, $candidateIDPs);
         $log->info(sprintf('%d candidate IdPs after scoping', count($candidateIDPs)), array('idps' => array_values($candidateIDPs)));
     } else {
         $log->info(sprintf('No IdP scoping required, %d candidate IdPs', count($candidateIDPs)), array('idps' => array_values($candidateIDPs)));
     }
     // 0 IdPs found! Throw an exception.
     if (count($candidateIDPs) === 0) {
         throw new EngineBlock_Corto_Module_Service_SingleSignOn_NoIdpsException('No candidate IdPs found');
     }
     // Exactly 1 candidate found, send authentication request to the first one.
     if (count($candidateIDPs) === 1) {
         $idp = array_shift($candidateIDPs);
         $log->info("Only 1 candidate IdP ('{$idp}'): omitting WAYF, sending authentication request");
         $this->_server->sendAuthenticationRequest($request, $idp);
         return;
     }
     // Multiple IdPs found...
     // > 1 IdPs found, but isPassive attribute given, unable to show WAYF.
     if ($request->getIsPassive()) {
         $log->info('Request is passive, but can be handled by more than one IdP: responding with NoPassive status');
         $response = $this->_server->createErrorResponse($request, 'NoPassive');
         $this->_server->sendResponseToRequestIssuer($request, $response);
         return;
     }
     $authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($log);
     $authnRequestRepository->store($request);
     // Show WAYF
     $log->info("Multiple candidate IdPs: redirecting to WAYF");
     $this->_showWayf($request, $candidateIDPs);
 }