Skip to content

Commit 881c3ac

Browse files
authored
Resolve PHP v8 depreciations in v2 (#199)
* Update nette/forms to v3.0 * Use SSP session instead of nette session for CSRF * Use own quality tools * Fix psalm errors * Fix tests * Move phpcs to dev * Bump conformance-suite version * Update test.yml --------- Co-authored-by: Marko Ivančić <[email protected]>
1 parent a3f7643 commit 881c3ac

File tree

17 files changed

+96
-98
lines changed

17 files changed

+96
-98
lines changed

.github/workflows/test.yaml

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
php-versions: ["7.4"]
16+
php-versions: ["7.4", "8.0", "8.1"]
1717

1818
steps:
1919
- name: Setup PHP, with composer and extensions
@@ -35,14 +35,14 @@ jobs:
3535
git config --global core.autocrlf false
3636
git config --global core.eol lf
3737
38-
- uses: actions/checkout@v2
38+
- uses: actions/checkout@v3
3939

4040
- name: Get composer cache directory
4141
id: composer-cache
4242
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
4343

4444
- name: Cache composer dependencies
45-
uses: actions/cache@v1
45+
uses: actions/cache@v3
4646
with:
4747
path: ${{ steps.composer-cache.outputs.dir }}
4848
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
@@ -54,9 +54,6 @@ jobs:
5454
- name: Install Composer dependencies
5555
run: composer install --no-progress --prefer-dist --optimize-autoloader
5656

57-
- name: Syntax check PHP
58-
run: bash vendor/bin/check-syntax-php.sh
59-
6057
- name: Decide whether to run code coverage or not
6158
if: ${{ matrix.php-versions != '7.4' }}
6259
run: |
@@ -90,7 +87,7 @@ jobs:
9087
- name: Setup problem matchers for PHP
9188
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
9289

93-
- uses: actions/checkout@v2
90+
- uses: actions/checkout@v3
9491

9592
- name: Get composer cache directory
9693
id: composer-cache
@@ -131,14 +128,14 @@ jobs:
131128
- name: Setup problem matchers for PHP
132129
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
133130

134-
- uses: actions/checkout@v2
131+
- uses: actions/checkout@v3
135132

136133
- name: Get composer cache directory
137134
id: composer-cache
138135
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
139136

140137
- name: Cache composer dependencies
141-
uses: actions/cache@v1
138+
uses: actions/cache@v3
142139
with:
143140
path: ${{ steps.composer-cache.outputs.dir }}
144141
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
@@ -147,12 +144,6 @@ jobs:
147144
- name: Install Composer dependencies
148145
run: composer install --no-progress --prefer-dist --optimize-autoloader
149146

150-
- name: Syntax check YAML / XML / JSON
151-
run: |
152-
bash vendor/bin/check-syntax-yaml.sh
153-
bash vendor/bin/check-syntax-xml.sh
154-
bash vendor/bin/check-syntax-json.sh
155-
156147
quality:
157148
name: Quality control
158149
runs-on: [ubuntu-latest]
@@ -169,14 +160,14 @@ jobs:
169160
- name: Setup problem matchers for PHP
170161
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
171162

172-
- uses: actions/checkout@v2
163+
- uses: actions/checkout@v3
173164

174165
- name: Get composer cache directory
175166
id: composer-cache
176167
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
177168

178169
- name: Cache composer dependencies
179-
uses: actions/cache@v1
170+
uses: actions/cache@v3
180171
with:
181172
path: ${{ steps.composer-cache.outputs.dir }}
182173
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
@@ -185,13 +176,13 @@ jobs:
185176
- name: Install Composer dependencies
186177
run: composer install --no-progress --prefer-dist --optimize-autoloader
187178

188-
- uses: actions/download-artifact@v1
179+
- uses: actions/download-artifact@v3
189180
with:
190181
name: build-data
191182
path: ${{ github.workspace }}/build
192183

193184
- name: Codecov
194-
uses: codecov/codecov-action@v1
185+
uses: codecov/codecov-action@v3
195186

196187
- name: PHP Code Sniffer
197188
if: always()
@@ -201,21 +192,19 @@ jobs:
201192
if: always()
202193
run: php vendor/bin/psalm --show-info=true
203194

204-
- name: Psalter
205-
if: always()
206-
run: php vendor/bin/psalter --issues=UnnecessaryVarAnnotation --dry-run
207-
208-
build-conformance-suite:
195+
conformance-suite:
209196
runs-on: ubuntu-latest
210197
env:
211-
VERSION: release-v4.1.11
198+
SUITE_BASE_URL: https://localhost.emobix.co.uk:8443
199+
VERSION: release-v4.1.45
212200
steps:
213-
- name: Load Cached Conformance Suite Build
214-
uses: actions/cache@v2
215-
id: cache
201+
- uses: actions/checkout@v3
216202
with:
217-
path: ./conformance-suite
218-
key: suite-${{ hashFiles('**/test.yml') }}
203+
path: main
204+
- name: Setup Python Dependencies
205+
run: |
206+
pip install --upgrade pip
207+
pip install httpx
219208
- name: Conformance Suite Checkout
220209
if: ${{ steps.cache.outputs.cache-hit != 'true' }}
221210
run: git clone --depth 1 --single-branch --branch $VERSION https://gitlab.com/openid/conformance-suite.git
@@ -228,23 +217,6 @@ jobs:
228217
sed -i -e 's/localhost/localhost.emobix.co.uk/g' src/main/resources/application.properties
229218
sed -i -e 's/-B clean/-B -DskipTests=true/g' builder-compose.yml
230219
docker-compose -f builder-compose.yml run builder
231-
232-
conformance-suite:
233-
runs-on: ubuntu-latest
234-
needs:
235-
- build-conformance-suite
236-
env:
237-
SUITE_BASE_URL: https://localhost.emobix.co.uk:8443
238-
steps:
239-
- uses: actions/checkout@v2
240-
with:
241-
path: main
242-
- name: Load Cached Conformance Suite Build
243-
uses: actions/cache@v2
244-
id: cache
245-
with:
246-
path: ./conformance-suite
247-
key: suite-${{ hashFiles('**/test.yml') }}
248220
- name: Run Conformance Suite
249221
working-directory: ./conformance-suite
250222
run: |

CONFORMANCE_TEST.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Clone the conformance test git repo, build the software and run it.
1515
git clone https://gitlab.com/openid/conformance-suite.git
1616
cd conformance-suite
1717
# Version 4.1.10 has a bug when building
18-
git checkout release-v4.1.9
18+
git checkout release-v4.1.45
1919
MAVEN_CACHE=./m2 docker-compose -f builder-compose.yml run builder
2020
docker-compose up
2121
```

composer.json

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"laminas/laminas-httphandlerrunner": "^1.1.0",
2828
"lcobucci/jwt": "^4.1",
2929
"league/oauth2-server": "^8.1.0",
30-
"nette/forms": "^2.4",
30+
"nette/forms": "^3.1",
3131
"psr/container": "^1.0",
3232
"psr/log": "^1.1",
3333
"simplesamlphp/composer-module-installer": "^1.0",
@@ -43,7 +43,8 @@
4343
"phpunit/phpcov": "^8.2.0",
4444
"phpunit/phpunit": "^9.0.0",
4545
"simplesamlphp/simplesamlphp": "^1.19,<2",
46-
"simplesamlphp/simplesamlphp-test-framework": "^0.1.9"
46+
"squizlabs/php_codesniffer": "^3.7",
47+
"vimeo/psalm": "^5.8"
4748
},
4849
"config": {
4950
"preferred-install": {
@@ -71,12 +72,7 @@
7172
},
7273
"scripts": {
7374
"pre-commit": [
74-
"vendor/bin/check-syntax-php.sh",
75-
"vendor/bin/check-syntax-json.sh",
76-
"vendor/bin/check-syntax-xml.sh",
77-
"vendor/bin/check-syntax-yaml.sh",
7875
"vendor/bin/psalm",
79-
"vendor/bin/psalter --issues=UnnecessaryVarAnnotation --dry-run",
8076
"vendor/bin/phpcs -p"
8177
],
8278
"tests": [

lib/Form/ClientForm.php

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
class ClientForm extends Form
2323
{
24+
protected const TYPE_ARRAY = 'array';
25+
2426
/**
2527
* RFC3986. AppendixB. Parsing a URI Reference with a Regular Expression.
2628
*/
@@ -55,26 +57,35 @@ public function __construct(ConfigurationService $configurationService)
5557

5658
public function validateRedirectUri(Form $form): void
5759
{
60+
/** @var array $values */
61+
$values = $form->getValues(self::TYPE_ARRAY);
62+
5863
$this->validateByMatchingRegex(
59-
$form->getValues()['redirect_uri'],
64+
$values['redirect_uri'] ?? [],
6065
self::REGEX_URI,
6166
'Invalid URI: '
6267
);
6368
}
6469

6570
public function validateAllowedOrigin(Form $form): void
6671
{
72+
/** @var array $values */
73+
$values = $form->getValues(self::TYPE_ARRAY);
74+
6775
$this->validateByMatchingRegex(
68-
$form->getValues()['allowed_origin'] ?? [],
76+
$values['allowed_origin'] ?? [],
6977
self::REGEX_ALLOWED_ORIGIN_URL,
7078
'Invalid allowed origin: '
7179
);
7280
}
7381

7482
public function validatePostLogoutRedirectUri(Form $form): void
7583
{
84+
/** @var array $values */
85+
$values = $form->getValues(self::TYPE_ARRAY);
86+
7687
$this->validateByMatchingRegex(
77-
$form->getValues()['post_logout_redirect_uri'] ?? [],
88+
$values['post_logout_redirect_uri'] ?? [],
7889
self::REGEX_URI,
7990
'Invalid post-logout redirect URI: '
8091
);
@@ -108,9 +119,10 @@ protected function validateByMatchingRegex(
108119
*
109120
* @return array
110121
*/
111-
public function getValues($asArray = false): array
122+
public function getValues($returnType = null, ?array $controls = null): array
112123
{
113-
$values = parent::getValues(true);
124+
/** @var array $values */
125+
$values = parent::getValues(self::TYPE_ARRAY);
114126

115127
// Sanitize redirect_uri and allowed_origin
116128
$values['redirect_uri'] = $this->convertTextToArrayWithLinesAsValues($values['redirect_uri']);
@@ -136,37 +148,43 @@ public function getValues($asArray = false): array
136148
return $values;
137149
}
138150

139-
/**
140-
* @param array $values
141-
* @param bool $erase
142-
*
143-
* @return Form
144-
*/
145-
public function setDefaults($values, $erase = false): Form
151+
public function setDefaults($data, bool $erase = false)
146152
{
147-
$values['redirect_uri'] = implode("\n", $values['redirect_uri']);
153+
if (! is_array($data)) {
154+
if ($data instanceof \Traversable) {
155+
$data = iterator_to_array($data);
156+
} else {
157+
$data = (array) $data;
158+
}
159+
}
160+
161+
$data['redirect_uri'] = implode("\n", $data['redirect_uri']);
148162

149163
// Allowed origins are only available for public clients (not for confidential clients).
150-
if (! $values['is_confidential'] && isset($values['allowed_origin'])) {
151-
$values['allowed_origin'] = implode("\n", $values['allowed_origin']);
164+
if (! $data['is_confidential'] && isset($data['allowed_origin'])) {
165+
$data['allowed_origin'] = implode("\n", $data['allowed_origin']);
152166
} else {
153-
$values['allowed_origin'] = '';
167+
$data['allowed_origin'] = '';
154168
}
155169

156-
$values['post_logout_redirect_uri'] = implode("\n", $values['post_logout_redirect_uri']);
170+
$data['post_logout_redirect_uri'] = implode("\n", $data['post_logout_redirect_uri']);
157171

158-
$values['scopes'] = array_intersect($values['scopes'], array_keys($this->getScopes()));
172+
$data['scopes'] = array_intersect($data['scopes'], array_keys($this->getScopes()));
159173

160-
return parent::setDefaults($values, $erase);
174+
return parent::setDefaults($data, $erase);
161175
}
162176

163177
protected function buildForm(): void
164178
{
165179
$this->getElementPrototype()->addAttributes(['class' => 'ui form']);
166180

181+
/** @psalm-suppress InvalidPropertyAssignmentValue According to docs this is fine. */
167182
$this->onValidate[] = [$this, 'validateRedirectUri'];
183+
/** @psalm-suppress InvalidPropertyAssignmentValue According to docs this is fine. */
168184
$this->onValidate[] = [$this, 'validateAllowedOrigin'];
185+
/** @psalm-suppress InvalidPropertyAssignmentValue According to docs this is fine. */
169186
$this->onValidate[] = [$this, 'validatePostLogoutRedirectUri'];
187+
/** @psalm-suppress InvalidPropertyAssignmentValue According to docs this is fine. */
170188
$this->onValidate[] = [$this, 'validateBackChannelLogoutUri'];
171189

172190
$this->setMethod('POST');

lib/Form/Controls/CsrfProtection.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
namespace SimpleSAML\Module\oidc\Form\Controls;
1616

1717
use Nette\Forms\Controls\CsrfProtection as BaseCsrfProtection;
18+
use Nette\InvalidStateException;
1819
use Nette\Utils\Random;
1920
use SimpleSAML\Session;
2021
use SimpleSAML\SessionHandler;
@@ -25,7 +26,15 @@ class CsrfProtection extends BaseCsrfProtection
2526

2627
public function __construct($errorMessage)
2728
{
28-
parent::__construct($errorMessage);
29+
// Instead of calling CsrfProtection parent class constructor, go to it's parent (HiddenField), and call
30+
// its constructor. This is to avoid setting a Nette session in CsrfProtection parent, and use the SSP one.
31+
$hiddentFieldParent = get_parent_class(get_parent_class($this));
32+
33+
if (! is_string($hiddentFieldParent)) {
34+
throw new InvalidStateException('CsrfProtection initialization error');
35+
}
36+
37+
$hiddentFieldParent::__construct();
2938

3039
$this->getRules()->reset();
3140
$this->addRule(self::PROTECTION, $errorMessage);

lib/Repositories/AuthCodeRepository.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ public function revokeAuthCode($codeId)
102102
/**
103103
* {@inheritdoc}
104104
*/
105-
public function isAuthCodeRevoked($tokenId): bool
105+
public function isAuthCodeRevoked($codeId): bool
106106
{
107-
$authCode = $this->findById($tokenId);
107+
$authCode = $this->findById($codeId);
108108

109109
if (!$authCode instanceof AuthCodeEntity) {
110-
throw new \RuntimeException("AuthCode not found: {$tokenId}");
110+
throw new \RuntimeException("AuthCode not found: {$codeId}");
111111
}
112112

113113
return $authCode->isRevoked();

lib/Server/Grants/AuthCodeGrant.php

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,10 @@ class AuthCodeGrant extends OAuth2AuthCodeGrant implements
7171
*/
7272
protected array $codeChallengeVerifiers = [];
7373

74-
/**
75-
* @var AuthCodeRepositoryInterface
76-
*/
7774
protected $authCodeRepository;
7875

79-
/**
80-
* @var AccessTokenRepositoryInterface
81-
*/
8276
protected $accessTokenRepository;
8377

84-
/**
85-
* @var RefreshTokenRepositoryInterface
86-
*/
8778
protected $refreshTokenRepository;
8879

8980
private RequestRulesManager $requestRulesManager;
@@ -120,10 +111,10 @@ public function __construct(
120111
}
121112

122113
/**
123-
* @param ClientEntityInterface $client
114+
* @param OAuth2ClientEntityInterface $client
124115
* @return bool
125116
*/
126-
protected function shouldCheckPkce(ClientEntityInterface $client): bool
117+
protected function shouldCheckPkce(OAuth2ClientEntityInterface $client): bool
127118
{
128119
return $this->requireCodeChallengeForPublicClients &&
129120
! $client->isConfidential();

0 commit comments

Comments
 (0)