Skip to content

Commit d0bc762

Browse files
committed
test: add Behat coverage for unsolicited SAML response (IdP-initiated SSO)
- Add omitInResponseTo flag to MockIdentityProvider (serialized in __sleep) - ResponseFactory: skip InResponseTo when flag set, explicitly null the template placeholder - MockIdpContext: new step 'the IdP omits InResponseTo from its response' - Bindings.feature: scenario asserting redirect to unsolicited-response error page
1 parent bdf8771 commit d0bc762

5 files changed

Lines changed: 41 additions & 3 deletions

File tree

library/EngineBlock/Corto/Module/Bindings/UnsolicitedAssertionException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
/**
4-
* Copyright 2010 SURFnet B.V.
4+
* Copyright 2026 SURFnet B.V.
55
*
66
* Licensed under the Apache License, Version 2.0 (the "License");
77
* you may not use this file except in compliance with the License.

src/OpenConext/EngineBlockFunctionalTestingBundle/Features/Bindings.feature

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,11 @@ Feature:
110110
Then no RelayState should be present
111111
And I pass through EngineBlock
112112
Then the url should match "functional-testing/Dummy%20SP/acs"
113+
114+
Scenario: EngineBlock rejects a SAMLResponse without InResponseTo (IdP-initiated SSO)
115+
Given the IdP omits InResponseTo from its response
116+
When I log in at "Dummy SP"
117+
And I pass through EngineBlock
118+
And I pass through the IdP
119+
Then the url should match "authentication/feedback/unsolicited-response"
120+
And I should see "Error - Sign-in could not be completed"

src/OpenConext/EngineBlockFunctionalTestingBundle/Features/Context/MockIdpContext.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,18 @@ public function theIdPIsConfiguredToNotSendAnAssertion()
301301
$this->mockIdpRegistry->save();
302302
}
303303

304+
/**
305+
* @Given /^the IdP omits InResponseTo from its response$/
306+
*/
307+
public function theIdpOmitsInResponseToFromItsResponse(): void
308+
{
309+
$idp = $this->mockIdpRegistry->getOnly();
310+
311+
$idp->omitInResponseTo();
312+
313+
$this->mockIdpRegistry->save();
314+
}
315+
304316
/**
305317
* @Given /^the IdP "([^"]*)" sends attribute "([^"]*)" with value "([^"]*)"$/
306318
* @param string $idpName

src/OpenConext/EngineBlockFunctionalTestingBundle/Mock/MockIdentityProvider.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class MockIdentityProvider extends AbstractMockEntityRole
3939

4040
private $fromTheFuture = false;
4141

42+
private $omitInResponseTo = false;
43+
4244
public function singleSignOnLocation()
4345
{
4446
return $this->getSsoRole()->getSingleSignOnService()[0]->getLocation();
@@ -341,6 +343,18 @@ public function fromTheFuture()
341343
return $this;
342344
}
343345

346+
public function omitInResponseTo(): self
347+
{
348+
$this->omitInResponseTo = true;
349+
350+
return $this;
351+
}
352+
353+
public function shouldOmitInResponseTo(): bool
354+
{
355+
return $this->omitInResponseTo;
356+
}
357+
344358
public function shouldNotSendAssertions()
345359
{
346360
return $this->sendAssertions === false;
@@ -374,7 +388,7 @@ public function __sleep()
374388
$role->setExtensions($extensions);
375389
}
376390

377-
return ['name', 'descriptor', 'sendAssertions', 'turnBackTime', 'fromTheFuture'];
391+
return ['name', 'descriptor', 'sendAssertions', 'turnBackTime', 'fromTheFuture', 'omitInResponseTo'];
378392
}
379393

380394
/**

src/OpenConext/EngineBlockFunctionalTestingBundle/Saml2/ResponseFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ public function createForEntityWithRequest(
3434
// Note that we expect the Mock IdP to always have a 'template' Response.
3535
$response = $mockIdp->getResponse();
3636

37-
$this->setResponseReferencesToRequest($request, $response);
37+
if ($mockIdp->shouldOmitInResponseTo()) {
38+
$response->setInResponseTo(null);
39+
} else {
40+
$this->setResponseReferencesToRequest($request, $response);
41+
}
3842

3943
$this->setResponseStatus($mockIdp, $response);
4044

0 commit comments

Comments
 (0)