/** * @return EngineBlock_Corto_Module_Bindings */ private function mockBindingsModule() { $spRequest = new SAML2_AuthnRequest(); $spRequest->setId('SPREQUEST'); $spRequest->setIssuer('testSp'); $spRequest = new EngineBlock_Saml2_AuthnRequestAnnotationDecorator($spRequest); $ebRequest = new SAML2_AuthnRequest(); $ebRequest->setId('EBREQUEST'); $ebRequest = new EngineBlock_Saml2_AuthnRequestAnnotationDecorator($ebRequest); $dummyLog = new Psr\Log\NullLogger(); $authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($dummyLog); $authnRequestRepository->store($spRequest); $authnRequestRepository->store($ebRequest); $authnRequestRepository->link($ebRequest, $spRequest); $assertion = new SAML2_Assertion(); $assertion->setAttributes(array('urn:org:openconext:corto:internal:sp-entity-id' => array('testSp'), 'urn:mace:dir:attribute-def:cn' => array(null))); $responseFixture = new SAML2_Response(); $responseFixture->setInResponseTo('EBREQUEST'); $responseFixture->setAssertions(array($assertion)); $responseFixture = new EngineBlock_Saml2_ResponseAnnotationDecorator($responseFixture); $responseFixture->setOriginalIssuer('testIdP'); // Mock bindings module /** @var EngineBlock_Corto_Module_Bindings $bindingsModuleMock */ $bindingsModuleMock = Phake::mock('EngineBlock_Corto_Module_Bindings'); Phake::when($bindingsModuleMock)->receiveResponse()->thenReturn($responseFixture); return $bindingsModuleMock; }
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); }
private function mockGlobals() { $_POST['ID'] = 'test'; $_POST['consent'] = 'yes'; $assertion = new SAML2_Assertion(); $assertion->setAttributes(array('urn:mace:dir:attribute-def:mail' => '*****@*****.**')); $spRequest = new SAML2_AuthnRequest(); $spRequest->setId('SPREQUEST'); $spRequest->setIssuer('https://sp.example.edu'); $spRequest = new EngineBlock_Saml2_AuthnRequestAnnotationDecorator($spRequest); $ebRequest = new SAML2_AuthnRequest(); $ebRequest->setId('EBREQUEST'); $ebRequest = new EngineBlock_Saml2_AuthnRequestAnnotationDecorator($ebRequest); $dummySessionLog = new Psr\Log\NullLogger(); $authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($dummySessionLog); $authnRequestRepository->store($spRequest); $authnRequestRepository->store($ebRequest); $authnRequestRepository->link($ebRequest, $spRequest); $sspResponse = new SAML2_Response(); $sspResponse->setInResponseTo('EBREQUEST'); $sspResponse->setAssertions(array($assertion)); $_SESSION['consent']['test']['response'] = new EngineBlock_Saml2_ResponseAnnotationDecorator($sspResponse); }
public function sendAuthenticationRequest(EngineBlock_Saml2_AuthnRequestAnnotationDecorator $spRequest, $idpEntityId) { $cookieExpiresStamp = null; if (isset($this->_configs['rememberIdp'])) { $cookieExpiresStamp = strtotime($this->_configs['rememberIdp']); } $this->setCookie('selectedIdp', $idpEntityId, $cookieExpiresStamp); $originalId = $spRequest->getId(); $identityProvider = $this->getRepository()->fetchIdentityProviderByEntityId($idpEntityId); $ebRequest = EngineBlock_Saml2_AuthnRequestFactory::createFromRequest($spRequest, $identityProvider, $this); $newId = $ebRequest->getId(); // Store the original Request $authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($this->_sessionLog); $authnRequestRepository->store($spRequest); $authnRequestRepository->link($ebRequest, $spRequest); $this->getBindingsModule()->send($ebRequest, $identityProvider); }