Skip to content

Commit f39f27e

Browse files
committed
fix: adjust WebAuthn code to new major version
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent c3988d3 commit f39f27e

9 files changed

Lines changed: 278 additions & 162 deletions

File tree

apps/settings/lib/Controller/WebAuthnController.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
use OCP\AppFramework\Http\Attribute\OpenAPI;
2020
use OCP\AppFramework\Http\Attribute\PasswordConfirmationRequired;
2121
use OCP\AppFramework\Http\Attribute\UseSession;
22+
use OCP\AppFramework\Http\DataDisplayResponse;
2223
use OCP\AppFramework\Http\JSONResponse;
24+
use OCP\AppFramework\Http\Response;
2325
use OCP\IRequest;
2426
use OCP\ISession;
2527
use OCP\IUserSession;
2628
use Psr\Log\LoggerInterface;
27-
use Webauthn\PublicKeyCredentialCreationOptions;
2829

2930
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
3031
class WebAuthnController extends Controller {
@@ -45,15 +46,17 @@ public function __construct(
4546
#[PasswordConfirmationRequired]
4647
#[UseSession]
4748
#[NoCSRFRequired]
48-
public function startRegistration(): JSONResponse {
49+
public function startRegistration(): Response {
4950
$this->logger->debug('Starting WebAuthn registration');
5051

5152
$credentialOptions = $this->manager->startRegistration($this->userSession->getUser(), $this->request->getServerHost());
5253

5354
// Set this in the session since we need it on finish
5455
$this->session->set(self::WEBAUTHN_REGISTRATION, $credentialOptions);
5556

56-
return new JSONResponse($credentialOptions);
57+
$response = new DataDisplayResponse($credentialOptions);
58+
$response->addHeader('Content-Type', 'application/json; charset=utf-8');
59+
return $response;
5760
}
5861

5962
#[NoSubAdminRequired]
@@ -69,11 +72,10 @@ public function finishRegistration(string $name, string $data): JSONResponse {
6972
}
7073

7174
// Obtain the publicKeyCredentialOptions from when we started the registration
72-
$publicKeyCredentialCreationOptions = PublicKeyCredentialCreationOptions::createFromArray($this->session->get(self::WEBAUTHN_REGISTRATION));
73-
75+
$registrationOptions = $this->session->get(self::WEBAUTHN_REGISTRATION);
7476
$this->session->remove(self::WEBAUTHN_REGISTRATION);
7577

76-
return new JSONResponse($this->manager->finishRegister($publicKeyCredentialCreationOptions, $name, $data));
78+
return new JSONResponse($this->manager->finishRegister($registrationOptions, $name, $data));
7779
}
7880

7981
#[NoSubAdminRequired]

build/psalm-baseline.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2337,11 +2337,6 @@
23372337
<code><![CDATA[validateMailAddress]]></code>
23382338
</DeprecatedMethod>
23392339
</file>
2340-
<file src="apps/settings/lib/Controller/WebAuthnController.php">
2341-
<DeprecatedMethod>
2342-
<code><![CDATA[PublicKeyCredentialCreationOptions::createFromArray($this->session->get(self::WEBAUTHN_REGISTRATION))]]></code>
2343-
</DeprecatedMethod>
2344-
</file>
23452340
<file src="apps/settings/lib/Hooks.php">
23462341
<DeprecatedMethod>
23472342
<code><![CDATA[getAppValue]]></code>
@@ -3205,7 +3200,6 @@
32053200
</file>
32063201
<file src="core/Controller/WebAuthnController.php">
32073202
<DeprecatedMethod>
3208-
<code><![CDATA[PublicKeyCredentialRequestOptions::createFromString($this->session->get(self::WEBAUTHN_LOGIN))]]></code>
32093203
<code><![CDATA[Util::emitHook(
32103204
'\OCA\Files_Sharing\API\Server2Server',
32113205
'preLoginNameUsedAsUserName',

core/Controller/WebAuthnController.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
use OCP\AppFramework\Http\Attribute\FrontpageRoute;
1919
use OCP\AppFramework\Http\Attribute\PublicPage;
2020
use OCP\AppFramework\Http\Attribute\UseSession;
21+
use OCP\AppFramework\Http\DataDisplayResponse;
2122
use OCP\AppFramework\Http\JSONResponse;
23+
use OCP\AppFramework\Http\Response;
2224
use OCP\IRequest;
2325
use OCP\ISession;
2426
use OCP\Util;
2527
use Psr\Log\LoggerInterface;
26-
use Webauthn\PublicKeyCredentialRequestOptions;
2728

2829
class WebAuthnController extends Controller {
2930
private const string WEBAUTHN_LOGIN = 'webauthn_login';
@@ -44,7 +45,7 @@ public function __construct(
4445
#[PublicPage]
4546
#[UseSession]
4647
#[FrontpageRoute(verb: 'POST', url: 'login/webauthn/start')]
47-
public function startAuthentication(string $loginName): JSONResponse {
48+
public function startAuthentication(string $loginName): Response {
4849
$this->logger->debug('Starting WebAuthn login');
4950

5051
$this->logger->debug('Converting login name to UID');
@@ -57,10 +58,12 @@ public function startAuthentication(string $loginName): JSONResponse {
5758
$this->logger->debug('Got UID: ' . $uid);
5859

5960
$publicKeyCredentialRequestOptions = $this->webAuthnManger->startAuthentication($uid, $this->request->getServerHost());
60-
$this->session->set(self::WEBAUTHN_LOGIN, json_encode($publicKeyCredentialRequestOptions));
61+
$this->session->set(self::WEBAUTHN_LOGIN, $publicKeyCredentialRequestOptions);
6162
$this->session->set(self::WEBAUTHN_LOGIN_UID, $uid);
6263

63-
return new JSONResponse($publicKeyCredentialRequestOptions);
64+
$response = new DataDisplayResponse($publicKeyCredentialRequestOptions);
65+
$response->addHeader('Content-Type', 'application/json; charset=utf-8');
66+
return $response;
6467
}
6568

6669
#[PublicPage]
@@ -75,7 +78,7 @@ public function finishAuthentication(string $data): JSONResponse {
7578
}
7679

7780
// Obtain the publicKeyCredentialOptions from when we started the registration
78-
$publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions::createFromString($this->session->get(self::WEBAUTHN_LOGIN));
81+
$publicKeyCredentialRequestOptions = $this->session->get(self::WEBAUTHN_LOGIN);
7982
$uid = $this->session->get(self::WEBAUTHN_LOGIN_UID);
8083
$authenticatorData = $this->webAuthnManger->finishAuthentication($publicKeyCredentialRequestOptions, $data, $uid);
8184

lib/composer/composer/InstalledVersions.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ public static function getRawData()
277277
if (null === self::$installed) {
278278
// only require the installed.php file if this file is loaded from its dumped location,
279279
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
280-
if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
280+
if (substr(__DIR__, -8, 1) !== 'C') {
281281
self::$installed = include __DIR__ . '/installed.php';
282282
} else {
283283
self::$installed = array();
@@ -378,7 +378,7 @@ private static function getInstalled()
378378
if (null === self::$installed) {
379379
// only require the installed.php file if this file is loaded from its dumped location,
380380
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
381-
if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
381+
if (substr(__DIR__, -8, 1) !== 'C') {
382382
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
383383
$required = require __DIR__ . '/installed.php';
384384
self::$installed = $required;
Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,68 @@
11
{
2-
"packages": [],
3-
"dev": false,
4-
"dev-package-names": []
2+
"packages": [
3+
{
4+
"name": "bamarni/composer-bin-plugin",
5+
"version": "1.9.1",
6+
"version_normalized": "1.9.1.0",
7+
"source": {
8+
"type": "git",
9+
"url": "https://github.com/bamarni/composer-bin-plugin.git",
10+
"reference": "641d0663f5ac270b1aeec4337b7856f76204df47"
11+
},
12+
"dist": {
13+
"type": "zip",
14+
"url": "https://api.github.com/repos/bamarni/composer-bin-plugin/zipball/641d0663f5ac270b1aeec4337b7856f76204df47",
15+
"reference": "641d0663f5ac270b1aeec4337b7856f76204df47",
16+
"shasum": ""
17+
},
18+
"require": {
19+
"composer-plugin-api": "^2.0",
20+
"php": "^7.2.5 || ^8.0"
21+
},
22+
"require-dev": {
23+
"composer/composer": "^2.2.26",
24+
"ext-json": "*",
25+
"phpstan/extension-installer": "^1.1",
26+
"phpstan/phpstan": "^1.8 || ^2.0",
27+
"phpstan/phpstan-phpunit": "^1.1 || ^2.0",
28+
"phpunit/phpunit": "^8.5 || ^9.6 || ^10.0",
29+
"symfony/console": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
30+
"symfony/finder": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0",
31+
"symfony/process": "^2.8.52 || ^3.4.35 || ^4.4 || ^5.0 || ^6.0"
32+
},
33+
"time": "2026-02-04T10:18:12+00:00",
34+
"type": "composer-plugin",
35+
"extra": {
36+
"class": "Bamarni\\Composer\\Bin\\BamarniBinPlugin"
37+
},
38+
"installation-source": "dist",
39+
"autoload": {
40+
"psr-4": {
41+
"Bamarni\\Composer\\Bin\\": "src"
42+
}
43+
},
44+
"notification-url": "https://packagist.org/downloads/",
45+
"license": [
46+
"MIT"
47+
],
48+
"description": "No conflicts for your bin dependencies",
49+
"keywords": [
50+
"composer",
51+
"conflict",
52+
"dependency",
53+
"executable",
54+
"isolation",
55+
"tool"
56+
],
57+
"support": {
58+
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
59+
"source": "https://github.com/bamarni/composer-bin-plugin/tree/1.9.1"
60+
},
61+
"install-path": "../bamarni/composer-bin-plugin"
62+
}
63+
],
64+
"dev": true,
65+
"dev-package-names": [
66+
"bamarni/composer-bin-plugin"
67+
]
568
}

lib/composer/composer/installed.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@
33
'name' => '__root__',
44
'pretty_version' => 'dev-master',
55
'version' => 'dev-master',
6-
'reference' => '671cec33f134e670bb21c5e3c49c685bd78fc339',
6+
'reference' => 'e8ef2d85a1995cb8f707a0f21f7ec8ad63b0162d',
77
'type' => 'library',
88
'install_path' => __DIR__ . '/../../../',
99
'aliases' => array(),
10-
'dev' => false,
10+
'dev' => true,
1111
),
1212
'versions' => array(
1313
'__root__' => array(
1414
'pretty_version' => 'dev-master',
1515
'version' => 'dev-master',
16-
'reference' => '671cec33f134e670bb21c5e3c49c685bd78fc339',
16+
'reference' => 'e8ef2d85a1995cb8f707a0f21f7ec8ad63b0162d',
1717
'type' => 'library',
1818
'install_path' => __DIR__ . '/../../../',
1919
'aliases' => array(),
2020
'dev_requirement' => false,
2121
),
22+
'bamarni/composer-bin-plugin' => array(
23+
'pretty_version' => '1.9.1',
24+
'version' => '1.9.1.0',
25+
'reference' => '641d0663f5ac270b1aeec4337b7856f76204df47',
26+
'type' => 'composer-plugin',
27+
'install_path' => __DIR__ . '/../bamarni/composer-bin-plugin',
28+
'aliases' => array(),
29+
'dev_requirement' => true,
30+
),
2231
),
2332
);

lib/private/Authentication/WebAuthn/CredentialRepository.php

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,41 @@
1212
use OC\Authentication\WebAuthn\Db\PublicKeyCredentialEntity;
1313
use OC\Authentication\WebAuthn\Db\PublicKeyCredentialMapper;
1414
use OCP\AppFramework\Db\IMapperException;
15-
use Webauthn\PublicKeyCredentialSource;
16-
use Webauthn\PublicKeyCredentialSourceRepository;
15+
use Webauthn\CredentialRecord;
1716
use Webauthn\PublicKeyCredentialUserEntity;
1817

19-
class CredentialRepository implements PublicKeyCredentialSourceRepository {
18+
class CredentialRepository {
2019
public function __construct(
2120
private PublicKeyCredentialMapper $credentialMapper,
2221
) {
2322
}
2423

25-
#[\Override]
26-
public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource {
24+
public function findOneByCredentialId(string $publicKeyCredentialId): ?CredentialRecord {
2725
try {
2826
$entity = $this->credentialMapper->findOneByCredentialId($publicKeyCredentialId);
29-
return $entity->toPublicKeyCredentialSource();
27+
return $entity->toCredentialRecord();
3028
} catch (IMapperException $e) {
3129
return null;
3230
}
3331
}
3432

3533
/**
36-
* @return PublicKeyCredentialSource[]
34+
* @return CredentialRecord[]
3735
*/
38-
#[\Override]
3936
public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array {
40-
$uid = $publicKeyCredentialUserEntity->getId();
37+
$uid = $publicKeyCredentialUserEntity->id;
4138
$entities = $this->credentialMapper->findAllForUid($uid);
4239

4340
return array_map(function (PublicKeyCredentialEntity $entity) {
44-
return $entity->toPublicKeyCredentialSource();
41+
return $entity->toCredentialRecord();
4542
}, $entities);
4643
}
4744

48-
public function saveAndReturnCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource, ?string $name = null, bool $userVerification = false): PublicKeyCredentialEntity {
45+
public function saveCredentialSource(CredentialRecord $credentialRecord, ?string $name = null, bool $userVerification = false): PublicKeyCredentialEntity {
4946
$oldEntity = null;
5047

5148
try {
52-
$oldEntity = $this->credentialMapper->findOneByCredentialId($publicKeyCredentialSource->getPublicKeyCredentialId());
49+
$oldEntity = $this->credentialMapper->findOneByCredentialId($credentialRecord->publicKeyCredentialId);
5350
} catch (IMapperException $e) {
5451
}
5552

@@ -59,7 +56,7 @@ public function saveAndReturnCredentialSource(PublicKeyCredentialSource $publicK
5956
$name = 'default';
6057
}
6158

62-
$entity = PublicKeyCredentialEntity::fromPublicKeyCrendentialSource($name, $publicKeyCredentialSource, $userVerification);
59+
$entity = PublicKeyCredentialEntity::fromCredentialRecord($name, $userVerification, $credentialRecord);
6360

6461
if ($oldEntity) {
6562
$entity->setId($oldEntity->getId());
@@ -75,9 +72,4 @@ public function saveAndReturnCredentialSource(PublicKeyCredentialSource $publicK
7572

7673
return $this->credentialMapper->insertOrUpdate($entity);
7774
}
78-
79-
#[\Override]
80-
public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource, ?string $name = null): void {
81-
$this->saveAndReturnCredentialSource($publicKeyCredentialSource, $name);
82-
}
8375
}

lib/private/Authentication/WebAuthn/Db/PublicKeyCredentialEntity.php

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
use JsonSerializable;
1313
use OCP\AppFramework\Db\Entity;
14-
use Webauthn\PublicKeyCredentialSource;
14+
use Webauthn\CredentialRecord;
1515

1616
/**
1717
* @since 19.0.0
@@ -53,22 +53,36 @@ public function __construct() {
5353
$this->addType('userVerification', 'boolean');
5454
}
5555

56-
public static function fromPublicKeyCrendentialSource(string $name, PublicKeyCredentialSource $publicKeyCredentialSource, bool $userVerification): PublicKeyCredentialEntity {
56+
public static function fromCredentialRecord(string $name, bool $userVerification, CredentialRecord $record) {
5757
$publicKeyCredentialEntity = new self();
5858

5959
$publicKeyCredentialEntity->setName($name);
60-
$publicKeyCredentialEntity->setUid($publicKeyCredentialSource->getUserHandle());
61-
$publicKeyCredentialEntity->setPublicKeyCredentialId(base64_encode($publicKeyCredentialSource->getPublicKeyCredentialId()));
62-
$publicKeyCredentialEntity->setData(json_encode($publicKeyCredentialSource));
60+
$publicKeyCredentialEntity->setUid($record->userHandle);
61+
$publicKeyCredentialEntity->setPublicKeyCredentialId(base64_encode($record->publicKeyCredentialId));
62+
$publicKeyCredentialEntity->setData(json_encode($record));
6363
$publicKeyCredentialEntity->setUserVerification($userVerification);
6464

6565
return $publicKeyCredentialEntity;
6666
}
6767

68-
public function toPublicKeyCredentialSource(): PublicKeyCredentialSource {
69-
return PublicKeyCredentialSource::createFromArray(
70-
json_decode($this->getData(), true)
68+
public function toCredentialRecord(): CredentialRecord {
69+
$data = json_decode($this->getData(), true, flags: JSON_THROW_ON_ERROR);
70+
$record = CredentialRecord::create(
71+
$this->publicKeyCredentialId,
72+
$data['type'],
73+
$data['transports'],
74+
$data['attestationType'],
75+
$data['trustPath'],
76+
$data['aaguid'],
77+
$data['credentialPublicKey'],
78+
$data['userHandle'],
79+
$data['counter'],
80+
$data['otherUI'] ?? null,
81+
$data['backupEligible'] ?? null,
82+
$data['backupStatus'] ?? null,
83+
$data['uvInitialized'] ?? null
7184
);
85+
return $record;
7286
}
7387

7488
/**

0 commit comments

Comments
 (0)