Skip to content

Commit

Permalink
Write contractual base to production entities
Browse files Browse the repository at this point in the history
The new service will ensure the business rules are followed for this
feature. The tests have been updated to cover the new Coin entry on the
Manage entity.

See: https://www.pivotaltracker.com/story/show/187977233
  • Loading branch information
MKodde committed Aug 15, 2024
1 parent c6c15a3 commit 9a8dcec
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@
use Surfnet\ServiceProviderDashboard\Domain\Entity\Constants;
use Surfnet\ServiceProviderDashboard\Domain\Entity\ManageEntity;
use Surfnet\ServiceProviderDashboard\Domain\Repository\PublishEntityRepository;
use Surfnet\ServiceProviderDashboard\Domain\Service\ContractualBaseService;
use Surfnet\ServiceProviderDashboard\Infrastructure\HttpClient\Exceptions\RuntimeException\PublishMetadataException;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class PublishEntityProductionCommandHandler implements CommandHandler
{
private readonly string $summaryTranslationKey;
Expand All @@ -40,6 +44,7 @@ class PublishEntityProductionCommandHandler implements CommandHandler

public function __construct(
private readonly PublishEntityRepository $publishClient,
private readonly ContractualBaseService $contractualBaseHelper,
private readonly EntityServiceInterface $entityService,
private readonly TicketService $ticketService,
private readonly RequestStack $requestStack,
Expand Down Expand Up @@ -79,6 +84,7 @@ public function handle(PublishProductionCommandInterface $command): void
$entity->getMetaData()->getNameEn()
)
);
$this->contractualBaseHelper->writeContractualBase($entity);
$publishResponse = $this->publishClient->publish(
$entity,
$pristineEntity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ private function buildCoinFromCommand(SaveEntityCommandInterface $command): Coin
$command->getApplicationUrl(),
$typeOfServiceCollection,
$command->getEulaUrl(),
null,
null
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class Constants
final public const STATE_PUBLICATION_REQUESTED = 'requested';
final public const STATE_REMOVAL_REQUESTED = 'removal requested';

final public const SERVICE_TYPE_INSTITUTE = 'institute';
final public const SERVICE_TYPE_NON_INSTITUTE = 'non-institute';
final public const CONTRACTUAL_BASE_IX = 'IX';
final public const CONTRACTUAL_BASE_AO = 'AO';

final public const TYPE_SAML = 'saml20';
final public const TYPE_OPENID_CONNECT_TNG = 'oidcng';
final public const TYPE_OPENID_CONNECT_TNG_RESOURCE_SERVER = 'oauth20_rs';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@

class Coin implements Comparable
{


public static function fromApiResponse(array $metaDataFields): self
{
$signatureMethod = $metaDataFields['coin:signature_method'] ?? '';
$serviceTeamId = $metaDataFields['coin:service_team_id'] ?? '';
$originalMetadataUrl = $metaDataFields['coin:original_metadata_url'] ?? '';
$applicationUrl = $metaDataFields['coin:application_url'] ?? '';
$contractualBase = $metaDataFields['coin:contractual_base'] ?? null;
$eula = $metaDataFields['coin:eula'] ?? '';
$excludeFromPush = isset($metaDataFields['coin:exclude_from_push'])
? (int)$metaDataFields['coin:exclude_from_push'] : null;
Expand All @@ -48,6 +51,7 @@ public static function fromApiResponse(array $metaDataFields): self
Assert::string($eula);
Assert::nullOrIntegerish($excludeFromPush);
Assert::integer($oidcClient);
Assert::nullOrString($contractualBase);

return new self(
$signatureMethod,
Expand All @@ -57,7 +61,8 @@ public static function fromApiResponse(array $metaDataFields): self
$applicationUrl,
$typeOfService,
$eula,
$oidcClient
$oidcClient,
$contractualBase,
);
}

Expand All @@ -70,6 +75,7 @@ public function __construct(
private ?TypeOfServiceCollection $typeOfService,
private ?string $eula,
private ?int $oidcClient,
private ?string $contractualBase,
) {
}

Expand Down Expand Up @@ -115,6 +121,17 @@ public function getTypeOfService(): TypeOfServiceCollection
}
return $this->typeOfService;
}

public function getContractualBase(): ?string
{
return $this->contractualBase;
}

public function setContractualBase(string $contractualBase): void
{
$this->contractualBase = $contractualBase;
}

/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
Expand All @@ -131,6 +148,7 @@ public function merge(Coin $coin): void
$this->eula = is_null($coin->getEula()) ? null : $coin->getEula();
$this->oidcClient = is_null($coin->getOidcClient()) ? null : $coin->getOidcClient();
$this->typeOfService = $coin->getTypeOfService();
$this->contractualBase = $coin->getContractualBase();
}

public function asArray(): array
Expand All @@ -143,6 +161,7 @@ public function asArray(): array
'metaDataFields.coin:original_metadata_url' => $this->getOriginalMetadataUrl(),
'metaDataFields.coin:ss:type_of_service:en' => $this->getTypeOfService()->getServicesAsEnglishString(),
'metaDataFields.coin:ss:type_of_service:nl' => $this->getTypeOfService()->getServicesAsDutchString(),
'metaDataFields.coin:contractual_base' => $this->getContractualBase(),
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types = 1);

/**
* Copyright 2024 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 Surfnet\ServiceProviderDashboard\Domain\Service;

use Surfnet\ServiceProviderDashboard\Domain\Entity\Constants;
use Surfnet\ServiceProviderDashboard\Domain\Entity\ManageEntity;

class ContractualBaseService
{
public function writeContractualBase(ManageEntity $entity): void
{
// 1. The entity must be targeted at the production env
if ($entity->getEnvironment() !== Constants::ENVIRONMENT_PRODUCTION) {
return;
}

// 2. It must be a SAML or OIDC entity
$protocol = $entity->getProtocol()->getProtocol();
if (!in_array($protocol, [Constants::TYPE_SAML, Constants::TYPE_OPENID_CONNECT_TNG], true)) {
return;
}

// 3. Determine the contractual base, based on the service type
$serviceType = $entity->getService()->getServiceType();
$contractualBase = match ($serviceType) {
Constants::SERVICE_TYPE_INSTITUTE => Constants::CONTRACTUAL_BASE_IX,
Constants::SERVICE_TYPE_NON_INSTITUTE => Constants::CONTRACTUAL_BASE_AO,
default => null,
};

if ($contractualBase === null) {
return;
}

// 4. Set the coin value on the entity
$entity->getMetaData()?->getCoin()->setContractualBase($contractualBase);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ services:
class: Surfnet\ServiceProviderDashboard\Application\CommandHandler\Entity\PublishEntityProductionCommandHandler
arguments:
- '@surfnet.manage.client.publish_client.prod_environment'
- '@Surfnet\ServiceProviderDashboard\Domain\Service\ContractualBaseService'
- '@Surfnet\ServiceProviderDashboard\Application\Service\EntityService'
- '@Surfnet\ServiceProviderDashboard\Application\Service\TicketService'
- '@request_stack'
Expand Down Expand Up @@ -644,6 +645,8 @@ services:
Surfnet\ServiceProviderDashboard\Domain\Repository\ServiceRepository:
'@Surfnet\ServiceProviderDashboard\Infrastructure\DashboardBundle\Repository\ServiceRepository'

Surfnet\ServiceProviderDashboard\Domain\Service\ContractualBaseService:

Surfnet\ServiceProviderDashboard\Application\Service\AttributeServiceInterface:
'@Surfnet\ServiceProviderDashboard\Application\Service\AttributeService'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@
use Surfnet\ServiceProviderDashboard\Application\Service\TicketService;
use Surfnet\ServiceProviderDashboard\Domain\Entity\Constants;
use Surfnet\ServiceProviderDashboard\Domain\Entity\Contact;
use Surfnet\ServiceProviderDashboard\Domain\Entity\Entity\Coin;
use Surfnet\ServiceProviderDashboard\Domain\Entity\Entity\Protocol;
use Surfnet\ServiceProviderDashboard\Domain\Entity\ManageEntity;
use Surfnet\ServiceProviderDashboard\Domain\Repository\PublishEntityRepository;
use Surfnet\ServiceProviderDashboard\Domain\Service\ContractualBaseService;
use Surfnet\ServiceProviderDashboard\Infrastructure\DashboardSamlBundle\Security\Identity;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
Expand Down Expand Up @@ -88,6 +91,7 @@ public function setUp(): void

$this->commandHandler = new PublishEntityProductionCommandHandler(
$this->publishEntityClient,
new ContractualBaseService(),
$this->entityService,
$this->ticketService,
$this->requestStack,
Expand All @@ -107,6 +111,17 @@ public function test_it_can_publish()
->andReturn('Test Entity Name');
$manageEntity->shouldReceive('isManageEntity')->andReturnTrue();
$manageEntity->shouldReceive('getEnvironment')->andReturn('production');
$manageEntity->shouldReceive('getService->getServiceType')->andReturn(Constants::SERVICE_TYPE_INSTITUTE);

$coin = m::mock(Coin::class);
$coin->shouldReceive('setContractualBase')->with(Constants::CONTRACTUAL_BASE_IX);
$manageEntity->shouldReceive('getMetaData->getCoin')->andReturn($coin);

$protocol = m::mock(Protocol::class);
$protocol->shouldReceive('getProtocol')->andReturn(Constants::TYPE_SAML);

$manageEntity
->shouldReceive('getProtocol')->andReturn($protocol);

$manageEntity
->shouldReceive('getMetaData->getEntityId')
Expand Down Expand Up @@ -172,7 +187,17 @@ public function test_it_can_republish()
->andReturn('123');
$manageEntity->shouldReceive('isManageEntity')->andReturnTrue();
$manageEntity->shouldReceive('getEnvironment')->andReturn('production');
$manageEntity->shouldReceive('getService->getServiceType')->andReturn(Constants::SERVICE_TYPE_INSTITUTE);

$coin = m::mock(Coin::class);
$coin->shouldReceive('setContractualBase')->with(Constants::CONTRACTUAL_BASE_IX);
$manageEntity->shouldReceive('getMetaData->getCoin')->andReturn($coin);

$protocol = m::mock(Protocol::class);
$protocol->shouldReceive('getProtocol')->andReturn(Constants::TYPE_SAML);

$manageEntity
->shouldReceive('getProtocol')->andReturn($protocol);
$manageEntity
->shouldReceive('setStatus')
->with(Constants::STATE_PUBLISHED);
Expand Down Expand Up @@ -272,6 +297,17 @@ public function test_does_not_create_ticket_when_client_resetting()
$manageEntity
->shouldReceive('getMetaData->getEntityId')
->andReturn('https://app.example.com/');
$manageEntity->shouldReceive('getService->getServiceType')->andReturn(Constants::SERVICE_TYPE_INSTITUTE);

$coin = m::mock(Coin::class);
$coin->shouldReceive('setContractualBase')->with(Constants::CONTRACTUAL_BASE_IX);
$manageEntity->shouldReceive('getMetaData->getCoin')->andReturn($coin);

$protocol = m::mock(Protocol::class);
$protocol->shouldReceive('getProtocol')->andReturn(Constants::TYPE_SAML);

$manageEntity
->shouldReceive('getProtocol')->andReturn($protocol);

$manageEntity
->shouldReceive('getId')
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Application/Service/EntityMergeServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public function test_it_can_merge_saml_save_command_data_into_an_empty_manage_en
$service = m::mock(Service::class);
$service->shouldReceive('getOrganizationNameEn', 'getOrganizationNameNl', 'getOrganizationDisplayNameEn', 'getOrganizationDisplayNameNl')
->andReturn('Organization Name');
$manageEntity = $this->service->mergeEntityCommand($this->buildSamlCommand($service), null);
$manageEntity = $this->service->mergeEntityCommand($this->buildSamlCommand($service));

self::assertNull($manageEntity->getId());
self::assertFalse($manageEntity->isManageEntity());
Expand Down
18 changes: 9 additions & 9 deletions tests/unit/Domain/Entity/Entity/CoinTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,19 @@ public function test_it_can_merge_data(Coin $coin, Coin $newData, Coin $expectat
public function provideCoinTestData()
{
yield [
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1),
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1),
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1)
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null),
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null),
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null)
];
yield [
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1),
new Coin('signatureMethod', null, 'https://www.example.com', null, 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1),
new Coin('signatureMethod', null, 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1),
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null),
new Coin('signatureMethod', null, 'https://www.example.com', null, 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null),
new Coin('signatureMethod', null, 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null),
];
yield [
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1),
new Coin(null, null, null, null, null, new TypeOfServiceCollection(), null, null),
new Coin(null, null, null, '1', null, new TypeOfServiceCollection(), null, null)
new Coin('signatureMethod', '23', 'https://www.example.com', '1', 'https://example.com', new TypeOfServiceCollection(), 'https://example.com/eula', 1, null),
new Coin(null, null, null, null, null, new TypeOfServiceCollection(), null, null, null),
new Coin(null, null, null, '1', null, new TypeOfServiceCollection(), null, null, null)
];
}
public function provideCoinTestDataWithTypeOfService()
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/Domain/Entity/Entity/MetaDataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ private function metaData(string $mode)
$contactList = m::mock(ContactList::class);
$contactList->shouldReceive('merge');

$coin = m::mock(Coin::class, [null, null, null, null, null, null, null, null]);
$coin = m::mock(Coin::class, [null, null, null, null, null, null, null, null, null]);
$coin->shouldReceive('merge');

$logo = m::mock(Logo::class);
Expand Down
Loading

0 comments on commit 9a8dcec

Please sign in to comment.