Skip to content

Commit

Permalink
Add coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
cicnavi committed Jan 9, 2025
1 parent ff2ffe6 commit 9016075
Show file tree
Hide file tree
Showing 8 changed files with 424 additions and 15 deletions.
19 changes: 19 additions & 0 deletions src/Federation/EntityStatement.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace SimpleSAML\OpenID\Federation;

use SimpleSAML\OpenID\Codebooks\ClaimsEnum;
use SimpleSAML\OpenID\Codebooks\EntityTypesEnum;
use SimpleSAML\OpenID\Codebooks\JwtTypesEnum;
use SimpleSAML\OpenID\Decorators\DateIntervalDecorator;
use SimpleSAML\OpenID\Exceptions\EntityStatementException;
Expand Down Expand Up @@ -192,6 +193,24 @@ public function getKeyId(): string
return parent::getKeyId() ?? throw new EntityStatementException('No KeyId header claim found.');
}

/**
* @throws \SimpleSAML\OpenID\Exceptions\JwsException
*/
public function getFederationFetchEndpoint(): ?string
{
/** @psalm-suppress MixedAssignment */
$federationFetchEndpoint = $this->getPayload()
[ClaimsEnum::Metadata->value]
[EntityTypesEnum::FederationEntity->value]
[ClaimsEnum::FederationFetchEndpoint->value] ?? null;

if (is_null($federationFetchEndpoint)) {
return null;
}

return (string)$federationFetchEndpoint;
}

/**
* @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException
* @throws \SimpleSAML\OpenID\Exceptions\JwsException
Expand Down
15 changes: 8 additions & 7 deletions src/Federation/EntityStatementFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use SimpleSAML\OpenID\Codebooks\EntityTypesEnum;
use SimpleSAML\OpenID\Codebooks\WellKnownEnum;
use SimpleSAML\OpenID\Decorators\DateIntervalDecorator;
use SimpleSAML\OpenID\Exceptions\EntityStatementException;
use SimpleSAML\OpenID\Exceptions\FetchException;
use SimpleSAML\OpenID\Exceptions\JwsException;
use SimpleSAML\OpenID\Federation\Factories\EntityStatementFactory;
Expand All @@ -34,7 +35,7 @@ protected function buildJwsInstance(string $token): EntityStatement
return $this->parsedJwsFactory->fromToken($token);
}

protected function getExpectedContentTypeHttpHeader(): string
public function getExpectedContentTypeHttpHeader(): string
{
return ContentTypesEnum::ApplicationEntityStatementJwt->value;
}
Expand Down Expand Up @@ -74,12 +75,8 @@ public function fromCacheOrFetchEndpoint(
string $subjectId,
EntityStatement $entityConfiguration,
): EntityStatement {
$entityConfigurationPayload = $entityConfiguration->getPayload();

$fetchEndpointUri = (string)($entityConfigurationPayload[ClaimsEnum::Metadata->value]
[EntityTypesEnum::FederationEntity->value]
[ClaimsEnum::FederationFetchEndpoint->value] ??
throw new JwsException('No fetch endpoint found in entity configuration.'));
$fetchEndpointUri = $entityConfiguration->getFederationFetchEndpoint() ??
throw new EntityStatementException('No fetch endpoint found in entity configuration.');

$this->logger?->debug(
'Entity statement fetch from cache or fetch endpoint.',
Expand Down Expand Up @@ -125,13 +122,15 @@ public function fromCache(string $uri): ?EntityStatement
return $entityStatement;
}

// @codeCoverageIgnoreStart
$message = 'Unexpected entity statement instance encountered for cache fetch.';
$this->logger?->error(
$message,
compact('uri', 'entityStatement'),
);

throw new FetchException($message);
// @codeCoverageIgnoreEnd
}

/**
Expand All @@ -148,12 +147,14 @@ public function fromNetwork(string $uri): EntityStatement
return $entityStatement;
}

// @codeCoverageIgnoreStart
$message = 'Unexpected entity statement instance encountered for network fetch.';
$this->logger?->error(
$message,
compact('uri', 'entityStatement'),
);

throw new FetchException($message);
// @codeCoverageIgnoreEnd
}
}
2 changes: 1 addition & 1 deletion src/Jws/AbstractJwsFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ public function __construct(
* @throws \SimpleSAML\OpenID\Exceptions\JwsException
*/
abstract protected function buildJwsInstance(string $token): ParsedJws;
abstract protected function getExpectedContentTypeHttpHeader(): ?string;
abstract public function getExpectedContentTypeHttpHeader(): ?string;
}
2 changes: 1 addition & 1 deletion src/Jws/JwsFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected function buildJwsInstance(string $token): ParsedJws
return $this->parsedJwsFactory->fromToken($token);
}

protected function getExpectedContentTypeHttpHeader(): ?string
public function getExpectedContentTypeHttpHeader(): ?string
{
return null;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Utils/ArtifactFetcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use SimpleSAML\OpenID\Decorators\CacheDecorator;
use SimpleSAML\OpenID\Decorators\HttpClientDecorator;
use SimpleSAML\OpenID\Exceptions\FetchException;
use SimpleSAML\OpenID\Exceptions\HttpException;
use Throwable;

class ArtifactFetcher
Expand Down Expand Up @@ -49,6 +48,7 @@ public function fromCacheAsString(string $keyElement, string ...$keyElements): ?
'Artifact not found in cache.',
compact('keyElement', 'keyElements'),
);
return null;
}

if (is_string($artifact)) {
Expand Down
71 changes: 66 additions & 5 deletions tests/src/Federation/EntityStatementFetcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use SimpleSAML\OpenID\Codebooks\ContentTypesEnum;
use SimpleSAML\OpenID\Codebooks\WellKnownEnum;
use SimpleSAML\OpenID\Decorators\DateIntervalDecorator;
use SimpleSAML\OpenID\Exceptions\EntityStatementException;
use SimpleSAML\OpenID\Exceptions\FetchException;
use SimpleSAML\OpenID\Federation\EntityStatement;
use SimpleSAML\OpenID\Federation\EntityStatementFetcher;
use SimpleSAML\OpenID\Federation\Factories\EntityStatementFactory;
Expand All @@ -21,13 +26,16 @@
#[CoversClass(EntityStatementFetcher::class)]
#[UsesClass(AbstractJwsFetcher::class)]
#[UsesClass(JwsFetcher::class)]
#[UsesClass(WellKnownEnum::class)]
class EntityStatementFetcherTest extends TestCase
{
protected MockObject $entityStatementFactoryMock;
protected MockObject $artifactFetcherMock;
protected MockObject $maxCacheDurationMock;
protected MockObject $helpersMock;
protected MockObject $loggerMock;
protected MockObject $responseMock;
protected MockObject $entityStatementMock;

protected function setUp(): void
{
Expand All @@ -36,6 +44,11 @@ protected function setUp(): void
$this->maxCacheDurationMock = $this->createMock(DateIntervalDecorator::class);
$this->helpersMock = $this->createMock(Helpers::class);
$this->loggerMock = $this->createMock(LoggerInterface::class);

$this->responseMock = $this->createMock(ResponseInterface::class);
$this->artifactFetcherMock->method('fromNetwork')->willReturn($this->responseMock);

$this->entityStatementMock = $this->createMock(EntityStatement::class);
}

protected function sut(
Expand Down Expand Up @@ -65,20 +78,68 @@ public function testCanCreateInstance(): void
$this->assertInstanceOf(EntityStatementFetcher::class, $this->sut());
}

public function testCanFetchFromCache(): void
public function testHasRightExpectedContentTypeHttpHeader(): void
{
$this->assertSame(
ContentTypesEnum::ApplicationEntityStatementJwt->value,
$this->sut()->getExpectedContentTypeHttpHeader(),
);
}

public function testCanFetchFromCacheOrWellKnownEndpoint(): void
{
$this->artifactFetcherMock->expects($this->once())->method('fromCacheAsString')
->with('uri')
->willReturn(null);

$this->responseMock->method('getStatusCode')->willReturn(200);
$this->responseMock->method('getHeaderLine')
->willReturn(ContentTypesEnum::ApplicationEntityStatementJwt->value);

$this->artifactFetcherMock->expects($this->once())->method('fromNetwork')
->willReturn($this->responseMock);

$this->assertInstanceOf(
EntityStatement::class,
$this->sut()->fromCacheOrWellKnownEndpoint('entityId'),
);
}

public function testCanFetchFromCacheOrFetchEndpoint(): void
{
$this->entityStatementMock->expects($this->once())
->method('getFederationFetchEndpoint')
->willReturn('fetch-uri');

$this->artifactFetcherMock->expects($this->once())->method('fromCacheAsString')
->willReturn('token');

$this->entityStatementFactoryMock->expects($this->once())->method('fromToken')
->with('token');

$this->assertInstanceOf(EntityStatement::class, $this->sut()->fromCache('uri'));
$this->sut()->fromCacheOrFetchEndpoint('entityId', $this->entityStatementMock);
}

public function testFetchFromCacheOrFetchEndpointThrowsIfNoFetchEndpoint(): void
{
$this->entityStatementMock->expects($this->once())
->method('getFederationFetchEndpoint')
->willReturn(null);

$this->expectException(EntityStatementException::class);
$this->expectExceptionMessage('fetch');

$this->sut()->fromCacheOrFetchEndpoint('entityId', $this->entityStatementMock);
}

public function testFetchFromCacheReturnsNull(): void
public function testCanFetchFromCache(): void
{
$this->markTestIncomplete('TODO mivanci');
$this->artifactFetcherMock->expects($this->once())->method('fromCacheAsString')
->with('uri')
->willReturn('token');

$this->entityStatementFactoryMock->expects($this->once())->method('fromToken')
->with('token');

$this->assertInstanceOf(EntityStatement::class, $this->sut()->fromCache('uri'));
}
}
Loading

0 comments on commit 9016075

Please sign in to comment.