Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ jobs:
- ubuntu-latest

php-version:
- "8.1"
- "8.2"
- "8.3"
- "8.4"
- "8.5"

dependencies:
- lowest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
vendor
Packages
composer.lock
.phpunit.cache
2 changes: 1 addition & 1 deletion Classes/Authentication/OpenIdConnectEntryPoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
final class OpenIdConnectEntryPoint extends AbstractEntryPoint
{
/**
* @Flow\Inject(name="Neos.Flow:SecurityLogger")
* @var LoggerInterface
*/
#[Flow\Inject(name: 'Neos.Flow:SecurityLogger')]
protected $logger;

/**
Expand Down
13 changes: 6 additions & 7 deletions Classes/Authentication/OpenIdConnectProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,33 @@
final class OpenIdConnectProvider extends AbstractProvider
{
/**
* @Flow\Inject(lazy = false)
* @var Context
*/
#[Flow\Inject(lazy: false)]
protected $securityContext;

/**
* @Flow\Inject(lazy = false)
* @var PolicyService
*/
#[Flow\Inject(lazy: false)]
protected $policyService;

/**
* @Flow\Inject(name="Neos.Flow:SecurityLogger")
* @var LoggerInterface
*/
#[Flow\Inject(name: 'Neos.Flow:SecurityLogger')]
protected $logger;

/**
* @Flow\Inject
* @var AccountRepository
*/
#[Flow\Inject]
protected $accountRepository;

/**
* @Flow\Inject
* @var SessionInterface
*/
#[Flow\Inject]
protected $session;

/**
Expand Down Expand Up @@ -206,9 +206,8 @@ public function getServiceName(): string
* @param TokenInterface $authenticationToken
* @param IdentityToken $identityToken
* @param Role[] $roles
* @return void
* @Flow\Signal()
*/
#[Flow\Signal]
public function emitAuthenticated(TokenInterface $authenticationToken, IdentityToken $identityToken, array $roles): void
{
}
Expand Down
4 changes: 2 additions & 2 deletions Classes/Authentication/TokenArguments.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ final class TokenArguments implements \ArrayAccess
public const SERVICE_NAME = 'service';

/**
* @Flow\Inject
* @var HashService
*/
#[Flow\Inject]
protected $hashService;

/**
* @Flow\Inject
* @var LoggerInterface
*/
#[Flow\Inject]
protected $logger;

/**
Expand Down
2 changes: 1 addition & 1 deletion Classes/Command/OidcCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ final class OidcCommandController extends CommandController
protected $entityManager;

/**
* @Flow\InjectConfiguration
* @var array
*/
#[Flow\InjectConfiguration]
protected $settings;

/**
Expand Down
2 changes: 1 addition & 1 deletion Classes/OAuthClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class OAuthClient extends \Flownative\OAuth2\Client\OAuthClient
public const SERVICE_TYPE= 'oidc';

/**
* @Flow\InjectConfiguration(path="http.baseUri", package="Neos.Flow")
* @var string
*/
#[Flow\InjectConfiguration(path: 'http.baseUri', package: 'Neos.Flow')]
protected $flowBaseUriSetting;

private array $options = [];
Expand Down
10 changes: 7 additions & 3 deletions Classes/OpenIdConnectClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ final class OpenIdConnectClient
private $oAuthClient;

/**
* @Flow\InjectConfiguration
* @var array
*/
#[Flow\InjectConfiguration]
protected $settings;

/**
Expand All @@ -55,9 +55,9 @@ final class OpenIdConnectClient
protected $httpClient;

/**
* @Flow\Inject(name="Neos.Flow:SecurityLogger")
* @var LoggerInterface
*/
#[Flow\Inject(name: 'Neos.Flow:SecurityLogger')]
protected $logger;

/**
Expand Down Expand Up @@ -350,7 +350,11 @@ private function amendOptionsWithDiscovery(string $discoveryUri): void
} catch (GuzzleException $e) {
throw new ConnectionException(sprintf('OpenID Connect Client: Failed discovering options at %s: %s', $discoveryUri, $e->getMessage()), 1554902567);
}
$discoveredOptions = \GuzzleHttp\json_decode($response->getBody()->getContents(), true);
try {
$discoveredOptions = json_decode($response->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException) {
$discoveredOptions = null;
}
if (!is_array($discoveredOptions)) {
throw new ConnectionException('OpenID Connect Client: Discovery endpoint returned invalid response.', 1554903349);
}
Expand Down
29 changes: 9 additions & 20 deletions Tests/Unit/IdentityTokenTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
* source code.
*/

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

class IdentityTokenTest extends TestCase
Expand All @@ -28,11 +30,8 @@ public static function invalidJsonStrings(): array
];
}

/**
* @test
* @dataProvider invalidJsonStrings
* @throws
*/
#[Test]
#[DataProvider('invalidJsonStrings')]
public function fromJsonRejectsInvalidJsonStrings(string $json, int $expectedExceptionCode): void
{
$this->expectException(\InvalidArgumentException::class);
Expand All @@ -44,10 +43,8 @@ public function fromJsonRejectsInvalidJsonStrings(string $json, int $expectedExc
* {"kid":"dfebe5e7-4232-4464-8f2e-151681a0d173","typ":"JWT","alg":"RS256"}
* {"iss":"https://id.example.com","aud":"@!DDD5.370D.8547.FFD9!0001!A1C9.92C1!0008!13DB.54D8.65DE.2761","exp":1559205560,"iat":1559201960,"auth_time":1559201959,"at_hash":"_SPGts59ISlWMHxs2a03sw","oxOpenIDConnectVersion":"openidconnect-1.0","sub":"UWAYfzzmcaNAZy_C8a8UoUxMmhT1IlcKlXG8TnWkyIM"}
* … (binary data of signature) …
*
* @test
* @throws
*/
#[Test]
public function fromJsonSetsValuesCorrectly(): void
{
$json = 'eyJraWQiOiJkZmViZTVlNy00MjMyLTQ0NjQtOGYyZS0xNTE2ODFhMGQxNzMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lkLmV4YW1wbGUuY29tIiwiYXVkIjoiQCFEREQ1LjM3MEQuODU0Ny5GRkQ5ITAwMDEhQTFDOS45MkMxITAwMDghMTNEQi41NEQ4LjY1REUuMjc2MSIsImV4cCI6MTU1OTIwNTU2MCwiaWF0IjoxNTU5MjAxOTYwLCJhdXRoX3RpbWUiOjE1NTkyMDE5NTksImF0X2hhc2giOiJfU1BHdHM1OUlTbFdNSHhzMmEwM3N3Iiwib3hPcGVuSURDb25uZWN0VmVyc2lvbiI6Im9wZW5pZGNvbm5lY3QtMS4wIiwic3ViIjoiVVdBWWZ6em1jYU5BWnlfQzhhOFVvVXhNbWhUMUlsY0tsWEc4VG5Xa3lJTSJ9.VsOdosHuRWVaoacWG1CNJl0IZrHH-HbFTCZDcQDtFPSma13sHO-C69tm_HTjHX5DnMX6B_lDCgu3A8AsSZIQEG71z_Mnd2uxHoUrKUtHr8iM9bhpPKMnaXx9jr0O1EtKAJDLkz4qdzNunyOU7Ud94Lc8YxIjf7FZH_-jJc0UqFyFKY2rdEiZQVATNG94F-SIWA4CK5FZtW47TCL8EPBUzP8gGG8g6eMBEIfv80uWQxpJ59_UB91D8U6zSOiA4JrFDBRLkIX2kGnUZ7eu1G-4O6TglL_Id0oMeJdNEsMARYKHGmYZjvHGFVoLyoxca1KDK5dlcnLsYyxfKsZWNrTaqA';
Expand All @@ -58,10 +55,7 @@ public function fromJsonSetsValuesCorrectly(): void
static::assertSame('@!DDD5.370D.8547.FFD9!0001!A1C9.92C1!0008!13DB.54D8.65DE.2761', $identityToken->values['aud']);
}

/**
* @test
* @throws
*/
#[Test]
public function asJwtReturnsTokenAsString(): void
{
$json = 'eyJraWQiOiJkZmViZTVlNy00MjMyLTQ0NjQtOGYyZS0xNTE2ODFhMGQxNzMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lkLmV4YW1wbGUuY29tIiwiYXVkIjoiQCFEREQ1LjM3MEQuODU0Ny5GRkQ5ITAwMDEhQTFDOS45MkMxITAwMDghMTNEQi41NEQ4LjY1REUuMjc2MSIsImV4cCI6MTU1OTIwNTU2MCwiaWF0IjoxNTU5MjAxOTYwLCJhdXRoX3RpbWUiOjE1NTkyMDE5NTksImF0X2hhc2giOiJfU1BHdHM1OUlTbFdNSHhzMmEwM3N3Iiwib3hPcGVuSURDb25uZWN0VmVyc2lvbiI6Im9wZW5pZGNvbm5lY3QtMS4wIiwic3ViIjoiVVdBWWZ6em1jYU5BWnlfQzhhOFVvVXhNbWhUMUlsY0tsWEc4VG5Xa3lJTSJ9.VsOdosHuRWVaoacWG1CNJl0IZrHH-HbFTCZDcQDtFPSma13sHO-C69tm_HTjHX5DnMX6B_lDCgu3A8AsSZIQEG71z_Mnd2uxHoUrKUtHr8iM9bhpPKMnaXx9jr0O1EtKAJDLkz4qdzNunyOU7Ud94Lc8YxIjf7FZH_-jJc0UqFyFKY2rdEiZQVATNG94F-SIWA4CK5FZtW47TCL8EPBUzP8gGG8g6eMBEIfv80uWQxpJ59_UB91D8U6zSOiA4JrFDBRLkIX2kGnUZ7eu1G-4O6TglL_Id0oMeJdNEsMARYKHGmYZjvHGFVoLyoxca1KDK5dlcnLsYyxfKsZWNrTaqA';
Expand All @@ -70,9 +64,7 @@ public function asJwtReturnsTokenAsString(): void
static::assertSame((string)$identityToken, $json);
}

/**
* @test
*/
#[Test]
public function isExpiredAtReturnsCorrectResult(): void
{
$json = 'eyJraWQiOiJkZmViZTVlNy00MjMyLTQ0NjQtOGYyZS0xNTE2ODFhMGQxNzMiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2lkLmV4YW1wbGUuY29tIiwiYXVkIjoiQCFEREQ1LjM3MEQuODU0Ny5GRkQ5ITAwMDEhQTFDOS45MkMxITAwMDghMTNEQi41NEQ4LjY1REUuMjc2MSIsImV4cCI6MTU1OTIwNTU2MCwiaWF0IjoxNTU5MjAxOTYwLCJhdXRoX3RpbWUiOjE1NTkyMDE5NTksImF0X2hhc2giOiJfU1BHdHM1OUlTbFdNSHhzMmEwM3N3Iiwib3hPcGVuSURDb25uZWN0VmVyc2lvbiI6Im9wZW5pZGNvbm5lY3QtMS4wIiwic3ViIjoiVVdBWWZ6em1jYU5BWnlfQzhhOFVvVXhNbWhUMUlsY0tsWEc4VG5Xa3lJTSJ9.VsOdosHuRWVaoacWG1CNJl0IZrHH-HbFTCZDcQDtFPSma13sHO-C69tm_HTjHX5DnMX6B_lDCgu3A8AsSZIQEG71z_Mnd2uxHoUrKUtHr8iM9bhpPKMnaXx9jr0O1EtKAJDLkz4qdzNunyOU7Ud94Lc8YxIjf7FZH_-jJc0UqFyFKY2rdEiZQVATNG94F-SIWA4CK5FZtW47TCL8EPBUzP8gGG8g6eMBEIfv80uWQxpJ59_UB91D8U6zSOiA4JrFDBRLkIX2kGnUZ7eu1G-4O6TglL_Id0oMeJdNEsMARYKHGmYZjvHGFVoLyoxca1KDK5dlcnLsYyxfKsZWNrTaqA';
Expand All @@ -96,11 +88,8 @@ public static function audiences(): array
];
}

/**
* @test
* @dataProvider audiences
* @throws
*/
#[Test]
#[DataProvider('audiences')]
public function audienceContainsSupportsSingleAndMultipleAudiences(string|array|null $audienceClaim, string $audience, bool $expectedResult): void
{
$values = ['iss' => 'https://id.example.com', 'sub' => 'subject'];
Expand Down
42 changes: 12 additions & 30 deletions Tests/Unit/OpenIdConnectClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use Neos\Cache\Backend\TransientMemoryBackend;
use Neos\Cache\Frontend\VariableFrontend;
use Neos\Flow\Utility\Algorithms;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\StreamInterface;
Expand Down Expand Up @@ -77,7 +79,7 @@ public function setUp(): void
$this->jwksCache = new VariableFrontend('jwks', new TransientMemoryBackend());
$this->jwksCache->initializeObject();

$this->oAuthClient = $this->createPartialMock(OAuthClient::class, ['getAuthorization']);
$this->oAuthClient = $this->createStub(OAuthClient::class);

$logger = $this->createStub(LoggerInterface::class);

Expand All @@ -88,10 +90,7 @@ public function setUp(): void
$this->inject($this->oidcClient, 'logger', $logger);
}

/**
* @test
* @throws
*/
#[Test]
public function getJwksReturnsJwksAndStoresItInCache(): void
{
$mockHttpClient = $this->createMock(HttpClient::class);
Expand All @@ -115,14 +114,11 @@ public function getJwksReturnsJwksAndStoresItInCache(): void
static::assertSame($expectedJwks, $this->jwksCache->get($cacheEntryIdentifier));
}

/**
* @test
* @throws
*/
#[Test]
public function getJwksThrowsExceptionOnFailedDiscoveryRequest(): void
{
$mockHttpClient = $this->createMock(HttpClient::class);
$mockHttpRequest = $this->createMock(Request::class);
$mockHttpRequest = $this->createStub(Request::class);

$this->inject($this->oidcClient, 'settings', $this->settings);
$this->inject($this->oidcClient, 'httpClient', $mockHttpClient);
Expand All @@ -134,10 +130,7 @@ public function getJwksThrowsExceptionOnFailedDiscoveryRequest(): void
$this->oidcClient->getJwks();
}

/**
* @test
* @throws
*/
#[Test]
public function getJwksThrowsExceptionOnMalformedResponseFromDiscoveryService(): void
{
$mockHttpClient = $this->createMock(HttpClient::class);
Expand All @@ -156,10 +149,7 @@ public function getJwksThrowsExceptionOnMalformedResponseFromDiscoveryService():
$this->oidcClient->getJwks();
}

/**
* @test
* @throws
*/
#[Test]
public function getJwksReturnsJwksFromCacheIfItExists(): void
{
$this->inject($this->oidcClient, 'settings', $this->settings);
Expand All @@ -172,10 +162,7 @@ public function getJwksReturnsJwksFromCacheIfItExists(): void
static::assertSame($expectedJwks, $this->oidcClient->getJwks());
}

/**
* @test
* @throws
*/
#[Test]
public function getAccessTokenReturnsAccessTokenFromAuthorization(): void
{
$serviceName = 'test';
Expand All @@ -192,7 +179,7 @@ public function getAccessTokenReturnsAccessTokenFromAuthorization(): void
$authorization = new Authorization($authorizationId, $serviceName, $clientId, Authorization::GRANT_CLIENT_CREDENTIALS, $scope);
$authorization->setSerializedAccessToken(json_encode($expectedAccessToken, JSON_THROW_ON_ERROR, 512));

$this->oAuthClient->method('getAuthorization')->with($authorizationId)->willReturn($authorization);
$this->oAuthClient->method('getAuthorization')->willReturnMap([[$authorizationId, $authorization]]);

$actualAccessToken = $this->oidcClient->getAccessToken($serviceName, $clientId, $clientSecret, $scope);

Expand All @@ -212,15 +199,11 @@ public static function authorizationScopes(): array
];
}

/**
* @test
* @dataProvider authorizationScopes
* @throws
*/
#[Test]
#[DataProvider('authorizationScopes')]
public function buildAuthorizationScopeAddsRequiredScopeIdentifiers(string $scope, bool $requestRefreshToken, string $expectedScope): void
{
$method = new \ReflectionMethod(OpenIdConnectClient::class, 'buildAuthorizationScope');
$method->setAccessible(true);

static::assertSame($expectedScope, $method->invoke($this->oidcClient, $scope, $requestRefreshToken));
}
Expand Down Expand Up @@ -253,7 +236,6 @@ protected function inject($target, $name, $dependency): void
$target->$methodName($dependency);
} elseif ($objectReflection->hasProperty($name)) {
$property = $objectReflection->getProperty($name);
$property->setAccessible(true);
$property->setValue($target, $dependency);
} else {
throw new \RuntimeException('Could not inject ' . $name . ' into object of type ' . get_class($target));
Expand Down
Loading
Loading