Skip to content

Commit 1d6a404

Browse files
author
Bas
committed
Add configurable sso registration bypass
#539
1 parent 68a97be commit 1d6a404

19 files changed

Lines changed: 432 additions & 1 deletion

config/packages/doctrine.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ doctrine:
103103
stepup_sso_on_2fa_option:
104104
class: Surfnet\StepupMiddleware\ApiBundle\Doctrine\Type\SsoOn2faOptionType
105105
commented: false
106+
stepup_sso_registration_bypass_option:
107+
class: Surfnet\StepupMiddleware\ApiBundle\Doctrine\Type\SsoOn2faOptionType
108+
commented: false
106109
stepup_institution_role:
107110
class: Surfnet\StepupMiddleware\ApiBundle\Doctrine\Type\InstitutionRoleType
108111
commented: false

config/packages/monolog.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ when@dev: &override
2424
main_syslog:
2525
type: stream
2626
path: php://stderr
27-
level: error
27+
level: debug
2828
channels: ["!event", "!doctrine", "!deprecation", "!console"]
2929
console:
3030
type: console
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/**
4+
* Copyright 2025 SURFnet bv
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+
declare(strict_types=1);
20+
21+
namespace Surfnet\Migrations;
22+
23+
use Doctrine\DBAL\Schema\Schema;
24+
use Doctrine\Migrations\AbstractMigration;
25+
use Surfnet\Stepup\MigrationsFactory\ConfigurationAwareMigrationInterface;
26+
use Surfnet\Stepup\MigrationsFactory\ConfigurationAwareMigrationTrait;
27+
28+
final class Version20250501121457 extends AbstractMigration implements ConfigurationAwareMigrationInterface
29+
{
30+
use ConfigurationAwareMigrationTrait;
31+
32+
public function up(Schema $schema): void
33+
{
34+
$this->abortIf(
35+
$this->connection->getDatabasePlatform()->getName() !== 'mysql',
36+
'Migration can only be executed safely on \'mysql\'.',
37+
);
38+
// Create the new sso_on_2fa option, note the name conversion 'error' made by doctrine.
39+
$this->addSql('ALTER TABLE institution_configuration_options ADD sso_registration_bypass_option INT DEFAULT \'0\' NOT NULL');
40+
// Create the institution_configuration gateway schema
41+
$gatewaySchema = $this->getGatewaySchema();
42+
$this->addSql(
43+
sprintf(
44+
'ALTER TABLE %s.institution_configuration ADD sso_registration_bypass_option TINYINT(1) NOT NULL DEFAULT \'0\' NOT NULL',
45+
$gatewaySchema,
46+
),
47+
);
48+
}
49+
50+
public function down(Schema $schema): void
51+
{
52+
$this->abortIf(
53+
$this->connection->getDatabasePlatform()->getName() !== 'mysql',
54+
'Migration can only be executed safely on \'mysql\'.',
55+
);
56+
// Down the Middleware schema change
57+
$this->addSql('ALTER TABLE institution_configuration_options DROP sso_registration_bypass_option');
58+
// Gateway schema change (remove the institution_configuration)
59+
$gatewaySchema = $this->getGatewaySchema();
60+
$this->addSql(sprintf('ALTER TABLE %s.institution_configuration DROP sso_registration_bypass_option', $gatewaySchema));
61+
}
62+
}

src/Surfnet/Stepup/Configuration/Event/NewInstitutionConfigurationCreatedEvent.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use Surfnet\Stepup\Configuration\Value\SelfVetOption;
2727
use Surfnet\Stepup\Configuration\Value\ShowRaaContactInformationOption;
2828
use Surfnet\Stepup\Configuration\Value\SsoOn2faOption;
29+
use Surfnet\Stepup\Configuration\Value\SsoRegistrationBypassOption;
2930
use Surfnet\Stepup\Configuration\Value\UseRaLocationsOption;
3031
use Surfnet\Stepup\Configuration\Value\VerifyEmailOption;
3132

@@ -43,6 +44,7 @@ public function __construct(
4344
public VerifyEmailOption $verifyEmailOption,
4445
public NumberOfTokensPerIdentityOption $numberOfTokensPerIdentityOption,
4546
public SsoOn2faOption $ssoOn2faOption,
47+
public SsoRegistrationBypassOption $ssoRegistrationBypassOption,
4648
public SelfVetOption $selfVetOption,
4749
public SelfAssertedTokensOption $selfAssertedTokensOption
4850
) {
@@ -60,6 +62,10 @@ public static function deserialize(array $data): self
6062
if (!isset($data['sso_on_2fa_option'])) {
6163
$data['sso_on_2fa_option'] = false;
6264
}
65+
// If sso registration bypass option is not yet present, default to false
66+
if (!isset($data['sso_registration_bypass_option'])) {
67+
$data['sso_registration_bypass_option'] = false;
68+
}
6369
// If self vet option is not yet present, default to false
6470
if (!isset($data['self_vet_option'])) {
6571
$data['self_vet_option'] = false;
@@ -76,6 +82,7 @@ public static function deserialize(array $data): self
7682
new VerifyEmailOption($data['verify_email_option']),
7783
new NumberOfTokensPerIdentityOption($data['number_of_tokens_per_identity_option']),
7884
new SsoOn2faOption($data['sso_on_2fa_option']),
85+
new SsoRegistrationBypassOption($data['sso_registration_bypass_option']),
7986
new SelfVetOption($data['self_vet_option']),
8087
new SelfAssertedTokensOption($data['self_asserted_tokens_option']),
8188
);
@@ -91,6 +98,7 @@ public function serialize(): array
9198
'verify_email_option' => $this->verifyEmailOption->isEnabled(),
9299
'number_of_tokens_per_identity_option' => $this->numberOfTokensPerIdentityOption->getNumberOfTokensPerIdentity(),
93100
'sso_on_2fa_option' => $this->ssoOn2faOption->isEnabled(),
101+
'sso_registration_bypass_option' => $this->ssoRegistrationBypassOption->isEnabled(),
94102
'self_vet_option' => $this->selfVetOption->isEnabled(),
95103
'self_asserted_tokens_option' => $this->selfAssertedTokensOption->isEnabled(),
96104
];
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright 2025 SURFnet B.V.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
namespace Surfnet\Stepup\Configuration\Event;
22+
23+
use Broadway\Serializer\Serializable as SerializableInterface;
24+
use Surfnet\Stepup\Configuration\Value\Institution;
25+
use Surfnet\Stepup\Configuration\Value\InstitutionConfigurationId;
26+
use Surfnet\Stepup\Configuration\Value\SsoRegistrationBypassOption;
27+
28+
final class SsoRegistrationBypassOptionChangedEvent implements SerializableInterface
29+
{
30+
public function __construct(
31+
public InstitutionConfigurationId $institutionConfigurationId,
32+
public Institution $institution,
33+
public SsoRegistrationBypassOption $ssoRegistrationBypassOption,
34+
) {
35+
}
36+
37+
public static function deserialize(array $data): self
38+
{
39+
return new self(
40+
new InstitutionConfigurationId($data['institution_configuration_id']),
41+
new Institution($data['institution']),
42+
new SsoRegistrationBypassOption($data['sso_registration_bypass_option']),
43+
);
44+
}
45+
46+
public function serialize(): array
47+
{
48+
return [
49+
'institution_configuration_id' => $this->institutionConfigurationId->getInstitutionConfigurationId(),
50+
'institution' => $this->institution->getInstitution(),
51+
'sso_registration_bypass_option' => $this->ssoRegistrationBypassOption->isEnabled(),
52+
];
53+
}
54+
}

src/Surfnet/Stepup/Configuration/InstitutionConfiguration.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Surfnet\Stepup\Configuration\Event\SelfVetOptionChangedEvent;
3636
use Surfnet\Stepup\Configuration\Event\ShowRaaContactInformationOptionChangedEvent;
3737
use Surfnet\Stepup\Configuration\Event\SsoOn2faOptionChangedEvent;
38+
use Surfnet\Stepup\Configuration\Event\SsoRegistrationBypassOptionChangedEvent;
3839
use Surfnet\Stepup\Configuration\Event\UseRaaOptionChangedEvent;
3940
use Surfnet\Stepup\Configuration\Event\UseRaLocationsOptionChangedEvent;
4041
use Surfnet\Stepup\Configuration\Event\UseRaOptionChangedEvent;
@@ -54,6 +55,7 @@
5455
use Surfnet\Stepup\Configuration\Value\SelfVetOption;
5556
use Surfnet\Stepup\Configuration\Value\ShowRaaContactInformationOption;
5657
use Surfnet\Stepup\Configuration\Value\SsoOn2faOption;
58+
use Surfnet\Stepup\Configuration\Value\SsoRegistrationBypassOption;
5759
use Surfnet\Stepup\Configuration\Value\UseRaLocationsOption;
5860
use Surfnet\Stepup\Configuration\Value\VerifyEmailOption;
5961
use Surfnet\Stepup\Exception\DomainException;
@@ -93,6 +95,8 @@ class InstitutionConfiguration extends EventSourcedAggregateRoot implements Inst
9395

9496
private ?SsoOn2faOption $ssoOn2faOption = null;
9597

98+
private ?SsoRegistrationBypassOption $ssoRegistrationBypassOption = null;
99+
96100
private ?SelfAssertedTokensOption $selfAssertedTokensOption = null;
97101

98102
private ?InstitutionAuthorizationOption $useRaOption = null;
@@ -119,6 +123,7 @@ public static function create(
119123
VerifyEmailOption::getDefault(),
120124
NumberOfTokensPerIdentityOption::getDefault(),
121125
SsoOn2faOption::getDefault(),
126+
SsoRegistrationBypassOption::getDefault(),
122127
SelfVetOption::getDefault(),
123128
SelfAssertedTokensOption::getDefault(),
124129
),
@@ -320,6 +325,21 @@ public function configureSsoOn2faOption(SsoOn2faOption $ssoOn2faOption): void
320325
);
321326
}
322327

328+
public function configureSsoRegistrationBypassOption(SsoRegistrationBypassOption $ssoRegistrationBypassOption)
329+
{
330+
if ($this->ssoRegistrationBypassOption->equals($ssoRegistrationBypassOption)) {
331+
return;
332+
}
333+
334+
$this->apply(
335+
new SsoRegistrationBypassOptionChangedEvent(
336+
$this->institutionConfigurationId,
337+
$this->institution,
338+
$ssoRegistrationBypassOption
339+
)
340+
);
341+
}
342+
323343
public function updateUseRaOption(InstitutionAuthorizationOption $useRaOption): void
324344
{
325345
if ($this->useRaOption instanceof \Surfnet\Stepup\Configuration\Value\InstitutionAuthorizationOption
@@ -526,6 +546,7 @@ protected function applyNewInstitutionConfigurationCreatedEvent(NewInstitutionCo
526546
$this->verifyEmailOption = $event->verifyEmailOption;
527547
$this->selfVetOption = $event->selfVetOption;
528548
$this->ssoOn2faOption = $event->ssoOn2faOption;
549+
$this->ssoRegistrationBypassOption = $event->ssoRegistrationBypassOption;
529550
$this->selfAssertedTokensOption = $event->selfAssertedTokensOption;
530551
$this->numberOfTokensPerIdentityOption = $event->numberOfTokensPerIdentityOption;
531552
$this->raLocations = new RaLocationList([]);
@@ -592,6 +613,12 @@ protected function applySsoOn2faOptionChangedEvent(
592613
$this->ssoOn2faOption = $event->ssoOn2faOption;
593614
}
594615

616+
protected function applySsoRegistrationBypassOptionChangedEvent(
617+
SsoRegistrationBypassOptionChangedEvent $event,
618+
): void {
619+
$this->ssoRegistrationBypassOption = $event->ssoRegistrationBypassOption;
620+
}
621+
595622
protected function applyNumberOfTokensPerIdentityOptionChangedEvent(
596623
NumberOfTokensPerIdentityOptionChangedEvent $event,
597624
): void {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* Copyright 2025 SURFnet B.V.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
namespace Surfnet\Stepup\Configuration\Value;
22+
23+
use JsonSerializable;
24+
25+
final readonly class SsoRegistrationBypassOption implements JsonSerializable
26+
{
27+
public static function getDefault(): self
28+
{
29+
return new self(false);
30+
}
31+
32+
public function __construct(
33+
private bool $ssoRegistrationBypass
34+
) {
35+
}
36+
37+
public function equals(SsoRegistrationBypassOption $other): bool
38+
{
39+
return $this->ssoRegistrationBypass === $other->isEnabled();
40+
}
41+
42+
public function isEnabled(): bool
43+
{
44+
return $this->ssoRegistrationBypass;
45+
}
46+
47+
public function jsonSerialize(): bool
48+
{
49+
return $this->ssoRegistrationBypass;
50+
}
51+
}

src/Surfnet/Stepup/Tests/Configuration/Event/EventSerializationAndDeserializationTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
use Surfnet\Stepup\Configuration\Event\ShowRaaContactInformationOptionChangedEvent;
4141
use Surfnet\Stepup\Configuration\Event\SraaUpdatedEvent;
4242
use Surfnet\Stepup\Configuration\Event\SsoOn2faOptionChangedEvent;
43+
use Surfnet\Stepup\Configuration\Event\SsoRegistrationBypassOptionChangedEvent;
4344
use Surfnet\Stepup\Configuration\Event\UseRaLocationsOptionChangedEvent;
4445
use Surfnet\Stepup\Configuration\Event\VerifyEmailOptionChangedEvent;
4546
use Surfnet\Stepup\Configuration\Value\AllowedSecondFactorList;
@@ -54,6 +55,7 @@
5455
use Surfnet\Stepup\Configuration\Value\SelfVetOption;
5556
use Surfnet\Stepup\Configuration\Value\ShowRaaContactInformationOption;
5657
use Surfnet\Stepup\Configuration\Value\SsoOn2faOption;
58+
use Surfnet\Stepup\Configuration\Value\SsoRegistrationBypassOption;
5759
use Surfnet\Stepup\Configuration\Value\UseRaLocationsOption;
5860
use Surfnet\Stepup\Configuration\Value\VerifyEmailOption;
5961
use Surfnet\StepupBundle\Value\SecondFactorType;
@@ -171,6 +173,13 @@ public function institutionConfigurationEventsProvider(): array
171173
new SsoOn2faOption(false),
172174
),
173175
],
176+
'SsoRegistrationBypassOptionChangedEvent' => [
177+
new SsoRegistrationBypassOptionChangedEvent(
178+
$institutionConfigurationId,
179+
$institution,
180+
new SsoRegistrationBypassOption(false),
181+
),
182+
],
174183
'AllowedSecondFactorListUpdatedEvent:withSecondFactors' => [
175184
new AllowedSecondFactorListUpdatedEvent(
176185
$institutionConfigurationId,

0 commit comments

Comments
 (0)