public function execute()
 {
     if (!$this->_response->getIntendedNameId()) {
         $this->_response->setIntendedNameId($this->_collabPersonId);
     }
     if ($this->_type === self::TYPE_IDP) {
         $entity = $this->_identityProvider;
         $serviceProvider = $this->_serviceProvider;
     } else {
         if ($this->_type === self::TYPE_SP) {
             $entity = $this->_serviceProvider;
             $serviceProvider = $entity;
         } else {
             if ($this->_type === self::TYPE_REQUESTER_SP) {
                 $entity = EngineBlock_SamlHelper::findRequesterServiceProvider($this->_serviceProvider, $this->_request, $this->_server->getRepository());
                 if (!$entity) {
                     return;
                 }
                 $serviceProvider = $entity;
             } else {
                 throw new EngineBlock_Exception('Attribute Manipulator encountered an unexpected type: ' . $this->_type);
             }
         }
     }
     // Try entity specific file based manipulation from Service Registry
     $manipulator = new EngineBlock_Attributes_Manipulator_ServiceRegistry($this->_type);
     $manipulator->manipulate($entity, $this->_collabPersonId, $this->_responseAttributes, $this->_response, $this->_identityProvider, $serviceProvider);
     $this->_response->setIntendedNameId($this->_collabPersonId);
 }
 /**
  * Handle the forwarding of the user to the proper IdP0 after the WAYF screen.
  *
  * @param string $serviceName
  * @throws EngineBlock_Corto_Module_Services_Exception
  * @throws EngineBlock_Exception
  * @throws EngineBlock_Corto_Module_Services_SessionLostException
  */
 public function serve($serviceName)
 {
     $selectedIdp = urldecode($_REQUEST['idp']);
     if (!$selectedIdp) {
         throw new EngineBlock_Corto_Module_Services_Exception('No IdP selected after WAYF');
     }
     // Retrieve the request from the session.
     $id = $_POST['ID'];
     if (!$id) {
         throw new EngineBlock_Exception('Missing ID for AuthnRequest after WAYF', EngineBlock_Exception::CODE_NOTICE);
     }
     $authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($this->_server->getSessionLog());
     $request = $authnRequestRepository->findRequestById($id);
     if (!$request) {
         throw new EngineBlock_Corto_Module_Services_SessionLostException('Session lost after WAYF');
     }
     // Flush log if SP or IdP has additional logging enabled
     $sp = $this->_server->getRepository()->fetchServiceProviderByEntityId($request->getIssuer());
     $idp = $this->_server->getRepository()->fetchIdentityProviderByEntityId($selectedIdp);
     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()));
     }
     $this->_server->sendAuthenticationRequest($request, $selectedIdp);
 }
 public function serve($serviceName)
 {
     if (!isset($_SESSION['consent'])) {
         throw new EngineBlock_Corto_Module_Services_SessionLostException('Session lost after consent');
     }
     if (!isset($_SESSION['consent'][$_POST['ID']]['response'])) {
         throw new EngineBlock_Corto_Module_Services_SessionLostException("Stored response for ResponseID '{$_POST['ID']}' not found");
     }
     /** @var SAML2_Response|EngineBlock_Saml2_ResponseAnnotationDecorator $response */
     $response = $_SESSION['consent'][$_POST['ID']]['response'];
     $request = $this->_server->getReceivedRequestFromResponse($response);
     $serviceProvider = $this->_server->getRepository()->fetchServiceProviderByEntityId($request->getIssuer());
     $destinationMetadata = EngineBlock_SamlHelper::getDestinationSpMetadata($serviceProvider, $request, $this->_server->getRepository());
     if (!isset($_POST['consent']) || $_POST['consent'] !== 'yes') {
         throw new EngineBlock_Corto_Exception_NoConsentProvided('No consent given...');
     }
     $attributes = $response->getAssertion()->getAttributes();
     $consent = $this->_consentFactory->create($this->_server, $response, $attributes);
     $consent->storeConsent($destinationMetadata);
     if ($consent->countTotalConsent() === 1) {
         $this->_sendIntroductionMail($attributes);
     }
     $response->setConsent(SAML2_Const::CONSENT_OBTAINED);
     $response->setDestination($response->getReturn());
     $response->setDeliverByBinding('INTERNAL');
     $this->_server->getBindingsModule()->send($response, $serviceProvider);
 }
 /**
  * Resolve the eduPersonTargetedId we should send.
  */
 public function execute()
 {
     // Note that we try to service the final destination SP, if we know them and are allowed to do so.
     $destinationMetadata = EngineBlock_SamlHelper::getDestinationSpMetadata($this->_serviceProvider, $this->_request, $this->_server->getRepository());
     // Resolve what NameID we should send the destination.
     $resolver = new EngineBlock_Saml2_NameIdResolver();
     $nameId = $resolver->resolve($this->_request, $this->_response, $destinationMetadata, $this->_collabPersonId);
     // EPTID requires us to embed the <saml:NameID> element instead of just the value, so we generate that here.
     $document = new DOMDocument();
     $document->loadXML('<base />');
     SAML2_Utils::addNameId($document->documentElement, $nameId);
     // Add the eduPersonTargetedId attribute.
     $this->_responseAttributes['urn:mace:dir:attribute-def:eduPersonTargetedID'] = array($document->documentElement->childNodes);
 }
 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 serve($serviceName)
 {
     $response = $this->_server->getBindingsModule()->receiveResponse();
     $receivedRequest = $this->_server->getReceivedRequestFromResponse($response);
     if ($receivedRequest->getKeyId()) {
         $this->_server->setKeyId($receivedRequest->getKeyId());
     }
     $remainingProcessingEntities =& $_SESSION['Processing'][$receivedRequest->getId()]['RemainingEntities'];
     // @todo check if this is the correct place to flush log
     // Flush log if SP or IdP has additional logging enabled
     $sp = $this->_server->getRepository()->fetchServiceProviderByEntityId($receivedRequest->getIssuer());
     $idp = $this->_server->getRepository()->fetchIdentityProviderByEntityId($response->getOriginalIssuer());
     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 (!empty($remainingProcessingEntities)) {
         // Moar processing!
         /** @var AbstractRole $nextProcessingEntity */
         $nextProcessingEntity = array_shift($remainingProcessingEntities);
         $this->_server->setProcessingMode();
         $newResponse = $this->_server->createEnhancedResponse($receivedRequest, $response);
         // Change the destiny of the received response
         $newResponse->setId($response->getId());
         $newResponse->setDestination($nextProcessingEntity->responseProcessingService->location);
         $newResponse->setDeliverByBinding($nextProcessingEntity->responseProcessingService->binding);
         $newResponse->setReturn($this->_server->getUrl('processedAssertionConsumerService'));
         $this->_server->getBindingsModule()->send($newResponse, $nextProcessingEntity);
         return;
     } else {
         // Done processing! Send off to SP
         $response->setDestination($_SESSION['Processing'][$receivedRequest->getId()]['OriginalDestination']);
         $response->setDeliverByBinding($_SESSION['Processing'][$receivedRequest->getId()]['OriginalBinding']);
         $response->setOriginalIssuer($_SESSION['Processing'][$receivedRequest->getId()]['OriginalIssuer']);
         $this->_server->unsetProcessingMode();
         $sentResponse = $this->_server->createEnhancedResponse($receivedRequest, $response);
         $this->_server->sendResponseToRequestIssuer($receivedRequest, $sentResponse);
         return;
     }
 }
 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 execute()
 {
     $serviceProvider = EngineBlock_SamlHelper::findRequesterServiceProvider($this->_serviceProvider, $this->_request, $this->_server->getRepository());
     if (!$serviceProvider) {
         $serviceProvider = $this->_serviceProvider;
     }
     if (!$serviceProvider->policyEnforcementDecisionRequired) {
         return;
     }
     EngineBlock_ApplicationSingleton::getLog()->debug("Policy Enforcement Point consult");
     $validator = $this->_getValidator();
     $hasAccess = $validator->hasAccess($this->_collabPersonId, $this->_identityProvider->entityId, $serviceProvider->entityId, $this->_responseAttributes);
     if ($hasAccess) {
         return;
     }
     $message = "Policy Decision Point: access denied.";
     if ($validator->getMessage()) {
         $message = $validator->getMessage();
     }
     EngineBlock_ApplicationSingleton::getLog()->debug("Policy Enforcement Point access denied: " . $message);
     throw new EngineBlock_Corto_Exception_PEPNoAccess($message);
 }
 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);
 }