Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions config/services/logging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ services:
tags:
- { name: monolog.processor }

OpenConext\EngineBlock\Logger\Processor\CorrelationIdProcessor:
arguments:
- '@OpenConext\EngineBlock\Request\CorrelationId'
tags:
- { name: monolog.processor }

OpenConext\EngineBlock\Logger\Processor\SessionIdProcessor:
tags:
- { name: monolog.processor }
Expand Down
16 changes: 16 additions & 0 deletions config/services/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ services:
class: OpenConext\EngineBlockBundle\HealthCheck\DoctrineConnectionHealthCheck
arguments:
- '%monitor_database_health_check_query%'
- '@logger'
calls:
- [ setEntityManager, ['@?doctrine.orm.entity_manager']]
tags:
Expand Down Expand Up @@ -56,6 +57,15 @@ services:
- '@OpenConext\EngineBlock\Request\UniqidGenerator'
public: true

OpenConext\EngineBlock\Request\CorrelationId:
public: true

OpenConext\EngineBlock\Request\CorrelationIdRepository:
public: true
arguments:
- '@OpenConext\EngineBlock\Request\CorrelationId'
- '@request_stack'

OpenConext\EngineBlockBundle\Security\Http\EntryPoint\JsonBasicAuthenticationEntryPoint:
arguments:
- 'engine-api.%domain%'
Expand Down Expand Up @@ -377,3 +387,9 @@ services:
class: OpenConext\EngineBlockBundle\Sbs\SbsAttributeMerger
arguments:
- "%sram.allowed_attributes%"

EngineBlock_Saml2_AuthnRequestSessionRepository:
class: EngineBlock_Saml2_AuthnRequestSessionRepository
public: true
arguments:
- '@request_stack'
16 changes: 16 additions & 0 deletions library/EngineBlock/Application/DiContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -613,4 +613,20 @@ public function getNameIdSubstituteResolver()
{
return new EngineBlock_Arp_NameIdSubstituteResolver($this->container->get('engineblock.compat.logger'));
}

/**
* @return \OpenConext\EngineBlock\Request\CorrelationIdRepository
*/
public function getCorrelationIdRepository(): \OpenConext\EngineBlock\Request\CorrelationIdRepository
{
return $this->container->get(\OpenConext\EngineBlock\Request\CorrelationIdRepository::class);
}

/**
* @return EngineBlock_Saml2_AuthnRequestSessionRepository
*/
public function getAuthnRequestSessionRepository(): EngineBlock_Saml2_AuthnRequestSessionRepository
{
return $this->container->get(EngineBlock_Saml2_AuthnRequestSessionRepository::class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public function serve($serviceName, Request $httpRequest)
$receivedRequest = $this->_server->getReceivedRequestFromResponse($receivedResponse);

$application = EngineBlock_ApplicationSingleton::getInstance();

$correlationIdRepository = $application->getDiContainer()->getCorrelationIdRepository();
$correlationIdRepository->resolve($receivedResponse->getInResponseTo());
$log = $application->getLogInstance();

if(!$receivedRequest instanceof EngineBlock_Saml2_AuthnRequestAnnotationDecorator){
Expand Down
13 changes: 12 additions & 1 deletion library/EngineBlock/Corto/Module/Service/ContinueToIdp.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ public function serve($serviceName, Request $httpRequest)
);
}

$authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($this->_server->getLogger());
$authnRequestRepository = EngineBlock_ApplicationSingleton::getInstance()
->getDiContainer()
->getAuthnRequestSessionRepository();
$request = $authnRequestRepository->findRequestById($id);

if (!$request) {
Expand All @@ -94,6 +96,15 @@ public function serve($serviceName, Request $httpRequest)
);
}

// Resolve here so log entries emitted during this leg (e.g. the debug
// block below) carry the correlation ID. ProxyServer::sendAuthenticationRequest
// will also call resolve() when it links the IdP request ID — that is
// idempotent and sets the same value.
$correlationIdRepository = EngineBlock_ApplicationSingleton::getInstance()
->getDiContainer()
->getCorrelationIdRepository();
$correlationIdRepository->resolve($id);

// Flush log if SP or IdP has additional logging enabled
if ($request->isDebugRequest()) {
$sp = $this->getEngineSpRole($this->_server);
Expand Down
6 changes: 6 additions & 0 deletions library/EngineBlock/Corto/Module/Service/ProcessConsent.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ public function serve($serviceName, Request $httpRequest)
$response = $processStep->getResponse();

$request = $this->_server->getReceivedRequestFromResponse($response);

$correlationIdRepository = EngineBlock_ApplicationSingleton::getInstance()
->getDiContainer()
->getCorrelationIdRepository();
$correlationIdRepository->resolve($request->getId());

$serviceProvider = $this->_server->getRepository()->fetchServiceProviderByEntityId($request->getIssuer()->getValue());

$destinationMetadata = EngineBlock_SamlHelper::getDestinationSpMetadata(
Expand Down
5 changes: 5 additions & 0 deletions library/EngineBlock/Corto/Module/Service/ProvideConsent.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ public function serve($serviceName, Request $httpRequest)

$receivedRequest = $this->_server->getReceivedRequestFromResponse($response);

$correlationIdRepository = EngineBlock_ApplicationSingleton::getInstance()
->getDiContainer()
->getCorrelationIdRepository();
$correlationIdRepository->resolve($receivedRequest->getId());

// update previous response with current response
$this->_processingStateHelper->updateStepResponseByRequestId(
$receivedRequest->getId(),
Expand Down
18 changes: 11 additions & 7 deletions library/EngineBlock/Corto/Module/Service/SingleSignOn.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,11 @@ public function serve($serviceName, Request $httpRequest)
}

// Multiple IdPs found...

$container = $application->getDiContainer();
// Auto-select IdP when 'feature_enable_sso_notification' is enabled and send AuthenticationRequest on success
if ($application->getDiContainer()->getFeatureConfiguration()->isEnabled("eb.enable_sso_notification")) {
$idpEntityId = $application->getDiContainer()->getSsoNotificationService()->
handleSsoNotification($application->getDiContainer()->getSymfonyRequest()->cookies, $this->_server);
if ($container->getFeatureConfiguration()->isEnabled("eb.enable_sso_notification")) {
$idpEntityId = $container->getSsoNotificationService()
->handleSsoNotification($container->getSymfonyRequest()->cookies, $this->_server);

if (!empty($idpEntityId)) {
try {
Expand All @@ -214,8 +214,8 @@ public function serve($serviceName, Request $httpRequest)
}

// Auto-select IdP when 'wayf.rememberChoice' feature is enabled and is allowed for the current request
if (($application->getDiContainer()->getRememberChoice() === true) && !($request->getForceAuthn() || $request->isDebugRequest())) {
$cookies = $application->getDiContainer()->getSymfonyRequest()->cookies->all();
if (($container->getRememberChoice() === true) && !($request->getForceAuthn() || $request->isDebugRequest())) {
$cookies = $container->getSymfonyRequest()->cookies->all();
if (array_key_exists('rememberchoice', $cookies)) {
$remembered = json_decode($cookies['rememberchoice']);
if (array_search($remembered, $candidateIDPs) !== false) {
Expand All @@ -234,9 +234,13 @@ public function serve($serviceName, Request $httpRequest)
return;
}

$authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($log);
$authnRequestRepository = $container->getAuthnRequestSessionRepository();
$authnRequestRepository->store($request);

$correlationIdRepository = $container->getCorrelationIdRepository();
$correlationIdRepository->mint($request->getId());
$correlationIdRepository->resolve($request->getId());

// Show WAYF
$log->info("Multiple candidate IdPs: redirecting to WAYF");
$this->_showWayf($request, $candidateIDPs);
Expand Down
22 changes: 16 additions & 6 deletions library/EngineBlock/Corto/ProxyServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -461,16 +461,19 @@ public function sendAuthenticationRequest(
}
}

$authenticationState = EngineBlock_ApplicationSingleton::getInstance()->getDiContainer()
->getAuthenticationStateHelper()
->getAuthenticationState();
$diContainer = EngineBlock_ApplicationSingleton::getInstance()->getDiContainer();
$authenticationState = $diContainer->getAuthenticationStateHelper()->getAuthenticationState();
$authenticationState->startAuthenticationOnBehalfOf($ebRequest->getId(), $serviceProvider);

// Store the original Request
$authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($this->_logger);
$authnRequestRepository = $diContainer->getAuthnRequestSessionRepository();
$authnRequestRepository->store($spRequest);
$authnRequestRepository->link($ebRequest, $spRequest);

$correlationIdRepository = $diContainer->getCorrelationIdRepository();
$correlationIdRepository->mint($spRequest->getId());
$correlationIdRepository->link($ebRequest->getId(), $spRequest->getId());
$correlationIdRepository->resolve($spRequest->getId());

$this->getBindingsModule()->send($ebRequest, $identityProvider);
}
Expand Down Expand Up @@ -552,10 +555,15 @@ public function sendStepupAuthenticationRequest(


// Link with the original Request
$authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($this->_logger);
$authnRequestRepository = $container->getAuthnRequestSessionRepository();
$authnRequestRepository->store($spRequest);
$authnRequestRepository->link($ebRequest, $spRequest);

$correlationIdRepository = $container->getCorrelationIdRepository();
$correlationIdRepository->mint($spRequest->getId());
$correlationIdRepository->link($ebRequest->getId(), $spRequest->getId());
$correlationIdRepository->resolve($spRequest->getId());

$this->getBindingsModule()->send($ebRequest, $identityProvider, true);
}

Expand Down Expand Up @@ -1101,7 +1109,9 @@ public function getReceivedRequestFromResponse(EngineBlock_Saml2_ResponseAnnotat

public function findRequestFromRequestId(string $requestId): ?EngineBlock_Saml2_AuthnRequestAnnotationDecorator
{
$authnRequestRepository = new EngineBlock_Saml2_AuthnRequestSessionRepository($this->getLogger());
$authnRequestRepository = EngineBlock_ApplicationSingleton::getInstance()
->getDiContainer()
->getAuthnRequestSessionRepository();

$spRequestId = $authnRequestRepository->findLinkedRequestId($requestId);
if ($spRequestId === null) {
Expand Down
87 changes: 46 additions & 41 deletions library/EngineBlock/Saml2/AuthnRequestSessionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,81 +16,77 @@
* limitations under the License.
*/

use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* Session storage for Authentication Requests. Store AuthnRequests and link requests together.
*/
class EngineBlock_Saml2_AuthnRequestSessionRepository
{
/**
* @var Psr\Log\LoggerInterface
*/
private $sessionLog;

/**
* @var
*/
private $requestStorage;
private const SESSION_KEY_REQUESTS = 'SAMLRequest';
private const SESSION_KEY_LINKS = 'SAMLRequestLinks';

/**
* @var array
* @var RequestStack
*/
private $linkStorage;
private $requestStack;

/**
* @param Psr\Log\LoggerInterface $sessionLog
*/
public function __construct(Psr\Log\LoggerInterface $sessionLog)
public function __construct(RequestStack $requestStack)
{
if (!isset($_SESSION['SAMLRequest'])) {
$_SESSION['SAMLRequest'] = array();
}
$this->requestStorage = &$_SESSION['SAMLRequest'];

if (!isset($_SESSION['SAMLRequestLinks'])) {
$_SESSION['SAMLRequestLinks'] = array();
}
$this->linkStorage = &$_SESSION['SAMLRequestLinks'];

$this->sessionLog = $sessionLog;
$this->requestStack = $requestStack;
}

/**
* @param string $requestId
* @return EngineBlock_Saml2_AuthnRequestAnnotationDecorator
* @return EngineBlock_Saml2_AuthnRequestAnnotationDecorator|null
*/
public function findRequestById($requestId)
{
if (!isset($this->requestStorage[$requestId])) {
try {
$session = $this->requestStack->getSession();
} catch (SessionNotFoundException $e) {
return null;
}

return $this->requestStorage[$requestId];
return $session->get(self::SESSION_KEY_REQUESTS, [])[$requestId] ?? null;
}

/**
* @param $requestId
* @param string|null $requestId
* @return string|null
*/
public function findLinkedRequestId($requestId)
{
// Check the session for a AuthnRequest with the given ID
// Expect to get back an AuthnRequest issued by EngineBlock and destined for the IdP
if (!$requestId || !isset($this->linkStorage[$requestId])) {
if (!$requestId) {
return null;
}

return $this->linkStorage[$requestId];
try {
$session = $this->requestStack->getSession();
} catch (SessionNotFoundException $e) {
return null;
}

return $session->get(self::SESSION_KEY_LINKS, [])[$requestId] ?? null;
}

/**
* @param EngineBlock_Saml2_AuthnRequestAnnotationDecorator $spRequest
* @return $this
*/
public function store(
EngineBlock_Saml2_AuthnRequestAnnotationDecorator $spRequest
) {
// Store the original Request
$this->requestStorage[$spRequest->getId()] = $spRequest;
public function store(EngineBlock_Saml2_AuthnRequestAnnotationDecorator $spRequest)
{
try {
$session = $this->requestStack->getSession();
} catch (SessionNotFoundException $e) {
return $this;
}

$requests = $session->get(self::SESSION_KEY_REQUESTS, []);
$requests[$spRequest->getId()] = $spRequest;
$session->set(self::SESSION_KEY_REQUESTS, $requests);

return $this;
}

Expand All @@ -103,8 +99,17 @@ public function link(
EngineBlock_Saml2_AuthnRequestAnnotationDecorator $fromRequest,
EngineBlock_Saml2_AuthnRequestAnnotationDecorator $toRequest
) {
// Store the mapping from the new request ID to the original request ID
$this->linkStorage[$fromRequest->getId()] = $toRequest->getId();
try {
$session = $this->requestStack->getSession();
} catch (SessionNotFoundException $e) {
return $this;
}

$links = $session->get(self::SESSION_KEY_LINKS, []);
$links[$fromRequest->getId()] = $toRequest->getId();
$session->set(self::SESSION_KEY_LINKS, $links);

return $this;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/**
* Copyright 2010 SURFnet B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace OpenConext\EngineBlock\Logger\Processor;

use Monolog\LogRecord;
use Monolog\Processor\ProcessorInterface;
use OpenConext\EngineBlock\Request\CorrelationId;

final class CorrelationIdProcessor implements ProcessorInterface
{
public function __construct(private readonly CorrelationId $correlationId)
{
}

public function __invoke(LogRecord $record): LogRecord
{
$record->extra['correlation_id'] = $this->correlationId->get();

return $record;
}
}
Loading