Skip to content

Commit 2ba2bf3

Browse files
committed
Add explicit IdP signing key feedback
An explicit IdP signing key check is added for easier debugging. The ease of debugging should outweigh the drawbacks of moving the responsibility of the SAML2 library also to EB and the performance penalties for doing this twice. #1328
1 parent 742eaae commit 2ba2bf3

File tree

10 files changed

+133
-0
lines changed

10 files changed

+133
-0
lines changed

languages/messages.en.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@
197197
'error_unknown_identity_provider_no_idp_name' => 'Error - Unknown %organisationNoun%',
198198
'error_unknown_identity_provider_desc' => '%idpName%, which you are trying to log in with, is unknown to %suiteName%.',
199199
'error_unknown_identity_provider_desc_no_idp_name' => 'The %organisationNoun% you are trying to log in with is unknown to %suiteName%.',
200+
'error_unknown_signing_key' => 'Error - unknown signing key',
201+
'error_unknown_signing_key_desc' => 'The signing key used is not known to %suiteName%. This is possibly a configuration error.',
200202
'error_generic' => 'Error - An error occurred',
201203
'error_generic_desc' => 'Logging in has failed and we don\'t know exactly why. Please try again first by going back to %spName% and logging in again. If this doesn\'t work, please contact the service desk of %idpName%.',
202204
'error_generic_desc_no_sp_name' => 'Logging in has failed and we don\'t know exactly why. Please try again first by going back to the service and logging in again. If this doesn\'t work, please contact the service desk of %idpName%.',

languages/messages.nl.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@
195195
'error_unknown_identity_provider_no_idp_name' => 'Error - Onbekende %organisationNoun%',
196196
'error_unknown_identity_provider_desc' => '%idpName%, waarmee je probeert in te loggen, is onbekend bij %suiteName%.',
197197
'error_unknown_identity_provider_desc_no_idp_name' => 'De %organisationNoun% waarmee je probeert in te loggen is onbekend bij %suiteName%.',
198+
'error_unknown_signing_key' => 'Error - onbekende signing key',
199+
'error_unknown_signing_key_desc' => 'De gebruikte signing key is niet bekend bij %suiteName%. Dit komt waarschijnlijk door een configuratiefout.',
198200
'error_generic' => 'Fout - Generieke foutmelding',
199201
'error_generic_desc' => 'Inloggen is niet gelukt en we weten niet precies waarom. Probeer het eerst eens opnieuw door terug te gaan naar %spName% en opnieuw in te loggen. Lukt dit niet, neem dan contact op met de helpdesk van %idpName%.',
200202
'error_generic_desc_no_sp_name' => 'Inloggen is niet gelukt en we weten niet precies waarom. Probeer het eerst eens opnieuw door terug te gaan naar de dienst en opnieuw in te loggen. Lukt dit niet, neem dan contact op met de helpdesk van %idpName%.',

languages/messages.pt.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@
193193
'error_unknown_identity_provider_no_idp_name' => 'Erro - %organisationNoun% desconhecido',
194194
'error_unknown_identity_provider_desc' => 'O %organisationNoun% a que pretende autenticar-se é desconhecido para a %suiteName%.',
195195
'error_unknown_identity_provider_desc_no_idp_name' => 'O %organisationNoun% a que pretende autenticar-se é desconhecido para a %suiteName%.',
196+
'error_unknown_signing_key' => 'Erro - chave de assinatura desconhecida',
197+
'error_unknown_signing_key_desc' => 'A chave de assinatura utilizada não é conhecida por %suiteName%. Isto pode ser um erro de configuração.',
196198
'error_generic' => 'Erro - Ocorreu um erro',
197199
'error_generic_desc' => 'A sua autenticação falhou e não sabemos exactamente porquê. Tente de novo e no caso de voltar a não funcionar, entre em contacto com o suporte da %idpName% para pedir ajuda.',
198200
'error_missing_required_fields' => 'Erro - Campo necessário em falta',
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/**
4+
* Copyright 2010 SURFnet B.V.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
class EngineBlock_Corto_Exception_UnknownIdentityProviderSigningKey extends EngineBlock_Exception
20+
{
21+
/**
22+
* @var string
23+
*/
24+
private $entityId;
25+
26+
public function __construct($message, string $entityId, $severity = self::CODE_NOTICE, Exception $previous = null)
27+
{
28+
$this->entityId = $entityId;
29+
parent::__construct($message, $severity, $previous);
30+
}
31+
32+
public function getEntityId(): string
33+
{
34+
return $this->entityId;
35+
}
36+
}

library/EngineBlock/Corto/Module/Bindings.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,11 @@ public function receiveResponse($serviceEntityId, $expectedDestination)
342342
// check the IssueInstant against our own time to see if the SP's clock is getting out of sync
343343
$this->_checkIssueInstant( $sspResponse->getIssueInstant(), 'IdP', $idpEntityId );
344344

345+
// This is an initial check to validate when a signing key is in the
346+
// response if it's the one that's expected by EB for that IdP,
347+
// so a decent error message can be shown if this is not the case.
348+
$this->assertKnownIdPSigningKey($cortoIdpMetadata, $sspResponse);
349+
345350
try {
346351
// 'Process' the response, verify the signature, verify the timings.
347352
if ($this->hasEncryptedAssertion($sspResponse)
@@ -886,4 +891,44 @@ private function hasEncryptedAssertion(Response $sspResponse)
886891
}
887892
return $hasEncryptedAssertion;
888893
}
894+
895+
/**
896+
* This is an initial check to validate when a signing key is in the
897+
* response, if it's the one that's expected by EB for that IdP,
898+
* so a decent error message can be shown if this is not the case.
899+
*/
900+
private function assertKnownIdPSigningKey(IdentityProvider $metadata, Response $sspResponse): void {
901+
902+
// If no key is in the response we don't need to validate if it's known because the
903+
// validation if the signature is present is the responsibility of the SamlResponseValidator.
904+
if (count($sspResponse->getCertificates()) === 0) {
905+
return;
906+
}
907+
908+
if (count($sspResponse->getCertificates()) > 1) {
909+
$this->_logger->notice(
910+
sprintf(
911+
'Tried to verify a message from issuer "%s", but requests with multiple signing keys are not supported.',
912+
$metadata->entityId
913+
)
914+
);
915+
916+
throw new EngineBlock_Corto_Module_Bindings_Exception(sprintf('Multiple signing keys supplied for issuer: %s', $metadata->entityId));
917+
}
918+
919+
foreach ($metadata->certificates as $metaDataCertificate) {
920+
if ($metaDataCertificate->toCertData() === $sspResponse->getCertificates()[0]) {
921+
return;
922+
}
923+
}
924+
925+
$this->_logger->notice(
926+
sprintf(
927+
'Tried to verify a message from issuer "%s", but the expected signing key does not match.',
928+
$metadata->entityId
929+
)
930+
);
931+
932+
throw new EngineBlock_Corto_Exception_UnknownIdentityProviderSigningKey('Unknown signing key supplied for issuer', $metadata->entityId);
933+
}
889934
}

src/OpenConext/EngineBlockBundle/Controller/FeedbackController.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,19 @@ public function unknownIdentityProviderAction(Request $request)
201201
return new Response($body, 404);
202202
}
203203

204+
/**
205+
* @param Request $request
206+
* @return Response
207+
* @throws \EngineBlock_Exception
208+
*/
209+
public function unknownSigningKeyAction(Request $request)
210+
{
211+
return new Response(
212+
$this->twig->render('@theme/Authentication/View/Feedback/unknown-signing-key.html.twig'),
213+
400
214+
);
215+
}
216+
204217
/**
205218
* @return Response
206219
* @throws \EngineBlock_Exception

src/OpenConext/EngineBlockBundle/EventListener/RedirectToFeedbackPageExceptionListener.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use EngineBlock_Corto_Exception_MissingRequiredFields;
2929
use EngineBlock_Corto_Exception_PEPNoAccess;
3030
use EngineBlock_Corto_Exception_ReceivedErrorStatusCode;
31+
use EngineBlock_Corto_Exception_UnknownIdentityProviderSigningKey;
3132
use EngineBlock_Corto_Exception_UnknownPreselectedIdp;
3233
use EngineBlock_Corto_Exception_InvalidAttributeValue;
3334
use EngineBlock_Corto_Exception_UserCancelledStepupCallout;
@@ -171,6 +172,9 @@ public function onKernelException(GetResponseForExceptionEvent $event)
171172
'entity-id' => $exception->getEntityId(),
172173
'destination' => $exception->getDestination()
173174
];
175+
} elseif ($exception instanceof EngineBlock_Corto_Exception_UnknownIdentityProviderSigningKey) {
176+
$message = $exception->getMessage();
177+
$redirectToRoute = 'authentication_feedback_unknown_signing_key';
174178
} elseif ($exception instanceof EngineBlock_Exception_UnknownRequesterIdInAuthnRequest) {
175179
$message = 'Encountered unknown RequesterID for the Service Provider (transparant proxying)';
176180
$redirectToRoute = 'authentication_feedback_unknown_requesterid_in_authnrequest';

src/OpenConext/EngineBlockBundle/Resources/config/routing/feedback.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ authentication_feedback_unknown_identity_provider:
4848
methods: [GET]
4949
defaults: { _controller: engineblock.controller.authentication.feedback:unknownIdentityProviderAction }
5050

51+
authentication_feedback_unknown_signing_key:
52+
path: '/authentication/feedback/unknown-signing-key'
53+
methods: [GET]
54+
defaults: { _controller: engineblock.controller.authentication.feedback:unknownSigningKeyAction }
55+
5156
authentication_feedback_missing_required_fields:
5257
path: '/authentication/feedback/missing-required-fields'
5358
methods: [GET]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends '@theme/Default/View/Error/error.html.twig' %}
2+
3+
{% set pageTitle = 'error_unknown_signing_key'|trans %}
4+
{% block pageTitle %}
5+
{{ 'error_unknown_signing_key'|trans }}
6+
{% endblock %}
7+
{% block title %}{{ parent() }} - {{ pageTitle }} {% endblock %}
8+
{% block pageHeading %}{{ pageTitle }}{% endblock %}
9+
10+
{% block errorMessage %}
11+
{{ 'error_unknown_signing_key_desc'|trans }}
12+
{% endblock %}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% extends '@theme/Default/View/Error/error.html.twig' %}
2+
3+
{% set pageTitle = 'error_unknown_signing_key'|trans %}
4+
{% block pageTitle %}
5+
{{ 'error_unknown_signing_key'|trans }}
6+
{% endblock %}
7+
{% block title %}{{ parent() }} - {{ pageTitle }} {% endblock %}
8+
{% block pageHeading %}{{ pageTitle }}{% endblock %}
9+
10+
{% block errorMessage %}
11+
{{ 'error_unknown_signing_key_desc'|trans }}
12+
{% endblock %}

0 commit comments

Comments
 (0)